Skip to content

Commit 779ae83

Browse files
committed
Add gnu static binary build support
1 parent a9cf944 commit 779ae83

File tree

2 files changed

+231
-49
lines changed

2 files changed

+231
-49
lines changed

build-static.sh

Lines changed: 97 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,51 @@ fi
1010

1111
arch="$(uname -m)"
1212
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
13-
# FIXME: re-enable PHP errors when SPC will be compatible with PHP 8.4
14-
spcCommand="php -ddisplay_errors=Off ./bin/spc"
13+
14+
# Supported variables:
15+
# - PHP_VERSION: PHP version to build (default: "8.4")
16+
# - PHP_EXTENSIONS: PHP extensions to build (default: ${defaultExtensions} set below)
17+
# - PHP_EXTENSION_LIBS: PHP extension libraries to build (default: ${defaultExtensionLibs} set below)
18+
# - FRANKENPHP_VERSION: FrankenPHP version (default: current Git commit)
19+
# - EMBED: Path to the PHP app to embed (default: none)
20+
# - DEBUG_SYMBOLS: Enable debug symbols if set to 1 (default: none)
21+
# - MIMALLOC: Use mimalloc as the allocator if set to 1 (default: none)
22+
# - XCADDY_ARGS: Additional arguments to pass to xcaddy
23+
# - RELEASE: [maintainer only] Create a GitHub release if set to 1 (default: none)
24+
25+
# - SPC_REL_TYPE: Release type to download (accept "source" and "binary", default: "source")
26+
# - SPC_OPT_BUILD_ARGS: Additional arguments to pass to spc build
27+
# - SPC_OPT_DOWNLOAD_ARGS: Additional arguments to pass to spc download
28+
# - SPC_BUILD_GNU: Set to 1 to build with GNU toolchain (default: musl toolchain)
29+
30+
# init spc command, if we use spc binary, just use it instead of fetching source
31+
if [ -z "${SPC_REL_TYPE}" ]; then
32+
SPC_REL_TYPE="source"
33+
fi
34+
# init spc build additional args
35+
if [ -z "${SPC_OPT_BUILD_ARGS}" ]; then
36+
SPC_OPT_BUILD_ARGS="--debug"
37+
fi
38+
# init spc download additional args
39+
if [ -z "${SPC_OPT_DOWNLOAD_ARGS}" ]; then
40+
SPC_OPT_DOWNLOAD_ARGS="--prefer-pre-built --debug --ignore-cache-sources=php-src"
41+
fi
42+
# linux build need to disable opcache jit
43+
if [ "${os}" = "linux" ]; then
44+
SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --disable-opcache-jit"
45+
fi
46+
# if we need debug symbols, disable strip
47+
if [ -n "${DEBUG_SYMBOLS}" ]; then
48+
SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --no-strip"
49+
fi
50+
# php version to build
51+
if [ -z "${PHP_VERSION}" ]; then
52+
export PHP_VERSION="8.4"
53+
fi
54+
# default extension set
55+
defaultExtensions="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd"
56+
defaultExtensionLibs="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"
57+
1558
md5binary="md5sum"
1659
if [ "${os}" = "darwin" ]; then
1760
os="mac"
@@ -35,32 +78,6 @@ else
3578
fpie="-fpie"
3679
fi
3780

38-
if [ -z "${PHP_EXTENSIONS}" ]; then
39-
if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ]; then
40-
cd "${EMBED}"
41-
# read the composer.json file and extract the required PHP extensions
42-
# remove internal extensions from the list: https://github.com/crazywhalecc/static-php-cli/blob/4b16631d45a57370b4747df15c8f105130e96d03/src/globals/defines.php#L26-L34
43-
PHP_EXTENSIONS="$(composer check-platform-reqs --no-dev 2>/dev/null | grep ^ext | sed -e 's/^ext-core//' -e 's/^ext-hash//' -e 's/^ext-json//' -e 's/^ext-pcre//' -e 's/^ext-reflection//' -e 's/^ext-spl//' -e 's/^ext-standard//' -e 's/^ext-//' -e 's/ .*//' | xargs | tr ' ' ',')"
44-
export PHP_EXTENSIONS
45-
cd -
46-
else
47-
export PHP_EXTENSIONS="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd"
48-
fi
49-
fi
50-
51-
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
52-
export PHP_EXTENSION_LIBS="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"
53-
fi
54-
55-
# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
56-
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
57-
export PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
58-
fi
59-
60-
if [ -z "${PHP_VERSION}" ]; then
61-
export PHP_VERSION="8.4"
62-
fi
63-
6481
if [ -z "${FRANKENPHP_VERSION}" ]; then
6582
FRANKENPHP_VERSION="$(git rev-parse --verify HEAD)"
6683
export FRANKENPHP_VERSION
@@ -98,14 +115,6 @@ else
98115
cd dist/
99116
echo -n "${cache_key}" >cache_key
100117

101-
if [ -d "static-php-cli/" ]; then
102-
cd static-php-cli/
103-
git pull
104-
else
105-
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli
106-
cd static-php-cli/
107-
fi
108-
109118
if type "brew" >/dev/null 2>&1; then
110119
if ! type "composer" >/dev/null; then
111120
packages="composer"
@@ -123,20 +132,48 @@ else
123132
fi
124133
fi
125134

