How to run the php-compiler test gate on a developer machine or Runforge harness (#245). The full PHPUnit matrix remains CircleCI / local scripts (#394); GitHub Actions runs an optional bootstrap self-host gate on master only (see below).
Repository defaults live in script/ci-defaults.env:
| Variable | Default | Role |
|---|---|---|
PHP_COMPILER_MEMORY_LIMIT |
1536M |
PHP heap for PHPUnit and bin/vm.php children |
PHP_COMPILER_LLVM_MEMORY_LIMIT |
4096M |
LLVM compile phases in ci-local.sh |
PHP_COMPILER_CI_RAM_GB |
8 |
ulimit -v for the CI shell |
PHP_COMPILER_DOCKER_MEM |
10g |
Docker cgroup RAM cap |
PHP_COMPILER_VM_PEAK_RSS_MB |
2048 |
Kill VM subprocess if RSS exceeds this (when guard enabled) |
PHP_COMPILER_VM_RSS_GUARD |
1 in CI |
Wrap PHPT vm.php spawns with run-vm-guarded.sh |
Workflow: .github/workflows/bootstrap-selfhost.yml. Triggers on push and pull_request to master. Timeout 30 minutes.
| Step | Command |
|---|---|
| Checkout | actions/checkout@v4 |
| Bootstrap probe | make bootstrap-selfhost-probe |
| Native link | ./script/bootstrap-selfhost-link.sh |
| Wave gate | ./script/bootstrap-wave-check.sh --fail-fast |
Runner strategy
| Path | When | Setup |
|---|---|---|
Docker (default on ubuntu-22.04 runners) |
docker info succeeds |
Build or reuse php-compiler:22.04-dev (docker build -f Docker/dev/ubuntu-22.04/Dockerfile -t php-compiler:22.04-dev . in GHA; local devs may use make docker-build-22) |
| Host fallback | Docker unavailable | Ubuntu 22.04 + ppa:ondrej/php PHP 8.2 + ./script/install-llvm9.sh |
Both paths run composer install, script/apply-patches.sh, then the three bootstrap gates above. This workflow does not change default ci-local.sh / ci-fast.sh behavior locally.
Env vars (inherited from Docker image / script/ci-defaults.env when relevant):
| Variable | Role in workflow |
|---|---|
PHP_COMPILER_LLVM_PATH |
/opt/llvm9 in Docker; repo .llvm/ after install-llvm9.sh on host fallback |
PHP_COMPILER_MEMORY_LIMIT |
PHP heap during compile (default 1536M) |
PHP_COMPILER_LLVM_MEMORY_LIMIT |
LLVM compile phases (default 4096M) |
PHP_COMPILER_SELFHOST_AOT |
Set by probe/link scripts for stub gating |
BOOTSTRAP_WAVE_CHECK |
N/A in workflow (always runs wave-check); set 0 in ci-local.sh to skip locally |
Local equivalent (Docker):
docker run --rm -v "$(pwd):/compiler" -w /compiler php-compiler:22.04-dev bash -lc \
'make bootstrap-selfhost-probe && ./script/bootstrap-selfhost-link.sh && ./script/bootstrap-wave-check.sh'
Local equivalent (host, no Docker): composer install, ./script/install-llvm9.sh, then the same three commands.
| Goal | Host PHP + LLVM | Docker (recommended on harness) |
|---|---|---|
| Full gate (VM + JIT + AOT) | ./script/ci-local.sh |
make test or ./script/docker-ci-local.sh |
| Fast gate (no LLVM compile) | ./script/ci-fast.sh |
make test-fast or ./script/docker-ci-local.sh fast |
| Fast gate + bootstrap tail (optional) | CI_FAST_BOOTSTRAP=1 ./script/ci-fast.sh |
make test-fast-bootstrap |
| Fast gate + JIT preflight (optional) | JIT_PREFLIGHT_GATE=1 ./script/ci-fast.sh |
make test-fast-jit-preflight or make test-docker-fast-jit-preflight |
| Explicit memory-capped Docker | — | ./script/ci-docker-safe.sh ci-local.sh or make test-docker-safe |
| Single PHPUnit filter | Append args: ./script/ci-fast.sh --filter VMTest |
Same inside Docker wrappers |
Defaults are exported from script/ci-defaults.env and read by ci-local.sh, ci-fast.sh, and helpers in script/ci-common.sh. For the progressive stage ladder (lint → serve → AOT link → execute), see miniwebapp-gates.md (#472); probe status with script/miniwebapp-gates.sh, make miniwebapp-gates, or phpc doctor --gates.
| Variable | Default | Script | Notes |
|---|---|---|---|
MINIWEBAPP_VM_CLI_GATE |
1 |
ci-fast.sh |
PHPUnit MiniWebApp*VmCli matrix (#597) |
MINIWEBAPP_SERVE_GATE |
1 |
ci-local.sh, ci-fast.sh |
ServeTest @group miniwebapp (#641) |
MINIWEBAPP_WEB_SMOKE_GATE |
1 |
ci-local.sh |
examples-web-smoke.sh --miniwebapp-only (#664) |
MINIWEBAPP_AOT_LINK_GATE |
1 |
ci-local.sh (PHPUnit @group aot-link) |
ExamplesCompileTest 003 native link (#754) |
MINIWEBAPP_AOT_EXECUTE_GATE |
1 |
ci-local.sh after @group aot-link (ci_run_miniwebapp_aot_execute) |
PHPUnit @group miniwebapp-aot-execute / MiniWebAppAotExecuteTest (#747, #791) |
EXAMPLES_AOT_SMOKE_GATE |
1 |
ci-local.sh |
examples-aot-smoke.sh after LLVM phases (#674) |
EXAMPLES_AOT_SMOKE_ONLY |
unset | examples-aot-smoke.sh |
Slice e.g. 003 only (#738, #683) |
DEPLOY_SMOKE_GATE |
1 |
ci-local.sh |
deploy-smoke.sh 001/002 after examples-aot-smoke when LLVM ready (#718, #737); 003 execute when DEPLOY_SMOKE_003_EXECUTE=1 or MINIWEBAPP_AOT_EXECUTE_GATE=1 (#745) |
DEPLOY_SMOKE_003_EXECUTE |
0 |
deploy-smoke.sh, ci-local.sh |
Opt-in 003 deploy execute E2E; also runs when MINIWEBAPP_AOT_EXECUTE_GATE=1 (#745) |
BOOTSTRAP_SELFHOST_PROBE_GATE |
unset → 1 in ci-local.sh llvm tail; set 0 to skip |
ci-local.sh, ci-fast.sh (CI_FAST_BOOTSTRAP=1) |
make bootstrap-selfhost-probe on compiler_minimal (#829) |
BOOTSTRAP_SELFHOST_PROBE_UPDATE |
0 |
ci_run_bootstrap_selfhost_probe |
Pass --update-inventory to probe (dev only) |
BOOTSTRAP_WAVE_CHECK |
unset → 1 in ci-local.sh llvm tail; set 0 to skip |
ci-local.sh, ci-fast.sh (CI_FAST_BOOTSTRAP=1) |
./script/bootstrap-wave-check.sh --fail-fast after @group aot-lint |
CI_FAST_BOOTSTRAP |
0 |
ci-fast.sh |
Optional llvm tail: bootstrap aot-lint + probe + wave-check when LLVM 9 present |
JIT_PREFLIGHT_GATE |
0 |
ci-fast.sh |
Early MCJIT probe after composer install (#728) |
Ladder-only env vars (not in ci-defaults.env): MINIWEBAPP_LINT_GATE (default 1 in web-smoke.sh), MINIWEBAPP_AOT_BISECT_GATE (default 0 in miniwebapp-gates.sh — #879).
003 link gate (default on when LLVM ready — set 0 during execute-only iteration):
./script/ci-local.sh --filter 'ExamplesCompileTest::test003MiniWebAppBuildLinks'
MINIWEBAPP_AOT_LINK_GATE=0 ./script/ci-local.sh --filter ExamplesCompileTest # skip 003 link (#754)
003 AOT execute (MINIWEBAPP_AOT_EXECUTE_GATE=1 default; set 0 to skip during iteration):
MINIWEBAPP_AOT_EXECUTE_GATE=1 ./script/ci-local.sh --filter MiniWebAppAotExecuteTest
./script/ci-local.sh --filter test003MiniWebAppHomeRouteAotExecutes
./script/ci-local.sh --filter test003MiniWebAppExecutesWithCgiEnv
EXAMPLES_AOT_SMOKE_ONLY=003 ./script/examples-aot-smoke.sh
DEPLOY_SMOKE_GATE=0 ./script/ci-local.sh # skip 001/002 deploy smoke (#737)
MINIWEBAPP_AOT_BISECT_GATE=1 ./script/miniwebapp-gates.sh
Set any gate to 0 to skip that stage during iteration (e.g. MINIWEBAPP_SERVE_GATE=0 ./script/ci-fast.sh, MINIWEBAPP_AOT_EXECUTE_GATE=0 ./script/ci-local.sh).
make test runs can exhaust RAM (#497).script/ci-docker-run.sh (-m 10g + env from ci-defaults.env).bin/vm.php RSS in BaseTest when PHP_COMPILER_VM_RSS_GUARD=1 (default); manual profiling uses script/run-vm-guarded.sh (#500)../script/scan-vm-phpt-peak-rss.sh [dir] [limit].export PHP_COMPILER_MEMORY_LIMIT=4G
export PHP_COMPILER_CI_RAM_GB=16
export PHP_COMPILER_DOCKER_MEM=16g
export PHP_COMPILER_VM_PEAK_RSS_MB=4096
export PHP_COMPILER_VM_RSS_GUARD=0 # disable RSS killer (debug only)
make test
ci-fast skips @group llvm tests, so a broken LD_LIBRARY_PATH with LLVM present may only surface at the end of ci-local (#250). Enable an early MCJIT probe after composer install:
JIT_PREFLIGHT_GATE=1 ./script/ci-fast.sh
# or: make test-fast-jit-preflight
# Docker: JIT_PREFLIGHT_GATE=1 ./script/docker-ci-local.sh fast
Standalone probe (same logic as phpc doctor --jit-probe):
php script/check-jit-compliance-ran.php --preflight
Exits 0 when LLVM 9 is missing (nothing to guard). Exits non-zero when LLVM is present but PHPLLVM/MCJIT cannot bootstrap (#98). Default off until contributors opt in.
Fast north-star check before a full ci-local.sh llvm phase — phpc build --project plus CGI execute on examples/003-MiniWebApp (or optional project dir):
phpc doctor --aot-project-probe
# or: php script/aot-project-probe.php
Exits 0 with skip message when LLVM 9 is missing. Exits 0 when build succeeds and stdout contains the app_name needle (MiniWebApp). Exits non-zero on link failure or empty stdout (execute gap — was #764). Mirrors MiniWebAppCgiEnv::queryRouteHome() / stage 4b2 in script/miniwebapp-gates.sh.
Unlimited memory is blocked: PHP_COMPILER_MEMORY_LIMIT=-1 and memory_limit=-1 in tracked files fail script/check-no-unlimited-memory.sh (run at CI start).
Stale closed-issue blockers: script/check-stale-issue-refs.sh fails when closed issues (e.g. #568, #67) still appear as active blockers in script/, lib/Cli/, examples/, and docs/deploy-web-aot.md. Opt out per line with # stale-issue-ok: <reason>. Wired in ci-fast.sh / ci-local.sh inventory via script/ci-common.sh (#802).
Set PHP_COMPILER_SKIP_SERVE_TESTS=1 only when loopback TCP bind is unavailable. Harness Docker CI should not set this by default.
Harness hosts and contributors without host PHP/LLVM should use the 22.04 dev image, not legacy ircmaxell/php-compiler:* tags (Docker Hub 404).
| Step | Command |
|---|---|
| Build locally | make docker-build-22 → php-compiler:22.04-dev |
| Smoke | docker run --rm php-compiler:22.04-dev php -v |
| Full CI in container | make test-docker or ./script/docker-ci-local.sh |
| Harness empty bind-mount | ./script/docker-ci-local.sh (tar fallback, #272) |
| Fast CI in container | ./script/docker-ci-local.sh fast |
| Pull (optional) | docker pull ghcr.io/PurHur/php-compiler:dev then export PHP_COMPILER_DEV_IMAGE=ghcr.io/PurHur/php-compiler:dev |
| Publish (maintainer) | docker login ghcr.io then ./script/docker-publish-dev.sh --push or make docker-publish-dev |
make docker-build-22 tags both php-compiler:22.04-dev and ghcr.io/PurHur/php-compiler:dev. CI wrappers default to the local tag unless PHP_COMPILER_DEV_IMAGE is set.
MINIWEBAPP_WEB_SMOKE_GATE in ci-localMINIWEBAPP_AOT_LINK_GATEMINIWEBAPP_AOT_EXECUTE_GATE splitci_run_miniwebapp_aot_execute after aot-linkDEPLOY_SMOKE_GATE in ci-localci-fast vs ci-local)JIT_PREFLIGHT_GATE on ci-fast