PHP: ship intl as an optional ICU-backed side module#839
Merged
brandonpayton merged 12 commits intoJul 12, 2026
Conversation
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| icu | wasm32 | built | 89ba9e6e |
| libcurl | wasm32 | built | 608a2cd0 |
| libcxx | wasm32 | built | b4e54a56 |
| libcxx | wasm64 | built | 3787dc5e |
| libiconv | wasm32 | built | 99619c53 |
| libpng | wasm32 | built | c11fe7a3 |
| libxml2 | wasm32 | built | d37e55b0 |
| libzip | wasm32 | built | 1548aa2c |
| openssl | wasm32 | built | 3bef3b47 |
| openssl | wasm64 | built | dd55f594 |
| sqlite | wasm32 | built | acaab402 |
| sqlite | wasm64 | built | d8c4bd83 |
| zlib | wasm32 | built | c2644c11 |
| zlib | wasm64 | built | 0a92e1fd |
| bc | wasm32 | built | a59b6b69 |
| bzip2 | wasm32 | built | 949ff502 |
| coreutils | wasm32 | built | 39a3cc51 |
| curl | wasm32 | built | e8f5ddda |
| dash | wasm32 | built | 3d50460e |
| diffutils | wasm32 | built | 85b92dde |
| dinit | wasm32 | built | 221fe8bc |
| fbdoom | wasm32 | built | 47c37ec5 |
| file | wasm32 | built | 15fcd9b9 |
| findutils | wasm32 | built | b9c0c6e3 |
| gawk | wasm32 | built | f6930ef0 |
| git | wasm32 | built | 0012c03b |
| grep | wasm32 | built | 93876756 |
| gzip | wasm32 | built | 6599b79a |
| hello | wasm32 | built | 65f94017 |
| kandelo-sdk | wasm32 | built | eebd138c |
| kernel | wasm32 | built | b697326f |
| less | wasm32 | built | e5fd4d44 |
| lsof | wasm32 | built | c6f6fc76 |
| m4 | wasm32 | built | 93e9875c |
| make | wasm32 | built | 49c532f3 |
| mariadb | wasm32 | built | bd8b7ee5 |
| mariadb | wasm64 | built | 7b3053c7 |
| modeset | wasm32 | built | 80aa3f6a |
| msmtpd | wasm32 | built | 5bca0f0b |
| nano | wasm32 | built | ad03e346 |
| ncurses | wasm32 | built | e67397eb |
| netcat | wasm32 | built | fb699a1f |
| nginx | wasm32 | built | 2c296da1 |
| php | wasm32 | built | 8e2b6815 |
| posix-utils-lite | wasm32 | built | 3830adcc |
| ruby | wasm32 | built | bf41a46b |
| sed | wasm32 | built | 43edede7 |
| spidermonkey | wasm32 | built | 608a829f |
| tar | wasm32 | built | 2d39220c |
| tcl | wasm32 | built | d0336feb |
| unzip | wasm32 | built | 990b360f |
| userspace | wasm32 | built | 1f3f8b39 |
| vim | wasm32 | built | 678b22ef |
| wget | wasm32 | built | f0503b24 |
| xz | wasm32 | built | 7ef7ea7e |
| zip | wasm32 | built | 55ee3121 |
| zstd | wasm32 | built | db024284 |
| bash | wasm32 | built | e5c92cbf |
| mariadb-test | wasm32 | built | cbb09e63 |
| mariadb-vfs | wasm32 | built | bfeb6b22 |
| mariadb-vfs | wasm64 | built | a351a119 |
| nethack | wasm32 | built | 5df5f220 |
| node | wasm32 | built | 6e2568ea |
| spidermonkey-node | wasm32 | built | e9571a92 |
| vim-browser-bundle | wasm32 | built | f74d5f17 |
| nethack-browser-bundle | wasm32 | built | 86775d63 |
| rootfs | wasm32 | built | d7a30a3f |
| shell | wasm32 | built | aa96fffe |
| lamp | wasm32 | built | aadd9846 |
| node-vfs | wasm32 | built | ff759795 |
| wordpress | wasm32 | built | e676ab95 |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
mho22
added a commit
that referenced
this pull request
Jul 2, 2026
## Why - The ICU package's Stage-1 HOST build compiles the native data tools (genrb/pkgdata/icupkg/…) with the dev-shell clang++. On the Nix Linux CI runner those tools link the GNU C++/GCC runtime dynamically, but `libstdc++.so.6` is not on the runner's loader path, so they abort at exec with "error while loading shared libraries: libstdc++.so.6: cannot open shared object file". - Stage 2's `make` invokes icupkg/pkgdata to package the ICU common data, so an unrunnable host tool fails the ICU build itself — which reddened `lib-matrix-build (icu, wasm32)` and every job that depends on icu (`matrix-build (wasm32, php)`, `lamp`, `wordpress`) on PR #839. - macOS did not surface this: local clang links a self-contained libc++, so a macOS from-source build (or a reused macOS cache) never exercises the Linux host-tool loader linkage. ## What - **packages/registry/icu/build-icu.sh** — on Linux, pass `-static-libstdc++ -static-libgcc` as the Stage-1 host LDFLAGS so the C++/GCC runtime is folded into each data tool and no runtime `.so` is needed. The flags are Linux-guarded because macOS clang links libc++ and rejects them; `runConfigureICU` re-exports the pre-set LDFLAGS to configure, so setting them here reaches the host tool link. - **packages/registry/icu/build.toml** — bump revision 3 → 4 so CI rebuilds and re-stages icu from source. ## Validation - `bash -n packages/registry/icu/build-icu.sh` passes. - Linux from-source validation is deferred to CI (matrix-build rebuilds icu from source on the Nix Linux runner); it was not run locally because this Mac cannot reproduce the Linux host-tool linkage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 10, 2026
Introduce the initial ICU and PIC libc++ package outputs, C++ weak-self-import coverage, and the PHP intl side-module link path while keeping ICU data outside the base PHP executable. Follow-up commits in this serial reconcile the ABI-19 build, fail-closed linker behavior, reproducibility, runtime closure, fork replay, and host/browser validation. This commit intentionally makes no standalone completion or validation claim. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ICU's native Stage-1 data tools must execute during the cross build. On the Nix Linux runner, link their libstdc++ and libgcc runtimes statically so Stage 2 does not depend on loader paths for host runtime shared libraries; keep the flags Linux-only because the macOS toolchain rejects them. Linux execution evidence remains the responsibility of the later package rebuild/CI validation in this serial. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ICU previously left its common data and pkg-config files outside the declared library output contract, embedded the resolver temporary prefix in libicuuc.a, and relied on undeclared native build tools. The libcxx revision provenance also pointed at a fork commit that did not contain the published PIC recipe. Add a backward-compatible outputs.files contract with parse, cache-key, missing-output, and accepted-output coverage. Declare ICU data/pkg-config outputs and host probes, build from a clean verified source tree, and compile the fallback data path as /usr/lib/php so clean archives are stable. Keep existing package keys unchanged when files is absent, and mark the ICU/libcxx producer revisions as unpublished Automattic work. Validation: the four focused runtime-file xtask tests passed; build-deps check reported 10 consistent tools across four consumers; the six ICU tools matched the dev-shell versions. Two clean ICU rev5 builds produced byte-identical four archives, 197 headers, and icu.dat; resolver validation accepted all declared outputs and rewrote the three .pc prefixes to the canonical cache path. Two clean libcxx rev6 builds in distinct cache locations produced byte-identical four archives and 1,680 headers. Scope limits: the clean producer comparisons were run on macOS/aarch64 in the repository dev shell. The repaired Linux host-tool build is not re-claimed here beyond the original PR CI evidence, and performance was not measured.
The original intl linker change synthesized delayed stubs for every missing env function. That can hide real ABI gaps on unexecuted paths, while name-only self-import detection can also mistake an imported-function re-export for a definition and recurse through its own trampoline. Preserve Batch 2 transactional and fork-replay behavior. Supply a trampoline only when the export section proves the same-name function index is module-defined, keep main-module interposition first, and leave every other unresolved import as an eager instantiation failure. At this point in the serial, provide the wasm-exceptions C++ tag required by the intl side module. Validation: host type generation passed; host/test/dylink.test.ts passed 37/37, including genuine self-definition, missing import, imported-function re-export, C++ tag, rollback, and fork-replay cases. The built ABI-19 intl.so had zero unresolved env/GOT symbols under this rule, and all four real PHP intl Node/kernel cases passed after the stricter index check. Scope limits: this intermediate commit creates the C++ tag at the side-module linker boundary. The later process-state replay commit in this same landing serial deliberately supersedes that ownership model with one process-owned tag and adds cross-side identity coverage. Browser behavior is validated later; performance was not measured.
The original recipe was based on an older PHP tree, linked into the package source directory, and masked make failures with `|| true`. On the reconciled ABI-19 recipe that could publish a partial module: the first strict attempt exposed that only one newline-delimited object had been consumed. Preserve PHP 8.3.15, GNU libiconv, the Batch 2 extensions, forced shared-libc symbols, and fork instrumentation. Add ICU/libcxx as direct resolver dependencies, build every generated shared_objects_intl target without invoking the unsupported libtool link, then link all PIC objects and declared ICU/libcxx archives into OUT_DIR/intl.so. Reserve PHP revision 13 for the serial zip(11), curl(12), intl(13) Batch 3 order. Make the Node data fixture prefer an explicit resolved ICU file and restrict its cache fallback to the current ICU version/revision. Validation: a clean ABI-19 source resolve built 70 intl PIC objects and a 5,860,812-byte side module; php, php-fpm, opcache, phar, and zend_test were byte-identical across two clean temporary builds. The link consumed both libcxx PIC archives, and static inspection found all 3,040 intl imports resolved by PHP, the side module, or linker-owned objects. The focused Node/kernel suite passed 4/4: base PHP excludes intl, explicit loading succeeds, Locale reads icu.dat, and Collator applies locale rules. Scope limits: this evidence is for #839 on the ABI-19 Batch 2 base. The final #647 -> #648 -> #839 serial tree and real browser path are validated separately before recommendation. This adds no kernel/process ABI shape, so no ABI bump or snapshot change is included; performance was not measured.
Instantiation alone did not prove that the host supplied the C++ exception tag with the expected payload signature, and synthetic fork-state tests did not prove that ICU common-data state survives replay of a real PHP side module. Make the WAT fixture throw and catch an i32 payload through env.__cpp_exception. Add a PHP case that loads intl and icu.dat before pcntl_fork, calls an ICU-backed Locale API in the replayed child, calls Locale and Collator again in the parent, and verifies wait/exit status. Validation: with the ABI-19 sysroot present, host/test/dylink.test.ts passed 37/37. packages/registry/php/test/php-intl.test.ts passed 5/5 against the resolver-built PHP/intl/ICU artifacts; the fork-replay case completed in both branches and reaped a zero-status child. Scope limits: this commit records Node/kernel evidence. The equivalent Chromium path is added and run only on the exact landed #647 -> #648 -> #839 serial tree; it is not claimed here.
libc++abi archive members retained the absolute checkout path because both PIC
and non-PIC CMake builds lacked compiler prefix maps. ICU metadata was likewise
rewritten from the resolver temporary prefix to one producer cache path, so
fetched or moved archives still pointed back to the build machine.
Map the entire worktree, including assembled LLVM sources, both build variants,
the smoke source, and sysroots, to /usr/src/kandelo in libcxx compiler paths and
advance it to revision 7. Rewrite ICU pkg-config prefix fields to
${pcfiledir}/../.. and advance it to revision 6, keeping headers and libraries
relative to each extracted package tree.
Validation: two libcxx revision-7 builds from distinct checkout/output roots
produced byte-identical PIC and non-PIC archives, and producer-path scans were
clean. Two ICU revision-6 builds from distinct roots produced byte-identical
declared archives and icu.dat. After moving an ICU prefix, pkg-config resolved
the relocated include/library paths and a consumer compile/link succeeded.
Scope limits: the reproducibility and relocation checks ran on macOS/aarch64 in
the repository dev shell. Linux host-tool execution, the final PHP package,
Node/browser runtime behavior, and aggregate gates are validated by later
commits; performance was not measured.
Problem: program manifests could describe only executable outputs, leaving required data blobs outside cache keys, archives, local mirrors, fetched-artifact validation, and VFS installation metadata. Existing archive collection could also follow external/cyclic symlinks, and unvalidated package/output paths could escape or collide in the mirror. Design: add a program-only runtime_files contract with normalized artifact and absolute guest paths, mode metadata, length-framed cache-key fields, exact nested-artifact lookup, collision checks, and regular-file validation on build/cache/fetch paths. Archive staging dereferences only contained symlinks and rejects escapes, cycles, specials, empty declared trees, and incomplete closures. Local and fetched materialization use one package-scoped mirror layout and a structured repository-build query. Compatibility: manifests with no runtime_files retain their historical cache keys. The previously additive library outputs.files section is versioned and length-framed now, before its first published consumer, while older output sections retain their encoding for cache compatibility. Focused evidence: pkg_manifest tests passed 112/112; archive_stage tests passed 8/8; runtime-filtered tests passed 19/19; delimiter framing, fetched/source mirror parity, incomplete-archive fallback/fetch-only failure, nested paths, collisions, and symlink safety are covered. The full xtask run reached 336 passed and the same 7 pre-existing malformed-Wasm/filename fixture failures observed on the base. Limits: shell helper syntax and host resolver precedence passed, but the full aggregate package build, published-archive round trip, full host/libc gate, and browser gate have not run. The metadata helper is a repository build/materialization API, not a guest or runtime host API.
Problem: replay instantiated a fresh side module without restoring its live TLS-base global, and each module could receive a different C++ exception-tag identity. Pthread workers also have separate instances, tables, and tags, so allowing them to race process dlopen or inherit the process archive could corrupt replay. Design: keep process-owned pointer-width-correct exception/longjmp tags, archive and validate each module's exact positive TLS base, restore only that global over the fork-copied live TLS bytes, and arbitrate process dlopen against pthread fork with a host-private atomic record. Pthread dlopen now fails through dlerror; pthread fork returns ENOTSUP once the process archive is nonempty. Focused evidence: host declaration generation passed; dylink plus binary-resolver Vitest ran 33 tests passed with 16 compiler-dependent skips; the compiled fork/dlopen replay file ran 3/3, including mutated C++ thread_local state plus throw/catch and the real pthread boundary. Limits: the i64 cases exercise 64-bit pointer encoding only, not a memory64 end-to-end runtime. The full host, libc, ABI-classifier, and real browser aggregate gates have not yet run. The archive-size change is intended to remain host-private and transient; the ABI check is still required before landing.
Problem: intl.so needs an ICU data blob at runtime, but the original branch relied on cache scanning and host-only path overrides. That made local, fetched, Node, VFS, and browser executions observe different closures and allowed a present extension to run without its matching data. Design: PHP copies the exact resolver-selected ICU data into its program archive as a declared runtime file at /usr/lib/php/icu.dat. Repository image/test builders query structured package metadata for the guest path and mode, fail when intl exists without its closure, and exercise the same resolver-selected bytes on Node and browser. The PHP build exports __tls_base for fork-safe side-module replay and tracks the loader source as a cache-key input. Focused evidence: runtime metadata resolved to php/icu.dat, /usr/lib/php/icu.dat, mode 0644; the local mirror is byte-identical to both reproducible ICU rev6 outputs; shell syntax, host declarations, and the PHP browser Vite bundle passed. The dev middleware served all 30,782,896 ICU bytes and returned 400 for dot, encoded-dot, and malformed-percent artifact paths. The base-PHP focused case passed against an ABI-19 base-manifest image. Limits: the four intl runtime cases intentionally remain unvalidated on the stale cached intl.so, which the repaired host correctly rejects because it does not export mutable __tls_base. A fresh PHP rebuild, artifact inspection, Node intl/fork tests, real Chromium run, and full aggregate gates are still required. The focused base-manifest rootfs omitted unrelated lazy package entries and is not canonical browser evidence.
Reject unsafe manifest and dependency path components before registry, cache, and archive interpolation, and make package.toml's top-level schema fail closed so a misspelled runtime_files declaration cannot disappear silently. Expose every program output and runtime file in structured runtime metadata. Resolve the complete set from one local, fetched, or installed-package root, allowing whole-tier fallback while refusing mixed partial closures. Route the PHP Node, VFS, and browser consumers through that selected closure. Validation: - pkg_manifest focused suite: 116 passed - runtime metadata focused test: 1 passed - binary resolver/runtime metadata Vitest: 14 passed - live build-deps manifest check: passed - host declaration build: passed - PHP browser Vite production build: passed with ABI-19 kernel/rootfs fixtures - ABI snapshot/version check: passed - full xtask suite: 342 passed; the same 7 pre-existing archive/program fixture failures remain The full host, libc, PHPT, and manual browser suites were not run for this focused repair. Performance was not measured.
Make the shared VFS image writer honor positive partial writes until all bytes are staged, reject zero/negative/invalid progress, and close its descriptor on every exit path. Route the browser-demo wrappers through that shared implementation. Give the Node PHP intl fixture a 256 MiB rebased filesystem before adding the 30.8 MB ICU data file and verify the staged bytes by size and SHA-256. Preserve the browser fixture's proven 256 MiB growable restore and byte-check its injected side-module/runtime fixtures without re-reading the large PHP executable on every invocation. Validation: - focused VFS image-helper tests: 5 passed - exact ABI-19 PHP intl Node suite: 5 passed, including ICU data and fork replay - exact ABI-19 Chromium intl/fork case: 1 passed - host declaration build: passed - PHP browser Vite production build: passed The full browser app typecheck was attempted and remains blocked by pre-existing unrelated type errors. Its production build was attempted and remains blocked by absent coreutils/node/nc binary assets in this isolated worktree. The full host, libc, and manual browser suites were not run. Performance was not measured.
9aaf2aa to
5ec4d89
Compare
e6d080f
into
integration/kd-6nz-php-extensions
2 checks passed
brandonpayton
added a commit
that referenced
this pull request
Jul 12, 2026
The original recipe was based on an older PHP tree, linked into the package source directory, and masked make failures with `|| true`. On the reconciled ABI-19 recipe that could publish a partial module: the first strict attempt exposed that only one newline-delimited object had been consumed. Preserve PHP 8.3.15, GNU libiconv, the Batch 2 extensions, forced shared-libc symbols, and fork instrumentation. Add ICU/libcxx as direct resolver dependencies, build every generated shared_objects_intl target without invoking the unsupported libtool link, then link all PIC objects and declared ICU/libcxx archives into OUT_DIR/intl.so. Reserve PHP revision 13 for the serial zip(11), curl(12), intl(13) Batch 3 order. Make the Node data fixture prefer an explicit resolved ICU file and restrict its cache fallback to the current ICU version/revision. Validation: a clean ABI-19 source resolve built 70 intl PIC objects and a 5,860,812-byte side module; php, php-fpm, opcache, phar, and zend_test were byte-identical across two clean temporary builds. The link consumed both libcxx PIC archives, and static inspection found all 3,040 intl imports resolved by PHP, the side module, or linker-owned objects. The focused Node/kernel suite passed 4/4: base PHP excludes intl, explicit loading succeeds, Locale reads icu.dat, and Collator applies locale rules. Scope limits: this evidence is for #839 on the ABI-19 Batch 2 base. The final #647 -> #648 -> #839 serial tree and real browser path are validated separately before recommendation. This adds no kernel/process ABI shape, so no ABI bump or snapshot change is included; performance was not measured.
brandonpayton
added a commit
that referenced
this pull request
Jul 12, 2026
Instantiation alone did not prove that the host supplied the C++ exception tag with the expected payload signature, and synthetic fork-state tests did not prove that ICU common-data state survives replay of a real PHP side module. Make the WAT fixture throw and catch an i32 payload through env.__cpp_exception. Add a PHP case that loads intl and icu.dat before pcntl_fork, calls an ICU-backed Locale API in the replayed child, calls Locale and Collator again in the parent, and verifies wait/exit status. Validation: with the ABI-19 sysroot present, host/test/dylink.test.ts passed 37/37. packages/registry/php/test/php-intl.test.ts passed 5/5 against the resolver-built PHP/intl/ICU artifacts; the fork-replay case completed in both branches and reaped a zero-status child. Scope limits: this commit records Node/kernel evidence. The equivalent Chromium path is added and run only on the exact landed #647 -> #648 -> #839 serial tree; it is not claimed here.
brandonpayton
added a commit
that referenced
this pull request
Jul 12, 2026
The #839 side-module repair gave each pthread fork exclusive ownership of the process dlopen lock. In the existing two-thread, 16-round concurrent-fork fixture, one thread therefore received ENOTSUP and left its peer blocked at the next barrier. Encode the unchanged host-private slot as an exclusive negative dlopen writer or a positive pthread-fork reader count. Concurrent empty-archive pthread forks can now snapshot in parallel, while dlopen remains excluded until every parent completes unwind, SYS_FORK, and rewind. Keep child reset, archive rejection, error releases, and ownership diagnostics explicit. Validation: the exact pre-#839 base passed the concurrent fixture while the prior aggregate timed out. On this repair, fork-from-thread plus dlopen/fork replay passed 5/5. Full host Vitest reached 1,251 passes, 2 expected failures, and 95 skips; its only two failures are the lazy-rootfs memory64/posix-utils fixtures reproduced on the exact base. Host declarations and the ABI consistency check passed. Browser behavior was not rerun for this host-only arbitration follow-up, and performance was not measured.
13 tasks
brandonpayton
pushed a commit
that referenced
this pull request
Jul 13, 2026
PHP intl needs reproducible ICU and libc++ inputs plus fail-closed C++ side-module linking before the host/guest replay contract can advance safely. Build PIC ICU/libc++ outputs without producer paths, declare non-Wasm runtime files explicitly, complete the initial intl.so link path, reject unresolved C++ imports, and cover exceptions and fork replay. This compatible setup intentionally precedes ABI 36; the next commit owns the incompatible replay-memory and pthread-fork contract, while the following PHP commit owns final ICU runtime-data materialization. Source-era package and focused runtime evidence is retained as review provenance, but the final ABI-38 artifact rebuild and complete Node/browser gate apply at the super-batch tip. Source-PR: #839 Source-PR: #894 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
brandonpayton
added a commit
that referenced
this pull request
Jul 13, 2026
intl.so needs the exact resolver-selected ICU data blob at runtime. Cache scanning and host-only path overrides made local, fetched, Node, VFS, and browser executions observe different closures and could leave a present extension without matching data. Copy the selected ICU data into the PHP program archive as declared /usr/lib/php/icu.dat state, keep general runtime files in one artifact tier, query structured package metadata from image/test builders, and reject incomplete VFS staging. The PHP consumers now follow the ABI-36 side-module replay contract established by the preceding epoch. Source-era evidence covers reproducible ICU/libc++ outputs, runtime metadata and byte identity, complete PHP artifacts, focused Node/browser intl behavior, and fail-closed stale-artifact handling. Those results are provenance rather than a claim about an ABI-19 artifact; final ABI-38 archives and broad gates remain the super-batch tip's responsibility. Pthread-side dynamic loading remains truthfully unsupported. Source-PR: #839 Source-PR: #894
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.
Purpose
Ship PHP's
intlextension as a runtime-optional C++ side module withoutadding ICU's roughly 30 MB common-data payload to every base PHP launch. The
extension, its matching
icu.dat, the host dynamic linker, fork replay, andthe package resolver must follow the same normal platform path on Node.js and
browser hosts.
This PR is the third constituent of stacked PHP extension Batch 3 (#894). It
targets
integration/kd-6nz-php-extensions; merging this PR incorporates itsreviewed commits into that still-open aggregate and does not merge anything to
main.What changed
archives, headers, pkg-config metadata, and ICU common data are declared,
relocation-safe, producer-path-free, and validated through the package
resolver.
intl.soat ABI 19. Basephp.wasmremains intl/ICU-free;icu.datis a declared non-Wasm runtimefile installed at
/usr/lib/php/icu.datthrough the normal package/VFSclosure.
allowed only for exports proven to be module-defined, while genuinely
missing imports fail eagerly.
preserved validated side-module TLS state across
fork()replay. Dynamicloading from pthread workers remains an explicit unsupported boundary rather
than racing process-owned replay state.
runtime_filespackage contract with cache, archive,materialization, path-safety, and structured-metadata coverage. Related
executable, side-module, and runtime-data outputs are selected atomically
from one complete local, fetched, or installed-package tier.
completion and zero/negative/invalid progress fails loudly. Node's intl
fixture rebases to a 256 MiB filesystem before adding ICU data; Node and
browser fixtures verify the staged runtime bytes.
Review repairs
The original two-commit branch was rebuilt as a 12-commit, purpose-led serial
on the exact Batch 3 tip while preserving the original author's two commits
and attribution. The review removed masked build failures, incomplete intl
object discovery, checkout-local outputs, cache scanning, host-only ICU path
overrides, permissive missing-import stubs, per-module exception tags,
unrestored TLS state, unsafe package/archive/output paths, mixed-provenance
runtime closures, and silent VFS truncation.
Validation
distinct roots produced byte-identical declared outputs; producer-path scans
were clean, and relocated ICU pkg-config metadata compiled and linked a
consumer.
linked all 70 intl objects, resolved the final import closure, retained ABI
19, and matched the installed local package mirror.
staging repair. Package manifest coverage passed 116 tests; focused
resolver/runtime metadata passed 14; VFS write-helper coverage passed 5/5.
The exact integrated candidate's focused closure/VFS/dylink/compiled-fork
and PHP hello/curl set passed 90/90.
base-PHP exclusion, explicit loading,
Locale,Collator, and parent/childfork replay. The complete real-Chromium PHP spec passed 2/2: the existing
inline/file/session/SQLite/fileinfo/XML/OpenSSL/ZIP/curl scenarios and the
new intl/ICU fork-replay scenario.
this PR does not add another ABI epoch beyond the Batch 2 ABI-19 base.
libc gate: 303 passed, 20 documented XFAIL, one known FLAKE-PASS, and zero
failures, build failures, timeouts, or unexpected passes.
checkout: seven failures disappeared when the verified ABI-19 test mirrors
were supplied, and the remaining two rootfs/lazy-exec fixture failures
reproduced identically on exact base
ec8b9e318with the same fixtures.The final aggregate Batch 3 gate and manual
./run.sh browserverificationremain aggregate work and are not claimed by this constituent review.
Boundaries
relies on the package CI path for Linux execution evidence.
memory64 end-to-end runtime run.
dlopenremains truthfully unsupported by this process-ownedmodel.
not claimed fixed.
Nothing in this PR or Batch 3 is authorized to merge to
mainwithoutBrandon's explicit approval.