126-
composer install --no-dev -a
127-
128-
if [ "${os}" = "linux" ]; then
129-
extraOpts="--disable-opcache-jit"
130-
fi
131-
132-
if [ -n "${DEBUG_SYMBOLS}" ]; then
133-
extraOpts="${extraOpts} --no-strip"
134-
fi
135+
if [ "${SPC_REL_TYPE}" = "binary" ]; then
136+
mkdir static-php-cli/
137+
cd static-php-cli/
138+
curl -o spc -fsSL https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-$(uname -m)
139+
chmod +x spc
140+
spcCommand="./spc"
141+
elif [ -d "static-php-cli/src" ]; then
142+
cd static-php-cli/
143+
git pull
144+
composer install --no-dev -a
145+
spcCommand="./bin/spc"
146+
else
147+
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli --branch main
148+
cd static-php-cli/
149+
composer install --no-dev -a
150+
spcCommand="./bin/spc"
151+
fi
152+
153+
# extensions to build
154+
if [ -z "${PHP_EXTENSIONS}" ]; then
155+
# enable EMBED mode, first check if project has dumped extensions
156+
if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ] && [ -f "${EMBED}/composer.lock" ] && [ -f "${EMBED}/vendor/installed.json" ]; then
157+
cd "${EMBED}"
158+
# read the extensions using spc dump-extensions
159+
PHP_EXTENSIONS=$(${spcCommand} dump-extensions "${EMBED}" --format=text --no-dev --no-ext-output="${defaultExtensions}")
160+
else
161+
PHP_EXTENSIONS="${defaultExtensions}"
162+
fi
163+
fi
164+
# additional libs to build
165+
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
166+
PHP_EXTENSION_LIBS="${defaultExtensionLibs}"
167+
fi
168+
# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
169+
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
170+
PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
171+
fi
135172

