Skip to content

Commit 3abeb0a

Browse files
ondrejmirtesclaude
andcommitted
Build Linux ZTS turbo binaries for PHP 8.6+
The official Docker images build every PHP 8.6+ variant thread-safe, cli and alpine included (docker-library/php#1686), and no NTS 8.6 image is published any more. The NTS binaries refuse to load there ("undefined symbol: executor_globals"), which failed the 8.6 turbo-docker-run legs. Distros, ppa:ondrej/php, sury, Remi and setup-php keep shipping an NTS CLI (php-src 8.6 still defaults to NTS), so 8.6+ needs both variants. - turbo-build image gnu-php8.6-zts: build-php.sh builds the pinned tarball thread-safe when PHP_ZTS=1; the pin moved into the script so the glibc image and the musl legs build the same release - turbo-compile gains linux-gnu-x86_64/arm64 and linux-musl-x86_64 8.6 ZTS legs, turbo-compile-musl-arm64 a linux-musl-arm64 one; Alpine packages no thread-safe PHP, so those build the tarball in alpine:3.24 (.github/scripts/install-alpine-php.sh, shared by the musl legs) - turbo-docker-run loads the -zts binaries into the 8.6 images and gains a php:8.6-rc-cli-alpine leg for the musl one - TURBO_RETIRED_BINARIES only retires the 8.3-8.5 Linux ZTS binaries Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LcypAP4x58BCa8dzQm5UHQ
1 parent 7002950 commit 3abeb0a

6 files changed

Lines changed: 216 additions & 91 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/sh
2+
# Installs PHP $PHP_MINOR and the extension's build tools into the Alpine
3+
# containers of the musl turbo legs in phar.yml. With PHP_ZTS=1 it builds a
4+
# thread-safe PHP from the release tarball instead (build-php.sh): Alpine
5+
# packages no thread-safe PHP, while the official php:*-alpine Docker images
6+
# are thread-safe from 8.6 on.
7+
set -eu
8+
9+
apk add --no-cache bash curl git make g++ musl-dev linux-headers patch tar zstd
10+
11+
if [ "${PHP_ZTS:-0}" = "1" ]; then
12+
apk add --no-cache pkgconf xz libxml2-dev oniguruma-dev curl-dev openssl-dev zlib-dev
13+
PHP_MINOR="$PHP_MINOR" PHP_ZTS=1 sh "$(dirname "$0")/../turbo-build/build-php.sh"
14+
exit 0
15+
fi
16+
17+
V="$(echo "$PHP_MINOR" | tr -d .)"
18+
# Alpine's php86 packages are currently only in edge/testing.
19+
if [ "$PHP_MINOR" = "8.6" ]; then
20+
echo 'https://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories
21+
fi
22+
apk add --no-cache \
23+
"php$V" "php$V-dev" "php$V-ctype" "php$V-curl" "php$V-mbstring" \
24+
"php$V-tokenizer" "php$V-iconv" "php$V-openssl" "php$V-phar" \
25+
"php$V-dom" "php$V-xml" "php$V-xmlwriter" "php$V-simplexml"
26+
ln -sf "/usr/bin/php$V" /usr/local/bin/php
27+
ln -sf "/usr/bin/php-config$V" /usr/local/bin/php-config

‎.github/turbo-build/Dockerfile‎

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +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, gnu-php8.6; each a linux/amd64 + linux/arm64
4-
# manifest).
3+
# gnu-php8.4, gnu-php8.5, gnu-php8.6, gnu-php8.6-zts; each a linux/amd64 +
4+
# linux/arm64 manifest).
55
#
66
# Baking the PHP toolchain in keeps apt and the ondrej/php PPA out of the
77
# compile jobs entirely: ports.ubuntu.com (the only Ubuntu arm64 mirror,
@@ -14,18 +14,19 @@
1414
FROM ubuntu:22.04
1515

1616
ARG PHP_MINOR
17+
# 1 builds a thread-safe PHP (the -zts tags)
18+
ARG PHP_ZTS=0
1719
ENV DEBIAN_FRONTEND=noninteractive
1820

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
21+
# These images build PHP from the official release tarball pinned in
22+
# build-php.sh instead of installing it from ondrej/php:
23+
# - PHP 8.6 is a prerelease, and ondrej/php trails its tags by weeks: on
24+
# 2026-09-25 it still served 8.6.0beta3, whose module API (20250926) the
25+
# 8.6.0RC2 that the php:8.6-rc images ship had already replaced
26+
# (20260924) — an extension built against one refuses to load into the
27+
# other. Switch the NTS 8.6 image to the PPA once it ships 8.6.0.
28+
# - ondrej/php packages no thread-safe PHP at all, so the ZTS images always
29+
# build from source.
2930

3031
# The source label links the GHCR package to this repository.
3132
LABEL org.opencontainers.image.source="https://github.com/phpstan/phpstan-src"
@@ -48,9 +49,9 @@ RUN test -n "$PHP_MINOR"; \
4849
return 1; \
4950
}; \
5051
apt_install software-properties-common gnupg ca-certificates curl git make g++ patch unzip zstd \
51-
&& if [ "$PHP_MINOR" = "8.6" ]; then \
52+
&& if [ "$PHP_MINOR" = "8.6" ] || [ "$PHP_ZTS" = "1" ]; then \
5253
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+
&& PHP_MINOR="$PHP_MINOR" PHP_ZTS="$PHP_ZTS" sh /tmp/build-php.sh; \
5455
else \
5556
add-apt-repository -y ppa:ondrej/php \
5657
&& apt_install "php$PHP_MINOR-cli" "php$PHP_MINOR-dev" "php$PHP_MINOR-curl" "php$PHP_MINOR-mbstring" "php$PHP_MINOR-xml" \

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
#!/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.
2+
# Builds and installs PHP $PHP_MINOR into /usr/local from the official
3+
# release tarball pinned below, thread-safe when $PHP_ZTS is 1. Used by the
4+
# Dockerfile for the PHP builds ondrej/php does not ship (prerelease
5+
# minors, and every thread-safe build), and by the musl ZTS legs in
6+
# phar.yml, which run it in Alpine — Alpine packages no thread-safe PHP.
57
#
68
# The extensions match what the turbo-compile legs use from the PPA
79
# images: tokenizer for the parser tests, pcntl + posix for the fork
810
# tests, opcache (always built in since 8.5) for the trusted-types test,
911
# and curl, mbstring, openssl, xml and zlib for Composer.
1012
set -eu
1113

