diff --git a/.github/workflows/build-unix.yml b/.github/workflows/build-unix.yml index e0b516148..00dfb67b1 100644 --- a/.github/workflows/build-unix.yml +++ b/.github/workflows/build-unix.yml @@ -116,7 +116,7 @@ jobs: linux-x86_64) DOWN_CMD="./bin/spc-alpine-docker download" BUILD_CMD="./bin/spc-alpine-docker build" - RUNS_ON="ubuntu-latest" + RUNS_ON="ubuntu-24.04" ;; linux-aarch64) DOWN_CMD="./bin/spc-alpine-docker download" @@ -136,7 +136,7 @@ jobs: macos-x86_64) DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download" BUILD_CMD="./bin/spc build" - RUNS_ON="macos-13" + RUNS_ON="macos-14" ;; macos-aarch64) DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download" diff --git a/.github/workflows/ext-matrix-tests.yml b/.github/workflows/ext-matrix-tests.yml index 1c04f5c93..f943f8ef2 100644 --- a/.github/workflows/ext-matrix-tests.yml +++ b/.github/workflows/ext-matrix-tests.yml @@ -85,7 +85,6 @@ jobs: - "8.4" operating-system: - "ubuntu-latest" - #- "macos-13" #- "debian-arm64-self-hosted" - "macos-14" @@ -99,11 +98,11 @@ jobs: OS="" if [ "${{ matrix.operating-system }}" = "ubuntu-latest" ]; then OS="linux-x86_64" - elif [ "${{ matrix.operating-system }}" = "macos-13" ]; then + elif [ "${{ matrix.operating-system }}" = "macos-14" ]; then OS="macos-x86_64" elif [ "${{ matrix.operating-system }}" = "debian-arm64-self-hosted" ]; then OS="linux-aarch64" - elif [ "${{ matrix.operating-system }}" = "macos-14" ]; then + elif [ "${{ matrix.operating-system }}" = "macos-15" ]; then OS="macos-aarch64" fi echo "OS=$OS" >> $GITHUB_ENV diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 5c0c4f0d5..c6c06a2cc 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -23,13 +23,13 @@ jobs: os: "ubuntu-latest" filename: "spc-linux-x86_64.tar.gz" - name: "macos-x86_64" - os: "macos-13" + os: "macos-14" filename: "spc-macos-x86_64.tar.gz" - name: "linux-aarch64" os: "ubuntu-latest" filename: "spc-linux-aarch64.tar.gz" - name: "macos-aarch64" - os: "macos-14" + os: "macos-15" filename: "spc-macos-aarch64.tar.gz" - name: "windows-x64" os: "ubuntu-latest" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b42eef7dc..c44528419 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -105,7 +105,7 @@ jobs: run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: "Run PHPUnit Tests" - run: SPC_LIBC=glibc vendor/bin/phpunit tests/ --no-coverage + run: vendor/bin/phpunit tests/ --no-coverage define-matrix: name: "Define Matrix" diff --git a/bin/build-static-frankenphp b/bin/build-static-frankenphp deleted file mode 100755 index 10a693a78..000000000 --- a/bin/build-static-frankenphp +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env bash - -# This file is using docker to run commands -set -e - -# Detect docker can run -if ! which docker >/dev/null; then - echo "Docker is not installed, please install docker first !" - exit 1 -fi -DOCKER_EXECUTABLE="docker" -# shellcheck disable=SC2046 -if [ $(id -u) -ne 0 ]; then - if ! docker info > /dev/null 2>&1; then - if [ "$SPC_USE_SUDO" != "yes" ]; then - echo "Docker command requires sudo" - # shellcheck disable=SC2039 - echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again' - exit 1 - fi - DOCKER_EXECUTABLE="sudo docker" - fi -fi - - - -# to check if qemu-docker run -if [ "$SPC_USE_ARCH" = "" ]; then - SPC_USE_ARCH=current -fi -case $SPC_USE_ARCH in -current) - BASE_ARCH=$(uname -m) - if [ "$BASE_ARCH" = "arm64" ]; then - BASE_ARCH=aarch64 - GO_ARCH=arm64 - else - GO_ARCH=amd64 - fi - ;; -aarch64) - BASE_ARCH=aarch64 - GO_ARCH=arm64 - # shellcheck disable=SC2039 - echo -e "\e[033m* Using different arch needs to setup qemu-static for docker !\e[0m" - $DOCKER_EXECUTABLE run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null - ;; -*) - echo "Current arch is not supported to run in docker: $SPC_USE_ARCH" - exit 1 - ;; -esac - -# Detect docker env is setup -if ! $DOCKER_EXECUTABLE images | grep -q cwcc-frankenphp-gnu-$SPC_USE_ARCH; then - echo "Docker container does not exist. Building docker image ..." - $DOCKER_EXECUTABLE build -t cwcc-frankenphp-gnu-$SPC_USE_ARCH -f- . <> /etc/bashrc -RUN source /etc/bashrc - -RUN curl -o cmake.tgz -fsSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$BASE_ARCH.tar.gz && \ - mkdir /cmake && \ - tar -xzf cmake.tgz -C /cmake --strip-components 1 - -WORKDIR /app -ADD ./src /app/src -COPY ./composer.* /app/ -ADD ./bin/setup-runtime /app/bin/setup-runtime -ADD ./bin/spc /app/bin/spc -RUN /app/bin/setup-runtime -RUN /app/bin/php /app/bin/composer install --no-dev --classmap-authoritative -ENV PATH="/app/bin:/cmake/bin:/usr/local/go/bin:$PATH" -ENV SPC_LIBC=glibc - -ADD ./config/env.ini /app/config/env.ini -RUN bin/spc doctor --auto-fix --debug - -RUN curl -o make.tgz -fsSL https://ftp.gnu.org/gnu/make/make-4.4.tar.gz && \ - tar -zxvf make.tgz && \ - cd make-4.4 && \ - ./configure && \ - make && \ - make install && \ - ln -sf /usr/local/bin/make /usr/bin/make - -RUN curl -o automake.tgz -fsSL https://ftp.gnu.org/gnu/automake/automake-1.17.tar.xz && \ - tar -xvf automake.tgz && \ - cd automake-1.17 && \ - ./configure && \ - make && \ - make install && \ - ln -sf /usr/local/bin/automake /usr/bin/automake - -RUN git clone https://github.com/static-php/gnu-frankenphp --depth=1 /frankenphp -WORKDIR /frankenphp - -RUN curl -o go.tgz -fsSL https://go.dev/dl/go1.24.1.linux-$GO_ARCH.tar.gz && \ - rm -rf /usr/local/go && tar -C /usr/local -xzf go.tgz -EOF -fi - -# Check if in ci (local terminal can execute with -it) -if [ -t 0 ]; then - INTERACT=-it -else - INTERACT='' -fi - -# Mounting volumes -MOUNT_LIST="" -# shellcheck disable=SC2089 -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/config:/app/config" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/src:/app/src" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/buildroot:/app/buildroot" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/source:/app/source" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot" -MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/frankenphp-dist:/frankenphp/dist" - -# Apply env in temp env file -echo 'CC=/opt/rh/devtoolset-10/root/usr/bin/gcc' > /tmp/spc-gnu-docker.env -echo 'CXX=/opt/rh/devtoolset-10/root/usr/bin/g++' >> /tmp/spc-gnu-docker.env -echo 'AR=/opt/rh/devtoolset-10/root/usr/bin/ar' >> /tmp/spc-gnu-docker.env -echo 'LD=/opt/rh/devtoolset-10/root/usr/bin/ld' >> /tmp/spc-gnu-docker.env -echo 'SPC_DEFAULT_C_FLAGS=-fPIE -fPIC' >> /tmp/spc-gnu-docker.env -echo 'SPC_LIBC=glibc' >> /tmp/spc-gnu-docker.env -echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-Wl,-O1 -pie"' >> /tmp/spc-gnu-docker.env -echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' >> /tmp/spc-gnu-docker.env - -# Run docker -# shellcheck disable=SC2068 -# shellcheck disable=SC2086 -# shellcheck disable=SC2090 - -$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-frankenphp-gnu-$SPC_USE_ARCH ./build-static.sh diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index 6cc36bfa6..9b5d0aa38 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -108,7 +108,6 @@ ADD ./bin/spc /app/bin/spc RUN /app/bin/setup-runtime RUN /app/bin/php /app/bin/composer install --no-dev ENV PATH="/app/bin:/cmake/bin:$PATH" -ENV SPC_LIBC=glibc ADD ./config/env.ini /app/config/env.ini RUN CC=gcc bin/spc doctor --auto-fix --debug @@ -159,7 +158,6 @@ echo 'CXX=/opt/rh/devtoolset-10/root/usr/bin/g++' >> /tmp/spc-gnu-docker.env echo 'AR=/opt/rh/devtoolset-10/root/usr/bin/ar' >> /tmp/spc-gnu-docker.env echo 'LD=/opt/rh/devtoolset-10/root/usr/bin/ld' >> /tmp/spc-gnu-docker.env echo 'SPC_DEFAULT_C_FLAGS=-fPIC' >> /tmp/spc-gnu-docker.env -echo 'SPC_LIBC=glibc' >> /tmp/spc-gnu-docker.env echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-Wl,-O1 -pie"' >> /tmp/spc-gnu-docker.env echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' >> /tmp/spc-gnu-docker.env diff --git a/config/env.ini b/config/env.ini index d80bc3e7c..e6b72fb80 100644 --- a/config/env.ini +++ b/config/env.ini @@ -28,12 +28,6 @@ ; PATH: static-php-cli will add `$BUILD_BIN_PATH` to PATH. ; PKG_CONFIG: static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG. ; PKG_CONFIG_PATH: static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH. -; -; * These vars are only be defined in LinuxBuilder and cannot be changed anywhere: -; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`) -; SPC_LINUX_DEFAULT_CXX: the default c++ compiler for linux. (For alpine linux: `g++`, default: `$GNU_ARCH-linux-musl-g++`) -; SPC_LINUX_DEFAULT_AR: the default archiver for linux. (For alpine linux: `ar`, default: `$GNU_ARCH-linux-musl-ar`) - [global] ; Build concurrency for make -jN, default is CPU_COUNT, this value are used in every libs. @@ -63,13 +57,11 @@ UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe" SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static [linux] -; include PATH for musl libc. -SPC_LIBC=musl ; compiler environments -CC=${SPC_LINUX_DEFAULT_CC} -CXX=${SPC_LINUX_DEFAULT_CXX} -AR=${SPC_LINUX_DEFAULT_AR} -LD=${SPC_LINUX_DEFAULT_LD} +CC=gcc +CXX=g++ +AR=ar +LD=ld ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build SPC_DEFAULT_C_FLAGS="-fPIC -Os" SPC_DEFAULT_CXX_FLAGS="-fPIC -Os" @@ -78,7 +70,7 @@ SPC_EXTRA_LIBS= ; upx executable path UPX_EXEC=${PKG_ROOT_PATH}/bin/upx ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches -SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream +SPC_MICRO_PATCHES=cli_checks,disable_huge_page,zend_stream ; *** default build command for building php *** ; buildconf command diff --git a/docs/en/develop/system-build-tools.md b/docs/en/develop/system-build-tools.md index 48273f639..ca20a2ac0 100644 --- a/docs/en/develop/system-build-tools.md +++ b/docs/en/develop/system-build-tools.md @@ -35,40 +35,9 @@ One of the reasons it cannot be statically linked is that its network library `n For the glibc environment, in static-php-cli and spc in 2.0-RC8 and later, you can choose two ways to build static PHP: 1. Use Docker to build, you can use `bin/spc-alpine-docker` to build, it will build an Alpine Linux docker image. -2. Use `bin/spc doctor --auto-fix` to install the `musl-wrapper` and `musl-cross-make` packages, and then build directly. +2. Use `bin/spc doctor --auto-fix` and then build for glibc directly. ([Related source code](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php)) -Generally speaking, the build results in these two environments are consistent, and you can choose according to actual needs. - -In the doctor module, static-php-cli will first detect the current Linux distribution. -If the current distribution is a glibc environment, you will be prompted to install the musl-wrapper and musl-cross-make packages. - -The process of installing `musl-wrapper` in the glibc environment is as follows: - -1. Download the specific version of [musl-wrapper source code](https://musl.libc.org/releases/) from the musl official website. -2. Use `gcc` installed from the package management to compile the musl-wrapper source code and generate `musl-libc` and other libraries: `./configure --disable-gcc-wrapper && make -j && sudo make install`. -3. The musl-wrapper related libraries will be installed in the `/usr/local/musl` directory. - -The process of installing `musl-cross-make` in the glibc environment is as follows: - -1. Download the precompiled [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) compressed package from dl.static-php.dev . -2. Unzip to the `/usr/local/musl` directory. - -::: tip -In the glibc environment, static compilation can be achieved by directly installing musl-wrapper, -but musl-wrapper only contains `musl-gcc` and not `musl-g++`, which means that C++ code cannot be compiled. -So we need musl-cross-make to provide `musl-g++`. - -The reason why the musl-cross-make package cannot be compiled directly locally is that -its compilation environment requirements are relatively high (requires more than 36GB of memory, compiled under Alpine Linux), -so we provide precompiled binary packages that can be used for all Linux distributions. - -At the same time, the package management of some distributions provides musl-wrapper, -but musl-cross-make needs to match the corresponding musl-wrapper version, -so we do not use package management to install musl-wrapper. - -Compiling musl-cross-make will be introduced in the **musl-cross-make Toolchain Compilation** section of this chapter. -::: ### Musl Environment @@ -82,133 +51,14 @@ You only need to install basic compilation tools (such as `gcc`, `cmake`, etc.) For other distributions, if your distribution uses the musl environment, you can also use static-php-cli to build static PHP directly after installing the necessary compilation tools. -::: tip -In the musl environment, static-php-cli will automatically skip the installation of musl-wrapper and musl-cross-make. -::: - ### Docker Environment -The Docker environment refers to using Docker containers to build static PHP. You can use `bin/spc-alpine-docker` to build. -Before executing this command, you need to install Docker first, and then execute `bin/spc-alpine-docker` in the project root directory. +The Docker environment refers to using Docker containers to build static PHP. You can use `bin/spc-alpine-docker` or `bin/spc-gnu-docker` to build. +Before executing this command, you need to install Docker first. After executing `bin/spc-alpine-docker`, static-php-cli will automatically download the Alpine Linux image and then build a `cwcc-spc-x86_64` or `cwcc-spc-aarch64` image. Then all build process is performed within this image, which is equivalent to compiling in Alpine Linux. -## musl-cross-make Toolchain Compilation - -In Linux, although you do not need to manually compile the musl-cross-make tool, -if you want to understand its compilation process, you can refer here. -Another important reason is that this may not be compiled using automated tools such as CI and Actions, -because the existing CI service compilation environment does not meet the compilation requirements of musl-cross-make, -and the configuration that meets the requirements is too expensive. - -The compilation process of musl-cross-make is as follows: - -Prepare an Alpine Linux environment (either directly installed or using Docker). -The compilation process requires more than **36GB** of memory, -so you need to compile on a machine with larger memory. -Without this much memory, compilation may fail. - -Then write the following content into the `config.mak` file: - -```makefile -STAT = -static --static -FLAG = -g0 -Os -Wno-error - -ifneq ($(NATIVE),) -COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}" -else -COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}" -endif - -COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}" - -BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no -GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie -#--enable-default-pie - -CONFIG_SUB_REV = 888c8e3d5f7b -GCC_VER = 13.2.0 -BINUTILS_VER = 2.40 -MUSL_VER = 1.2.4 -GMP_VER = 6.2.1 -MPC_VER = 1.2.1 -MPFR_VER = 4.2.0 -LINUX_VER = 6.1.36 -``` - -And also you need to add `gcc-13.2.0.tar.xz.sha1` file, contents here: - -``` -5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz -``` - -If you are using Docker to build, create a new `Dockerfile` file and write the following content: - -```dockerfile -FROM alpine:edge - -RUN apk add --no-cache \ -gcc g++ git make curl perl \ -rsync patch wget libtool \ -texinfo autoconf automake \ -bison tar xz bzip2 zlib \ -file binutils flex \ -linux-headers libintl \ -gettext gettext-dev icu-libs pkgconf \ -pkgconfig icu-dev bash \ -ccache libarchive-tools zip - -WORKDIR /opt - -RUN git clone https://git.zv.io/toolchains/musl-cross-make.git -WORKDIR /opt/musl-cross-make -COPY config.mak /opt/musl-cross-make -COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes - -RUN make TARGET=x86_64-linux-musl -j || : -RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h -RUN make TARGET=x86_64-linux-musl -j -RUN make TARGET=x86_64-linux-musl install -j -RUN tar cvzf x86_64-musl-toolchain.tgz output/* -``` - -If you are using Alpine Linux in a non-Docker environment, you can directly execute the commands in the Dockerfile, for example: - -```bash -apk add --no-cache \ -gcc g++ git make curl perl \ -rsync patch wget libtool \ -texinfo autoconf automake \ -bison tar xz bzip2 zlib \ -file binutils flex \ -linux-headers libintl \ -gettext gettext-dev icu-libs pkgconf \ -pkgconfig icu-dev bash \ -ccache libarchive-tools zip - -git clone https://git.zv.io/toolchains/musl-cross-make.git -# Copy config.mak to the working directory of musl-cross-make. -# You need to replace /path/to/config.mak with your config.mak file path. -cp /path/to/config.mak musl-cross-make/ -cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes - -make TARGET=x86_64-linux-musl -j || : -sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h -make TARGET=x86_64-linux-musl -j -make TARGET=x86_64-linux-musl install -j -tar cvzf x86_64-musl-toolchain.tgz output/* -``` - -::: tip -All the above scripts are suitable for x86_64 architecture Linux. -If you need to build musl-cross-make for the ARM environment, just replace all `x86_64` above with `aarch64`. -::: - -This compilation process may fail due to insufficient memory, network problems, etc. -You can try a few more times, or use a machine with larger memory to compile. -If you encounter problems or you have better improvement solutions, go to [Discussion](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1). - ## macOS Environment For macOS systems, the main compilation tool we use is `clang`, diff --git a/docs/en/guide/manual-build.md b/docs/en/guide/manual-build.md index e8e4510e4..13dd6508a 100644 --- a/docs/en/guide/manual-build.md +++ b/docs/en/guide/manual-build.md @@ -335,7 +335,7 @@ During the compilation process, in some special cases, the compiler and the content of the compilation directory need to be intervened. You can try to use the following commands: -- `--cc=XXX`: Specifies the execution command of the C language compiler (Linux default `musl-gcc` or `gcc`, macOS default `clang`) +- `--cc=XXX`: Specifies the execution command of the C language compiler (Linux default `gcc`, macOS default `clang`) - `--cxx=XXX`: Specifies the execution command of the C++ language compiler (Linux defaults to `g++`, macOS defaults to `clang++`) - `--with-clean`: clean up old make files before compiling PHP - `--enable-zts`: Make compiled PHP thread-safe version (default is NTS version) @@ -657,8 +657,7 @@ By default, static-php uses the following compilers on different systems: - macOS: `clang` - Linux (Alpine Linux): `gcc` -- Linux (glibc based distros, x86_64): `/usr/local/musl/bin/x86_64-linux-musl-gcc` -- Linux (glibc based distros, aarch64): `/usr/local/musl/bin/aarch64-linux-musl-gcc` +- Linux (glibc based distros): `gcc` - FreeBSD: `clang` Here is an example of using embed SAPI: @@ -692,8 +691,10 @@ echo "Hello world!\n"; ``` ```bash -# compile in debian/ubuntu x86_64 -/usr/local/musl/bin/x86_64-linux-musl-gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed +# compile in Alpine +gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed +# compile in glibc distros +gcc embed.c $(bin/spc spc-config bcmath,zlib) -o embed # compile in macOS/FreeBSD clang embed.c $(bin/spc spc-config bcmath,zlib) -o embed diff --git a/docs/zh/develop/system-build-tools.md b/docs/zh/develop/system-build-tools.md index a96d4dace..347eedbdc 100644 --- a/docs/zh/develop/system-build-tools.md +++ b/docs/zh/develop/system-build-tools.md @@ -24,36 +24,10 @@ glibc 环境指的是系统底层的 `libc` 库(即所有 C 语言编写的程 而 glibc 环境下,我们使用的包管理、编译器都是默认指向 glibc 的,glibc 不能被良好地静态链接。它不能被静态链接的原因之一是它的网络库 `nss` 无法静态编译。 -对于 glibc 环境,在 2.0 RC8 及以后的 static-php-cli 及 spc 中,你可以选择两种方式来构建静态 PHP: +对于 glibc 环境,在 static-php-cli 及 spc 中,你可以选择两种方式来构建静态 PHP: -1. 使用 Docker 构建,这是最简单的方式,你可以使用 `bin/spc-alpine-docker` 来构建,它会在 Alpine Linux 环境下构建。 -2. 使用 `bin/spc doctor` 安装 musl-wrapper 和 musl-cross-make 套件,然后直接正常构建。([相关源码](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php)) - -一般来说,这两种构建方式的构建结果是一致的,你可以根据实际需求选择。 - -在 doctor 模块中,static-php-cli 会先检测当前的 Linux 发行版。如果当前发行版是 glibc 环境,会提示需要安装 musl-wrapper 和 musl-cross-make 套件。 - -在 glibc 环境下安装 musl-wrapper 的过程如下: - -1. 从 musl 官网下载特定版本的 [musl-wrapper 源码](https://musl.libc.org/releases/)。 -2. 使用从包管理安装的 `gcc` 编译 musl-wrapper 源码,生成 `musl-libc` 等库:`./configure --disable-gcc-wrapper && make -j && sudo make install`。 -3. musl-wrapper 相关库将被安装在 `/usr/local/musl` 目录。 - -在 glibc 环境下安装 musl-cross-make 的过程如下: - -1. 从 dl.static-php.dev 下载预编译好的 [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) 压缩包。 -2. 解压到 `/usr/local/musl` 目录。 - -::: tip -在 glibc 环境下,静态编译可以通过直接安装 musl-wrapper 来实现,但是 musl-wrapper 仅包含了 `musl-gcc`,而没有 `musl-g++`,这也就意味着无法编译 C++ 代码。 -所以我们需要 musl-cross-make 来提供 `musl-g++`。 - -而 musl-cross-make 套件无法在本地直接编译的原因是它的编译环境要求比较高(需要 36GB 以上内存,Alpine Linux 下编译),所以我们提供了预编译好的二进制包,可用于所有 Linux 发行版。 - -同时,部分发行版的包管理提供了 musl-wrapper,但 musl-cross-make 需要匹配对应的 musl-wrapper 版本,所以我们不使用包管理安装 musl-wrapper。 - -对于如何编译 musl-cross-make,将在本章节内的 **编译 musl-cross-make** 小节中介绍。 -::: +1. 使用 Docker 构建,你可以使用 `bin/spc-alpine-docker` 或 `bin/spc-gnu-docker` 来构建。 +2. 使用 `bin/spc doctor --auto-fix` 然后直接构建 glibc。) ### musl 环境 @@ -63,124 +37,14 @@ musl 环境指的是系统底层的 `libc` 库使用的是 `musl`,这是一种 对于其他发行版,如果你的发行版使用的是 musl 环境,那么你也可以在安装必要的编译工具后直接使用 static-php-cli 构建静态 PHP。 -::: tip -在 musl 环境下,static-php-cli 会自动跳过 musl-wrapper 和 musl-cross-make 的安装。 -::: - ### Docker 环境 -Docker 环境指的是使用 Docker 容器来构建静态 PHP,你可以使用 `bin/spc-alpine-docker` 来构建。 +Docker 环境指的是使用 Docker 容器来构建静态 PHP,你可以使用 `bin/spc-alpine-docker` 或 `bin/spc-gnu-docker` 来构建。 执行这个命令前需要先安装 Docker,然后在项目根目录执行 `bin/spc-alpine-docker` 即可。 在执行 `bin/spc-alpine-docker` 后,static-php-cli 会自动下载 Alpine Linux 镜像,然后构建一个 `cwcc-spc-x86_64` 或 `cwcc-spc-aarch64` 的镜像。 然后一切的构建都在这个镜像内进行,相当于在 Alpine Linux 内编译。总的来说,Docker 环境就是 musl 环境。 -## musl-cross-make 工具链编译 - -在 Linux 中,尽管你不需要手动编译 musl-cross-make 工具,但是如果你想了解它的编译过程,可以参考这里。 -还有一个重要的原因就是,这个可能无法使用 CI、Actions 等自动化工具编译,因为现有的 CI 服务编译环境不满足 musl-cross-make 的编译要求,满足要求的配置价格太高。 - -musl-cross-make 的编译过程如下: - -准备一个 Alpine Linux 环境(直接安装或使用 Docker 均可),编译的过程需要 36GB 以上内存,所以你需要在内存较大的机器上编译。如果没有这么多内存,可能会导致编译失败。 - -然后将以下内容写入 `config.mak` 文件内: - -```makefile -STAT = -static --static -FLAG = -g0 -Os -Wno-error - -ifneq ($(NATIVE),) -COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}" -else -COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}" -endif - -COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}" - -BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no -GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie -#--enable-default-pie - -CONFIG_SUB_REV = 888c8e3d5f7b -GCC_VER = 13.2.0 -BINUTILS_VER = 2.40 -MUSL_VER = 1.2.4 -GMP_VER = 6.2.1 -MPC_VER = 1.2.1 -MPFR_VER = 4.2.0 -LINUX_VER = 6.1.36 -``` - -同时,你需要新建一个 `gcc-13.2.0.tar.xz.sha1` 文件,文件内容如下: - -``` -5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz -``` - -如果你使用的是 Docker 构建,新建一个 `Dockerfile` 文件,写入以下内容: - -```dockerfile -FROM alpine:edge - -RUN apk add --no-cache \ -gcc g++ git make curl perl \ -rsync patch wget libtool \ -texinfo autoconf automake \ -bison tar xz bzip2 zlib \ -file binutils flex \ -linux-headers libintl \ -gettext gettext-dev icu-libs pkgconf \ -pkgconfig icu-dev bash \ -ccache libarchive-tools zip - -WORKDIR /opt - -RUN git clone https://git.zv.io/toolchains/musl-cross-make.git -WORKDIR /opt/musl-cross-make -COPY config.mak /opt/musl-cross-make -COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes - -RUN make TARGET=x86_64-linux-musl -j || : -RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h -RUN make TARGET=x86_64-linux-musl -j -RUN make TARGET=x86_64-linux-musl install -j -RUN tar cvzf x86_64-musl-toolchain.tgz output/* -``` - -如果你使用的是非 Docker 环境的 Alpine Linux,可以直接执行 Dockerfile 中的命令,例如: - -```bash -apk add --no-cache \ -gcc g++ git make curl perl \ -rsync patch wget libtool \ -texinfo autoconf automake \ -bison tar xz bzip2 zlib \ -file binutils flex \ -linux-headers libintl \ -gettext gettext-dev icu-libs pkgconf \ -pkgconfig icu-dev bash \ -ccache libarchive-tools zip - -git clone https://git.zv.io/toolchains/musl-cross-make.git -# 将 config.mak 拷贝到 musl-cross-make 的工作目录内,你需要将 /path/to/config.mak 替换为你的 config.mak 文件路径 -cp /path/to/config.mak musl-cross-make/ -cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes - -make TARGET=x86_64-linux-musl -j || : -sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h -make TARGET=x86_64-linux-musl -j -make TARGET=x86_64-linux-musl install -j -tar cvzf x86_64-musl-toolchain.tgz output/* -``` - -::: tip -以上所有脚本都适用于 x86_64 架构的 Linux。如果你需要构建 ARM 环境的 musl-cross-make,只需要将上方所有 `x86_64` 替换为 `aarch64` 即可。 -::: - -这个编译过程可能会因为内存不足、网络问题等原因导致编译失败,你可以多尝试几次,或者使用更大内存的机器来编译。 -如果遇到了问题,或者你有更好的改进方案,可以在 [讨论](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1) 中提出。 - ## macOS 环境编译工具 对于 macOS 系统来说,我们使用的编译工具主要是 `clang`,它是 macOS 系统默认的编译器,同时也是 Xcode 的编译器。 diff --git a/docs/zh/guide/manual-build.md b/docs/zh/guide/manual-build.md index 5301fca14..340094f35 100644 --- a/docs/zh/guide/manual-build.md +++ b/docs/zh/guide/manual-build.md @@ -292,7 +292,7 @@ bin/spc build bcmath,curl,openssl,ftp,posix,pcntl --build-cli 在编译过程中,有些特殊情况需要对编译器、编译目录的内容进行干预,可以尝试使用以下命令: -- `--cc=XXX`: 指定 C 语言编译器的执行命令(Linux 默认 `musl-gcc` 或 `gcc`,macOS 默认 `clang`) +- `--cc=XXX`: 指定 C 语言编译器的执行命令(Linux 默认 `gcc`,macOS 默认 `clang`) - `--cxx=XXX`: 指定 C++ 语言编译器的执行命令(Linux 默认 `g++`,macOS 默认 `clang++`) - `--with-clean`: 编译 PHP 前先清理旧的 make 产生的文件 - `--enable-zts`: 让编译的 PHP 为线程安全版本(默认为 NTS 版本) @@ -592,8 +592,7 @@ bin/spc spc-config curl,zlib,phar,openssl --includes - macOS: `clang` - Linux (Alpine Linux): `gcc` -- Linux (glibc based distros, x86_64): `/usr/local/musl/bin/x86_64-linux-musl-gcc` -- Linux (glibc based distros, aarch64): `/usr/local/musl/bin/aarch64-linux-musl-gcc` +- Linux (glibc based distros): `gcc` - FreeBSD: `clang` 下面是一个使用 embed SAPI 的例子: @@ -627,8 +626,10 @@ echo "Hello world!\n"; ``` ```bash -# compile in debian/ubuntu x86_64 -/usr/local/musl/bin/x86_64-linux-musl-gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed +# compile in Alpine +gcc embed.c $(bin/spc spc-config bcmath,zlib) -static -o embed +# compile in glibc distros +gcc embed.c $(bin/spc spc-config bcmath,zlib) -o embed # compile in macOS/FreeBSD clang embed.c $(bin/spc spc-config bcmath,zlib) -o embed diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php index 7951ea69d..b57c964f6 100644 --- a/src/SPC/builder/extension/imagick.php +++ b/src/SPC/builder/extension/imagick.php @@ -15,7 +15,7 @@ public function patchBeforeMake(): bool if (PHP_OS_FAMILY !== 'Linux') { return false; } - if (getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) { + if (getenv('NO_LIBGOMP')) { return false; } // imagick with calls omp_pause_all, which requires openmp, on non-musl we build imagick without openmp @@ -26,7 +26,7 @@ public function patchBeforeMake(): bool public function getUnixConfigureArg(bool $shared = false): string { - $disable_omp = !(getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) ? '' : ' ac_cv_func_omp_pause_resource_all=no'; + $disable_omp = !(getenv('NO_LIBGOMP')) ? '' : ' ac_cv_func_omp_pause_resource_all=no'; return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $disable_omp; } @@ -34,7 +34,7 @@ protected function getStaticAndSharedLibs(): array { // on centos 7, it will use the symbol _ZTINSt6thread6_StateE, which is not defined in system libstdc++.so.6 [$static, $shared] = parent::getStaticAndSharedLibs(); - if (getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) { + if (str_contains(getenv('CC'), 'devtoolset-10')) { $static .= ' -lstdc++'; $shared = str_replace('-lstdc++', '', $shared); } diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 722601d18..66a657bb2 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -30,18 +30,6 @@ public function __construct(array $options = []) GlobalEnvManager::init($this); - if (getenv('SPC_LIBC') === 'musl' && !SystemUtil::isMuslDist()) { - $this->setOptionIfNotExist('library_path', "LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\""); - $this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\""); - $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE'); - $configure = "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\" " . $configure; - GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE={$configure}"); - - if (!file_exists("/usr/local/musl/{$arch}-linux-musl/lib/libc.a")) { - throw new WrongUsageException('You are building with musl-libc target in glibc distro, but musl-toolchain is not installed, please install musl-toolchain first. (You can use `doctor` command to install it)'); - } - } - // concurrency $this->concurrency = intval(getenv('SPC_CONCURRENCY')); // cflags diff --git a/src/SPC/builder/linux/SystemUtil.php b/src/SPC/builder/linux/SystemUtil.php index a85f3dec6..861e5fe7c 100644 --- a/src/SPC/builder/linux/SystemUtil.php +++ b/src/SPC/builder/linux/SystemUtil.php @@ -62,6 +62,11 @@ public static function isMuslDist(): bool return static::getOSRelease()['dist'] === 'alpine'; } + public static function isGlibcDist(): bool + { + return PHP_OS_FAMILY === 'Linux' && static::getOSRelease()['dist'] !== 'alpine'; + } + public static function getCpuCount(): int { $ncpu = 1; @@ -193,7 +198,7 @@ public static function getLibcVersionIfExists(): ?string if (self::$libc_version !== null) { return self::$libc_version; } - if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'glibc') { + if (PHP_OS_FAMILY === 'Linux' && !SystemUtil::isMuslDist()) { $result = shell()->execWithResult('ldd --version', false); if ($result[0] !== 0) { return null; @@ -208,12 +213,8 @@ public static function getLibcVersionIfExists(): ?string } return null; } - if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') { - if (self::isMuslDist()) { - $result = shell()->execWithResult('ldd 2>&1', false); - } else { - $result = shell()->execWithResult('/usr/local/musl/lib/libc.so 2>&1', false); - } + if (PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist()) { + $result = shell()->execWithResult('ldd 2>&1', false); // Match Version * line // match ldd version: "Version 1.2.3" match 1.2.3 $pattern = '/Version\s+(\d+\.\d+\.\d+)/'; @@ -224,4 +225,15 @@ public static function getLibcVersionIfExists(): ?string } return null; } + + public static function getLibcName() + { + if (PHP_OS_FAMILY === 'Darwin') { + return 'libSystem'; + } + if (PHP_OS_FAMILY === 'Windows') { + return 'msvcrt'; + } + return self::isMuslDist() ? 'musl' : 'glibc'; + } } diff --git a/src/SPC/builder/linux/library/icu.php b/src/SPC/builder/linux/library/icu.php index aa2825b7d..96235bb3f 100644 --- a/src/SPC/builder/linux/library/icu.php +++ b/src/SPC/builder/linux/library/icu.php @@ -4,6 +4,7 @@ namespace SPC\builder\linux\library; +use SPC\builder\linux\SystemUtil; use SPC\store\FileSystem; class icu extends LinuxLibraryBase @@ -16,7 +17,7 @@ protected function build(): void { $cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"'; $cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"'; - $ldflags = getenv('SPC_LIBC') !== 'glibc' ? 'LDFLAGS="-static"' : ''; + $ldflags = SystemUtil::isMuslDist() ? 'LDFLAGS="-static"' : ''; shell()->cd($this->source_dir . '/source')->initializeEnv($this) ->exec( "{$cppflags} {$cxxflags} {$ldflags} " . diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 0d56b0eb3..4eb50bdea 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -7,6 +7,7 @@ use SPC\builder\BuilderBase; use SPC\builder\freebsd\library\BSDLibraryBase; use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\linux\SystemUtil; use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; @@ -200,7 +201,7 @@ protected function sanityCheck(int $build_target): void $util = new SPCConfigUtil($this); $config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs')); $lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}"; - if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') { + if (SystemUtil::isMuslDist()) { $lens .= ' -static'; } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens); @@ -334,7 +335,7 @@ protected function buildFrankenphp(): void $debugFlags = $this->getOption('no-strip') ? "'-w -s' " : ''; $extLdFlags = "-extldflags '-pie'"; $muslTags = ''; - if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') { + if (SystemUtil::isMuslDist()) { $extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'"; $muslTags = 'static_build,'; } diff --git a/src/SPC/builder/unix/library/imagemagick.php b/src/SPC/builder/unix/library/imagemagick.php index ead786a22..7892f69cd 100644 --- a/src/SPC/builder/unix/library/imagemagick.php +++ b/src/SPC/builder/unix/library/imagemagick.php @@ -4,7 +4,7 @@ namespace SPC\builder\unix\library; -use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\linux\SystemUtil; use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; @@ -33,13 +33,13 @@ protected function build(): void ->optionalLib('bzip2', ...ac_with_args('bzlib')) ->addConfigureArgs( // TODO: glibc rh 10 toolset's libgomp.a was built without -fPIC so we can't use openmp without depending on libgomp.so - getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10') ? '--disable-openmp' : '--enable-openmp', + getenv('NO_LIBGOMP') ? '--disable-openmp' : '--enable-openmp', '--without-jxl', '--without-x', ); // special: linux musl needs `-static` - $ldflags = ($this instanceof LinuxLibraryBase) && getenv('SPC_LIBC') !== 'glibc' ? ('-static -ldl') : '-ldl'; + $ldflags = SystemUtil::isMuslDist() ? '-static -ldl' : '-ldl'; // special: macOS needs -iconv $libs = $this instanceof MacOSLibraryBase ? '-liconv' : ''; diff --git a/src/SPC/builder/unix/library/ldap.php b/src/SPC/builder/unix/library/ldap.php index 62f7bcd75..a0c5658e0 100644 --- a/src/SPC/builder/unix/library/ldap.php +++ b/src/SPC/builder/unix/library/ldap.php @@ -4,6 +4,7 @@ namespace SPC\builder\unix\library; +use SPC\builder\linux\SystemUtil; use SPC\store\FileSystem; use SPC\util\executor\UnixAutoconfExecutor; @@ -11,7 +12,7 @@ trait ldap { public function patchBeforeBuild(): bool { - $extra = getenv('SPC_LIBC') === 'glibc' ? '-ldl -lpthread -lm -lresolv -lutil' : ''; + $extra = SystemUtil::isGlibcDist() ? '-ldl -lpthread -lm -lresolv -lutil' : ''; FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz ' . $extra); return true; } diff --git a/src/SPC/builder/unix/library/mimalloc.php b/src/SPC/builder/unix/library/mimalloc.php index 788688565..a102d4ad4 100644 --- a/src/SPC/builder/unix/library/mimalloc.php +++ b/src/SPC/builder/unix/library/mimalloc.php @@ -4,6 +4,7 @@ namespace SPC\builder\unix\library; +use SPC\builder\linux\SystemUtil; use SPC\util\executor\UnixCMakeExecutor; trait mimalloc @@ -15,7 +16,7 @@ protected function build(): void '-DMI_BUILD_SHARED=OFF', '-DMI_INSTALL_TOPLEVEL=ON' ); - if (getenv('SPC_LIBC') === 'musl') { + if (SystemUtil::isMuslDist()) { $cmake->addConfigureArgs('-DMI_LIBC_MUSL=ON'); } $cmake->build(); diff --git a/src/SPC/builder/unix/library/pkgconfig.php b/src/SPC/builder/unix/library/pkgconfig.php index 05727f96a..e22418e50 100644 --- a/src/SPC/builder/unix/library/pkgconfig.php +++ b/src/SPC/builder/unix/library/pkgconfig.php @@ -4,7 +4,7 @@ namespace SPC\builder\unix\library; -use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\linux\SystemUtil; use SPC\util\executor\UnixAutoconfExecutor; trait pkgconfig @@ -14,7 +14,7 @@ protected function build(): void UnixAutoconfExecutor::create($this) ->appendEnv([ 'CFLAGS' => PHP_OS_FAMILY !== 'Linux' ? '-Wimplicit-function-declaration -Wno-int-conversion' : '', - 'LDFLAGS' => !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? '' : '--static', + 'LDFLAGS' => SystemUtil::isMuslDist() ? '--static' : '', ]) ->configure( '--with-internal-glib', diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index 1de3e4c28..7d1f9ea1c 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -5,6 +5,7 @@ namespace SPC\builder\unix\library; use SPC\builder\linux\library\LinuxLibraryBase; +use SPC\builder\linux\SystemUtil; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -50,7 +51,7 @@ protected function build(): void $error_exec_cnt += $output[0] === 0 ? 0 : 1; if (!empty($output[1][0])) { $ldflags = $output[1][0]; - $envs .= !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? " LDFLAGS=\"{$ldflags}\" " : " LDFLAGS=\"{$ldflags} -static\" "; + $envs .= (SystemUtil::isMuslDist() ? " LDFLAGS=\"{$ldflags} -static\" " : " LDFLAGS=\"{$ldflags}\" "); } $output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}"); $error_exec_cnt += $output[0] === 0 ? 0 : 1; diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 21a848a5e..c5646de3b 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -5,6 +5,7 @@ namespace SPC\command; use SPC\builder\BuilderProvider; +use SPC\builder\linux\SystemUtil; use SPC\exception\ExceptionHandler; use SPC\exception\WrongUsageException; use SPC\store\Config; @@ -63,7 +64,7 @@ public function handle(): int // check dynamic extension build env // linux must build with glibc - if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') { + if (!empty($shared_extensions) && SystemUtil::isMuslDist()) { $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!'); return static::FAILURE; } diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index d5054aa95..10bc7f732 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -223,8 +223,8 @@ public function handle(): int '{name}' => $source, '{arch}' => arch2gnu(php_uname('m')), '{os}' => strtolower(PHP_OS_FAMILY), - '{libc}' => getenv('SPC_LIBC') ?: 'default', - '{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default', + '{libc}' => SystemUtil::getLibcName(), + '{libcver}' => SystemUtil::getLibcVersionIfExists() ?? 'default', ]; $find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern')); // find filename in asset list diff --git a/src/SPC/command/dev/PackLibCommand.php b/src/SPC/command/dev/PackLibCommand.php index d0d9797e5..296b3e658 100644 --- a/src/SPC/command/dev/PackLibCommand.php +++ b/src/SPC/command/dev/PackLibCommand.php @@ -76,7 +76,7 @@ public function handle(): int '{name}' => $lib->getName(), '{arch}' => arch2gnu(php_uname('m')), '{os}' => strtolower(PHP_OS_FAMILY), - '{libc}' => getenv('SPC_LIBC') ?: 'default', + '{libc}' => SystemUtil::getLibcName(), '{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default', ]; // detect suffix, for proper tar option diff --git a/src/SPC/doctor/item/LinuxMuslCheck.php b/src/SPC/doctor/item/LinuxMuslCheck.php deleted file mode 100644 index 155163552..000000000 --- a/src/SPC/doctor/item/LinuxMuslCheck.php +++ /dev/null @@ -1,123 +0,0 @@ -warning('Current user is not root, using sudo for running command'); - } - // The hardcoded version here is to be consistent with the version compiled by `musl-cross-toolchain`. - $musl_version_name = 'musl-1.2.5'; - $musl_source = [ - 'type' => 'url', - 'url' => "https://musl.libc.org/releases/{$musl_version_name}.tar.gz", - ]; - logger()->info('Downloading ' . $musl_source['url']); - Downloader::downloadSource($musl_version_name, $musl_source); - FileSystem::extractSource($musl_version_name, SPC_SOURCE_ARCHIVE, DOWNLOAD_PATH . "/{$musl_version_name}.tar.gz"); - - // Apply CVE-2025-26519 patch - SourcePatcher::patchFile('musl-1.2.5_CVE-2025-26519_0001.patch', SOURCE_PATH . "/{$musl_version_name}"); - SourcePatcher::patchFile('musl-1.2.5_CVE-2025-26519_0002.patch', SOURCE_PATH . "/{$musl_version_name}"); - logger()->info('Installing musl wrapper'); - shell()->cd(SOURCE_PATH . "/{$musl_version_name}") - ->exec('CC=gcc CXX=g++ AR=ar LD=ld ./configure --disable-gcc-wrapper') - ->exec('CC=gcc CXX=g++ AR=ar LD=ld make -j') - ->exec("CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install"); - // TODO: add path using putenv instead of editing /etc/profile - return true; - } catch (RuntimeException) { - return false; - } - } - - /** @noinspection PhpUnused */ - /** - * @throws FileSystemException - * @throws WrongUsageException - */ - #[AsFixItem('fix-musl-cross-make')] - public function fixMuslCrossMake(): bool - { - try { - $prefix = ''; - if (get_current_user() !== 'root') { - $prefix = 'sudo '; - logger()->warning('Current user is not root, using sudo for running command'); - } - $arch = arch2gnu(php_uname('m')); - logger()->info("Downloading package musl-toolchain-{$arch}-linux"); - PackageManager::installPackage("musl-toolchain-{$arch}-linux"); - $pkg_root = PKG_ROOT_PATH . "/musl-toolchain-{$arch}-linux"; - shell()->exec("{$prefix}cp -rf {$pkg_root}/* /usr/local/musl"); - FileSystem::removeDir($pkg_root); - return true; - } catch (RuntimeException) { - return false; - } - } -} diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index ba0cd124d..9f8d451c2 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -591,7 +591,7 @@ public static function curlDown(string $url, string $path, string $method = 'GET public static function getPreBuiltLockName(string $source): string { - return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . (getenv('SPC_LIBC') ?: 'default') . '-' . (SystemUtil::getLibcVersionIfExists() ?? 'default'); + return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . SystemUtil::getLibcName() . '-' . (SystemUtil::getLibcVersionIfExists() ?? 'default'); } /** diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 26bd8ffc3..b22c2d9fc 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -99,7 +99,7 @@ public static function patchBeforeConfigure(BuilderBase $builder): void } // patch capstone FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"'); - if ($builder instanceof LinuxBuilder && getenv('SPC_LIBC') === 'glibc') { + if (SystemUtil::isGlibcDist()) { FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Zend/zend_operators.h', '# define ZEND_USE_ASM_ARITHMETIC 1', '# define ZEND_USE_ASM_ARITHMETIC 0'); } } diff --git a/src/SPC/util/GlobalEnvManager.php b/src/SPC/util/GlobalEnvManager.php index 177852057..f298c2822 100644 --- a/src/SPC/util/GlobalEnvManager.php +++ b/src/SPC/util/GlobalEnvManager.php @@ -5,7 +5,6 @@ namespace SPC\util; use SPC\builder\BuilderBase; -use SPC\builder\linux\SystemUtil; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; @@ -42,23 +41,6 @@ public static function init(?BuilderBase $builder = null): void self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig'); } - // Define env vars for linux - if (PHP_OS_FAMILY === 'Linux') { - $arch = getenv('GNU_ARCH'); - if (SystemUtil::isMuslDist() || getenv('SPC_LIBC') === 'glibc') { - self::putenv('SPC_LINUX_DEFAULT_CC=gcc'); - self::putenv('SPC_LINUX_DEFAULT_CXX=g++'); - self::putenv('SPC_LINUX_DEFAULT_AR=ar'); - self::putenv('SPC_LINUX_DEFAULT_LD=ld.gold'); - } else { - self::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc"); - self::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++"); - self::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar"); - self::putenv("SPC_LINUX_DEFAULT_LD={$arch}-linux-musl-ld"); - GlobalEnvManager::putenv("PATH=/usr/local/musl/bin:/usr/local/musl/{$arch}-linux-musl/bin:" . getenv('PATH')); - } - } - // Init env.ini file, read order: // WORKING_DIR/config/env.ini // ROOT_DIR/config/env.ini diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 8e69e89ce..71f244eca 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -146,7 +146,7 @@ private function getLibsString(array $libraries, bool $withDependencies = false) } } // patch: imagick (imagemagick wrapper) for linux needs libgomp - if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux' && !(getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10'))) { + if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux' && !getenv('NO_LIBGOMP')) { $short_name[] = '-lgomp'; } return implode(' ', $short_name); diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 990cbdd9f..5f579bd01 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -19,16 +19,14 @@ '8.4', ]; -// test os (macos-13, macos-14, macos-15, ubuntu-latest, windows-latest are available) +// test os $test_os = [ - // 'macos-13', - // 'macos-14', - // 'macos-15', - // 'ubuntu-latest', - // 'ubuntu-22.04', - // 'ubuntu-24.04', + 'macos-14', + 'macos-15', + 'ubuntu-22.04', + 'ubuntu-24.04', 'ubuntu-22.04-arm', - // 'ubuntu-24.04-arm', + 'ubuntu-24.04-arm', // 'windows-latest', ]; @@ -143,8 +141,7 @@ function quote2(string $param): string $prefix = match ($argv[2] ?? null) { 'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ', - 'ubuntu-latest' => 'bin/spc-alpine-docker ', - 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ', + 'ubuntu-24.04', 'ubuntu-24.04-arm' => 'bin/spc-alpine-docker ', 'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ', default => 'bin/spc ', }; @@ -154,13 +151,9 @@ function quote2(string $param): string switch ($argv[2] ?? null) { case 'ubuntu-22.04': case 'ubuntu-22.04-arm': - $shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' '; - break; - case 'macos-13': case 'macos-14': case 'macos-15': $shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' '; - $no_strip = true; break; default: $shared_cmd = '';