diff --git a/.gitignore b/.gitignore index 14d4ae81..0560542f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ packlib_files.txt !/bin/setup-runtime* !/bin/spc-alpine-docker !/bin/php-cs-fixer-wrapper +!/bin/build-static-frankenphp # exclude windows build tools /php-sdk-binary-tools/ diff --git a/bin/build-static-frankenphp b/bin/build-static-frankenphp new file mode 100755 index 00000000..1de01c39 --- /dev/null +++ b/bin/build-static-frankenphp @@ -0,0 +1,150 @@ +#!/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_SKIP_DOCTOR_CHECK_ITEMS="if musl-wrapper is installed,if musl-cross-make is installed" + +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 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)""/dist:/frankenphp/dist" + +# Apply env in temp env file +echo 'SPC_SKIP_DOCTOR_CHECK_ITEMS=if musl-wrapper is installed,if musl-cross-make is installed' > /tmp/spc-gnu-docker.env +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' >> /tmp/spc-gnu-docker.env +echo 'SPC_NO_MUSL_PATH=yes' >> /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 b/bin/spc index c1f7331f..18dd3a38 100755 --- a/bin/spc +++ b/bin/spc @@ -4,6 +4,11 @@ use SPC\ConsoleApplication; use SPC\exception\ExceptionHandler; +// Load custom php if exists +if (PHP_OS_FAMILY !== 'Windows' && PHP_BINARY !== (__DIR__ . '/php') && file_exists(__DIR__ . '/php') && is_executable(__DIR__ . '/php')) { + pcntl_exec(__DIR__ . '/php', $argv); +} + if (file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { // Current: ./bin (git/project mode) require_once dirname(__DIR__) . '/vendor/autoload.php'; diff --git a/bin/spc-alpine-docker b/bin/spc-alpine-docker index 9beb694f..bee9d13c 100755 --- a/bin/spc-alpine-docker +++ b/bin/spc-alpine-docker @@ -119,4 +119,8 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot" # shellcheck disable=SC2068 # shellcheck disable=SC2086 # shellcheck disable=SC2090 -$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@ +if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 +else + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@ +fi diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker new file mode 100755 index 00000000..e589b8ba --- /dev/null +++ b/bin/spc-gnu-docker @@ -0,0 +1,140 @@ +#!/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 + fi + ;; +aarch64) + BASE_ARCH=aarch64 + # 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-spc-gnu-$SPC_USE_ARCH; then + echo "Docker container does not exist. Building docker image ..." + $DOCKER_EXECUTABLE build -t cwcc-spc-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:$PATH" +ENV SPC_SKIP_DOCTOR_CHECK_ITEMS="if musl-wrapper is installed,if musl-cross-make is installed" + +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 + +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" + +# Apply env in temp env file +echo 'SPC_SKIP_DOCTOR_CHECK_ITEMS=if musl-wrapper is installed,if musl-cross-make is installed' > /tmp/spc-gnu-docker.env +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_NO_MUSL_PATH=yes' >> /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-spc-gnu-$SPC_USE_ARCH # bin/spc $@ diff --git a/config/env.ini b/config/env.ini index 3d504baf..1849a371 100644 --- a/config/env.ini +++ b/config/env.ini @@ -76,13 +76,15 @@ SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime ; buildconf command SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" ; configure command -SPC_CMD_PREFIX_PHP_CONFIGURE="${SPC_PHP_DEFAULT_LD_LIBRARY_PATH_CMD} ./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-cgi --disable-phpdbg" +SPC_CMD_PREFIX_PHP_CONFIGURE="${SPC_PHP_DEFAULT_LD_LIBRARY_PATH_CMD} ./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-cgi --disable-phpdbg --with-pic" ; make command SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" +; embed type for php, static (libphp.a) or shared (libphp.so) +SPC_CMD_VAR_PHP_EMBED_TYPE="shared" ; *** default build vars for building php *** ; CFLAGS for configuring php -SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS}" +SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -fPIE" ; CPPFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}" ; LDFLAGS for configuring php @@ -90,7 +92,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; LIBS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE -fPIC" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="" ; EXTRA_LDFLAGS_PROGRAM for `make` php @@ -115,6 +117,8 @@ SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-cgi --disable-phpdbg" ; make command SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" +; embed type for php, static or shared +SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; *** default build vars for building php *** ; CFLAGS for configuring php diff --git a/docs/.vitepress/sidebar.en.ts b/docs/.vitepress/sidebar.en.ts index b9c80aae..1bd0686d 100644 --- a/docs/.vitepress/sidebar.en.ts +++ b/docs/.vitepress/sidebar.en.ts @@ -1,22 +1,24 @@ export default { '/en/guide/': [ { - text: 'Guide', + text: 'Basic Build Guides', items: [ {text: 'Guide', link: '/en/guide/'}, - {text: 'Actions Build', link: '/en/guide/action-build'}, - {text: 'Manual Build', link: '/en/guide/manual-build'}, - {text: 'Extension List', link: '/en/guide/extensions'}, + {text: 'Build (Local)', link: '/en/guide/manual-build'}, + {text: 'Build (CI)', link: '/en/guide/action-build'}, + {text: 'Supported Extensions', link: '/en/guide/extensions'}, {text: 'Extension Notes', link: '/en/guide/extension-notes'}, - {text: 'Command Generator', link: '/en/guide/cli-generator'}, + {text: 'Build Command Generator', link: '/en/guide/cli-generator'}, {text: 'Environment Variables', link: '/en/guide/env-vars', collapsed: true,}, {text: 'Dependency Table', link: '/en/guide/deps-map'}, ] }, { + text: 'Extended Build Guides', items: [ {text: 'Troubleshooting', link: '/en/guide/troubleshooting'}, {text: 'Build on Windows', link: '/en/guide/build-on-windows'}, + {text: 'Build with GNU libc', link: '/en/guide/build-with-glibc'}, ], } ], diff --git a/docs/.vitepress/sidebar.zh.ts b/docs/.vitepress/sidebar.zh.ts index a17ac0f0..cf1630b1 100644 --- a/docs/.vitepress/sidebar.zh.ts +++ b/docs/.vitepress/sidebar.zh.ts @@ -4,8 +4,8 @@ export default { text: '构建指南', items: [ {text: '指南', link: '/zh/guide/'}, - {text: 'Actions 构建', link: '/zh/guide/action-build'}, {text: '本地构建', link: '/zh/guide/manual-build'}, + {text: 'Actions 构建', link: '/zh/guide/action-build'}, {text: '扩展列表', link: '/zh/guide/extensions'}, {text: '扩展注意事项', link: '/zh/guide/extension-notes'}, {text: '编译命令生成器', link: '/zh/guide/cli-generator'}, @@ -14,9 +14,11 @@ export default { ] }, { + text: '扩展构建指南', items: [ {text: '故障排除', link: '/zh/guide/troubleshooting'}, {text: '在 Windows 上构建', link: '/zh/guide/build-on-windows'}, + {text: '构建 GNU libc 兼容的二进制', link: '/zh/guide/build-with-glibc'}, ], } ], diff --git a/docs/en/guide/build-with-glibc.md b/docs/en/guide/build-with-glibc.md new file mode 100644 index 00000000..9573511b --- /dev/null +++ b/docs/en/guide/build-with-glibc.md @@ -0,0 +1,68 @@ +# Build glibc Compatible Linux Binary + +## Why Build glibc Compatible Binary + +Currently, the binaries built by static-php-cli on Linux by default are based on musl-libc (statically linked). +musl-libc is a lightweight libc implementation +that aims to be compatible with glibc and provides good support for pure static linking. +This means that the compiled static PHP executable can be used on almost any Linux distribution without worrying about the versions of libc, libstdc++, etc. + +However, there are some issues with pure static linking of musl-libc binaries on Linux: + +- The `dl()` function in PHP cannot be used to load dynamic libraries and external PHP extensions. +- The FFI extension in PHP cannot be used. +- In some extreme cases, performance issues may occur. See [musl-libc performance issues](https://github.com/php/php-src/issues/13648). + +Different Linux distributions use different default libc. +For example, Alpine Linux uses musl libc, while most Linux distributions use glibc. +However, even so, we cannot directly use any distribution using glibc to build portable static binaries because glibc has some issues: + +- Binaries built with gcc and other tools on newer versions of distributions cannot run on older versions of distributions. +- glibc is not recommended to be statically linked because some of its features require the support of dynamic libraries. + +However, we can use Docker to solve this problem. +The final output is a binary **dynamically linked with glibc** and some necessary libraries, +but **statically linked with all other dependencies**. + +1. Use an older version of a Linux distribution (such as CentOS 7.x), which has an older version of glibc but can run on most modern Linux distributions. +2. Build the static binary of PHP in this container so that it can run on most modern Linux distributions. + +> Using glibc static binaries can run on most modern Linux distributions but cannot run on musl libc distributions, such as CentOS 6, Alpine Linux, etc. + +## Build glibc Compatible Linux Binary + +The latest version of static-php-cli includes the `bin/spc-gnu-docker` script, +which can create a CentOS 7.x (glibc-2.17) Docker container with one click and build a glibc compatible PHP static binary in the container. + +Then, run the following command once. +The first run will take a long time because it needs to download the CentOS 7.x image and some build tools. + +```bash +bin/spc-gnu-docker +``` + +After the image is built, you will see the same command help menu as `bin/spc`, which means the container is ready. + +After the container is ready, you can refer to the [local build](./manual-build) section to build your PHP static binary. +Just replace `bin/spc` or `./spc` with `bin/spc-gnu-docker`. + +Unlike the default build, when building in the glibc environment, you **must** add the parameter `--libc=glibc`, such as: + +```bash +bin/spc-gnu-docker --libc=glibc build bcmath,ctype,openssl,pdo,phar,posix,session,tokenizer,xml,zip --build-cli --debug +``` + +## Notes + +In rare cases, glibc-based static PHP may encounter segment faults and other errors, but there are currently few examples. +If you encounter any issues, please submit an issue. + +glibc build is an extended feature and is not part of the default static-php support. +If you have related issues or requirements, please indicate that you are building based on glibc when submitting an issue. + +If you need to build glibc-based binaries without using Docker, +please refer to the `bin/spc-gnu-docker` script to manually create a similar environment. + +Since glibc binaries are not the main goal of the project, +we generally do not test the compatibility of various libraries and extensions under glibc. +If any specific library builds successfully on musl-libc but fails on glibc, please submit an issue. diff --git a/docs/en/guide/env-vars.md b/docs/en/guide/env-vars.md index 10581733..11cf9339 100644 --- a/docs/en/guide/env-vars.md +++ b/docs/en/guide/env-vars.md @@ -39,6 +39,21 @@ Or, if you need to modify an environment variable for a long time, you can modif For example, if you need to modify the `./configure` command for compiling PHP, you can find the `SPC_CMD_PREFIX_PHP_CONFIGURE` environment variable in the `config/env.ini` file, and then modify its value. +If your build conditions are more complex and require multiple `env.ini` files to switch, +we recommend that you use the `config/env.custom.ini` file. +In this way, you can specify your environment variables by writing additional override items +without modifying the default `config/env.ini` file. + +```ini +; This is an example of `config/env.custom.ini` file, +; we modify the `SPC_CONCURRENCY` and linux default CFLAGS passing to libs and PHP +[global] +SPC_CONCURRENCY=4 + +[linux] +SPC_DEFAULT_C_FLAGS="-O3" +``` + ## Library environment variables (Unix only) Starting from 2.2.0, static-php-cli supports custom environment variables for all compilation dependent library commands of macOS, Linux, FreeBSD and other Unix systems. diff --git a/docs/en/guide/index.md b/docs/en/guide/index.md index 6ae37db7..9f9bee4c 100644 --- a/docs/en/guide/index.md +++ b/docs/en/guide/index.md @@ -5,14 +5,10 @@ currently supporting Linux and macOS systems. In the guide section, you will learn how to use static php cli to build standalone PHP programs. -- [GitHub Action Build](./action-build) -- [Manual Build](./manual-build) +- [Build (local)](./manual-build) +- [Build (GitHub Actions)](./action-build) - [Supported Extensions](./extensions) -::: tip -If you are a native English speaker, some corrections to the documentation are welcome. -::: - ## Compilation Environment The following is the architecture support situation, where :gear: represents support for GitHub Action build, diff --git a/docs/en/guide/troubleshooting.md b/docs/en/guide/troubleshooting.md index c3366f6d..7fc79e35 100644 --- a/docs/en/guide/troubleshooting.md +++ b/docs/en/guide/troubleshooting.md @@ -38,3 +38,5 @@ and then determine the command that reported the error. The error terminal output is very important for fixing compilation errors. When submitting an issue, please upload the last error fragment of the terminal log (or the entire terminal log output), and include the `spc` command and parameters used. + +If you are rebuilding, please refer to the [Local Build - Multiple Builds](./manual-build#multiple-builds) section. diff --git a/docs/zh/guide/build-with-glibc.md b/docs/zh/guide/build-with-glibc.md new file mode 100644 index 00000000..98883f3b --- /dev/null +++ b/docs/zh/guide/build-with-glibc.md @@ -0,0 +1,57 @@ +# 构建 glibc 兼容的 Linux 二进制 + +## 为什么要构建 glibc 兼容的二进制 + +目前,static-php-cli 在默认条件下在 Linux 系统构建的二进制都是基于 musl-libc(静态链接)的。 +musl-libc 是一个轻量级的 libc 实现,它的目标是与 glibc 兼容,并且提供良好的纯静态链接支持。 +这意味着,编译出来的静态 PHP 可执行文件在几乎任何 Linux 发行版都可以使用,而不需要考虑 libc、libstdc++ 等库的版本问题。 + +但是,Linux 系统的纯静态链接 musl-libc 二进制文件存在以下问题: + +- 无法使用 PHP 的 `dl()` 函数加载动态链接库和外部 PHP 扩展。 +- 无法使用 PHP 的 FFI 扩展。 +- 部分极端情况下,可能会出现性能问题,参见 [musl-libc 的性能问题](https://github.com/php/php-src/issues/13648)。 + +对于不同的 Linux 发行版,它们使用的默认 libc 可能不同,比如 Alpine Linux 使用 musl libc,而大多数 Linux 发行版使用 glibc。 +但即便如此,我们也不能直接使用任意的发行版和 glibc 构建便携的静态二进制文件,因为 glibc 有一些问题: + +- 基于新版本的发行版在使用 gcc 等工具构建的二进制,无法在旧版本的发行版上运行。 +- glibc 不推荐被静态链接,因为它的一些特性需要动态链接库的支持。 + +但是,我们可以使用 Docker 容器来解决这个问题,最终输出的结果是一个动态链接 glibc 和一些必要库的二进制,但它静态链接所有其他依赖。 + +1. 使用一个旧版本的 Linux 发行版(如 CentOS 7.x),它的 glibc 版本比较旧,但是可以在大多数现代 Linux 发行版上运行。 +2. 在这个容器中构建 PHP 的静态二进制文件,这样就可以在大多数现代 Linux 发行版上运行了。 + +> 使用 glibc 的静态二进制文件,可以在大多数现代 Linux 发行版上运行,但是不能在 musl libc 的发行版上运行,如 CentOS 6、Alpine Linux 等。 + +## 构建 glibc 兼容的 Linux 二进制 + +最新版的 static-php-cli 内置了 `bin/spc-gnu-docker` 脚本,可以一键创建一个 CentOS 7.x (glibc-2.17) 的 Docker 容器,并在容器中构建 glibc 兼容的 PHP 静态二进制文件。 + +然后,先运行一次以下命令。首次运行时时间较长,因为需要下载 CentOS 7.x 的镜像和一些编译工具。 + +```bash +bin/spc-gnu-docker +``` + +构建镜像完成后,你将看到和 `bin/spc` 一样的命令帮助菜单,这时说明容器已经准备好了。 + +在容器准备好后,你可以参考 [本地构建](./manual-build) 章节的内容,构建你的 PHP 静态二进制文件。仅需要把 `bin/spc` 或 `./spc` 替换为 `bin/spc-gnu-docker` 即可。 + +与默认构建不同的是,在 glibc 环境构建时**必须添加**参数 `--libc=glibc`,如: + +```bash +bin/spc-gnu-docker --libc=glibc build bcmath,ctype,openssl,pdo,phar,posix,session,tokenizer,xml,zip --build-cli --debug +``` + +## 注意事项 + +极少数情况下,基于 glibc 的静态 PHP 可能会出现 segment fault 等错误,但目前例子较少,如果遇到问题请提交 issue。 + +glibc 构建为扩展的特性,不属于默认 static-php 的支持范围。如果有相关问题或需求,请在提交 Issue 时注明你是基于 glibc 构建的。 + +如果你需要不使用 Docker 构建基于 glibc 的二进制,请参考 `bin/spc-gnu-docker` 脚本,手动构建一个类似的环境。 + +由于 glibc 二进制不是项目的主要目标,一般情况下我们不会额外测试 glibc 下的各个库和扩展的兼容性。 +任何特定库如果在 musl-libc 上构建成功,但在 glibc 上构建失败,请提交 issue,我们将会单独解决。 diff --git a/docs/zh/guide/env-vars.md b/docs/zh/guide/env-vars.md index 7a42d32c..9a2f9deb 100644 --- a/docs/zh/guide/env-vars.md +++ b/docs/zh/guide/env-vars.md @@ -36,6 +36,19 @@ SPC_CONCURRENCY=4 bin/spc build mbstring,pcntl --build-cli 例如,你需要修改编译 PHP 的 `./configure` 命令,你可以在 `config/env.ini` 文件中找到 `SPC_CMD_PREFIX_PHP_CONFIGURE` 环境变量,然后修改其值即可。 +但如果你的构建条件比较复杂,需要多种 env.ini 进行切换,我们推荐你使用 `config/env.custom.ini` 文件,这样你可以在不修改默认的 `config/env.ini` 文件的情况下, +通过写入额外的重载项目指定你的环境变量。 + +```ini +; This is an example of `config/env.custom.ini` file, +; we modify the `SPC_CONCURRENCY` and linux default CFLAGS passing to libs and PHP +[global] +SPC_CONCURRENCY=4 + +[linux] +SPC_DEFAULT_C_FLAGS="-O3" +``` + ## 编译依赖库的环境变量(仅限 Unix 系统) 从 2.2.0 开始,static-php-cli 对所有 macOS、Linux、FreeBSD 等 Unix 系统的编译依赖库的命令均支持自定义环境变量。 diff --git a/docs/zh/guide/troubleshooting.md b/docs/zh/guide/troubleshooting.md index 030edf45..f56f2ac4 100644 --- a/docs/zh/guide/troubleshooting.md +++ b/docs/zh/guide/troubleshooting.md @@ -25,3 +25,5 @@ 遇到编译错误时,如果没有开启 `--debug` 日志,请先开启调试日志,然后确定报错的命令。 报错的终端输出对于修复编译错误非常重要,请在提交 Issue 时一并将终端日志的最后报错片段(或整个终端日志输出)上传,并且包含使用的 `spc` 命令和参数。 + +如果你是重复构建,请参考 [本地构建 - 多次构建](./manual-build#多次构建) 章节,清理构建缓存后再次构建。 diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index aca214ce..b809a005 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -15,6 +15,8 @@ use SPC\util\GlobalEnvManager; class LinuxBuilder extends UnixBuilderBase { + public string $libc; + /** @var bool Micro patch phar flag */ private bool $phar_patched = false; @@ -25,6 +27,9 @@ class LinuxBuilder extends UnixBuilderBase public function __construct(array $options = []) { $this->options = $options; + SystemUtil::initLibcVar($this->options['libc'] ?? null); + + $this->libc = getenv('SPC_LIBC') ?: LIBC_MUSL_WRAPPER; // check musl-cross make installed if we use musl-cross-make $arch = arch2gnu(php_uname('m')); @@ -115,6 +120,7 @@ class LinuxBuilder extends UnixBuilderBase $extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : ''); f_putenv('SPC_EXTRA_LIBS=' . $extra_libs); $cflags = $this->arch_c_flags; + f_putenv('CFLAGS=' . $cflags); $this->emitPatchPoint('before-php-buildconf'); SourcePatcher::patchBeforeBuildconf($this); @@ -163,12 +169,13 @@ class LinuxBuilder extends UnixBuilderBase // micro latest needs do strip and upx pack later (strip, upx, cut binary manually supported) } + $embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static'; shell()->cd(SOURCE_PATH . '/php-src') ->exec( getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' . ($enable_cli ? '--enable-cli ' : '--disable-cli ') . ($enable_fpm ? '--enable-fpm ' : '--disable-fpm ') . - ($enable_embed ? '--enable-embed=static ' : '--disable-embed ') . + ($enable_embed ? "--enable-embed={$embed_type} " : '--disable-embed ') . ($enable_micro ? '--enable-micro=all-static ' : '--disable-micro ') . $config_file_path . $config_file_scan_dir . diff --git a/src/SPC/builder/linux/SystemUtil.php b/src/SPC/builder/linux/SystemUtil.php index c0ae6766..aef748b8 100644 --- a/src/SPC/builder/linux/SystemUtil.php +++ b/src/SPC/builder/linux/SystemUtil.php @@ -182,4 +182,12 @@ class SystemUtil 'arch', 'manjaro', ]; } + + public static function initLibcVar(?string $libc = null): void + { + if ($libc === null) { + $libc = self::isMuslDist() ? 'musl' : 'musl-wrapper'; + } + f_putenv('SPC_LIBC=' . $libc); + } } diff --git a/src/SPC/builder/linux/library/icu.php b/src/SPC/builder/linux/library/icu.php index 05458a4e..77bd081d 100644 --- a/src/SPC/builder/linux/library/icu.php +++ b/src/SPC/builder/linux/library/icu.php @@ -14,9 +14,9 @@ class icu extends LinuxLibraryBase protected function build(): void { - $cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1"'; + $cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -fPIC -fPIE -fno-ident"'; $cxxflags = 'CXXFLAGS="-std=c++17"'; - $ldflags = 'LDFLAGS="-static"'; + $ldflags = $this->builder->libc !== 'glibc' ? 'LDFLAGS="-static"' : ''; shell()->cd($this->source_dir . '/source') ->exec( "{$cppflags} {$cxxflags} {$ldflags} " . diff --git a/src/SPC/builder/linux/library/libpng.php b/src/SPC/builder/linux/library/libpng.php index 5049a647..617f42a2 100644 --- a/src/SPC/builder/linux/library/libpng.php +++ b/src/SPC/builder/linux/library/libpng.php @@ -44,7 +44,8 @@ class libpng extends LinuxLibraryBase shell()->cd($this->source_dir) ->exec('chmod +x ./configure') ->exec('chmod +x ./install-sh') - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ' . './configure ' . '--disable-shared ' . @@ -54,9 +55,9 @@ class libpng extends LinuxLibraryBase $optimizations . '--prefix=' ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I{$this->source_dir} -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la") - ->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I{$this->source_dir} -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la") + ->execWithEnv('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX); $this->cleanLaFiles(); } diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index fb3ef045..4c83f2e7 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -43,7 +43,7 @@ class openssl extends LinuxLibraryBase $extra = ''; $ex_lib = '-ldl -pthread'; - $env = "CC='" . getenv('CC') . ' -static -idirafter ' . BUILD_INCLUDE_PATH . + $env = "CC='" . getenv('CC') . ' -idirafter ' . BUILD_INCLUDE_PATH . ' -idirafter /usr/include/ ' . ' -idirafter /usr/include/' . $this->builder->getOption('arch') . '-linux-gnu/ ' . "' "; @@ -70,7 +70,6 @@ class openssl extends LinuxLibraryBase '--prefix=/ ' . '--libdir=lib ' . '--openssldir=/etc/ssl ' . - '-static ' . "{$zlib_extra}" . 'no-legacy ' . "linux-{$this->builder->getOption('arch')}{$clang_postfix}" diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 95aa2c5e..dba0cd43 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -162,12 +162,13 @@ class MacOSBuilder extends UnixBuilderBase ); } + $embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static'; shell()->cd(SOURCE_PATH . '/php-src') ->exec( getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' . ($enableCli ? '--enable-cli ' : '--disable-cli ') . ($enableFpm ? '--enable-fpm ' : '--disable-fpm ') . - ($enableEmbed ? '--enable-embed=static ' : '--disable-embed ') . + ($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') . ($enableMicro ? '--enable-micro ' : '--disable-micro ') . $config_file_path . $config_file_scan_dir . diff --git a/src/SPC/builder/macos/library/glfw.php b/src/SPC/builder/macos/library/glfw.php index 91e8cb70..355785ed 100644 --- a/src/SPC/builder/macos/library/glfw.php +++ b/src/SPC/builder/macos/library/glfw.php @@ -21,7 +21,7 @@ class glfw extends MacOSLibraryBase shell()->cd(SOURCE_PATH . '/ext-glfw/vendor/glfw') ->exec("cmake . {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF") ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); // patch pkgconf $this->patchPkgconfPrefix(['glfw3.pc']); } diff --git a/src/SPC/builder/traits/UnixLibraryTrait.php b/src/SPC/builder/traits/UnixLibraryTrait.php index d5a19209..8e69f6d3 100644 --- a/src/SPC/builder/traits/UnixLibraryTrait.php +++ b/src/SPC/builder/traits/UnixLibraryTrait.php @@ -102,7 +102,11 @@ trait UnixLibraryTrait public function getLibExtraCFlags(): string { - return getenv($this->getSnakeCaseName() . '_CFLAGS') ?: ''; + $env = getenv($this->getSnakeCaseName() . '_CFLAGS') ?: ''; + if (!str_contains($env, $this->builder->arch_c_flags)) { + $env .= $this->builder->arch_c_flags; + } + return $env; } public function getLibExtraLdFlags(): string diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index 5aa325ab..8b8cb743 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -33,11 +33,11 @@ trait UnixSystemUtilTrait $root = BUILD_ROOT_PATH; $ccLine = ''; if ($cc) { - $ccLine = 'SET(CMAKE_C_COMPILER ' . self::findCommand($cc) . ')'; + $ccLine = 'SET(CMAKE_C_COMPILER ' . $cc . ')'; } $cxxLine = ''; if ($cxx) { - $cxxLine = 'SET(CMAKE_CXX_COMPILER ' . self::findCommand($cxx) . ')'; + $cxxLine = 'SET(CMAKE_CXX_COMPILER ' . $cxx . ')'; } $toolchain = <<cmake_toolchain_file}"; } @@ -185,14 +185,22 @@ abstract class UnixBuilderBase extends BuilderBase $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') { + if (PHP_OS_FAMILY === 'Linux' && $this->getOption('libc') !== 'glibc') { $lens .= ' -static'; } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens); if ($ret !== 0) { throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out)); } - [$ret, $output] = shell()->cd($sample_file_path)->execWithResult('./embed'); + // if someone changed to --enable-embed=shared, we need to add LD_LIBRARY_PATH + if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { + $ext_path = 'LD_LIBRARY_PATH=' . BUILD_ROOT_PATH . '/lib:$LD_LIBRARY_PATH '; + FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.a'); + } else { + $ext_path = ''; + FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.so'); + } + [$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed'); if ($ret !== 0 || trim(implode('', $output)) !== 'hello') { throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output)); } diff --git a/src/SPC/builder/unix/library/brotli.php b/src/SPC/builder/unix/library/brotli.php index fddcfbae..9e764fcb 100644 --- a/src/SPC/builder/unix/library/brotli.php +++ b/src/SPC/builder/unix/library/brotli.php @@ -21,12 +21,16 @@ trait brotli ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv( 'cmake ' . - "{$this->builder->makeCmakeArgs()} " . + '-DCMAKE_BUILD_TYPE=Release ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . + '-DCMAKE_INSTALL_LIBDIR=lib ' . + '-DSHARE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . '-DBUILD_SHARED_LIBS=OFF ' . '..' ) ->execWithEnv("cmake --build . -j {$this->builder->concurrency}") - ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make install'); $this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']); shell()->cd(BUILD_ROOT_PATH . '/lib')->exec('ln -sf libbrotlicommon.a libbrotli.a'); foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) { diff --git a/src/SPC/builder/unix/library/bzip2.php b/src/SPC/builder/unix/library/bzip2.php index 23428317..0241fb1b 100644 --- a/src/SPC/builder/unix/library/bzip2.php +++ b/src/SPC/builder/unix/library/bzip2.php @@ -4,8 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\store\FileSystem; + trait bzip2 { + public function patchBeforeBuild(): bool + { + FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall'); + return true; + } + protected function build(): void { shell()->cd($this->source_dir) diff --git a/src/SPC/builder/unix/library/curl.php b/src/SPC/builder/unix/library/curl.php index e01bec2c..96a5bf05 100644 --- a/src/SPC/builder/unix/library/curl.php +++ b/src/SPC/builder/unix/library/curl.php @@ -51,13 +51,14 @@ trait curl $extra .= $this->builder->getLib('libcares') ? '-DENABLE_ARES=ON ' : ''; FileSystem::resetDir($this->source_dir . '/build'); + // compile! shell()->cd($this->source_dir . '/build') ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt') ->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF -DBUILD_LIBCURL_DOCS=OFF {$extra} ..") ->execWithEnv("make -j{$this->builder->concurrency}") - ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make install'); // patch pkgconf $this->patchPkgconfPrefix(['libcurl.pc']); shell()->cd(BUILD_LIB_PATH . '/cmake/CURL/') diff --git a/src/SPC/builder/unix/library/gettext.php b/src/SPC/builder/unix/library/gettext.php index 281207f7..277df171 100644 --- a/src/SPC/builder/unix/library/gettext.php +++ b/src/SPC/builder/unix/library/gettext.php @@ -17,7 +17,7 @@ trait gettext $ldflags = $this->builder->getOption('enable-zts') ? '-lpthread' : ''; shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $cflags, 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()]) + ->setEnv(['CFLAGS' => "{$this->getLibExtraCFlags()} {$cflags}", 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv( './configure ' . '--enable-static ' . diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index 0748c870..49b207fb 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -16,7 +16,7 @@ trait gmp protected function build(): void { shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $this->builder->arch_c_flags, 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv( './configure ' . '--enable-static --disable-shared ' . diff --git a/src/SPC/builder/unix/library/gmssl.php b/src/SPC/builder/unix/library/gmssl.php index 0c18c69d..1d946621 100644 --- a/src/SPC/builder/unix/library/gmssl.php +++ b/src/SPC/builder/unix/library/gmssl.php @@ -23,6 +23,6 @@ trait gmssl ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..") ->execWithEnv("cmake --build . -j {$this->builder->concurrency}") - ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make install'); } } diff --git a/src/SPC/builder/unix/library/imagemagick.php b/src/SPC/builder/unix/library/imagemagick.php index ed08c667..639225a8 100644 --- a/src/SPC/builder/unix/library/imagemagick.php +++ b/src/SPC/builder/unix/library/imagemagick.php @@ -39,7 +39,7 @@ trait imagemagick } } - $ldflags = $this instanceof LinuxLibraryBase ? ('-static') : ''; + $ldflags = ($this instanceof LinuxLibraryBase) && $this->builder->libc !== 'glibc' ? ('-static -ldl') : '-ldl'; // libxml iconv patch $required_libs .= $this instanceof MacOSLibraryBase ? ('-liconv') : ''; diff --git a/src/SPC/builder/unix/library/ldap.php b/src/SPC/builder/unix/library/ldap.php index a061ce7f..c1896be6 100644 --- a/src/SPC/builder/unix/library/ldap.php +++ b/src/SPC/builder/unix/library/ldap.php @@ -10,7 +10,8 @@ trait ldap { public function patchBeforeBuild(): bool { - FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz'); + $extra = ($this->builder->libc ?? '') === 'glibc' ? '-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/libavif.php b/src/SPC/builder/unix/library/libavif.php index f8fcdbb8..c2aaafcd 100644 --- a/src/SPC/builder/unix/library/libavif.php +++ b/src/SPC/builder/unix/library/libavif.php @@ -25,7 +25,7 @@ trait libavif ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DAVIF_LIBYUV=OFF ..") ->execWithEnv("cmake --build . -j {$this->builder->concurrency}") - ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make install'); // patch pkgconfig $this->patchPkgconfPrefix(['libavif.pc']); $this->cleanLaFiles(); diff --git a/src/SPC/builder/unix/library/libiconv.php b/src/SPC/builder/unix/library/libiconv.php index 69c98862..a587c472 100644 --- a/src/SPC/builder/unix/library/libiconv.php +++ b/src/SPC/builder/unix/library/libiconv.php @@ -11,16 +11,17 @@ trait libiconv [,,$destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( './configure ' . '--enable-static ' . '--disable-shared ' . '--enable-extra-encodings ' . '--prefix=' ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . $destdir); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install DESTDIR=' . $destdir); if (file_exists(BUILD_BIN_PATH . '/iconv')) { unlink(BUILD_BIN_PATH . '/iconv'); diff --git a/src/SPC/builder/unix/library/libjpeg.php b/src/SPC/builder/unix/library/libjpeg.php index df02bd13..c4f9833d 100644 --- a/src/SPC/builder/unix/library/libjpeg.php +++ b/src/SPC/builder/unix/library/libjpeg.php @@ -29,7 +29,7 @@ trait libjpeg '..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); // patch pkgconfig $this->patchPkgconfPrefix(['libjpeg.pc', 'libturbojpeg.pc']); $this->cleanLaFiles(); diff --git a/src/SPC/builder/unix/library/liblz4.php b/src/SPC/builder/unix/library/liblz4.php index 697f8ed3..45e803bf 100644 --- a/src/SPC/builder/unix/library/liblz4.php +++ b/src/SPC/builder/unix/library/liblz4.php @@ -18,9 +18,10 @@ trait liblz4 protected function build(): void { shell()->cd($this->source_dir) - ->exec("make PREFIX='' clean") - ->exec("make -j{$this->builder->concurrency} PREFIX=''") - ->exec("make install PREFIX='' DESTDIR=" . BUILD_ROOT_PATH); + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv("make PREFIX='' clean") + ->execWithEnv("make -j{$this->builder->concurrency} PREFIX=''") + ->execWithEnv("make install PREFIX='' DESTDIR=" . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['liblz4.pc']); diff --git a/src/SPC/builder/unix/library/libssh2.php b/src/SPC/builder/unix/library/libssh2.php index 32d96b9a..9e999ca9 100644 --- a/src/SPC/builder/unix/library/libssh2.php +++ b/src/SPC/builder/unix/library/libssh2.php @@ -22,7 +22,10 @@ trait libssh2 shell()->cd($this->source_dir . '/build') ->exec( 'cmake ' . - "{$this->builder->makeCmakeArgs()} " . + '-DCMAKE_BUILD_TYPE=Release ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . + '-DCMAKE_INSTALL_LIBDIR=lib ' . '-DBUILD_SHARED_LIBS=OFF ' . '-DBUILD_EXAMPLES=OFF ' . '-DBUILD_TESTING=OFF ' . @@ -30,7 +33,7 @@ trait libssh2 '..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); $this->patchPkgconfPrefix(['libssh2.pc']); } } diff --git a/src/SPC/builder/unix/library/libtiff.php b/src/SPC/builder/unix/library/libtiff.php index 9adcfab6..5d2cb4c1 100644 --- a/src/SPC/builder/unix/library/libtiff.php +++ b/src/SPC/builder/unix/library/libtiff.php @@ -23,7 +23,8 @@ trait libtiff $extra_libs .= ' --disable-lzma --disable-zstd --disable-webp --disable-libdeflate'; $shell = shell()->cd($this->source_dir) - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( './configure ' . '--enable-static --disable-shared ' . "{$extra_libs} " . @@ -33,12 +34,12 @@ trait libtiff // TODO: Remove this check when https://gitlab.com/libtiff/libtiff/-/merge_requests/635 will be merged and released if (file_exists($this->source_dir . '/html')) { - $shell->exec('make clean'); + $shell->execWithEnv('make clean'); } $shell - ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['libtiff-4.pc']); } } diff --git a/src/SPC/builder/unix/library/libuv.php b/src/SPC/builder/unix/library/libuv.php index 8429b297..fda11c0a 100644 --- a/src/SPC/builder/unix/library/libuv.php +++ b/src/SPC/builder/unix/library/libuv.php @@ -22,7 +22,7 @@ trait libuv shell()->cd($this->source_dir . '/build') ->exec("cmake {$this->builder->makeCmakeArgs()} -DLIBUV_BUILD_SHARED=OFF ..") ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); // patch pkgconfig $this->patchPkgconfPrefix(['libuv-static.pc']); } diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 52eb8071..efb78a68 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -30,7 +30,7 @@ trait libwebp '..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); // patch pkgconfig $this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR); $this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']); diff --git a/src/SPC/builder/unix/library/libzip.php b/src/SPC/builder/unix/library/libzip.php index 83e0600c..5e2bd0d6 100644 --- a/src/SPC/builder/unix/library/libzip.php +++ b/src/SPC/builder/unix/library/libzip.php @@ -30,7 +30,9 @@ trait libzip shell()->cd($this->source_dir . '/build') ->exec( 'cmake ' . - "{$this->builder->makeCmakeArgs()} " . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_BUILD_TYPE=Release ' . '-DENABLE_GNUTLS=OFF ' . '-DENABLE_MBEDTLS=OFF ' . '-DBUILD_SHARED_LIBS=OFF ' . @@ -42,7 +44,7 @@ trait libzip '..' ) ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); $this->patchPkgconfPrefix(['libzip.pc'], PKGCONF_PATCH_PREFIX); } } diff --git a/src/SPC/builder/unix/library/ncurses.php b/src/SPC/builder/unix/library/ncurses.php index 721d5de6..a44ac175 100644 --- a/src/SPC/builder/unix/library/ncurses.php +++ b/src/SPC/builder/unix/library/ncurses.php @@ -12,7 +12,8 @@ trait ncurses { $filelist = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true); shell()->cd($this->source_dir) - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( './configure ' . '--enable-static ' . '--disable-shared ' . @@ -32,9 +33,9 @@ trait ncurses '--libdir=' . BUILD_ROOT_PATH . '/lib ' . '--prefix=' . BUILD_ROOT_PATH ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec('make install'); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install'); $final = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true); // Remove the new files diff --git a/src/SPC/builder/unix/library/nghttp2.php b/src/SPC/builder/unix/library/nghttp2.php index 0334beba..8f764c2a 100644 --- a/src/SPC/builder/unix/library/nghttp2.php +++ b/src/SPC/builder/unix/library/nghttp2.php @@ -36,7 +36,8 @@ trait nghttp2 [,,$destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( './configure ' . '--enable-static ' . '--disable-shared ' . @@ -45,9 +46,9 @@ trait nghttp2 $args . ' ' . '--prefix=' ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec("make install DESTDIR={$destdir}"); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv("make install DESTDIR={$destdir}"); $this->patchPkgconfPrefix(['libnghttp2.pc']); } } diff --git a/src/SPC/builder/unix/library/onig.php b/src/SPC/builder/unix/library/onig.php index b43d14b3..60ea84fa 100644 --- a/src/SPC/builder/unix/library/onig.php +++ b/src/SPC/builder/unix/library/onig.php @@ -18,9 +18,10 @@ trait onig [,,$destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) - ->exec('./configure --enable-static --disable-shared --prefix=') - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $this->builder->arch_c_flags, 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv('./configure --enable-static --disable-shared --prefix=') + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") ->exec("make install DESTDIR={$destdir}"); $this->patchPkgconfPrefix(['oniguruma.pc']); } diff --git a/src/SPC/builder/unix/library/pkgconfig.php b/src/SPC/builder/unix/library/pkgconfig.php index ca93fd25..4a060f02 100644 --- a/src/SPC/builder/unix/library/pkgconfig.php +++ b/src/SPC/builder/unix/library/pkgconfig.php @@ -4,15 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\builder\linux\library\LinuxLibraryBase; + trait pkgconfig { protected function build(): void { - $cflags = PHP_OS_FAMILY !== 'Linux' ? "{$this->builder->arch_c_flags} -Wimplicit-function-declaration -Wno-int-conversion" : ''; - $ldflags = PHP_OS_FAMILY !== 'Linux' ? '' : '--static'; + $cflags = PHP_OS_FAMILY !== 'Linux' ? '-Wimplicit-function-declaration -Wno-int-conversion' : ''; + $ldflags = !($this instanceof LinuxLibraryBase) || $this->builder->libc === 'glibc' ? '' : '--static'; shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $cflags, 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()]) + ->setEnv(['CFLAGS' => "{$this->getLibExtraCFlags()} {$cflags}", 'LDFLAGS' => "{$this->getLibExtraLdFlags()} {$ldflags}", 'LIBS' => $this->getLibExtraLibs()]) ->execWithEnv( './configure ' . '--disable-shared ' . diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index ce3679e9..9b92fee4 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace SPC\builder\unix\library; use SPC\builder\linux\library\LinuxLibraryBase; -use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -42,13 +41,13 @@ trait postgresql $error_exec_cnt += $output[0] === 0 ? 0 : 1; if (!empty($output[1][0])) { $cppflags = $output[1][0]; - $envs .= " CPPFLAGS=\"{$cppflags}\""; + $envs .= " CPPFLAGS=\"{$cppflags} -fPIC -fPIE -fno-ident\""; } $output = shell()->execWithResult("pkg-config --libs-only-L --static {$packages}"); $error_exec_cnt += $output[0] === 0 ? 0 : 1; if (!empty($output[1][0])) { $ldflags = $output[1][0]; - $envs .= $this instanceof MacOSLibraryBase ? " LDFLAGS=\"{$ldflags}\" " : " LDFLAGS=\"{$ldflags} -static\" "; + $envs .= !($this instanceof LinuxLibraryBase) || $this->builder->libc === 'glibc' ? " LDFLAGS=\"{$ldflags}\" " : " LDFLAGS=\"{$ldflags} -static\" "; } $output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}"); $error_exec_cnt += $output[0] === 0 ? 0 : 1; diff --git a/src/SPC/builder/unix/library/readline.php b/src/SPC/builder/unix/library/readline.php index 4f725129..d0369c1a 100644 --- a/src/SPC/builder/unix/library/readline.php +++ b/src/SPC/builder/unix/library/readline.php @@ -16,7 +16,8 @@ trait readline protected function build(): void { shell()->cd($this->source_dir) - ->exec( + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv( './configure ' . '--enable-static=yes ' . '--enable-shared=no ' . @@ -24,9 +25,9 @@ trait readline '--with-curses ' . '--enable-multibyte=yes' ) - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['readline.pc']); } } diff --git a/src/SPC/builder/unix/library/snappy.php b/src/SPC/builder/unix/library/snappy.php index d7a5ade0..f1b4c825 100644 --- a/src/SPC/builder/unix/library/snappy.php +++ b/src/SPC/builder/unix/library/snappy.php @@ -21,13 +21,12 @@ trait snappy shell()->cd($this->source_dir . '/cmake/build') ->exec( 'cmake ' . - "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . "{$this->builder->makeCmakeArgs()} " . '-DSNAPPY_BUILD_TESTS=OFF ' . '-DSNAPPY_BUILD_BENCHMARKS=OFF ' . '../..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); } } diff --git a/src/SPC/builder/unix/library/sqlite.php b/src/SPC/builder/unix/library/sqlite.php index d679a386..ee814702 100644 --- a/src/SPC/builder/unix/library/sqlite.php +++ b/src/SPC/builder/unix/library/sqlite.php @@ -9,10 +9,11 @@ trait sqlite protected function build(): void { shell()->cd($this->source_dir) - ->exec('./configure --enable-static --disable-shared --prefix=') - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv('./configure --enable-static --disable-shared --prefix=') + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['sqlite3.pc']); } } diff --git a/src/SPC/builder/unix/library/tidy.php b/src/SPC/builder/unix/library/tidy.php index 6bb957c0..31c851d1 100644 --- a/src/SPC/builder/unix/library/tidy.php +++ b/src/SPC/builder/unix/library/tidy.php @@ -26,7 +26,7 @@ trait tidy '..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); $this->patchPkgconfPrefix(['tidy.pc']); } } diff --git a/src/SPC/builder/unix/library/zlib.php b/src/SPC/builder/unix/library/zlib.php index b380f8b0..f764de91 100644 --- a/src/SPC/builder/unix/library/zlib.php +++ b/src/SPC/builder/unix/library/zlib.php @@ -18,10 +18,11 @@ trait zlib [,,$destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) - ->exec('./configure --static --prefix=') - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}") - ->exec("make install DESTDIR={$destdir}"); + ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) + ->execWithEnv('./configure --static --prefix=') + ->execWithEnv('make clean') + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv("make install DESTDIR={$destdir}"); $this->patchPkgconfPrefix(['zlib.pc']); } } diff --git a/src/SPC/builder/unix/library/zstd.php b/src/SPC/builder/unix/library/zstd.php index 399eeedc..1990f658 100644 --- a/src/SPC/builder/unix/library/zstd.php +++ b/src/SPC/builder/unix/library/zstd.php @@ -26,7 +26,7 @@ trait zstd '..' ) ->exec("cmake --build . -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->exec('make install'); $this->patchPkgconfPrefix(['libzstd.pc']); } } diff --git a/src/SPC/command/BuildCliCommand.php b/src/SPC/command/BuildCliCommand.php index 2750b5e4..d991719f 100644 --- a/src/SPC/command/BuildCliCommand.php +++ b/src/SPC/command/BuildCliCommand.php @@ -192,7 +192,7 @@ class BuildCliCommand extends BuildCommand $fixed = ''; if (!empty(getenv('SPC_FIX_DEPLOY_ROOT'))) { str_replace($cwd, '', $build_root_path); - $build_root_path = getenv('SPC_FIX_DEPLOY_ROOT') . $build_root_path; + $build_root_path = getenv('SPC_FIX_DEPLOY_ROOT') . '/' . basename($build_root_path); $fixed = ' (host system)'; } if (($rule & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) { diff --git a/src/SPC/command/BuildCommand.php b/src/SPC/command/BuildCommand.php index ef7a0197..0bb8054f 100644 --- a/src/SPC/command/BuildCommand.php +++ b/src/SPC/command/BuildCommand.php @@ -19,6 +19,8 @@ abstract class BuildCommand extends BaseCommand $this->addOption('arch', null, InputOption::VALUE_REQUIRED, 'architecture, "x64" or "arm64"', 'x64'); break; case 'Linux': + $this->addOption('libc', null, InputOption::VALUE_REQUIRED, 'glibc, musl or musl-wrapper', 'musl-wrapper'); + // no break case 'Darwin': $this->addOption('cc', null, InputOption::VALUE_REQUIRED, 'C compiler'); $this->addOption('cxx', null, InputOption::VALUE_REQUIRED, 'C++ compiler'); diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index e605c73b..0e4b236a 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -37,7 +37,7 @@ class LinuxToolCheckList 'git', 'autoconf', 'automake', 'tar', 'unzip', 'gzip', 'gcc', 'bzip2', 'cmake', 'patch', - 'xz', + 'xz', 'libtool', ]; public const TOOLS_ARCH = [ @@ -57,7 +57,8 @@ class LinuxToolCheckList $required = match ($distro['dist']) { 'alpine' => self::TOOLS_ALPINE, - 'redhat', 'centos' => self::TOOLS_RHEL, + 'redhat' => self::TOOLS_RHEL, + 'centos' => array_merge(self::TOOLS_RHEL, ['perl-IPC-Cmd']), 'arch' => self::TOOLS_ARCH, default => self::TOOLS_DEBIAN, }; diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 5780a216..67b21ec4 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -454,6 +454,13 @@ class FileSystem unlink($path . '.bak'); } + public static function removeFileIfExists(string $string): void + { + if (file_exists($string)) { + unlink($string); + } + } + /** * @throws RuntimeException * @throws FileSystemException diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index f6044927..5c7db38f 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -86,6 +86,9 @@ class SourcePatcher } // patch capstone FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"'); + if ($builder instanceof LinuxBuilder && $builder->libc === 'glibc') { + 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 7ad63a5b..49f334d9 100644 --- a/src/SPC/util/GlobalEnvManager.php +++ b/src/SPC/util/GlobalEnvManager.php @@ -66,6 +66,10 @@ class GlobalEnvManager WORKING_DIR . '/config/env.ini', ROOT_DIR . '/config/env.ini', ]; + $ini_custom = [ + WORKING_DIR . '/config/env.custom.ini', + ROOT_DIR . '/config/env.custom.ini', + ]; $ini = null; foreach ($ini_files as $ini_file) { if (file_exists($ini_file)) { @@ -79,6 +83,23 @@ class GlobalEnvManager if ($ini === false || !isset($ini['global'])) { throw new WrongUsageException('Failed to parse ' . $ini_file); } + // apply custom env + foreach ($ini_custom as $ini_file) { + if (file_exists($ini_file)) { + $ini_custom = parse_ini_file($ini_file, true); + if ($ini_custom !== false) { + $ini['global'] = array_merge($ini['global'], $ini_custom['global'] ?? []); + match (PHP_OS_FAMILY) { + 'Windows' => $ini['windows'] = array_merge($ini['windows'], $ini_custom['windows'] ?? []), + 'Darwin' => $ini['macos'] = array_merge($ini['macos'], $ini_custom['macos'] ?? []), + 'Linux' => $ini['linux'] = array_merge($ini['linux'], $ini_custom['linux'] ?? []), + 'BSD' => $ini['freebsd'] = array_merge($ini['freebsd'], $ini_custom['freebsd'] ?? []), + default => null, + }; + } + break; + } + } self::applyConfig($ini['global']); match (PHP_OS_FAMILY) { 'Windows' => self::applyConfig($ini['windows']), diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 1e60aa5a..2961ef90 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -36,7 +36,7 @@ class SPCConfigUtil $libs = '-lphp -lc ' . $libs; $extra_env = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'); if (is_string($extra_env)) { - $libs .= ' ' . $extra_env; + $libs .= ' ' . trim($extra_env, '"'); } // c++ if ($this->builder->hasCpp()) { diff --git a/src/globals/defines.php b/src/globals/defines.php index 956e5a9b..bbc2bd2f 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -83,4 +83,9 @@ const AUTOCONF_CPPFLAGS = 4; const AUTOCONF_LDFLAGS = 8; const AUTOCONF_ALL = 15; +const LIBC_MUSL_WRAPPER = 'musl-wrapper'; +const LIBC_MUSL = 'musl'; +const LIBC_GLIBC = 'glibc'; + ConsoleLogger::$date_format = 'H:i:s'; +ConsoleLogger::$format = '[%date%] [I] %body%'; diff --git a/src/globals/ext-tests/openssl.php b/src/globals/ext-tests/openssl.php index 8c42202d..3b3452b3 100644 --- a/src/globals/ext-tests/openssl.php +++ b/src/globals/ext-tests/openssl.php @@ -4,4 +4,6 @@ declare(strict_types=1); assert(function_exists('openssl_digest')); assert(openssl_digest('123456', 'md5') === 'e10adc3949ba59abbe56e057f20f883e'); -assert(file_get_contents('https://example.com/') !== false); +if (file_exists('/etc/ssl/openssl.cnf')) { + assert(file_get_contents('https://example.com/') !== false); +} diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 78c3421a..0c29ff45 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -26,7 +26,7 @@ $test_os = [ ]; // whether enable thread safe -$zts = false; +$zts = true; $no_strip = false; @@ -38,7 +38,7 @@ $prefer_pre_built = false; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imap,openssl,zlib,memcache', + 'Linux', 'Darwin' => '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', 'Windows' => 'gettext', };