136173
${spcCommand} doctor --auto-fix
137-
${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" --ignore-cache-sources=php-src --prefer-pre-built
174+
${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" ${SPC_OPT_DOWNLOAD_ARGS}
138175
# shellcheck disable=SC2086
139-
${spcCommand} build --debug --enable-zts --build-embed ${extraOpts} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
176+
${spcCommand} build --enable-zts --build-embed ${SPC_OPT_BUILD_ARGS} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
140177
fi
141178

142179
if ! type "go" >/dev/null 2>&1; then
@@ -166,7 +203,12 @@ curl -f --retry 5 "${curlGitHubHeaders[@]}" https://api.github.com/repos/e-dant/
166203
xargs curl -fL --retry 5 "${curlGitHubHeaders[@]}" |
167204
tar xz --strip-components 1
168205
cd watcher-c
169-
cc -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra "${fpic}"
206+
if [ -z "${CC}" ]; then
207+
watcherCC=cc
208+
else
209+
watcherCC="${CC}"
210+
fi
211+
${watcherCC} -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra "${fpic}"
170212
ar rcs libwatcher-c.a libwatcher-c.o
171213
cp libwatcher-c.a ../../buildroot/lib/libwatcher-c.a
172214
mkdir -p ../../buildroot/include/wtr
@@ -302,9 +344,15 @@ fi
302344

303345
go env
304346
cd caddy/
347+
if [ -z "${SPC_BUILD_GNU}" ]; then
348+
xcaddyGoBuildFlags="-buildmode=pie -tags cgo,netgo,osusergo,static_build,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-static-pie ${extraExtldflags}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\""
349+
else
350+
xcaddyGoBuildFlags="-buildmode=pie -tags cgo,netgo,osusergo,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-pie ${extraExtldflags}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\""
351+
fi
352+
305353
# shellcheck disable=SC2086
306354
CGO_ENABLED=1 \
307-
XCADDY_GO_BUILD_FLAGS="-buildmode=pie -tags cgo,netgo,osusergo,static_build,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-static-pie ${extraExtldflags}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\"" \
355+
XCADDY_GO_BUILD_FLAGS=${xcaddyGoBuildFlags} \
308356
XCADDY_DEBUG="${XCADDY_DEBUG}" \
309357
${XCADDY_COMMAND} build \
310358
--output "../dist/${bin}" \

gnu-static.Dockerfile

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
FROM centos:7
2+
3+
ARG FRANKENPHP_VERSION=''
4+
ENV FRANKENPHP_VERSION=${FRANKENPHP_VERSION}
5+
6+
ARG PHP_VERSION=''
7+
ENV PHP_VERSION=${PHP_VERSION}
8+
9+
# args passed to static-php-cli
10+
ARG PHP_EXTENSIONS=''
11+
ARG PHP_EXTENSION_LIBS=''
12+
13+
# args passed to xcaddy
14+
ARG XCADDY_ARGS=''
15+
ARG CLEAN=''
16+
ARG EMBED=''
17+
ARG DEBUG_SYMBOLS=''
18+
ARG MIMALLOC=''
19+
ARG NO_COMPRESS=''
20+
21+
# go version
22+
ENV GO_VERSION=1.24.1
23+
24+
# labels, same as static-builder.Dockerfile
25+
LABEL org.opencontainers.image.title=FrankenPHP
26+
LABEL org.opencontainers.image.description="The modern PHP app server"
27+
LABEL org.opencontainers.image.url=https://frankenphp.dev
28+
LABEL org.opencontainers.image.source=https://github.com/dunglas/frankenphp
29+
LABEL org.opencontainers.image.licenses=MIT
30+
LABEL org.opencontainers.image.vendor="Kévin Dunglas"
31+
32+
# yum update
33+
RUN sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo && \
34+
sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/*.repo && \
35+
sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/*.repo && \
36+
yum clean all && \
37+
yum makecache && \
38+
yum update -y && \
39+
yum install -y centos-release-scl
40+
41+
# different arch for different scl repo
42+
RUN if [ "$(uname -m)" = "aarch64" ]; then \
43+
sed -i 's|mirror.centos.org/centos|vault.centos.org/altarch|g' /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo ; \
44+
sed -i 's|mirror.centos.org/centos|vault.centos.org/altarch|g' /etc/yum.repos.d/CentOS-SCLo-scl.repo ; \
45+
sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/*.repo ; \
46+
sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/*.repo ; \
47+
else \
48+
sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo ; \
49+
sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/*.repo ; \
50+
sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/*.repo ; \
51+
fi ; \
52+
yum update -y && \
53+
yum install -y devtoolset-10-gcc-* && \
54+
echo "source scl_source enable devtoolset-10" >> /etc/bashrc && \
55+
source /etc/bashrc
56+
57+
# install newer cmake to build some newer libs
58+
RUN curl -o cmake.tgz -fsSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$(uname -m).tar.gz && \
59+
mkdir /cmake && \
60+
tar -xzf cmake.tgz -C /cmake --strip-components 1 && \
61+
rm cmake.tgz
62+
63+
# install build essentials
64+
RUN yum install -y \
65+
perl \
66+
make \
67+
bison \
68+
flex \
69+
git \
70+
autoconf \
71+
automake \
72+
tar \
73+
unzip \
74+
gzip \
75+
gcc \
76+
bzip2 \
77+
patch \
78+
xz \
79+
libtool \
80+
perl-IPC-Cmd ; \
81+
curl -o make.tgz -fsSL https://ftp.gnu.org/gnu/make/make-4.4.tar.gz && \
82+
tar -zxvf make.tgz && \
83+
rm make.tgz && \
84+
cd make-4.4 && \
85+
./configure && \
86+
make && \
87+
make install && \
88+
ln -sf /usr/local/bin/make /usr/bin/make ; \
89+
if [ "$(uname -m)" = "aarch64" ]; then \
90+
GO_ARCH="arm64" ; \
91+
else \
92+
GO_ARCH="amd64" ; \
93+
fi ; \
94+
curl -o go.tgz -fsSL https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
95+
rm -rf /usr/local/go && \
96+
tar -C /usr/local -xzf go.tgz && \
97+
rm go.tgz && \
98+
/usr/local/go/bin/go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
99+
100+
ENV PATH="/cmake/bin:/usr/local/go/bin:$PATH"
101+
102+
# Apply gnu mode
103+
ENV SPC_SKIP_DOCTOR_CHECK_ITEMS='if musl-wrapper is installed,if musl-cross-make is installed'
104+
ENV CC='/opt/rh/devtoolset-10/root/usr/bin/gcc'
105+
ENV CXX='/opt/rh/devtoolset-10/root/usr/bin/g++'
106+
ENV AR='/opt/rh/devtoolset-10/root/usr/bin/ar'
107+
ENV LD='/opt/rh/devtoolset-10/root/usr/bin/ld'
108+
ENV SPC_DEFAULT_C_FLAGS='-fPIE -fPIC'
109+
ENV SPC_NO_MUSL_PATH='yes'
110+
ENV SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM='-Wl,-O1 -pie'
111+
ENV SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS='-ldl -lpthread -lm -lresolv -lutil -lrt'
112+
ENV SPC_OPT_DOWNLOAD_ARGS='--debug --ignore-cache-sources=php-src'
113+
ENV SPC_OPT_BUILD_ARGS='--debug --libc=glibc'
114+
ENV SPC_REL_TYPE='binary'
115+
ENV SPC_BUILD_GNU='yes'
116+
117+
# not sure if this is needed
118+
ENV COMPOSER_ALLOW_SUPERUSER=1
119+
120+
WORKDIR /go/src/app
121+
COPY go.mod go.sum ./
122+
RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get
123+
124+
WORKDIR /go/src/app/caddy
125+
COPY caddy/go.mod caddy/go.sum ./
126+
RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get
127+
128+
WORKDIR /go/src/app
129+
COPY --link *.* ./
130+
COPY --link caddy caddy
131+
COPY --link internal internal
132+
133+
RUN --mount=type=secret,id=github-token ./build-static.sh && \
134+
rm -Rf dist/static-php-cli/source/*

0 commit comments

Comments
 (0)