Skip to content

macOS support: native generator mode, darwin artifacts via macOS runners, macOS CI matrix (#58) - #174

Merged
lisachenko merged 5 commits into
8.4from
claude/z-engine-macos-support-nfq97b
Aug 8, 2026
Merged

macOS support: native generator mode, darwin artifacts via macOS runners, macOS CI matrix (#58)#174
lisachenko merged 5 commits into
8.4from
claude/z-engine-macos-support-nfq97b

Conversation

@lisachenko

@lisachenko lisachenko commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #58: macOS (darwin, x64 + arm64) support, NTS scope. The full bootstrap has completed on this branch — darwin artifacts are generated, committed, and validated, and every CI leg including the new macOS ones is green.

The runtime was already darwin-ready — Core::platformKey() resolves include/8.4/darwin-{arch}-nts/ on macOS, and emit.php derives OS/arch/TS from the running interpreter. What was missing was a way to produce the darwin artifacts: the generator's Docker orchestration can only ever emit linux artifacts (containers are Linux by construction). This PR closes that gap and wires macOS into the CI matrix.

What's in here

  • generate.php --native (auto-selected on non-Linux hosts): runs emit.php directly against the running PHP build. Preflights clang/cc/php-config/ext-ffi with actionable errors, fetches the three php-src files the pipeline slices for the exact running patch release, or accepts --php-src=DIR. Verified on linux-x64-nts: native regeneration reproduces the committed Docker artifacts byte-identically.
  • include/8.4/darwin-{x64,arm64}-nts/: the generated artifacts themselves, produced and committed by the workflow below from real macOS PHP 8.4.24 builds. Validation proved on both arches: the header parses under macOS FFI, every extern resolves from the php process image (no FFI_LIB needed — same as Linux), and all 39 struct layouts match the C compiler exactly.
  • HeaderEmitter: opaque typedefs now emit a synthesized bodyless typedef struct <tag> <name>; — Darwin declares FILE with the struct body inline, which previously dragged the whole libc __sFILE/__sbuf surface into the header. symbols.php adds __sFILE to the opaque union list (name-matched per platform; Linux output unchanged, proven by the linux header-drift job).
  • tests/Support/ResidentMemory: the flat-memory/leak-plateau tests sampled RSS from /proc/self/status; they now use a portable helper (procfs on Linux, ps -o rss= on macOS/BSD) — so those assertions genuinely run on macOS instead of skipping.
  • New workflow "Generate darwin headers": runs generate.php --native on macos-latest (arm64) and macos-15-intel (x64); a single downstream job commits both artifact dirs in one commit (no push race). Triggers on pull_request touching tools/generator/** (same-repo PRs) and workflow_dispatch for refreshes — the canonical way to regenerate darwin artifacts, documented in AGENTS.md.
  • CI matrix: new tests-macos legs (arm64 + x64) mirroring the Linux tests job — full suite, blocking opcache non-skip gate (the file-cache relocator passes on both darwin arches), worker-loop soak (flat at +32 bytes / 10k iterations) — plus header-drift-darwin legs that natively regenerate and diff each runner's own arch dir. Both guard on artifact presence so future branches without darwin artifacts warn instead of failing spuriously.
  • Docs: README support matrix (8.4 row now includes darwin-x64-nts, darwin-arm64-nts), AGENTS.md native-mode + darwin sections.

Acceptance (issue #58)

  • generate.php --native produces include/8.4/darwin-{x64,arm64}-nts/* (via the generation workflow)
  • ✅ The layout probe validates against real macOS PHP 8.4 builds on both arches
  • ✅ The default test suite passes on macOS in CI (all 425 tests, both arches)

Follow-ups (out of scope)

  • darwin ZTS artifacts (Homebrew/setup-php default is NTS)
  • darwin artifacts for the 8.5 line: master gets the tooling via merge-up; one workflow_dispatch run of "Generate darwin headers" on master once its generator is ready
  • Run the test suite on macOS (darwin x64 + arm64) zdebug#17 turns on macOS CI for zdebug and should merge after this PR (its macOS legs go green once this lands on 8.4, via Packagist 8.4.x-dev)

Closes #58

🤖 Generated with Claude Code

https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj

claude added 2 commits August 8, 2026 11:27
Docker containers are Linux by construction, so darwin-{x64,arm64}
artifacts need the pipeline to run directly on a macOS host.

- generate.php learns --native (auto-selected off Linux): preflights the
  toolchain, fetches the three php-src files emit.php slices, and runs
  emit.php against the running interpreter. Verified on linux-x64-nts:
  native regeneration is byte-identical to the committed Docker output.
- symbols.php marks Darwin's __sFILE opaque alongside glibc's _IO_FILE;
  the opaque list is a per-platform name-match union, so unmatched names
  never affect the emitted header.
- New "Generate darwin headers" workflow: generates on macos-latest
  (arm64) and macos-15-intel (x64), validates via the FFI/probe stage,
  and commits both artifact dirs back to the branch in one commit.
- CI gains tests-macos and header-drift-darwin matrix legs; both warn
  and skip until the darwin artifacts are committed, then run for real.
  The darwin opcache non-skip gate stays informational until proven.
- Docs: support matrix, AGENTS.md native/darwin sections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
Darwin declares FILE as "typedef struct __sFILE { ... } FILE;" with the
record body inline, so slicing the typedef's source dragged the full
libc body (and its by-value member types like struct __sbuf) into the
header, which FFI then failed to parse. glibc forward-declares the tag
separately, which is why the slice worked on Linux.

Opaque typedefs with a named underlying tag now emit a synthesized
"typedef struct <tag> <name>;" instead of the source slice. On glibc the
synthesized text is identical to the source, verified byte-identical by
native regeneration against the committed linux-x64-nts artifacts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
github-actions Bot and others added 2 commits August 8, 2026 11:33
The flat-memory tests read VmRSS from /proc/self/status through five
copies of the same closure; on macOS the missing procfs made file()
emit a warning, which failOnWarning turns into a failed run even with
all 425 tests passing. The new ZEngine\Support\ResidentMemory helper
keeps the VmRSS path on Linux (guarded, warning-free) and samples
`ps -o rss=` on macOS/BSD - so the RSS-based leak assertions now run
on darwin instead of skipping.

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 12:19
Both macOS legs pass the full opcache group (26 tests, including the
file-cache relocator) with --fail-on-skipped, so the temporary
continue-on-error comes off - the gate now guards darwin exactly like
the Linux NTS leg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188iU6pEvBQgtjPTXEdzHwj
@lisachenko
lisachenko merged commit 5c37a34 into 8.4 Aug 8, 2026
14 checks passed
@lisachenko
lisachenko deleted the claude/z-engine-macos-support-nfq97b branch August 8, 2026 12:24
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.

macOS support (darwin, x64 + arm64)

2 participants