14+
# The tarball for each minor this script builds; one pin shared by the
15+
# glibc image and the musl legs, so both build the same release.
16+
case "$PHP_MINOR" in
17+
8.6)
18+
PHP_VERSION=8.6.0RC2
19+
PHP_URL=https://downloads.php.net/~mbeccati/php-8.6.0RC2.tar.xz
20+
PHP_SHA256=ef3fba21c311e9bbace0e2102702446d322c275b8a10e6b33b28f2561299671c
21+
;;
22+
*)
23+
echo "build-php.sh: no tarball pinned for PHP $PHP_MINOR" >&2
24+
exit 1
25+
;;
26+
esac
27+
export PHP_VERSION
28+
PHP_ZTS="${PHP_ZTS:-0}"
29+
export PHP_ZTS
30+
ZTS_FLAG=""
31+
if [ "$PHP_ZTS" = "1" ]; then
32+
ZTS_FLAG="--enable-zts"
33+
fi
34+
1235
cd /tmp
1336
curl -fsSLo php.tar.xz "$PHP_URL"
1437
echo "$PHP_SHA256 php.tar.xz" | sha256sum -c -
@@ -17,6 +40,7 @@ tar -xJf php.tar.xz -C php-src --strip-components=1
1740
rm php.tar.xz
1841

1942
cd php-src
43+
# shellcheck disable=SC2086 # ZTS_FLAG is empty or a single word
2044
./configure \
2145
--prefix=/usr/local \
2246
--disable-cgi \
@@ -27,7 +51,8 @@ cd php-src
2751
--enable-pcntl \
2852
--with-curl \
2953
--with-openssl \
30-
--with-zlib
54+
--with-zlib \
55+
$ZTS_FLAG
3156
make -j"$(nproc)"
3257
make install
3358

@@ -41,4 +66,5 @@ cd /tmp
4166
rm -rf php-src
4267

4368
php -r 'if (PHP_VERSION !== getenv("PHP_VERSION")) { fwrite(STDERR, "built PHP " . PHP_VERSION . ", expected " . getenv("PHP_VERSION") . "\n"); exit(1); }'
69+
php -r 'if ((int) PHP_ZTS !== (int) getenv("PHP_ZTS")) { fwrite(STDERR, "built PHP_ZTS=" . PHP_ZTS . ", expected " . getenv("PHP_ZTS") . "\n"); exit(1); }'
4470
php -m

0 commit comments

Comments
 (0)