merge: cascade 8.4 into master (windows x64, resolved) - #182
Merged
Conversation
Mirrors the darwin bootstrap: a "Generate windows headers" workflow builds
the windows-x64-{nts,zts} FFI definitions on real Windows runners (clang via
the MSVC INCLUDE environment) and commits them back to the branch, while CI
gains tests-windows and header-drift-windows legs that warn and skip until
the artifacts are committed. The FFI preflights bind the engine DLL
explicitly and prove __vectorcall (@@N-mangled) symbols resolve - the two
things Windows does differently from every POSIX platform.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
README gains windows-x64 (nts, zts) in the 8.4 support row; AGENTS.md gets a Windows artifacts section covering the four load-bearing platform differences (FFI_LIB/DLL binding, __vectorcall export mangling, devel-pack headers instead of php-config, ucrtbase free) and the #119 exclusions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Windows has no process-image symbol resolution, so Core::init() now passes
the engine DLL (php8.dll / php8ts.dll, already loaded by php.exe) to
FFI::cdef, which ignores the header's FFI_LIB define. platformKey()
lowercases php_uname('m') - Windows reports AMD64 and previously fell
through to a windows-AMD64-* key - and becomes public so the artifact tests
stop carrying their own copy of the mapping. persistentFree() binds
ucrtbase.dll on Windows: the PHP DLL does not export libc free, while
pemalloc draws from that same process-wide UCRT heap. PayloadRelocator
gains an isSupported() predicate so its tests can skip instead of erroring
on unsupported platforms (#118 ZTS, #119 Windows).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
ResidentMemory reports 0 (not measurable) on Windows instead of shelling out to a ps that does not exist; the rm -rf teardown in BinaryCacheFileTest becomes a portable recursive delete; the relocator suites skip via PayloadRelocator::isSupported() rather than erroring on the constructor guard; and the opcache.preload-dependent tests (ClassSpecializerShmTest, the preload leg of OpcacheSupportMatrixTest) plus the POSIX-path file-cache fixture skip on Windows, where preload does not exist and the cache layout differs (#119). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Ports the native pipeline to Windows. generate.php resolves the matching php-devel-pack from windows.php.net (releases.json, sha256-verified, cached in temp, --php-dev override, archives fallback) since Windows has no php-config; emit.php gains --include-dir to derive the -I set from the pack and passes -DZEND_WIN32/-DPHP_WIN32/-DWIN32/-D_MBCS (+-DZTS) explicitly - on Windows those come from build CFLAGS, not any header. All subprocess spawns move to proc_open argv arrays (no cmd.exe quoting, no POSIX-only shell builtins); the probe compiles with clang -o probe.exe and runs via cwd. The emitter converts clang's __attribute__((vectorcall)) qualType annotation into the __vectorcall keyword FFI mangles to the DLL's decorated name@@n exports (the attribute spelling is silently ignored by FFI), hard guards against zero-argument __vectorcall declarations (upstream FFI NULL-deref), and strips the MSVC-only tokens system headers leak while preserving __declspec(align). Windows headers carry FFI_LIB naming the engine DLL, 'free' leaves the Windows manifest (the DLL does not export the CRT), _iobuf joins the opaque libc types, and validate.php accepts the DLL so cdef eagerly resolves every declared function at generation time. Linux artifact generation stays byte-identical (verified against the committed linux-x64-nts artifacts after every refactor). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
proc_open resolves a relative program path against the parent's cwd on macOS, so './probe' with a cwd argument failed there with posix_spawn ENOENT - the absolute path works everywhere while cwd still controls where the probe writes its outputs. The Windows generation and drift jobs add ext-zip to setup-php: generate.php extracts the devel pack with ZipArchive, which Windows builds do not enable by default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Like the other Windows configuration macros it comes from the build's CFLAGS, not from any installed header. Preprocessing survived without it (#if reads an undefined macro as 0) but the probe uses ZEND_DEBUG as a C expression for the layouts meta, which needs a real definition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
… DLL in the raw-cdef scenario Three findings from the first real Windows test run (425 tests, 2 failures). clang's -E output goes through the CRT in text mode on Windows, so the sliced declarations carried CRLF into engine.h and tripped the drift check - pre.c is normalized before the AST pass so offsets and artifacts stay LF everywhere. EG(timed_out) reads back as a one-byte string on MSVC builds (the non-C11 atomic fallback stores a char), so isTimedOut() accepts that shape; the int-write in requestInterrupt() already works as proven by the passing interrupt tests. The throw-hook scenario's deliberate raw FFI::cdef now names the engine DLL on Windows, where process-image resolution does not exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
The generation workflow's commit lands with GITHUB_TOKEN and cannot retrigger CI itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
feat: Windows x64 platform support (#59)
…o-master-windows # Conflicts: # README.md # src/Core.php # tools/generator/generate.php
PHP 8.5's Windows overflow helpers call LongLongAdd/LongLongSub, but the engine headers only include <intsafe.h> for MSVC proper - under clang the calls parse as implicit declarations and fail both the AST pass and the probe compile. Both generated translation units now include it up front on Windows; POSIX output is untouched by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
The SDK's intsafe.h was in the translation unit all along (the unsigned ULongLong* helpers resolved fine); its signed variants (LongLongAdd &co, used by the 8.5 engine's overflow fast paths) sit behind ENABLE_INTSAFE_SIGNED_FUNCTIONS, which the real Windows PHP build defines in its CFLAGS. Pass the same define instead of force-including the header, which could never surface the guarded declarations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
lisachenko
marked this pull request as ready for review
August 8, 2026 22:01
This was referenced Aug 8, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves the conflicted automated cascade #181: merges the Windows x64 support from
8.4(#180, issue #59) intomaster, with the 8.5-line adaptations.Conflict resolutions
README.md: kept master's 8.5 row (with the darwin-x64-zts footnote) and addedwindows-x64 (nts, zts)to both the 8.5 and 8.4 rows.src/Core.php/tools/generator/generate.php: kept master's 8.5 examples in the docblocks, took 8.4's new content (@internalnote on the now-publicplatformKey(), the--php-dev=DIRoption).Master-line adaptations
.github/workflows/generate-windows-headers.yml:PHP_MINOR: '8.5'(the workflow reads it from the branch it runs on, exactly like the darwin one).AGENTS.mdWindows section closing reworded to the master phrasing: 8.4 artifacts live on8.4,include/8.5/windows-*is maintained here.Artifact bootstrap
This PR touches
tools/generator/**, so the "Generate windows headers" workflow runs against it with PHP 8.5 and its commit job pushesinclude/8.5/windows-x64-{nts,zts}/back to this branch (windows.php.net ships 8.5 x64 for both TS modes). The darwin workflow re-runs too and should find its 8.5 artifacts unchanged — the generator's Windows port keeps POSIX output byte-identical, which theheader-drift/header-drift-darwinjobs verify.Verification
origin/masterin the same environment (the known local opcache/SHM sandbox quirks) — the merge introduces zero regressions.tests-windowsandheader-drift-windowslive.🤖 Generated with Claude Code
https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Generated by Claude Code