Skip to content

merge: cascade 8.4 into master (windows x64, resolved) - #182

Merged
lisachenko merged 17 commits into
masterfrom
claude/cascade-8.4-into-master-windows
Aug 8, 2026
Merged

merge: cascade 8.4 into master (windows x64, resolved)#182
lisachenko merged 17 commits into
masterfrom
claude/cascade-8.4-into-master-windows

Conversation

@lisachenko

Copy link
Copy Markdown
Owner

Resolves the conflicted automated cascade #181: merges the Windows x64 support from 8.4 (#180, issue #59) into master, with the 8.5-line adaptations.

Conflict resolutions

  • README.md: kept master's 8.5 row (with the darwin-x64-zts footnote) and added windows-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 (@internal note on the now-public platformKey(), the --php-dev=DIR option).

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.md Windows section closing reworded to the master phrasing: 8.4 artifacts live on 8.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 pushes include/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 the header-drift/header-drift-darwin jobs verify.

Verification

  • Local merge tree under PHP 8.5.9: test-failure set byte-identical to pristine origin/master in the same environment (the known local opcache/SHM sandbox quirks) — the merge introduces zero regressions.
  • Lint + php-cs-fixer clean.
  • Full proof lands on CI once the 8.5 windows artifacts are committed by the generation workflow, with tests-windows and header-drift-windows live.

🤖 Generated with Claude Code

https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj


Generated by Claude Code

claude and others added 13 commits August 8, 2026 18:19
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
…o-master-windows

# Conflicts:
#	README.md
#	src/Core.php
#	tools/generator/generate.php
claude and others added 4 commits August 8, 2026 21:47
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
lisachenko marked this pull request as ready for review August 8, 2026 22:01
@lisachenko
lisachenko merged commit 4195cef into master Aug 8, 2026
27 checks passed
@lisachenko
lisachenko deleted the claude/cascade-8.4-into-master-windows branch August 8, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants