Skip to content

Commit 156f1ff

Browse files
ondrejmirtesclaude
andcommitted
Compile PHP 8.6 turbo binaries against 8.6.0RC2
8.6.0RC2 bumped the module API (20250926 -> 20260924). The Linux gnu 8.6 legs compiled against setup-php's nightly, still a Sep 22 snapshot with the old API, so the binary refused to load into the php:8.6-rc image and into every RC2+ PHP. Windows compiled against the pinned 8.6.0beta3 devel pack, with the same result for users. The gnu 8.6 legs now run in a ghcr.io/phpstan/turbo-build:gnu-php8.6 image like 8.3-8.5; ondrej/php only has 8.6.0beta3, so the image builds the checksum-pinned RC2 tarball on ubuntu:22.04 (glibc floor 2.34 kept). Windows moves to 8.6.0RC2. The ubuntu 8.6 turbo-run legs, which load the binary into setup-php's nightly, are dropped; turbo-docker-run covers them in the official prerelease image. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7KTTCjJCkx6FUNorJwUbW
1 parent 68c2e4e commit 156f1ff

4 files changed

Lines changed: 88 additions & 30 deletions

File tree

‎.github/turbo-build/Dockerfile‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Prebuilt image for the turbo-compile gnu legs in phar.yml, published to
22
# ghcr.io/phpstan/turbo-build by turbo-build-image.yml (tags gnu-php8.3,
3-
# gnu-php8.4, gnu-php8.5; each a linux/amd64 + linux/arm64 manifest).
3+
# gnu-php8.4, gnu-php8.5, gnu-php8.6; each a linux/amd64 + linux/arm64
4+
# manifest).
45
#
56
# Baking the PHP toolchain in keeps apt and the ondrej/php PPA out of the
67
# compile jobs entirely: ports.ubuntu.com (the only Ubuntu arm64 mirror,
@@ -15,10 +16,23 @@ FROM ubuntu:22.04
1516
ARG PHP_MINOR
1617
ENV DEBIAN_FRONTEND=noninteractive
1718

19+
# PHP 8.6 is a prerelease, and ondrej/php trails its tags by weeks: on
20+
# 2026-09-25 it still served 8.6.0beta3, whose module API (20250926) the
21+
# 8.6.0RC2 that the php:8.6-rc images ship had already replaced
22+
# (20260924) — an extension built against one refuses to load into the
23+
# other. The 8.6 image therefore builds the official release tarball on
24+
# the same base. Drop these and the source branch below once ondrej/php
25+
# ships 8.6.0.
26+
ARG PHP86_VERSION=8.6.0RC2
27+
ARG PHP86_URL=https://downloads.php.net/~mbeccati/php-8.6.0RC2.tar.xz
28+
ARG PHP86_SHA256=ef3fba21c311e9bbace0e2102702446d322c275b8a10e6b33b28f2561299671c
29+
1830
# The source label links the GHCR package to this repository.
1931
LABEL org.opencontainers.image.source="https://github.com/phpstan/phpstan-src"
2032
LABEL org.opencontainers.image.description="PHP and build toolchain for compiling the phpstan_turbo extension (glibc floor 2.34)"
2133

34+
COPY build-php.sh /tmp/build-php.sh
35+
2236
# apt mirrors 404 mid-sync (the fetched index can reference a superseded
2337
# .deb already pruned from the pool); only a fresh index fixes that, so
2438
# update+install retries as a unit
@@ -34,8 +48,13 @@ RUN test -n "$PHP_MINOR"; \
3448
return 1; \
3549
}; \
3650
apt_install software-properties-common gnupg ca-certificates curl git make g++ patch unzip zstd \
37-
&& add-apt-repository -y ppa:ondrej/php \
38-
&& apt_install "php$PHP_MINOR-cli" "php$PHP_MINOR-dev" "php$PHP_MINOR-curl" "php$PHP_MINOR-mbstring" "php$PHP_MINOR-xml" \
39-
&& rm -rf /var/lib/apt/lists/* \
40-
&& ln -sf "/usr/bin/php$PHP_MINOR" /usr/local/bin/php \
41-
&& ln -sf "/usr/bin/php-config$PHP_MINOR" /usr/local/bin/php-config
51+
&& if [ "$PHP_MINOR" = "8.6" ]; then \
52+
apt_install pkg-config xz-utils libxml2-dev libonig-dev libcurl4-openssl-dev libssl-dev zlib1g-dev \
53+
&& PHP_VERSION="$PHP86_VERSION" PHP_URL="$PHP86_URL" PHP_SHA256="$PHP86_SHA256" sh /tmp/build-php.sh; \
54+
else \
55+
add-apt-repository -y ppa:ondrej/php \
56+
&& apt_install "php$PHP_MINOR-cli" "php$PHP_MINOR-dev" "php$PHP_MINOR-curl" "php$PHP_MINOR-mbstring" "php$PHP_MINOR-xml" \
57+
&& ln -sf "/usr/bin/php$PHP_MINOR" /usr/local/bin/php \
58+
&& ln -sf "/usr/bin/php-config$PHP_MINOR" /usr/local/bin/php-config; \
59+
fi \
60+
&& rm -rf /var/lib/apt/lists/* /tmp/build-php.sh

‎.github/turbo-build/build-php.sh‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/sh
2+
# Builds and installs PHP $PHP_VERSION into /usr/local from the official
3+
# release tarball at $PHP_URL, verified against $PHP_SHA256. Used by the
4+
# Dockerfile for the PHP minors ondrej/php does not ship yet.
5+
#
6+
# The extensions match what the turbo-compile legs use from the PPA
7+
# images: tokenizer for the parser tests, pcntl + posix for the fork
8+
# tests, opcache (always built in since 8.5) for the trusted-types test,
9+
# and curl, mbstring, openssl, xml and zlib for Composer.
10+
set -eu
11+
12+
cd /tmp
13+
curl -fsSLo php.tar.xz "$PHP_URL"
14+
echo "$PHP_SHA256 php.tar.xz" | sha256sum -c -
15+
mkdir php-src
16+
tar -xJf php.tar.xz -C php-src --strip-components=1
17+
rm php.tar.xz
18+
19+
cd php-src
20+
./configure \
21+
--prefix=/usr/local \
22+
--disable-cgi \
23+
--disable-phpdbg \
24+
--without-sqlite3 \
25+
--without-pdo-sqlite \
26+
--enable-mbstring \
27+
--enable-pcntl \
28+
--with-curl \
29+
--with-openssl \
30+
--with-zlib
31+
make -j"$(nproc)"
32+
make install
33+
34+
# The distro CLI packages the other images use ship a production php.ini
35+
# with no memory limit; match it.
36+
INI_DIR="$(php -r 'echo PHP_CONFIG_FILE_PATH;')"
37+
mkdir -p "$INI_DIR"
38+
sed 's/^memory_limit = .*/memory_limit = -1/' php.ini-production > "$INI_DIR/php.ini"
39+
40+
cd /tmp
41+
rm -rf php-src
42+
43+
php -r 'if (PHP_VERSION !== getenv("PHP_VERSION")) { fwrite(STDERR, "built PHP " . PHP_VERSION . ", expected " . getenv("PHP_VERSION") . "\n"); exit(1); }'
44+
php -m

‎.github/workflows/phar.yml‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ env:
3535
COMPOSER_VERSION: "2.9.2"
3636
COMPOSER_PHAR_SHA256: "471f2d857abf0ec18af7b055e61472214d91adb24f9bdbbb864c1c64faad7dd6"
3737
# setup-php installs an 8.6 nightly, which has no matching Windows devel pack.
38-
PHP86_WINDOWS_VERSION: "8.6.0beta3"
38+
PHP86_WINDOWS_VERSION: "8.6.0RC2"
3939

4040
jobs:
4141
compiler-tests:
@@ -326,9 +326,9 @@ jobs:
326326
327327
turbo-compile:
328328
name: "Compile Turbo Extension"
329-
runs-on: ${{ matrix.php-version == '8.6' && matrix.target.family == 'gnu' && (matrix.target.name == 'linux-gnu-arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04') || matrix.target.runs-on }}
329+
runs-on: ${{ matrix.target.runs-on }}
330330
# Container legs pin the built binaries' userland floor independently of
331-
# the runner image. The 8.3–8.5 gnu legs run in a prebuilt ubuntu:22.04-based
331+
# the runner image. The gnu legs run in a prebuilt ubuntu:22.04-based
332332
# image (.github/turbo-build/Dockerfile, published to GHCR by
333333
# turbo-build-image.yml) with the PHP toolchain baked in: the glibc
334334
# symbol floor stays at 2.34 (RHEL 9, Ubuntu 22.04+, Debian 12+) and the
@@ -347,10 +347,9 @@ jobs:
347347
# not worth two binaries per PHP minor. Their binaries are deleted from
348348
# phpstan/phpstan by the commit job (TURBO_RETIRED_BINARIES). Windows
349349
# keeps its ZTS leg: XAMPP, WampServer and Scoop default to TS PHP.
350-
# PHP 8.6 has no ondrej/php packages or prebuilt GNU image yet. Use
351-
# setup-php on Jammy runners, preserving the shipped binary's glibc floor.
352-
# Alpine's php86 packages are currently only in edge/testing.
353-
container: ${{ matrix.target.family == 'gnu' && matrix.php-version != '8.6' && format('ghcr.io/phpstan/turbo-build:gnu-php{0}', matrix.php-version) || matrix.target.family == 'musl' && matrix.php-version == '8.6' && 'alpine:edge' || matrix.target.container }}
350+
# The gnu-php8.6 image builds the official 8.6 prerelease tarball (see the
351+
# Dockerfile). Alpine's php86 packages are currently only in edge/testing.
352+
container: ${{ matrix.target.family == 'gnu' && format('ghcr.io/phpstan/turbo-build:gnu-php{0}', matrix.php-version) || matrix.target.family == 'musl' && matrix.php-version == '8.6' && 'alpine:edge' || matrix.target.container }}
354353
timeout-minutes: 30
355354

356355
env:
@@ -393,7 +392,7 @@ jobs:
393392
# The Alpine leg installs PHP and tooling before checkout:
394393
# actions/checkout needs git inside the container, and the build needs
395394
# php/php-config symlinks pointing at the matrix PHP version. The GNU
396-
# container legs have the toolchain baked in; 8.6 uses setup-php below.
395+
# container legs have the toolchain baked in.
397396
- name: "Install PHP and build tools (Alpine container)"
398397
if: matrix.target.family == 'musl'
399398
run: |
@@ -432,13 +431,6 @@ jobs:
432431
coverage: "none"
433432
php-version: "${{ matrix.php-version }}"
434433

435-
- name: "Install PHP (GNU runners)"
436-
if: matrix.target.family == 'gnu' && matrix.php-version == '8.6'
437-
uses: "shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240" # v2.37.2
438-
with:
439-
coverage: "none"
440-
php-version: "${{ matrix.php-version }}"
441-
442434
- name: "Compile phpstan_turbo with strict warnings"
443435
working-directory: "turbo-ext"
444436
# Exemptions, each caused by third-party macro expansions, not our code:
@@ -481,15 +473,11 @@ jobs:
481473
if: matrix.target.family != 'macos'
482474
# checksum-pinned composer, run under the matrix PHP so platform
483475
# requirements are validated against the interpreter the tests below
484-
# run on. COMPOSER_HOME is isolated: on the runner (PHP 8.6) legs,
485-
# setup-php seeds ~/.composer/auth.json with the workflow's GitHub
486-
# token, which this pinned composer rejects at startup ("github oauth
487-
# token contains invalid characters") — everything here comes from
488-
# packagist dists, no auth needed.
476+
# run on
489477
run: |
490478
curl -fsSLo composer.phar "https://getcomposer.org/download/$COMPOSER_VERSION/composer.phar"
491479
echo "$COMPOSER_PHAR_SHA256 composer.phar" | sha256sum -c -
492-
COMPOSER_HOME="$(mktemp -d)" php composer.phar install --no-interaction --no-progress
480+
php composer.phar install --no-interaction --no-progress
493481
rm composer.phar
494482
495483
- name: "Smoke test (differential: native vs PHP implementations)"
@@ -1027,6 +1015,13 @@ jobs:
10271015
exclude:
10281016
- operating-system: "ubuntu-latest"
10291017
ts: "zts"
1018+
# setup-php's Linux 8.6 is a nightly snapshot that can predate the
1019+
# release the binary is compiled against (on 2026-09-25 it still
1020+
# had the module API 8.6.0RC2 replaced), and a module API mismatch
1021+
# refuses to load the extension at all. turbo-docker-run runs the
1022+
# same checks with this binary in the official 8.6 prerelease image.
1023+
- operating-system: "ubuntu-latest"
1024+
php-version: "8.6"
10301025
# macOS runs the shipped ad-hoc-signed arm64 binary; there is no
10311026
# macOS zts build, and 8.3/8.4 coverage comes from the other legs.
10321027
include:

‎.github/workflows/turbo-build-image.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
name: "Build Turbo compile images"
44

55
# Builds .github/turbo-build/Dockerfile natively on x86_64 and arm64
6-
# runners and publishes ghcr.io/phpstan/turbo-build:gnu-php{8.3,8.4,8.5}
6+
# runners and publishes ghcr.io/phpstan/turbo-build:gnu-php{8.3,8.4,8.5,8.6}
77
# as multi-arch manifests. The turbo-compile gnu legs in phar.yml run in
88
# these images, so their only network dependency is a GHCR pull — no apt,
99
# no ports.ubuntu.com, no PPA at compile time.
@@ -45,7 +45,7 @@ jobs:
4545
strategy:
4646
fail-fast: false
4747
matrix:
48-
php-version: ["8.3", "8.4", "8.5"]
48+
php-version: ["8.3", "8.4", "8.5", "8.6"]
4949
platform:
5050
- arch: "amd64"
5151
runs-on: "ubuntu-latest"
@@ -97,7 +97,7 @@ jobs:
9797

9898
strategy:
9999
matrix:
100-
php-version: ["8.3", "8.4", "8.5"]
100+
php-version: ["8.3", "8.4", "8.5", "8.6"]
101101

102102
env:
103103
TAG: "ghcr.io/phpstan/turbo-build:gnu-php${{ matrix.php-version }}"

0 commit comments

Comments
 (0)