Compare commits

..

2 Commits

Author SHA1 Message Date
Marc
ef3d4c22c0 Merge branch 'main' into feature/shared-exts 2025-10-02 16:21:11 +02:00
henderkes
9a37534fd3 add -shared suffix extension to allow building newest e.g. zip.so 2025-10-02 16:20:00 +02:00
126 changed files with 1536 additions and 4304 deletions

View File

@@ -136,12 +136,12 @@ 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-15-intel"
RUNS_ON="macos-13"
;;
macos-aarch64)
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"
BUILD_CMD="./bin/spc build"
RUNS_ON="macos-15"
RUNS_ON="macos-14"
;;
esac
DOWN_CMD="$DOWN_CMD --with-php=${{ inputs.php-version }} --for-extensions=${{ inputs.extensions }} --ignore-cache-sources=php-src"

View File

@@ -85,9 +85,9 @@ jobs:
- "8.4"
operating-system:
- "ubuntu-latest"
#- "macos-15-intel"
#- "macos-13"
#- "debian-arm64-self-hosted"
- "macos-15"
- "macos-14"
steps:
- name: "Checkout"
@@ -99,11 +99,11 @@ jobs:
OS=""
if [ "${{ matrix.operating-system }}" = "ubuntu-latest" ]; then
OS="linux-x86_64"
elif [ "${{ matrix.operating-system }}" = "macos-15-intel" ]; then
elif [ "${{ matrix.operating-system }}" = "macos-13" ]; then
OS="macos-x86_64"
elif [ "${{ matrix.operating-system }}" = "debian-arm64-self-hosted" ]; then
OS="linux-aarch64"
elif [ "${{ matrix.operating-system }}" = "macos-15" ]; then
elif [ "${{ matrix.operating-system }}" = "macos-14" ]; then
OS="macos-aarch64"
fi
echo "OS=$OS" >> $GITHUB_ENV

View File

@@ -27,7 +27,7 @@ jobs:
os: "ubuntu-latest"
filename: "spc-linux-x86_64.tar.gz"
- name: "macos-x86_64"
os: "macos-15-intel"
os: "macos-13"
filename: "spc-macos-x86_64.tar.gz"
- name: "linux-aarch64"
os: "ubuntu-latest"
@@ -147,11 +147,11 @@ jobs:
- name: "linux-x86_64"
os: "ubuntu-latest"
- name: "macos-x86_64"
os: "macos-15-intel"
os: "macos-13"
- name: "linux-aarch64"
os: "ubuntu-24.04-arm"
- name: "macos-aarch64"
os: "macos-15"
os: "macos-latest"
- name: "windows-x64"
os: "windows-latest"
steps:

View File

@@ -1,9 +1,13 @@
name: Tests
on:
push:
branches:
- main
paths:
- 'src/globals/test-extensions.php'
pull_request:
branches: [ "main" ]
types: [ opened, synchronize, reopened ]
paths:
- 'src/**'
- 'config/**'
@@ -175,7 +179,7 @@ jobs:
key: php-dependencies-${{ matrix.os }}
- name: "Install Dependencies"
run: composer update -vvv --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-plugins
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: "Run Build Tests (doctor)"
run: php src/globals/test-extensions.php doctor_cmd ${{ matrix.os }} ${{ matrix.php }}

3
.gitignore vendored
View File

@@ -22,9 +22,6 @@ docker/source/
# default package root directory
/pkgroot/**
# Windows PHP SDK binary tools
/php-sdk-binary-tools/**
# default pack:lib and release directory
/dist/**
packlib_files.txt

View File

@@ -19,7 +19,7 @@ with popular extensions.
- :wrench: Configurable source code patching
- :books: Intelligent dependency management
- 📦 Self-contained `spc` executable (built with [box](https://github.com/box-project/box))
- :fire: Support 100+ popular [extensions](https://static-php.dev/en/guide/extensions.html)
- :fire: Support 75+ popular [extensions](https://static-php.dev/en/guide/extensions.html)
- :floppy_disk: UPX compression support (reduces binary size by 30-50%)
**Single-file standalone php-cli:**

View File

@@ -108,7 +108,8 @@ RUN apk update; \
wget \
xz \
gettext-dev \
binutils-gold
binutils-gold \
patchelf
RUN curl -#fSL https://dl.static-php.dev/static-php-cli/bulk/php-8.4.4-cli-linux-\$(uname -m).tar.gz | tar -xz -C /usr/local/bin && \
chmod +x /usr/local/bin/php
@@ -149,7 +150,6 @@ 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)""/log:/app/log"
if [ -f "$(pwd)/craft.yml" ]; then
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/craft.yml:/app/craft.yml"
fi
@@ -161,47 +161,6 @@ if [ ! -z "$GITHUB_TOKEN" ]; then
ENV_LIST="$ENV_LIST -e GITHUB_TOKEN=$GITHUB_TOKEN"
fi
# Intercept and rewrite --with-frankenphp-app option, and mount host path to /app/app
FRANKENPHP_APP_PATH=""
NEW_ARGS=()
while [ $# -gt 0 ]; do
case "$1" in
--with-frankenphp-app=*)
FRANKENPHP_APP_PATH="${1#*=}"
NEW_ARGS+=("--with-frankenphp-app=/app/app")
shift
;;
--with-frankenphp-app)
if [ -n "${2:-}" ]; then
FRANKENPHP_APP_PATH="$2"
NEW_ARGS+=("--with-frankenphp-app=/app/app")
shift 2
else
NEW_ARGS+=("$1")
shift
fi
;;
*)
NEW_ARGS+=("$1")
shift
;;
esac
done
# Normalize the path and add mount if provided
if [ -n "$FRANKENPHP_APP_PATH" ]; then
# expand ~ to $HOME
if [ "${FRANKENPHP_APP_PATH#~}" != "$FRANKENPHP_APP_PATH" ]; then
FRANKENPHP_APP_PATH="$HOME${FRANKENPHP_APP_PATH#~}"
fi
# make absolute if relative
case "$FRANKENPHP_APP_PATH" in
/*) ABS_APP_PATH="$FRANKENPHP_APP_PATH" ;;
*) ABS_APP_PATH="$(pwd)/$FRANKENPHP_APP_PATH" ;;
esac
MOUNT_LIST="$MOUNT_LIST -v $ABS_APP_PATH:/app/app"
fi
# Run docker
# shellcheck disable=SC2068
# shellcheck disable=SC2086
@@ -223,5 +182,5 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
set -ex
$DOCKER_EXECUTABLE run $PLATFORM_ARG --rm $INTERACT $ENV_LIST $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION /bin/bash
else
$DOCKER_EXECUTABLE run $PLATFORM_ARG --rm $INTERACT $ENV_LIST $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION bin/spc "${NEW_ARGS[@]}"
$DOCKER_EXECUTABLE run $PLATFORM_ARG --rm $INTERACT $ENV_LIST $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION bin/spc $@
fi

View File

@@ -92,6 +92,11 @@ RUN echo "source scl_source enable devtoolset-10" >> /etc/bashrc
RUN source /etc/bashrc
RUN yum install -y which
RUN curl -fsSL -o patchelf.tgz https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0-$SPC_USE_ARCH.tar.gz && \
mkdir -p /patchelf && \
tar -xzf patchelf.tgz -C /patchelf --strip-components=1 && \
cp /patchelf/bin/patchelf /usr/bin/
RUN curl -o cmake.tgz -#fSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$SPC_USE_ARCH.tar.gz && \
mkdir /cmake && \
tar -xzf cmake.tgz -C /cmake --strip-components 1
@@ -153,7 +158,6 @@ 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)""/log:/app/log"
if [ -f "$(pwd)/craft.yml" ]; then
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/craft.yml:/app/craft.yml"
fi
@@ -169,47 +173,6 @@ if [ ! -z "$GITHUB_TOKEN" ]; then
ENV_LIST="$ENV_LIST -e GITHUB_TOKEN=$GITHUB_TOKEN"
fi
# Intercept and rewrite --with-frankenphp-app option, and mount host path to /app/app
FRANKENPHP_APP_PATH=""
NEW_ARGS=()
while [ $# -gt 0 ]; do
case "$1" in
--with-frankenphp-app=*)
FRANKENPHP_APP_PATH="${1#*=}"
NEW_ARGS+=("--with-frankenphp-app=/app/app")
shift
;;
--with-frankenphp-app)
if [ -n "${2:-}" ]; then
FRANKENPHP_APP_PATH="$2"
NEW_ARGS+=("--with-frankenphp-app=/app/app")
shift 2
else
NEW_ARGS+=("$1")
shift
fi
;;
*)
NEW_ARGS+=("$1")
shift
;;
esac
done
# Normalize the path and add mount if provided
if [ -n "$FRANKENPHP_APP_PATH" ]; then
# expand ~ to $HOME
if [ "${FRANKENPHP_APP_PATH#~}" != "$FRANKENPHP_APP_PATH" ]; then
FRANKENPHP_APP_PATH="$HOME${FRANKENPHP_APP_PATH#~}"
fi
# make absolute if relative
case "$FRANKENPHP_APP_PATH" in
/*) ABS_APP_PATH="$FRANKENPHP_APP_PATH" ;;
*) ABS_APP_PATH="$(pwd)/$FRANKENPHP_APP_PATH" ;;
esac
MOUNT_LIST="$MOUNT_LIST -v $ABS_APP_PATH:/app/app"
fi
# Run docker
# shellcheck disable=SC2068
# shellcheck disable=SC2086
@@ -232,5 +195,5 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
set -ex
$DOCKER_EXECUTABLE run $PLATFORM_ARG --privileged --rm -it $INTERACT $ENV_LIST --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH-$SPC_DOCKER_VERSION /bin/bash
else
$DOCKER_EXECUTABLE run $PLATFORM_ARG --rm $INTERACT $ENV_LIST --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH-$SPC_DOCKER_VERSION bin/spc "${NEW_ARGS[@]}"
$DOCKER_EXECUTABLE run $PLATFORM_ARG --rm $INTERACT $ENV_LIST --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH-$SPC_DOCKER_VERSION bin/spc $@
fi

679
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +1,39 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; static-php-cli (spc) env configuration
;
; This file is used to set default env vars for static-php-cli build.
; As dynamic build process, some of these vars can be overwritten by CLI options.
; And you can also overwrite these vars by setting them in your shell environment.
; The value should be changed only if you know what you are doing. Otherwise, please leave them as default.
;
; We need to use some pre-defined internal env vars, like `BUILD_ROOT_PATH`, `DOWNLOAD_PATH`, etc.
; Please note that these vars cannot be defined in this file, they should only be defined before static-php-cli running.
; Please note that these vars cannot be defined in this file, they are only be defined before static-php-cli running.
;
; Here's a list of env vars, these variables will be defined if not defined:
; Here's a list of env vars, these value cannot be changed anywhere:
;
; SPC_VERSION: the version of static-php-cli.
; WORKING_DIR: the working directory of the build process. (default: `$(pwd)`)
; ROOT_DIR: the root directory of static-php-cli. (default: `/path/to/static-php-cli`, when running in phar or micro mode: `phar://path/to/spc.phar`)
; BUILD_ROOT_PATH: the root path of the build process. (default: `$(pwd)/buildroot`)
; BUILD_INCLUDE_PATH: the path of the include files. (default: `$BUILD_ROOT_PATH/include`)
; BUILD_LIB_PATH: the path of the lib files. (default: `$BUILD_ROOT_PATH/lib`)
; BUILD_BIN_PATH: the path of the bin files. (default: `$BUILD_ROOT_PATH/bin`)
; BUILD_MODULES_PATH: the path of the php modules (shared extensions) files. (default: `$BUILD_ROOT_PATH/modules`)
; PKG_ROOT_PATH: the root path of the package files. (default: `$(pwd)/pkgroot/$GNU_ARCH-{darwin|linux|windows}`)
; PKG_ROOT_PATH: the root path of the package files. (default: `$(pwd)/pkgroot`)
; SOURCE_PATH: the path of the source files. (default: `$(pwd)/source`)
; DOWNLOAD_PATH: the path of the download files. (default: `$(pwd)/downloads`)
; PATH: (*nix only) static-php-cli will add `$BUILD_BIN_PATH` to PATH.
; PKG_CONFIG_PATH: (*nix only) static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH.
; CPU_COUNT: the count of the CPU cores. (default: `$(nproc)`)
; SPC_ARCH: the arch of the current system, for some libraries needed `--host=XXX` args. (default: `$(uname -m)`, e.g. `x86_64`, `aarch64`, `arm64`)
; GNU_ARCH: the GNU arch of the current system. (default: `$(uname -m)`, e.g. `x86_64`, `aarch64`)
; MAC_ARCH: the MAC arch of the current system. (default: `$(uname -m)`, e.g. `x86_64`, `arm64`)
;
; Here's a list of env vars, these variables is defined in SPC and cannot be changed anywhere:
; * These vars are only be defined in Unix (macOS, Linux, FreeBSD)Builder and cannot be changed anywhere:
; 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.
;
; SPC_VERSION: the version of static-php-cli.
; WORKING_DIR: the working directory of the build process. (default: `$(pwd)`)
; ROOT_DIR: the root directory of static-php-cli. (default: `/path/to/static-php-cli`, when running in phar or micro mode: `phar://path/to/spc.phar`)
; CPU_COUNT: the count of the CPU cores. (default: `$(nproc)`)
; SPC_ARCH: the arch of the current system, for some libraries needed `--host=XXX` args. (default: `$(uname -m)`, e.g. `x86_64`, `aarch64`, `arm64`)
; GNU_ARCH: the GNU arch of the current system. (default: `$(uname -m)`, e.g. `x86_64`, `aarch64`)
; MAC_ARCH: the MAC arch of the current system. (default: `$(uname -m)`, e.g. `x86_64`, `arm64`)
; PKG_CONFIG: (*nix only) static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG.
; SPC_LINUX_DEFAULT_CC: (linux only) the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`)
; SPC_LINUX_DEFAULT_CXX: (linux only) the default c++ compiler for linux. (For alpine linux: `g++`, default: `$GNU_ARCH-linux-musl-g++`)
; SPC_LINUX_DEFAULT_AR: (linux only) the default archiver for linux. (For alpine linux: `ar`, default: `$GNU_ARCH-linux-musl-ar`)
; SPC_EXTRA_PHP_VARS: (linux only) the extra vars for building php, used in `configure` and `make` command.
; * 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.
@@ -45,7 +43,7 @@ SPC_SKIP_PHP_VERSION_CHECK="no"
; Ignore some check item for bin/spc doctor command, comma separated (e.g. SPC_SKIP_DOCTOR_CHECK_ITEMS="if homebrew has installed")
SPC_SKIP_DOCTOR_CHECK_ITEMS=""
; extra modules that xcaddy will include in the FrankenPHP build
SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES="--with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy --with github.com/dunglas/caddy-cbrotli"
SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES="--with github.com/dunglas/frankenphp/caddy --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy --with github.com/dunglas/caddy-cbrotli"
; The display message for php version output (PHP >= 8.4 available)
PHP_BUILD_PROVIDER="static-php-cli ${SPC_VERSION}"
@@ -66,7 +64,7 @@ PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools"
; upx executable path
UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe"
; 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,cli_static,win32_api
SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static
[linux]
; Linux can use different build toolchains.
@@ -106,19 +104,19 @@ SPC_MICRO_PATCHES=cli_checks,disable_huge_page
SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force"
; configure command
SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-phpdbg --with-pic"
; make command
SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}"
; *** default build vars for building php ***
; embed type for php, static (libphp.a) or shared (libphp.so)
SPC_CMD_VAR_PHP_EMBED_TYPE="static"
; EXTRA_CFLAGS for `configure` and `make` php
; CFLAGS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -fPIE"
; EXTRA_CFLAGS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE ${SPC_DEFAULT_C_FLAGS}"
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
; optional, path to openssl conf. This affects where openssl will look for the default CA.
; default on Debian/Alpine: /etc/ssl, default on RHEL: /etc/pki/tls
OPENSSLDIR=""
[macos]
; build target: macho or macho (possibly we could support macho-universal in the future)
; Currently we do not support universal and cross-compilation for macOS.
@@ -140,14 +138,16 @@ SPC_MICRO_PATCHES=cli_checks,macos_iconv
SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force"
; configure command
SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-phpdbg"
; make command
SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}"
; *** default build vars for building php ***
; embed type for php, static (libphp.a) or shared (libphp.dylib)
SPC_CMD_VAR_PHP_EMBED_TYPE="static"
; EXTRA_CFLAGS for `configure` and `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Werror=unknown-warning-option ${SPC_DEFAULT_C_FLAGS}"
; minimum compatible macOS version (LLVM vars, availability not guaranteed)
MACOSX_DEPLOYMENT_TARGET=12.0
; CFLAGS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -Werror=unknown-warning-option"
; EXTRA_CFLAGS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie ${SPC_DEFAULT_C_FLAGS}"
[freebsd]
; compiler environments

View File

@@ -127,14 +127,6 @@
"sockets"
]
},
"excimer": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "external",
"source": "ext-excimer"
},
"exif": {
"type": "builtin"
},
@@ -240,13 +232,11 @@
"BSD": "wip"
},
"type": "external",
"source": "ext-grpc",
"source": "grpc",
"arg-type-unix": "enable-path",
"cpp-extension": true,
"lib-depends": [
"zlib",
"openssl",
"libcares"
"grpc"
]
},
"iconv": {
@@ -351,7 +341,6 @@
"ext-depends": [
"xml"
],
"build-with-php": true,
"target": [
"static"
]
@@ -368,18 +357,6 @@
"liblz4"
]
},
"maxminddb": {
"support": {
"BSD": "wip",
"Windows": "wip"
},
"type": "external",
"source": "ext-maxminddb",
"arg-type": "with",
"lib-depends": [
"libmaxminddb"
]
},
"mbregex": {
"type": "builtin",
"arg-type": "custom",
@@ -418,7 +395,8 @@
"ext-depends": [
"zlib",
"session"
]
],
"build-with-php": true
},
"memcached": {
"support": {
@@ -475,7 +453,7 @@
"type": "external",
"source": "msgpack",
"arg-type-unix": "with",
"arg-type-windows": "enable",
"arg-type-win": "enable",
"ext-depends": [
"session"
]
@@ -483,7 +461,6 @@
"mysqli": {
"type": "builtin",
"arg-type": "with",
"build-with-php": true,
"ext-depends": [
"mysqlnd"
]
@@ -491,45 +468,10 @@
"mysqlnd": {
"type": "builtin",
"arg-type-windows": "with",
"build-with-php": true,
"lib-depends": [
"zlib"
]
},
"mysqlnd_ed25519": {
"type": "external",
"source": "mysqlnd_ed25519",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium"
],
"lib-suggests": [
"openssl"
]
},
"mysqlnd_parsec": {
"type": "external",
"source": "mysqlnd_parsec",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium"
],
"lib-suggests": [
"openssl"
]
},
"oci8": {
"type": "wip",
"support": {
@@ -610,13 +552,6 @@
"type": "builtin",
"unix-only": true
},
"pcov": {
"type": "external",
"source": "pcov",
"target": [
"shared"
]
},
"pdo": {
"type": "builtin"
},
@@ -752,7 +687,7 @@
"type": "builtin",
"arg-type": "with-path",
"lib-depends": [
"libedit"
"readline"
],
"target": [
"static"
@@ -818,27 +753,17 @@
"apcu"
]
},
"snmp": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "builtin",
"arg-type-unix": "with",
"arg-type-windows": "with",
"lib-depends": [
"net-snmp"
]
},
"soap": {
"support": {
"BSD": "wip"
},
"type": "builtin",
"arg-type": "custom",
"ext-depends": [
"libxml",
"session"
"lib-depends": [
"libxml2"
],
"ext-depends-windows": [
"xml"
]
},
"sockets": {
@@ -874,7 +799,6 @@
"type": "builtin",
"arg-type": "with-path",
"arg-type-windows": "with",
"build-with-php": true,
"lib-depends": [
"sqlite"
]
@@ -963,22 +887,6 @@
"mysqli"
]
},
"swoole-hook-odbc": {
"support": {
"Windows": "no",
"BSD": "wip"
},
"notes": true,
"type": "addon",
"arg-type": "none",
"ext-depends": [
"pdo",
"swoole"
],
"lib-depends": [
"unixodbc"
]
},
"swoole-hook-pgsql": {
"support": {
"Windows": "no",
@@ -1008,6 +916,22 @@
"swoole"
]
},
"swoole-hook-odbc": {
"support": {
"Windows": "no",
"BSD": "wip"
},
"notes": true,
"type": "addon",
"arg-type": "none",
"ext-depends": [
"pdo",
"swoole"
],
"lib-depends": [
"unixodbc"
]
},
"swow": {
"support": {
"BSD": "wip"
@@ -1062,14 +986,6 @@
"type": "builtin",
"build-with-php": true
},
"trader": {
"support": {
"BSD": "wip",
"Windows": "wip"
},
"type": "external",
"source": "ext-trader"
},
"uuid": {
"support": {
"Windows": "wip",
@@ -1235,13 +1151,33 @@
]
},
"zip": {
"support": {
"BSD": "wip"
},
"type": "builtin",
"arg-type": "with-path",
"arg-type-windows": "enable",
"lib-depends-unix": [
"libzip"
],
"ext-depends-windows": [
"zlib",
"bz2"
],
"lib-depends-windows": [
"libzip",
"zlib",
"bzip2",
"xz"
]
},
"zip-shared": {
"support": {
"BSD": "wip"
},
"type": "external",
"source": "ext-zip",
"arg-type": "custom",
"arg-type-windows": "enable",
"arg-type": "enable",
"lib-depends-unix": [
"libzip"
],
@@ -1263,7 +1199,6 @@
"lib-depends": [
"zlib"
],
"build-with-php": true,
"target": [
"static"
]

View File

@@ -7,14 +7,12 @@
"source": "php-src",
"lib-depends": [
"lib-base",
"micro",
"frankenphp"
"micro"
],
"lib-depends-macos": [
"lib-base",
"micro",
"libxml2",
"frankenphp"
"libxml2"
],
"lib-suggests-linux": [
"libacl",
@@ -26,10 +24,6 @@
"watcher"
]
},
"frankenphp": {
"source": "frankenphp",
"type": "target"
},
"micro": {
"type": "target",
"source": "micro"
@@ -104,9 +98,7 @@
"ngtcp2",
"zstd",
"libcares",
"ldap",
"idn2",
"krb5"
"ldap"
],
"lib-suggests-windows": [
"brotli",
@@ -210,7 +202,7 @@
"openssl",
"libcares"
],
"cpp-library": true,
"provide-pre-built": true,
"frameworks": [
"CoreFoundation"
]
@@ -236,27 +228,8 @@
"unicode"
]
},
"idn2": {
"source": "libidn2",
"pkg-configs": [
"libidn2"
],
"headers": [
"idn2.h"
],
"lib-suggests-unix": [
"libiconv",
"gettext",
"libunistring"
],
"lib-depends-macos": [
"libiconv",
"gettext"
]
},
"imagemagick": {
"source": "imagemagick",
"cpp-library": true,
"pkg-configs": [
"Magick++-7.Q16HDRI",
"MagickCore-7.Q16HDRI",
@@ -301,26 +274,6 @@
"jbig_ar.h"
]
},
"krb5": {
"source": "krb5",
"pkg-configs": [
"krb5-gssapi"
],
"headers": [
"krb5.h",
"gssapi/gssapi.h"
],
"lib-depends": [
"openssl"
],
"lib-suggests": [
"ldap",
"libedit"
],
"frameworks": [
"Kerberos"
]
},
"ldap": {
"source": "ldap",
"pkg-configs": [
@@ -361,9 +314,6 @@
"source": "libargon2",
"static-libs-unix": [
"libargon2.a"
],
"lib-suggests": [
"libsodium"
]
},
"libavif": {
@@ -393,15 +343,6 @@
],
"cpp-library": true
},
"libedit": {
"source": "libedit",
"static-libs-unix": [
"libedit.a"
],
"lib-depends": [
"ncurses"
]
},
"libevent": {
"source": "libevent",
"static-libs-unix": [
@@ -509,16 +450,6 @@
"liblz4.a"
]
},
"libmaxminddb": {
"source": "libmaxminddb",
"static-libs-unix": [
"libmaxminddb.a"
],
"headers": [
"maxminddb.h",
"maxminddb_config.h"
]
},
"libmemcached": {
"source": "libmemcached",
"cpp-library": true,
@@ -565,16 +496,13 @@
},
"librdkafka": {
"source": "librdkafka",
"pkg-configs": [
"rdkafka++-static",
"rdkafka-static"
"static-libs-unix": [
"librdkafka.a",
"librdkafka++.a",
"librdkafka-static.a"
],
"cpp-library": true,
"lib-suggests": [
"curl",
"liblz4",
"openssl",
"zlib",
"zstd"
]
},
@@ -621,31 +549,6 @@
"zstd"
]
},
"libunistring": {
"source": "libunistring",
"static-libs-unix": [
"libunistring.a"
],
"headers": [
"unistr.h",
"unistring/"
]
},
"liburing": {
"source": "liburing",
"pkg-configs": [
"liburing",
"liburing-ffi"
],
"static-libs-linux": [
"liburing.a",
"liburing-ffi.a"
],
"headers-linux": [
"liburing/",
"liburing.h"
]
},
"libuuid": {
"source": "libuuid",
"static-libs-unix": [
@@ -679,8 +582,8 @@
},
"libxml2": {
"source": "libxml2",
"pkg-configs": [
"libxml-2.0"
"static-libs-unix": [
"libxml2.a"
],
"static-libs-windows": [
"libxml2s.lib",
@@ -769,17 +672,6 @@
"libncurses.a"
]
},
"net-snmp": {
"source": "net-snmp",
"pkg-configs": [
"netsnmp",
"netsnmp-agent"
],
"lib-depends": [
"openssl",
"zlib"
]
},
"nghttp2": {
"source": "nghttp2",
"static-libs-unix": [
@@ -878,7 +770,7 @@
"libxml2",
"openssl",
"zlib",
"libedit"
"readline"
],
"lib-suggests": [
"icu",
@@ -930,7 +822,6 @@
},
"snappy": {
"source": "snappy",
"cpp-library": true,
"static-libs-unix": [
"libsnappy.a"
],
@@ -976,7 +867,6 @@
},
"watcher": {
"source": "watcher",
"cpp-library": true,
"static-libs-unix": [
"libwatcher-c.a"
],
@@ -1037,5 +927,20 @@
"zstd.h",
"zstd_errors.h"
]
},
"liburing": {
"source": "liburing",
"pkg-configs": [
"liburing",
"liburing-ffi"
],
"static-libs-linux": [
"liburing.a",
"liburing-ffi.a"
],
"headers-linux": [
"liburing/",
"liburing.h"
]
}
}

View File

@@ -23,8 +23,8 @@
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip",
"extract-files": {
"nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
}
},
"pkg-config-aarch64-linux": {
@@ -84,7 +84,7 @@
"repo": "upx/upx",
"match": "upx.+-win64\\.zip",
"extract-files": {
"upx.exe": "{pkg_root_path}/bin/upx.exe"
"upx-*-win64/upx.exe": "{pkg_root_path}/bin/upx.exe"
}
},
"zig-aarch64-linux": {

View File

@@ -47,7 +47,7 @@
"provide-pre-built": true,
"license": {
"type": "file",
"path": "doc/COPYING.LGPL"
"path": "doc/COPYING"
}
},
"brotli": {
@@ -126,23 +126,13 @@
},
"ext-event": {
"type": "url",
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.1.4.tar.gz",
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz",
"path": "php-src/ext/event",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-excimer": {
"type": "url",
"url": "https://pecl.php.net/get/excimer",
"path": "php-src/ext/excimer",
"filename": "excimer.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-glfw": {
"type": "git",
"url": "https://github.com/mario-deluna/php-glfw",
@@ -161,18 +151,6 @@
"path": "LICENSE"
}
},
"ext-grpc": {
"type": "url",
"url": "https://pecl.php.net/get/grpc",
"path": "php-src/ext/grpc",
"filename": "grpc.tgz",
"license": {
"type": "file",
"path": [
"LICENSE"
]
}
},
"ext-imagick": {
"type": "url",
"url": "https://pecl.php.net/get/imagick",
@@ -206,15 +184,6 @@
]
}
},
"ext-maxminddb": {
"type": "url",
"url": "https://pecl.php.net/get/maxminddb",
"filename": "ext-maxminddb.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-memcache": {
"type": "url",
"url": "https://pecl.php.net/get/memcache",
@@ -264,16 +233,6 @@
"path": "LICENSE"
}
},
"ext-trader": {
"type": "url",
"url": "https://pecl.php.net/get/trader",
"path": "php-src/ext/trader",
"filename": "trader.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-uuid": {
"type": "url",
"url": "https://pecl.php.net/get/uuid",
@@ -307,6 +266,7 @@
"ext-zip": {
"type": "url",
"url": "https://pecl.php.net/get/zip",
"path": "php-src/ext/zip-shared",
"filename": "ext-zip.tgz",
"license": {
"type": "file",
@@ -332,19 +292,10 @@
"path": "LICENSE.MIT"
}
},
"frankenphp": {
"type": "ghtar",
"repo": "php/frankenphp",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
}
},
"freetype": {
"type": "ghtagtar",
"repo": "freetype/freetype",
"match": "VER-2-\\d+-\\d+",
"type": "git",
"rev": "VER-2-13-2",
"url": "https://github.com/freetype/freetype",
"license": {
"type": "file",
"path": "LICENSE.TXT"
@@ -356,17 +307,16 @@
"regex": "/href=\"(?<file>gettext-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"license": {
"type": "file",
"path": "gettext-runtime/intl/COPYING.LIB"
"path": "COPYING"
}
},
"gmp": {
"type": "filelist",
"url": "https://gmplib.org/download/gmp/",
"regex": "/href=\"(?<file>gmp-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz",
"provide-pre-built": true,
"alt": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz"
"type": "ghtagtar",
"repo": "alisw/GMP"
},
"license": {
"type": "text",
@@ -384,7 +334,7 @@
},
"grpc": {
"type": "git",
"rev": "v1.75.x",
"rev": "v1.68.x",
"url": "https://github.com/grpc/grpc.git",
"provide-pre-built": true,
"license": {
@@ -461,16 +411,6 @@
"path": "COPYING"
}
},
"krb5": {
"type": "ghtagtar",
"repo": "krb5/krb5",
"match": "krb5.+-final",
"prefer-stable": true,
"license": {
"type": "file",
"path": "NOTICE"
}
},
"ldap": {
"type": "filelist",
"url": "https://www.openldap.org/software/download/OpenLDAP/openldap-release/",
@@ -500,7 +440,7 @@
"provide-pre-built": true,
"license": {
"type": "file",
"path": "doc/COPYING.LGPL"
"path": "doc/COPYING"
}
},
"libaom": {
@@ -559,16 +499,6 @@
"path": "COPYING"
}
},
"libedit": {
"type": "filelist",
"url": "https://thrysoee.dk/editline/",
"regex": "/href=\"(?<file>libedit-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
}
},
"libevent": {
"type": "ghrel",
"repo": "libevent/libevent",
@@ -617,7 +547,7 @@
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING.LIB"
"path": "COPYING"
}
},
"libiconv-win": {
@@ -629,15 +559,6 @@
"path": "source/COPYING"
}
},
"libidn2": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libidn/",
"regex": "/href=\"(?<file>libidn2-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"license": {
"type": "file",
"path": "COPYING.LESSERv3"
}
},
"libjpeg": {
"type": "ghtar",
"repo": "libjpeg-turbo/libjpeg-turbo",
@@ -672,16 +593,6 @@
"path": "LICENSE"
}
},
"libmaxminddb": {
"type": "ghrel",
"repo": "maxmind/libmaxminddb",
"match": "libmaxminddb-.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
}
},
"libmemcached": {
"type": "ghtagtar",
"repo": "awesomized/libmemcached",
@@ -692,10 +603,9 @@
}
},
"libpng": {
"type": "ghtagtar",
"repo": "pnggroup/libpng",
"match": "v1\\.6\\.\\d+",
"query": "?per_page=150",
"type": "git",
"url": "https://github.com/glennrp/libpng.git",
"rev": "libpng16",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -703,9 +613,9 @@
}
},
"librabbitmq": {
"type": "ghtar",
"repo": "alanxz/rabbitmq-c",
"prefer-stable": true,
"type": "git",
"url": "https://github.com/alanxz/rabbitmq-c.git",
"rev": "master",
"license": {
"type": "file",
"path": "LICENSE"
@@ -722,7 +632,7 @@
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-(?!1\\.0\\.21)\\d+(\\.\\d+)*\\.tar\\.gz",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
@@ -750,30 +660,10 @@
"path": "LICENSE.md"
}
},
"libunistring": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libunistring/",
"regex": "/href=\"(?<file>libunistring-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING.LIB"
}
},
"liburing": {
"type": "ghtar",
"repo": "axboe/liburing",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
}
},
"libuuid": {
"type": "git",
"url": "https://github.com/static-php/libuuid.git",
"rev": "master",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -794,9 +684,8 @@
]
},
"libwebp": {
"type": "ghtagtar",
"repo": "webmproject/libwebp",
"match": "v1\\.\\d+\\.\\d+$",
"type": "url",
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -804,10 +693,8 @@
}
},
"libxml2": {
"type": "ghtagtar",
"repo": "GNOME/libxml2",
"match": "v2\\.\\d+\\.\\d+$",
"provide-pre-built": false,
"type": "url",
"url": "https://github.com/GNOME/libxml2/archive/refs/tags/v2.12.5.tar.gz",
"license": {
"type": "file",
"path": "Copyright"
@@ -856,7 +743,7 @@
"micro": {
"type": "git",
"path": "php-src/sapi/micro",
"rev": "master",
"rev": "php-85-win",
"url": "https://github.com/static-php/phpmicro",
"license": {
"type": "file",
@@ -894,24 +781,6 @@
"path": "LICENSE"
}
},
"mysqlnd_ed25519": {
"type": "pie",
"repo": "mariadb/mysqlnd_ed25519",
"path": "php-src/ext/mysqlnd_ed25519",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"mysqlnd_parsec": {
"type": "pie",
"repo": "mariadb/mysqlnd_parsec",
"path": "php-src/ext/mysqlnd_parsec",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ncurses": {
"type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/ncurses/",
@@ -922,14 +791,6 @@
"path": "COPYING"
}
},
"net-snmp": {
"type": "ghtagtar",
"repo": "net-snmp/net-snmp",
"license": {
"type": "file",
"path": "COPYING"
}
},
"nghttp2": {
"type": "ghrel",
"repo": "nghttp2/nghttp2",
@@ -1007,15 +868,6 @@
"path": "LICENSE"
}
},
"pcov": {
"type": "url",
"url": "https://pecl.php.net/get/pcov",
"filename": "pcov.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"pdo_sqlsrv": {
"type": "url",
"url": "https://pecl.php.net/get/pdo_sqlsrv",
@@ -1038,7 +890,7 @@
"postgresql": {
"type": "ghtagtar",
"repo": "postgres/postgres",
"match": "REL_18_\\d+",
"match": "REL_16_\\d+",
"license": {
"type": "file",
"path": "COPYRIGHT"
@@ -1129,6 +981,7 @@
},
"snappy": {
"type": "git",
"repo": "google/snappy",
"rev": "main",
"url": "https://github.com/google/snappy",
"license": {
@@ -1137,8 +990,9 @@
}
},
"spx": {
"type": "pie",
"repo": "noisebynorthwest/php-spx",
"type": "git",
"rev": "master",
"url": "https://github.com/static-php/php-spx.git",
"path": "php-src/ext/spx",
"license": {
"type": "file",
@@ -1213,8 +1067,9 @@
}
},
"xdebug": {
"type": "pie",
"repo": "xdebug/xdebug",
"type": "url",
"url": "https://pecl.php.net/get/xdebug",
"filename": "xdebug.tgz",
"license": {
"type": "file",
"path": "LICENSE"
@@ -1291,5 +1146,14 @@
"type": "file",
"path": "LICENSE"
}
},
"liburing": {
"type": "ghtar",
"repo": "axboe/liburing",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
}
}
}

View File

@@ -744,26 +744,10 @@ h2 {
}
select {
border-radius: 8px;
border-radius: 4px;
border: 1px solid var(--vp-c-divider);
padding: 8px 12px;
padding: 0 4px;
width: 300px;
background-color: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
font-size: 14px;
transition: all 0.2s ease;
cursor: pointer;
outline: none;
}
select:hover {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-bg);
}
select:focus {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
}
.my-btn {
@@ -797,160 +781,17 @@ select:focus {
.textarea {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
width: calc(100% - 24px);
padding: 12px;
background-color: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
font-size: 14px;
font-family: var(--vp-font-family-mono);
line-height: 1.5;
transition: all 0.2s ease;
outline: none;
resize: vertical;
}
.textarea:hover {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-bg);
}
.textarea:focus {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
border-radius: 4px;
width: calc(100% - 12px);
padding: 4px 8px;
}
.input {
display: block;
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
width: 100%;
padding: 10px 12px;
background-color: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
font-size: 14px;
transition: all 0.2s ease;
outline: none;
box-sizing: border-box;
}
.input:hover {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-bg);
}
.input:focus {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
}
/* Radio button styles */
input[type="radio"] {
appearance: none;
width: 18px;
height: 18px;
border: 2px solid var(--vp-c-border);
border-radius: 50%;
background-color: var(--vp-c-bg);
cursor: pointer;
position: relative;
vertical-align: middle;
margin-right: 6px;
transition: all 0.2s ease;
}
input[type="radio"]:hover {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-bg-soft);
}
input[type="radio"]:checked {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-brand-1);
}
input[type="radio"]:checked::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
border-radius: 50%;
background-color: var(--vp-c-bg);
}
input[type="radio"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Checkbox styles */
input[type="checkbox"] {
appearance: none;
width: 18px;
height: 18px;
border: 2px solid var(--vp-c-border);
border-radius: 4px;
background-color: var(--vp-c-bg);
cursor: pointer;
position: relative;
vertical-align: middle;
margin-right: 6px;
transition: all 0.2s ease;
}
input[type="checkbox"]:hover {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-bg-soft);
}
input[type="checkbox"]:checked {
border-color: var(--vp-c-brand-1);
background-color: var(--vp-c-brand-1);
}
input[type="checkbox"]:checked::after {
content: '';
position: absolute;
top: 2px;
left: 5px;
width: 4px;
height: 8px;
border: solid var(--vp-c-bg);
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Label styles */
label {
cursor: pointer;
user-select: none;
color: var(--vp-c-text-1);
font-size: 14px;
line-height: 1.5;
transition: color 0.2s ease;
}
label:hover {
color: var(--vp-c-brand-1);
}
input[type="radio"]:disabled + label,
input[type="checkbox"]:disabled + label {
opacity: 0.5;
cursor: not-allowed;
}
input[type="radio"]:disabled + label:hover,
input[type="checkbox"]:disabled + label:hover {
color: var(--vp-c-text-1);
width: 100%;
padding: 4px 8px;
}
.command-container {

View File

@@ -1,219 +0,0 @@
<template>
<div class="contributors-container">
<div class="contributors-header">
<h2>Contributors</h2>
<p class="contributors-description">
Thanks to all the amazing people who have contributed to this project!
</p>
</div>
<div v-if="loading" class="loading-state">
<div class="spinner"></div>
<p>Loading contributors...</p>
</div>
<div v-else-if="error" class="error-state">
<p>{{ error }}</p>
</div>
<div v-else class="contributors-grid">
<a
v-for="contributor in contributors"
:key="contributor.id"
:href="contributor.html_url"
target="_blank"
rel="noopener noreferrer"
class="contributor-card"
:title="contributor.login"
>
<img
:src="contributor.avatar_url"
:alt="contributor.login"
class="contributor-avatar"
loading="lazy"
/>
<div class="contributor-name">{{ contributor.login }}</div>
</a>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface Contributor {
id: number;
login: string;
avatar_url: string;
html_url: string;
contributions: number;
}
const contributors = ref<Contributor[]>([]);
const loading = ref(true);
const error = ref('');
const fetchContributors = async () => {
try {
loading.value = true;
error.value = '';
const response = await fetch(
'https://api.github.com/repos/crazywhalecc/static-php-cli/contributors?per_page=24'
);
if (!response.ok) {
throw new Error('Failed to fetch contributors');
}
const data = await response.json();
contributors.value = data;
} catch (err) {
error.value = 'Failed to load contributors. Please try again later.';
console.error('Error fetching contributors:', err);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchContributors();
});
</script>
<style scoped>
.contributors-container {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
}
.contributors-header {
text-align: center;
margin-bottom: 24px;
}
.contributors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.contributors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
.loading-state,
.error-state {
text-align: center;
padding: 40px 20px;
color: var(--vp-c-text-2);
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 16px;
border: 4px solid var(--vp-c-divider);
border-top-color: var(--vp-c-brand-1);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.contributors-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 16px;
}
.contributor-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 12px;
background: var(--vp-c-bg);
border-radius: 12px;
border: 1px solid var(--vp-c-divider);
transition: all 0.3s ease;
text-decoration: none;
color: var(--vp-c-text-1);
}
.contributor-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
border-color: var(--vp-c-brand-1);
}
.contributor-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
border: 2px solid var(--vp-c-divider);
transition: all 0.3s ease;
margin-bottom: 8px;
}
.contributor-card:hover .contributor-avatar {
border-color: var(--vp-c-brand-1);
transform: scale(1.05);
}
.contributor-name {
font-size: 12px;
font-weight: 500;
text-align: center;
word-break: break-word;
max-width: 100%;
}
@media (max-width: 768px) {
.contributors-container {
margin: 32px 16px;
padding: 24px 16px;
}
.contributors-header h2 {
font-size: 1.25rem;
}
.contributors-description {
font-size: 0.9rem;
}
.contributors-grid {
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
gap: 12px;
}
.contributor-card {
padding: 8px;
}
.contributor-avatar {
width: 48px;
height: 48px;
}
.contributor-name {
font-size: 11px;
}
}
</style>

View File

@@ -4,7 +4,7 @@ import sidebarZh from "./sidebar.zh";
// https://vitepress.dev/reference/site-config
export default {
title: "Static PHP",
title: "static-php-cli",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
locales: {
en: {
@@ -44,7 +44,6 @@ export default {
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/images/static-php_nobg.png',
nav: [],
socialLinks: [
{icon: 'github', link: 'https://github.com/crazywhalecc/static-php-cli'}

View File

@@ -4,21 +4,3 @@
max-width: 1000px !important;
}
.vp-doc .contributors-header h2 {
padding-top: 0;
border-top: none;
}
.vp-doc .sponsors-header h2 {
padding-top: 0;
border-top: none;
}
.dark .VPImage.logo {
filter: contrast(0.7);
}
.dark .VPImage.image-src {
filter: contrast(0.7);
}

View File

@@ -36,7 +36,6 @@ The following is the source download configuration corresponding to the `libeven
The most important field here is `type`. Currently, the types it supports are:
- `url`: Directly use URL to download, for example: `https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`.
- `pie`: Download PHP extensions from Packagist using the PIE (PHP Installer for Extensions) standard.
- `ghrel`: Use the GitHub Release API to download, download the artifacts uploaded from the latest version released by maintainers.
- `ghtar`: Use the GitHub Release API to download.
Different from `ghrel`, `ghtar` is downloaded from the `source code (tar.gz)` in the latest Release of the project.
@@ -90,37 +89,6 @@ Example (download the imagick extension and extract it to the extension storage
}
```
## Download type - pie
PIE (PHP Installer for Extensions) type sources refer to downloading PHP extensions from Packagist that follow the PIE standard.
This method automatically fetches extension information from the Packagist repository and downloads the appropriate distribution file.
The parameters included are:
- `repo`: The Packagist vendor/package name, such as `vendor/package-name`
Example (download a PHP extension from Packagist using PIE):
```json
{
"ext-example": {
"type": "pie",
"repo": "vendor/example-extension",
"path": "php-src/ext/example",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
::: tip
The PIE download type will automatically detect the extension information from Packagist metadata,
including the download URL, version, and distribution type.
The extension must be marked as `type: php-ext` or contain `php-ext` metadata in its Packagist package definition.
:::
## Download type - ghrel
ghrel will download files from Assets uploaded in GitHub Release.

View File

@@ -44,11 +44,6 @@ So on macOS, you can **directly** use SPC to build statically compiled PHP binar
2. You will get `buildroot/modules/xdebug.so` and `buildroot/bin/php`.
3. The `xdebug.so` file could be used for php that version and thread-safe are the same.
For the Windows platform, since officially built extensions (such as `php_yaml.dll`) force the use of the `php8.dll` dynamic library as a link, and statically built PHP does not include any dynamic libraries other than system libraries,
php.exe built by static-php cannot load officially built dynamic extensions. Since static-php-cli does not yet support building dynamic extensions, there is currently no way to load dynamic extensions with static-php.
However, Windows can normally use the `FFI` extension to load other dll files and call them.
## Can it support Oracle database extension?
Some extensions that rely on closed source libraries, such as `oci8`, `sourceguardian`, etc.,

View File

@@ -549,24 +549,22 @@ otherwise it will be executed repeatedly in other events.
The following are the supported `patch_point` event names and corresponding locations:
| Event name | Event description |
|---------------------------------|----------------------------------------------------------------------------------------------------|
| before-libs-extract | Triggered before the dependent libraries extracted |
| after-libs-extract | Triggered after the compiled dependent libraries extracted |
| before-php-extract | Triggered before PHP source code extracted |
| after-php-extract | Triggered after PHP source code extracted |
| before-micro-extract | Triggered before phpmicro extract |
| after-micro-extract | Triggered after phpmicro extracted |
| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory |
| after-exts-extract | Triggered after the extension extracted to the PHP source directory |
| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) |
| after-library[*name*]-build | Triggered after the library named `name` is compiled |
| after-shared-ext[*name*]-build | Triggered after the shared extension named `name` is compiled |
| before-shared-ext[*name*]-build | Triggered before the shared extension named `name` is compiled |
| before-php-buildconf | Triggered before compiling PHP command `./buildconf` |
| before-php-configure | Triggered before compiling PHP command `./configure` |
| before-php-make | Triggered before compiling PHP command `make` |
| before-sanity-check | Triggered after compiling PHP but before running extended checks |
| Event name | Event description |
|------------------------------|----------------------------------------------------------------------------------------------------|
| before-libs-extract | Triggered before the dependent libraries extracted |
| after-libs-extract | Triggered after the compiled dependent libraries extracted |
| before-php-extract | Triggered before PHP source code extracted |
| after-php-extract | Triggered after PHP source code extracted |
| before-micro-extract | Triggered before phpmicro extract |
| after-micro-extract | Triggered after phpmicro extracted |
| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory |
| after-exts-extract | Triggered after the extension extracted to the PHP source directory |
| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) |
| after-library[*name*]-build | Triggered after the library named `name` is compiled |
| before-php-buildconf | Triggered before compiling PHP command `./buildconf` |
| before-php-configure | Triggered before compiling PHP command `./configure` |
| before-php-make | Triggered before compiling PHP command `make` |
| before-sanity-check | Triggered after compiling PHP but before running extended checks |
The following is a simple example of temporarily modifying the PHP source code.
Enable the CLI function to search for the `php.ini` configuration in the current working directory:

View File

@@ -3,14 +3,11 @@
layout: home
hero:
name: "Static PHP"
name: "static-php-cli"
tagline: "Build standalone PHP binary on Linux, macOS, FreeBSD, Windows, with PHP project together, with popular extensions included."
image:
src: /images/static-php_nobg.png
alt: Static PHP CLI Logo
actions:
- theme: brand
text: Get Started
text: Guide
link: ./guide/
features:
@@ -22,121 +19,3 @@ features:
details: static-php-cli comes with dependency management and supports installation of different types of PHP extensions.
---
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from '../.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>Special Sponsors</h2>
<p class="sponsors-description">
Thank you to our amazing sponsors for supporting this project!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />

View File

@@ -3,11 +3,8 @@
layout: home
hero:
name: "Static PHP"
name: "static-php-cli"
tagline: "Build standalone PHP binary on Linux, macOS, FreeBSD, Windows, with PHP project together, with popular extensions included."
image:
src: /images/static-php_nobg.png
alt: Static PHP CLI Logo
actions:
- theme: brand
text: Get Started
@@ -27,121 +24,13 @@ features:
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from './.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>Special Sponsors</h2>
<p class="sponsors-description">
Thank you to our amazing sponsors for supporting this project!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
## Special Sponsors
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />
<VPSponsors :data="sponsors"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 KiB

View File

@@ -30,7 +30,6 @@ static-php-cli 的下载资源模块是一个主要的功能,它包含了所
这里最主要的字段是 `type`,目前它支持的类型有:
- `url`: 直接使用 URL 下载,例如:`https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`
- `pie`: 使用 PIEPHP Installer for Extensions标准从 Packagist 下载 PHP 扩展。
- `ghrel`: 使用 GitHub Release API 下载,即从 GitHub 项目发布的最新版本中上传的附件下载。
- `ghtar`: 使用 GitHub Release API 下载,与 `ghrel` 不同的是,`ghtar` 是从项目的最新 Release 中找 `source code (tar.gz)` 下载的。
- `ghtagtar`: 使用 GitHub Release API 下载,与 `ghtar` 相比,`ghtagtar` 可以从 `tags` 列表找最新的,并下载 `tar.gz` 格式的源码(因为有些项目只使用了 `tag` 发布版本)。
@@ -78,36 +77,6 @@ url 类型的资源指的是从 URL 直接下载文件。
}
```
## 下载类型 - pie
PIEPHP Installer for Extensions类型的资源是从 Packagist 下载遵循 PIE 标准的 PHP 扩展。
该方法会自动从 Packagist 仓库获取扩展信息,并下载相应的分发文件。
包含的参数有:
- `repo`: Packagist 的 vendor/package 名称,如 `vendor/package-name`
例子(使用 PIE 从 Packagist 下载 PHP 扩展):
```json
{
"ext-example": {
"type": "pie",
"repo": "vendor/example-extension",
"path": "php-src/ext/example",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}
```
::: tip
PIE 下载类型会自动从 Packagist 元数据中检测扩展信息,包括下载 URL、版本和分发类型。
扩展必须在其 Packagist 包定义中标记为 `type: php-ext` 或包含 `php-ext` 元数据。
:::
## 下载类型 - ghrel
ghrel 会从 GitHub Release 中上传的 Assets 下载文件。首先使用 GitHub Release API 获取最新版本,然后根据正则匹配方式下载相应的文件。

View File

@@ -41,11 +41,6 @@ buildroot/bin/php -d "zend_extension=/path/to/php{PHP_VER}-{ts/nts}/xdebug.so" -
2. 你将获得 `buildroot/modules/xdebug.so``buildroot/bin/php`
3. `xdebug.so` 文件可用于版本和线程安全相同的 php。
对于 Windows 平台,由于官方构建的扩展(如 `php_yaml.dll`)强制使用了 `php8.dll` 动态库作为链接,静态构建的 PHP 不包含任何系统库以外的动态库,
所以 Windows 下无法加载官方构建的动态扩展。 由于 static-php-cli 还暂未支持构建动态扩展,所以目前还没有让 static-php 加载动态扩展的方法。
不过Windows 可以正常使用 `FFI` 扩展加载其他的 dll 文件并调用。
## 可以支持 Oracle 数据库扩展吗?
部分依赖库闭源的扩展,如 `oci8``sourceguardian` 等,它们没有提供纯静态编译的依赖库文件(`.a`),仅提供了动态依赖库文件(`.so`

View File

@@ -500,8 +500,6 @@ bin/spc dev:sort-config ext
| after-exts-extract | 在要编译的扩展解压到 PHP 源码目录后触发 |
| before-library[*name*]-build | 在名称为 `name` 的库编译前触发(如 `before-library[postgresql]-build` |
| after-library[*name*]-build | 在名称为 `name` 的库编译后触发 |
| after-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译后触发(如 `after-shared-ext[redis]-build` |
| before-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译前触发 |
| before-php-buildconf | 在编译 PHP 命令 `./buildconf` 前触发 |
| before-php-configure | 在编译 PHP 命令 `./configure` 前触发 |
| before-php-make | 在编译 PHP 命令 `make` 前触发 |

View File

@@ -3,140 +3,18 @@
layout: home
hero:
name: "Static PHP"
name: "static-php-cli"
tagline: "在 Linux、macOS、FreeBSD、Windows 上与 PHP 项目一起构建独立的 PHP 二进制文件,并包含流行的扩展。"
image:
src: /images/static-php_nobg.png
alt: Static PHP CLI Logo
actions:
- theme: brand
text: 开始使用
text: 指南
link: ./guide/
features:
- title: 静态 CLI 二进制
details: 您可以轻松地编译一个独立的 PHP 二进制文件以供通用使用包括 CLI、FPM SAPI
- title: Micro 自解压可执行文件
details: 您可以编译一个自解压的可执行文件,并将 PHP 代码与二进制文件打包在一起
- title: 依赖管理
details: static-php-cli 附带依赖项管理,支持安装不同类型的 PHP 扩展。
- title: 静态二进制
details: 您可以轻松地编译一个独立的 PHP 二进制文件以供嵌入程序使用包括 cli、fpm、micro
- title: phpmicro 自执行二进制
details: 您可以使用 micro SAPI 编译一个自解压的可执行文件,并将 PHP 代码与二进制文件打包为一个文件
- title: 依赖管理
details: static-php-cli 附带依赖项管理,支持安装不同类型的 PHP 扩展和不同的依赖库
---
<script setup>
import {VPSponsors} from "vitepress/theme";
import Contributors from '../.vitepress/components/Contributors.vue';
const sponsors = [
{ name: 'Beyond Code', img: '/images/beyondcode-seeklogo.png', url: 'https://beyondco.de/' },
{ name: 'NativePHP', img: '/images/nativephp-logo.svg', url: 'https://nativephp.com/' },
];
</script>
<div class="sponsors-section">
<div class="sponsors-header">
<h2>特别赞助商</h2>
<p class="sponsors-description">
感谢我们出色的赞助商对本项目的支持!
</p>
</div>
<VPSponsors :data="sponsors"/>
</div>
<style scoped>
.sponsors-section {
margin: 48px auto;
padding: 32px 24px;
max-width: 1152px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-bg) 100%);
border-radius: 16px;
border: 1px solid var(--vp-c-divider);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.sponsors-section:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.sponsors-header {
text-align: center;
margin-bottom: 24px;
}
.sponsors-header h2 {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 8px 0;
background: linear-gradient(120deg, var(--vp-c-brand-1), var(--vp-c-brand-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sponsors-description {
font-size: 0.95rem;
color: var(--vp-c-text-2);
margin: 0;
line-height: 1.5;
}
@media (max-width: 768px) {
.sponsors-section {
margin: 32px 16px;
padding: 24px 16px;
}
.sponsors-header h2 {
font-size: 1.25rem;
}
.sponsors-description {
font-size: 0.9rem;
}
}
/* Hero logo styling */
:deep(.VPImage.image-src) {
border-radius: 20px;
background: linear-gradient(135deg, var(--vp-c-bg-soft) 0%, var(--vp-c-default-soft) 100%);
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:deep(.VPImage.image-src:hover) {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Dark mode adjustments for logo */
.dark :deep(.VPImage.image-src) {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
opacity: 0.9;
}
.dark :deep(.VPImage.image-src:hover) {
opacity: 1;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}
/* Additional styling for the logo image itself */
:deep(.VPImage.image-src img) {
max-height: 280px;
width: auto;
}
@media (max-width: 768px) {
:deep(.VPImage.image-src) {
padding: 24px;
}
:deep(.VPImage.image-src img) {
max-height: 200px;
}
}
</style>
<Contributors />

View File

@@ -34,7 +34,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
public const string VERSION = '2.8.0';
public const string VERSION = '2.7.4';
public function __construct()
{

View File

@@ -128,6 +128,27 @@ abstract class BuilderBase
return array_filter($this->exts, fn ($ext) => $ext->isBuildStatic());
}
/**
* Check if there is a cpp extensions or libraries.
*/
public function hasCpp(): bool
{
// judge cpp-extension
$exts = array_keys($this->getExts(false));
foreach ($exts as $ext) {
if (Config::getExt($ext, 'cpp-extension', false) === true) {
return true;
}
}
$libs = array_keys($this->getLibs());
foreach ($libs as $lib) {
if (Config::getLib($lib, 'cpp-library', false) === true) {
return true;
}
}
return false;
}
/**
* Set libs only mode.
*

View File

@@ -4,13 +4,17 @@ declare(strict_types=1);
namespace SPC\builder;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\EnvironmentException;
use SPC\exception\FileSystemException;
use SPC\exception\SPCException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\toolchain\ClangNativeToolchain;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
@@ -77,7 +81,7 @@ class Extension
{
$escapedPath = str_replace("'", '', escapeshellarg(BUILD_ROOT_PATH)) !== BUILD_ROOT_PATH || str_contains(BUILD_ROOT_PATH, ' ') ? escapeshellarg(BUILD_ROOT_PATH) : BUILD_ROOT_PATH;
$_name = str_replace('_', '-', $this->name);
return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
$arg = match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
'enable' => '--enable-' . $_name . ($shared ? '=shared' : '') . ' ',
'enable-path' => '--enable-' . $_name . '=' . ($shared ? 'shared,' : '') . $escapedPath . ' ',
'with' => '--with-' . $_name . ($shared ? '=shared' : '') . ' ',
@@ -85,6 +89,7 @@ class Extension
'none', 'custom' => '',
default => throw new WrongUsageException("argType does not accept {$arg_type}, use [enable/with/with-path] ."),
};
return str_replace('-shared', '', $arg);
}
/**
@@ -126,7 +131,7 @@ class Extension
public function getName(): string
{
return $this->name;
return str_replace('-shared', '', $this->name);
}
/**
@@ -134,7 +139,7 @@ class Extension
*/
public function getDistName(): string
{
return $this->name;
return str_replace('-shared', '', $this->name);
}
public function getWindowsConfigureArg(bool $shared = false): string
@@ -221,25 +226,13 @@ class Extension
*/
public function patchBeforeSharedMake(): bool
{
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
$lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
$makefileContent = file_get_contents($this->source_dir . '/Makefile');
if (preg_match('/^(.*_SHARED_LIBADD\s*=\s*)(.*)$/m', $makefileContent, $matches)) {
$prefix = $matches[1];
$currentLibs = trim($matches[2]);
$newLibs = trim("{$currentLibs} {$staticLibs} {$lstdcpp}");
$deduplicatedLibs = deduplicate_flags($newLibs);
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
$prefix . $deduplicatedLibs
);
}
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
[$staticLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
'$1 ' . trim($staticLibs)
);
if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) {
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
@@ -306,7 +299,7 @@ class Extension
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
if ($ret !== 0) {
throw new ValidationException(
"extension {$this->getName()} failed compile check: php-cli returned {$ret}",
@@ -336,7 +329,7 @@ class Extension
{
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
[$ret] = cmd()->execWithResult(BUILD_BIN_PATH . '/php.exe -n --ri "' . $this->getDistName() . '"', false);
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -n --ri "' . $this->getDistName() . '"', false);
if ($ret !== 0) {
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: "Extension {$this->getName()} sanity check");
}
@@ -385,9 +378,6 @@ class Extension
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
return;
}
if ((string) Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
@@ -398,12 +388,13 @@ class Extension
$dependency->buildShared([...$visited, $this->getName()]);
}
}
$this->builder->emitPatchPoint('before-shared-ext[' . $this->getName() . ']-build');
if (Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
};
$this->builder->emitPatchPoint('after-shared-ext[' . $this->getName() . ']-build');
} catch (SPCException $e) {
$e->bindExtensionInfo(['extension_name' => $this->getName()]);
throw $e;
@@ -415,7 +406,42 @@ class Extension
*/
public function buildUnixShared(): void
{
$env = $this->getSharedExtensionEnv();
$config = (new SPCConfigUtil($this->builder))->config(
[$this->getName()],
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
$this->builder->getOption('with-suggested-exts'),
$this->builder->getOption('with-suggested-libs'),
);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
$env = [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
if (str_contains($env['LIBS'], '-lstdc++') && SPCTarget::getTargetOS() === 'Linux') {
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$env['SPC_COMPILER_EXTRA'] = '-lstdc++';
} elseif (ToolchainManager::getToolchainClass() === GccNativeToolchain::class || ToolchainManager::getToolchainClass() === ClangNativeToolchain::class) {
try {
$content = FileSystem::readFile($this->source_dir . '/config.m4');
if ($content && !str_contains($content, 'PHP_ADD_LIBRARY(stdc++')) {
$pattern = '/(PHP_NEW_EXTENSION\(' . $this->name . ',.*\))/m';
$replacement = "$1\nPHP_ADD_LIBRARY(stdc++, 1, " . strtoupper($this->name) . '_SHARED_LIBADD)';
FileSystem::replaceFileRegex(
$this->source_dir . '/config.m4',
$pattern,
$replacement
);
}
} catch (FileSystemException) {
}
}
}
if ($this->patchBeforeSharedPhpize()) {
logger()->info("Extension [{$this->getName()}] patched before shared phpize");
}
@@ -430,15 +456,13 @@ class Extension
logger()->info("Extension [{$this->getName()}] patched before shared configure");
}
$phpvars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
shell()->cd($this->source_dir)
->setEnv($env)
->appendEnv($this->getExtraEnv())
->exec(
'./configure ' . $this->getUnixConfigureArg(true) .
' --with-php-config=' . BUILD_BIN_PATH . '/php-config ' .
"--enable-shared --disable-static {$phpvars}"
'--enable-shared --disable-static'
);
if ($this->patchBeforeSharedMake()) {
@@ -451,20 +475,6 @@ class Extension
->exec('make clean')
->exec('make -j' . $this->builder->concurrency)
->exec('make install');
// process *.so file
$soFile = BUILD_MODULES_PATH . '/' . $this->getName() . '.so';
$soDest = $soFile;
preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches);
if (!empty($matches[1])) {
$soDest = str_replace('.so', '-' . $matches[1] . '.so', $soFile);
}
if (!file_exists($soFile)) {
throw new ValidationException("extension {$this->getName()} build failed: {$soFile} not found", validation_module: "Extension {$this->getName()} build");
}
/** @var UnixBuilderBase $builder */
$builder = $this->builder;
$builder->deployBinary($soFile, $soDest, false);
}
/**
@@ -503,59 +513,6 @@ class Extension
return $this->build_static;
}
/**
* Get the library dependencies that current extension depends on.
*
* @param bool $recursive Whether it includes dependencies recursively
*/
public function getLibraryDependencies(bool $recursive = false): array
{
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
if (!$recursive) {
return $ret;
}
$deps = [];
$added = 1;
while ($added !== 0) {
$added = 0;
foreach ($ret as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!array_key_exists($depdepName, $deps)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!array_key_exists($depName, $deps)) {
$deps[$depName] = $dep;
}
}
}
return $deps;
}
/**
* Returns the environment variables a shared extension needs to be built.
* CFLAGS, CXXFLAGS, LDFLAGS and so on.
*/
protected function getSharedExtensionEnv(): array
{
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
return [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
}
protected function addLibraryDependency(string $name, bool $optional = false): void
{
$depLib = $this->builder->getLib($name);
@@ -565,7 +522,7 @@ class Extension
}
logger()->info("enabling {$this->name} without library {$name}");
} else {
$this->dependencies[$name] = $depLib;
$this->dependencies[] = $depLib;
}
}
@@ -578,7 +535,7 @@ class Extension
}
logger()->info("enabling {$this->name} without extension {$name}");
} else {
$this->dependencies[$name] = $depExt;
$this->dependencies[] = $depExt;
}
}
@@ -613,4 +570,37 @@ class Extension
}
return [trim($staticLibString), trim($sharedLibString)];
}
private function getLibraryDependencies(bool $recursive = false): array
{
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
if (!$recursive) {
return $ret;
}
$deps = [];
$added = 1;
while ($added !== 0) {
$added = 0;
foreach ($ret as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!in_array($depdepName, array_keys($deps), true)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!in_array($depName, array_keys($deps), true)) {
$deps[$depName] = $dep;
}
}
}
if (array_key_exists(0, $deps)) {
$zero = [0 => $deps[0]];
unset($deps[0]);
return $zero + $deps;
}
return $deps;
}
}

View File

@@ -184,18 +184,18 @@ abstract class LibraryBase
// extract first if not exists
if (!is_dir($this->source_dir)) {
$this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-extract');
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract');
SourceManager::initSource(libs: [static::NAME], source_only: true);
$this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-extract');
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract');
}
if (!$this->patched && $this->patchBeforeBuild()) {
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
}
$this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-build');
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
$this->build();
$this->installLicense();
$this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-build');
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
return LIB_STATUS_OK;
}
@@ -346,19 +346,19 @@ abstract class LibraryBase
*/
protected function installLicense(): void
{
FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName());
$source = Config::getLib($this->getName(), 'source');
FileSystem::createDir(BUILD_ROOT_PATH . "/source-licenses/{$source}");
$license_files = Config::getSource($source)['license'] ?? [];
if (is_assoc_array($license_files)) {
$license_files = [$license_files];
}
foreach ($license_files as $index => $license) {
if ($license['type'] === 'text') {
FileSystem::writeFile(BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt", $license['text']);
FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']);
continue;
}
if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt");
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt");
}
}
}
@@ -375,17 +375,8 @@ abstract class LibraryBase
return false;
}
}
$pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
$search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path));
foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) {
$found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$name}.pc")) {
$found = true;
break;
}
}
if (!$found) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) {
return false;
}
}

View File

@@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('excimer')]
class excimer extends Extension
{
public function getSharedExtensionEnv(): array
{
$env = parent::getSharedExtensionEnv();
$env['LIBS'] = clean_spaces(str_replace('-lphp', '', $env['LIBS']));
return $env;
}
}

View File

@@ -15,11 +15,7 @@ class gettext extends Extension
public function patchBeforeBuildconf(): bool
{
if ($this->builder instanceof MacOSBuilder) {
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/gettext/config.m4',
['AC_CHECK_LIB($GETTEXT_CHECK_IN_LIB', 'AC_CHECK_LIB([$GETTEXT_CHECK_IN_LIB'],
['AC_CHECK_LIB(intl', 'AC_CHECK_LIB([intl'] // new php versions use a bracket
);
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gettext/config.m4', 'AC_CHECK_LIB($GETTEXT_CHECK_IN_LIB', 'AC_CHECK_LIB(intl');
}
return true;
}

View File

@@ -21,14 +21,18 @@ class grpc extends Extension
if ($this->builder instanceof WindowsBuilder) {
throw new ValidationException('grpc extension does not support windows yet');
}
FileSystem::replaceFileStr(
$this->source_dir . '/src/php/ext/grpc/call.c',
'zend_exception_get_default(TSRMLS_C),',
'zend_ce_exception,',
);
if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) {
return false;
}
// soft link to the grpc source code
if (is_dir($this->source_dir . '/src/php/ext/grpc')) {
shell()->exec('ln -s ' . $this->source_dir . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc');
} else {
throw new ValidationException('Cannot find grpc source code in ' . $this->source_dir . '/src/php/ext/grpc');
}
if (SPCTarget::getTargetOS() === 'Darwin') {
FileSystem::replaceFileRegex(
$this->source_dir . '/config.m4',
SOURCE_PATH . '/php-src/ext/grpc/config.m4',
'/GRPC_LIBDIR=.*$/m',
'GRPC_LIBDIR=' . BUILD_LIB_PATH . "\n" . 'LDFLAGS="$LDFLAGS -framework CoreFoundation"'
);
@@ -39,7 +43,7 @@ class grpc extends Extension
public function patchBeforeConfigure(): bool
{
$util = new SPCConfigUtil($this->builder, ['libs_only_deps' => true]);
$config = $util->getExtensionConfig($this);
$config = $util->config(['grpc']);
$libs = $config['libs'];
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lgrpc', $libs);
return true;
@@ -52,11 +56,4 @@ class grpc extends Extension
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
return true;
}
protected function getSharedExtensionEnv(): array
{
$env = parent::getSharedExtensionEnv();
$env['CPPFLAGS'] = $env['CXXFLAGS'] . ' -Wno-attributes';
return $env;
}
}

View File

@@ -5,8 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\CustomExt;
#[CustomExt('imagick')]
@@ -21,9 +19,7 @@ class imagick extends Extension
protected function splitLibsIntoStaticAndShared(string $allLibs): array
{
[$static, $shared] = parent::splitLibsIntoStaticAndShared($allLibs);
if (ToolchainManager::getToolchainClass() !== ZigToolchain::class &&
(str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset'))
) {
if (str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) {
$static .= ' -l:libstdc++.a';
$shared = str_replace('-lstdc++', '', $shared);
}

View File

@@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('maxminddb')]
class maxminddb extends Extension
{
public function patchBeforeBuildconf(): bool
{
if (!is_dir(SOURCE_PATH . '/php-src/ext/maxminddb')) {
$original = $this->source_dir;
FileSystem::copyDir($original . '/ext', SOURCE_PATH . '/php-src/ext/maxminddb');
$this->source_dir = SOURCE_PATH . '/php-src/ext/maxminddb';
return true;
}
$this->source_dir = SOURCE_PATH . '/php-src/ext/maxminddb';
return false;
}
}

View File

@@ -18,9 +18,6 @@ class memcache extends Extension
public function patchBeforeBuildconf(): bool
{
if (!$this->isBuildStatic()) {
return false;
}
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/src ; then',
@@ -46,27 +43,4 @@ EOF
);
return true;
}
public function patchBeforeSharedConfigure(): bool
{
if (!$this->isBuildShared()) {
return false;
}
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/main ; then',
'if test -d $abs_srcdir/src ; then',
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"',
'export CPPFLAGS="$CPPFLAGS $INCLUDES"',
);
return true;
}
protected function getExtraEnv(): array
{
return ['CFLAGS' => '-std=c17'];
}
}

View File

@@ -24,9 +24,4 @@ class mongodb extends Extension
$arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled ';
return clean_spaces($arg);
}
public function getExtraEnv(): array
{
return ['CFLAGS' => '-std=c17'];
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_ed25519')]
class mysqlnd_ed25519 extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--with-mysqlnd_ed25519' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_parsec')]
class mysqlnd_parsec extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--enable-mysqlnd_parsec' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -24,6 +24,25 @@ class password_argon2 extends Extension
}
}
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
if ($this->builder->getLib('libsodium') !== null) {
$extraLibs = getenv('SPC_EXTRA_LIBS');
if ($extraLibs !== false) {
$extraLibs = str_replace(
[BUILD_LIB_PATH . '/libargon2.a', BUILD_LIB_PATH . '/libsodium.a'],
['', BUILD_LIB_PATH . '/libargon2.a ' . BUILD_LIB_PATH . '/libsodium.a'],
$extraLibs,
);
$extraLibs = trim(preg_replace('/\s+/', ' ', $extraLibs)); // normalize spacing
f_putenv('SPC_EXTRA_LIBS=' . $extraLibs);
return true;
}
}
return $patched;
}
public function getConfigureArg(bool $shared = false): string
{
if ($this->builder->getLib('openssl') !== null) {

View File

@@ -45,7 +45,7 @@ class pgsql extends Extension
protected function getExtraEnv(): array
{
return [
'CFLAGS' => '-std=c17 -Wno-int-conversion',
'CFLAGS' => '-Wno-int-conversion',
];
}
}

View File

@@ -7,7 +7,6 @@ namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\SPCConfigUtil;
#[CustomExt('rdkafka')]
class rdkafka extends Extension
@@ -16,7 +15,6 @@ class rdkafka extends Extension
{
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\n", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm \$RDKAFKA_LIBS\n");
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\"\n", '-L$RDKAFKA_DIR/$PHP_LIBDIR -lm $RDKAFKA_LIBS"');
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", 'PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,', 'AC_CHECK_LIB([$LIBNAME], [$LIBSYMBOL],');
return true;
}
@@ -39,7 +37,8 @@ class rdkafka extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
$pkgconf_libs = (new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]))->getExtensionConfig($this);
return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . " RDKAFKA_LIBS=\"{$pkgconf_libs['libs']}\"";
$pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1];
$pkgconf_libs = trim(implode('', $pkgconf_libs));
return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"';
}
}

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\ValidationException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
@@ -24,7 +23,12 @@ class readline extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-libedit --without-readline';
$enable = '--without-libedit --with-readline=' . BUILD_ROOT_PATH;
if ($this->builder->getPHPVersionID() < 84000) {
// the check uses `char rl_pending_input()` instead of `extern int rl_pending_input`, which makes LTO fail
$enable .= ' ac_cv_lib_readline_rl_pending_input=yes';
}
return $enable;
}
public function buildUnixShared(): void
@@ -35,13 +39,4 @@ class readline extends Extension
}
parent::buildUnixShared();
}
public function runCliCheckUnix(): void
{
parent::runCliCheckUnix();
[$ret, $out] = shell()->execWithResult('printf "exit\n" | ' . BUILD_BIN_PATH . '/php -a');
if ($ret !== 0 || !str_contains(implode("\n", $out), 'Interactive shell')) {
throw new ValidationException("readline extension failed sanity check. Code: {$ret}, output: " . implode("\n", $out));
}
}
}

View File

@@ -6,8 +6,6 @@ namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\CustomExt;
#[CustomExt('simdjson')]
@@ -19,7 +17,7 @@ class simdjson extends Extension
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/ext/simdjson/config.m4',
'/php_version=(`.*`)$/m',
'php_version=' . $php_ver
'php_version=' . strval($php_ver)
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/simdjson/config.m4',
@@ -33,18 +31,4 @@ class simdjson extends Extension
);
return true;
}
public function getSharedExtensionEnv(): array
{
$env = parent::getSharedExtensionEnv();
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$extra = getenv('SPC_COMPILER_EXTRA');
if (!str_contains((string) $extra, '-lstdc++')) {
f_putenv('SPC_COMPILER_EXTRA=' . clean_spaces($extra . ' -lstdc++'));
}
$env['CFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
$env['CXXFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
}
return $env;
}
}

View File

@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\PkgConfigUtil;
#[CustomExt('snmp')]
class snmp extends Extension
{
public function patchBeforeBuildconf(): bool
{
// Overwrite m4 config using newer PHP version
if ($this->builder->getPHPVersionID() < 80400) {
FileSystem::copy(ROOT_DIR . '/src/globals/extra/snmp-ext-config-old.m4', "{$this->source_dir}/config.m4");
}
$libs = implode(' ', PkgConfigUtil::getLibsArray('netsnmp'));
FileSystem::replaceFileStr(
"{$this->source_dir}/config.m4",
'PHP_EVAL_LIBLINE([$SNMP_LIBS], [SNMP_SHARED_LIBADD])',
"SNMP_LIBS=\"{$libs}\"\nPHP_EVAL_LIBLINE([\$SNMP_LIBS], [SNMP_SHARED_LIBADD])"
);
return true;
}
}

View File

@@ -13,7 +13,7 @@ class spx extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-SPX' . ($shared ? '=shared' : '');
$arg = '--enable-spx' . ($shared ? '=shared' : '');
if ($this->builder->getLib('zlib') !== null) {
$arg .= ' --with-zlib-dir=' . BUILD_ROOT_PATH;
}
@@ -29,20 +29,4 @@ class spx extends Extension
);
return true;
}
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(
$this->source_dir . '/config.m4',
'CFLAGS="$CFLAGS -Werror -Wall -O3 -pthread -std=gnu90"',
'CFLAGS="$CFLAGS -pthread"'
);
FileSystem::replaceFileStr(
$this->source_dir . '/src/php_spx.h',
"extern zend_module_entry spx_module_entry;\n",
"extern zend_module_entry spx_module_entry;;\n#define phpext_spx_ptr &spx_module_entry\n"
);
FileSystem::copy($this->source_dir . '/src/php_spx.h', $this->source_dir . '/php_spx.h');
return true;
}
}

View File

@@ -17,7 +17,6 @@ class swoole extends Extension
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
FileSystem::replaceFileStr($this->source_dir . '/ext-src/php_swoole_private.h', 'PHP_VERSION_ID > 80500', 'PHP_VERSION_ID >= 80600');
if ($this->builder instanceof MacOSBuilder) {
// Fix swoole with event extension <util.h> conflict bug
$util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h';
@@ -70,13 +69,10 @@ class swoole extends Extension
$arg .= $this->builder->getExt('swoole-hook-pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql';
$arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd';
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite';
if ($this->builder->getExt('swoole-hook-odbc')) {
$config = (new SPCConfigUtil($this->builder))->getLibraryConfig($this->builder->getLib('unixodbc'));
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}
if ($this->getExtVersion() >= '6.1.0') {
$arg .= ' --enable-swoole-stdext';
if ($this->builder->getExt('swoole-hook-odbc')) {
$config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']);
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}
if (SPCTarget::getTargetOS() === 'Darwin') {

View File

@@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('trader')]
class trader extends Extension
{
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/trader/config.m4', 'PHP_TA', 'PHP_TRADER');
return true;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('zip')]
class zip extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
return !$shared ? '--with-zip=' . BUILD_ROOT_PATH : '--enable-zip=shared';
}
}

View File

@@ -153,7 +153,7 @@ class BSDBuilder extends UnixBuilderBase
if (!$this->getOption('no-strip', false)) {
$shell->exec('strip sapi/cli/php');
}
$this->deploySAPIBinary(BUILD_TARGET_CLI);
$this->deployBinary(BUILD_TARGET_CLI);
}
/**
@@ -184,7 +184,7 @@ class BSDBuilder extends UnixBuilderBase
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec('strip --strip-unneeded micro.sfx');
}
$this->deploySAPIBinary(BUILD_TARGET_MICRO);
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::unpatchMicroPhar();
@@ -206,7 +206,7 @@ class BSDBuilder extends UnixBuilderBase
if (!$this->getOption('no-strip', false)) {
$shell->exec('strip sapi/fpm/php-fpm');
}
$this->deploySAPIBinary(BUILD_TARGET_FPM);
$this->deployBinary(BUILD_TARGET_FPM);
}
/**

View File

@@ -7,8 +7,6 @@ namespace SPC\builder\linux;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\PatchException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\DirDiff;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager;
@@ -91,14 +89,12 @@ class LinuxBuilder extends UnixBuilderBase
// prepare build php envs
// $musl_flag = SPCTarget::getLibc() === 'musl' ? ' -D__MUSL__' : ' -U__MUSL__';
$php_configure_env = SystemUtil::makeEnvVarString([
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH, // . ' -Dsomethinghere', // . $musl_flag,
'LDFLAGS' => '-L' . BUILD_LIB_PATH,
// 'LIBS' => SPCTarget::getRuntimeLibs(), // do not pass static libraries here yet, they may contain polyfills for libc functions!
]);
$phpvars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
if ($embed_type !== 'static' && SPCTarget::isStatic()) {
throw new WrongUsageException(
@@ -109,19 +105,18 @@ class LinuxBuilder extends UnixBuilderBase
$this->seekPhpSrcLogFileOnException(fn () => shell()->cd(SOURCE_PATH . '/php-src')->exec(
$php_configure_env . ' ' .
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableFpm ? '--enable-fpm ' . ($this->getLib('libacl') !== null ? '--with-fpm-acl ' : '') : '--disable-fpm ') .
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
$config_file_path .
$config_file_scan_dir .
$json_74 .
$zts .
$maxExecutionTimers .
$phpvars . ' ' .
$this->makeStaticExtensionArgs() . ' '
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableFpm ? '--enable-fpm ' . ($this->getLib('libacl') !== null ? '--with-fpm-acl ' : '') : '--disable-fpm ') .
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
$config_file_path .
$config_file_scan_dir .
$json_74 .
$zts .
$maxExecutionTimers .
$this->makeStaticExtensionArgs() . ' '
));
$this->emitPatchPoint('before-php-make');
@@ -158,14 +153,7 @@ class LinuxBuilder extends UnixBuilderBase
}
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
if (!empty($shared_extensions)) {
if (SPCTarget::isStatic()) {
throw new WrongUsageException(
"You're building against musl libc statically (the default on Linux), but you're trying to build shared extensions.\n" .
'Static musl libc does not implement `dlopen`, so your php binary is not able to load shared extensions.' . "\n" .
'Either use SPC_LIBC=glibc to link against glibc on a glibc OS, or use SPC_TARGET="native-native-musl -dynamic" to link against musl libc dynamically using `zig cc`.'
);
}
logger()->info('Building shared extensions...');
logger()->info('Building shared extensions ...');
$this->buildSharedExts();
}
}
@@ -181,32 +169,40 @@ class LinuxBuilder extends UnixBuilderBase
*/
protected function buildCli(): void
{
if ($this->getExt('readline') && SPCTarget::isStatic()) {
SourcePatcher::patchFile('musl_static_readline.patch', SOURCE_PATH . '/php-src');
}
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$vars} cli");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cli");
if ($this->getExt('readline') && SPCTarget::isStatic()) {
SourcePatcher::patchFile('musl_static_readline.patch', SOURCE_PATH . '/php-src', true);
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')->exec('strip --strip-unneeded php');
}
if ($this->getOption('with-upx-pack')) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')
->exec(getenv('UPX_EXEC') . ' --best php');
}
$this->deploySAPIBinary(BUILD_TARGET_CLI);
$this->deployBinary(BUILD_TARGET_CLI);
}
protected function buildCgi(): void
{
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$vars} cgi");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cgi");
$this->deploySAPIBinary(BUILD_TARGET_CGI);
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cgi')->exec('strip --strip-unneeded php-cgi');
}
if ($this->getOption('with-upx-pack')) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cgi')
->exec(getenv('UPX_EXEC') . ' --best php-cgi');
}
$this->deployBinary(BUILD_TARGET_CGI);
}
/**
@@ -217,33 +213,29 @@ class LinuxBuilder extends UnixBuilderBase
if ($this->getPHPVersionID() < 80000) {
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
}
try {
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = $this->getMakeExtraVars();
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = $this->getMakeExtraVars();
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
$vars = SystemUtil::makeEnvVarString($vars);
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
$vars = SystemUtil::makeEnvVarString($vars);
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$vars} micro");
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} micro");
// deploy micro.sfx
$dst = $this->deploySAPIBinary(BUILD_TARGET_MICRO);
$this->processMicroUPX();
// patch after UPX-ed micro.sfx
$this->processUpxedMicroSfx($dst);
} finally {
if ($this->phar_patched) {
SourcePatcher::unpatchMicroPhar();
}
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::unpatchMicroPhar();
}
}
@@ -253,12 +245,19 @@ class LinuxBuilder extends UnixBuilderBase
protected function buildFpm(): void
{
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$vars} fpm");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} fpm");
$this->deploySAPIBinary(BUILD_TARGET_FPM);
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')->exec('strip --strip-unneeded php-fpm');
}
if ($this->getOption('with-upx-pack')) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')
->exec(getenv('UPX_EXEC') . ' --best php-fpm');
}
$this->deployBinary(BUILD_TARGET_FPM);
}
/**
@@ -266,40 +265,79 @@ class LinuxBuilder extends UnixBuilderBase
*/
protected function buildEmbed(): void
{
$sharedExts = array_filter($this->exts, static fn ($ext) => $ext->isBuildShared());
$sharedExts = array_filter($sharedExts, static function ($ext) {
return Config::getExt($ext->getName(), 'build-with-php') === true;
});
$install_modules = $sharedExts ? 'install-modules' : '';
// detect changes in module path
$diff = new DirDiff(BUILD_MODULES_PATH, true);
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec('sed -i "s|^EXTENSION_DIR = .*|EXTENSION_DIR = /' . basename(BUILD_MODULES_PATH) . '|" Makefile')
->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi {$install_modules} install-build install-headers install-programs");
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
// process libphp.so for shared embed
$libphpSo = BUILD_LIB_PATH . '/libphp.so';
$libphpSoDest = BUILD_LIB_PATH . '/libphp.so';
if (file_exists($libphpSo)) {
// deploy libphp.so
preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches);
if (!empty($matches[1])) {
$libphpSoDest = str_replace('.so', '-' . $matches[1] . '.so', $libphpSo);
$ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: '';
$libDir = BUILD_LIB_PATH;
$modulesDir = BUILD_MODULES_PATH;
$libphpSo = "{$libDir}/libphp.so";
$realLibName = 'libphp.so';
$cwd = getcwd();
if (preg_match('/-release\s+(\S+)/', $ldflags, $matches)) {
$release = $matches[1];
$realLibName = "libphp-{$release}.so";
$libphpRelease = "{$libDir}/{$realLibName}";
if (!file_exists($libphpRelease) && file_exists($libphpSo)) {
rename($libphpSo, $libphpRelease);
}
$this->deployBinary($libphpSo, $libphpSoDest, false);
if (file_exists($libphpRelease)) {
chdir($libDir);
if (file_exists($libphpSo)) {
unlink($libphpSo);
}
symlink($realLibName, 'libphp.so');
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg($realLibName),
escapeshellarg($libphpRelease)
));
}
if (is_dir($modulesDir)) {
chdir($modulesDir);
foreach ($this->getExts() as $ext) {
if (!$ext->isBuildShared()) {
continue;
}
$name = $ext->getName();
$versioned = "{$name}-{$release}.so";
$unversioned = "{$name}.so";
$src = "{$modulesDir}/{$versioned}";
$dst = "{$modulesDir}/{$unversioned}";
if (is_file($src)) {
rename($src, $dst);
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg($unversioned),
escapeshellarg($dst)
));
}
}
}
chdir($cwd);
}
// process shared extensions build-with-php
$increment_files = $diff->getChangedFiles();
foreach ($increment_files as $increment_file) {
$this->deployBinary($increment_file, $increment_file, false);
$target = "{$libDir}/{$realLibName}";
if (file_exists($target)) {
[, $output] = shell()->execWithResult('readelf -d ' . escapeshellarg($target));
$output = implode("\n", $output);
if (preg_match('/SONAME.*\[(.+)]/', $output, $sonameMatch)) {
$currentSoname = $sonameMatch[1];
if ($currentSoname !== basename($target)) {
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg(basename($target)),
escapeshellarg($target)
));
}
}
}
// process libphp.a for static embed
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') {
$AR = getenv('AR') ?: 'ar';
f_passthru("{$AR} -t " . BUILD_LIB_PATH . "/libphp.a | grep '\\.a$' | xargs -n1 {$AR} d " . BUILD_LIB_PATH . '/libphp.a');
@@ -307,7 +345,9 @@ class LinuxBuilder extends UnixBuilderBase
SystemUtil::exportDynamicSymbols(BUILD_LIB_PATH . '/libphp.a');
}
// patch embed php scripts
if (!$this->getOption('no-strip', false) && file_exists(BUILD_LIB_PATH . '/' . $realLibName)) {
shell()->cd(BUILD_LIB_PATH)->exec("strip --strip-unneeded {$realLibName}");
}
$this->patchPhpScripts();
}
@@ -319,35 +359,38 @@ class LinuxBuilder extends UnixBuilderBase
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$static = SPCTarget::isStatic() ? '-all-static' : '';
$lib = BUILD_LIB_PATH;
return array_filter([
return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => $config['libs'],
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie",
]);
];
}
/**
* Patch micro.sfx after UPX compression.
* micro needs special section handling in LinuxBuilder.
* The micro.sfx does not support UPX directly, but we can remove UPX
* info segment to adapt.
* This will also make micro.sfx with upx-packed more like a malware fore antivirus
* Strip micro.sfx for Linux.
* The micro.sfx does not support UPX directly, but we can remove UPX-info segment to adapt.
* This will also make micro.sfx with upx-packed more like a malware fore antivirus :(
*/
private function processUpxedMicroSfx(string $dst): void
private function processMicroUPX(): void
{
if ($this->getOption('with-upx-pack') && version_compare($this->getMicroVersion(), '0.2.0') >= 0) {
// strip first
// cut binary with readelf
[$ret, $out] = shell()->execWithResult("readelf -l {$dst} | awk '/LOAD|GNU_STACK/ {getline; print \$1, \$2, \$3, \$4, \$6, \$7}'");
$out[1] = explode(' ', $out[1]);
$offset = $out[1][0];
if ($ret !== 0 || !str_starts_with($offset, '0x')) {
throw new PatchException('phpmicro UPX patcher', 'Cannot find offset in readelf output');
if (version_compare($this->getMicroVersion(), '0.2.0') >= 0 && !$this->getOption('no-strip', false)) {
shell()->exec('strip --strip-unneeded ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx');
if ($this->getOption('with-upx-pack')) {
// strip first
shell()->exec(getenv('UPX_EXEC') . ' --best ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx');
// cut binary with readelf
[$ret, $out] = shell()->execWithResult('readelf -l ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx | awk \'/LOAD|GNU_STACK/ {getline; print $1, $2, $3, $4, $6, $7}\'');
$out[1] = explode(' ', $out[1]);
$offset = $out[1][0];
if ($ret !== 0 || !str_starts_with($offset, '0x')) {
throw new PatchException('phpmicro UPX patcher', 'Cannot find offset in readelf output');
}
$offset = hexdec($offset);
// remove upx extra wastes
file_put_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx', substr(file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx'), 0, $offset));
}
$offset = hexdec($offset);
// remove upx extra wastes
file_put_contents($dst, substr(file_get_contents($dst), 0, $offset));
}
}
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class idn2 extends LinuxLibraryBase
{
use \SPC\builder\unix\library\idn2;
public const NAME = 'idn2';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class krb5 extends LinuxLibraryBase
{
use \SPC\builder\unix\library\krb5;
public const NAME = 'krb5';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class libedit extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libedit;
public const NAME = 'libedit';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class libmaxminddb extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libmaxminddb;
public const NAME = 'libmaxminddb';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class libunistring extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libunistring;
public const NAME = 'libunistring';
}

View File

@@ -6,8 +6,6 @@ namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCTarget;
@@ -17,19 +15,26 @@ class liburing extends LinuxLibraryBase
public function patchBeforeBuild(): bool
{
if (SystemUtil::isMuslDist()) {
FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath');
return true;
if (!SystemUtil::isMuslDist()) {
return false;
}
return false;
FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath');
return true;
}
protected function build(): void
{
$use_libc = ToolchainManager::getToolchainClass() !== GccNativeToolchain::class || version_compare(SPCTarget::getLibcVersion(), '2.30', '>=');
$use_libc = SPCTarget::getLibc() !== 'glibc' || version_compare(SPCTarget::getLibcVersion(), '2.30', '>=');
$make = UnixAutoconfExecutor::create($this);
if ($use_libc) {
if (!$use_libc) {
$make->appendEnv([
'CC' => 'gcc', // libc-less version fails to compile with clang or zig
'CXX' => 'g++',
'AR' => 'ar',
'LD' => 'ld',
]);
} else {
$make->appendEnv([
'CFLAGS' => '-D_GNU_SOURCE',
]);
@@ -46,7 +51,7 @@ class liburing extends LinuxLibraryBase
$use_libc ? '--use-libc' : '',
)
->configure()
->make('library ENABLE_SHARED=0', 'install ENABLE_SHARED=0', with_clean: false);
->make('library', 'install ENABLE_SHARED=0', with_clean: false);
$this->patchPkgconfPrefix();
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class net_snmp extends LinuxLibraryBase
{
use \SPC\builder\unix\library\net_snmp;
public const NAME = 'net-snmp';
}

View File

@@ -21,7 +21,6 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem;
class openssl extends LinuxLibraryBase
@@ -52,9 +51,6 @@ class openssl extends LinuxLibraryBase
$zlib_extra = '';
}
$openssl_dir = getenv('OPENSSLDIR') ?: null;
// TODO: in v3 use the following: $openssl_dir ??= SystemUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl';
$openssl_dir ??= '/etc/ssl';
$ex_lib = trim($ex_lib);
shell()->cd($this->source_dir)->initializeEnv($this)
@@ -62,11 +58,10 @@ class openssl extends LinuxLibraryBase
"{$env} ./Configure no-shared {$extra} " .
'--prefix=' . BUILD_ROOT_PATH . ' ' .
'--libdir=' . BUILD_LIB_PATH . ' ' .
"--openssldir={$openssl_dir} " .
'--openssldir=/etc/ssl ' .
"{$zlib_extra}" .
'enable-pie ' .
'no-legacy ' .
'no-tests ' .
"linux-{$arch}"
)
->exec('make clean')
@@ -83,7 +78,7 @@ class openssl extends LinuxLibraryBase
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
}
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Requires.private: zlib');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
}
}

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* gmp is a template library class for unix
*/
class readline extends LinuxLibraryBase
{
use \SPC\builder\unix\library\readline;

View File

@@ -7,8 +7,6 @@ namespace SPC\builder\macos;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\DirDiff;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager;
@@ -106,7 +104,7 @@ class MacOSBuilder extends UnixBuilderBase
// prepare build php envs
$envs_build_php = SystemUtil::makeEnvVarString([
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH,
'LDFLAGS' => '-L' . BUILD_LIB_PATH,
]);
@@ -188,9 +186,12 @@ class MacOSBuilder extends UnixBuilderBase
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$shell->exec("make {$concurrency} {$vars} cli");
$this->deploySAPIBinary(BUILD_TARGET_CLI);
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
$shell->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cli");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip -S sapi/cli/php');
}
$this->deployBinary(BUILD_TARGET_CLI);
}
protected function buildCgi(): void
@@ -198,9 +199,12 @@ class MacOSBuilder extends UnixBuilderBase
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$shell->exec("make {$concurrency} {$vars} cgi");
$this->deploySAPIBinary(BUILD_TARGET_CGI);
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
$shell->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cgi");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/cgi/php-cgi')->exec('strip -S sapi/cgi/php-cgi');
}
$this->deployBinary(BUILD_TARGET_CGI);
}
/**
@@ -211,30 +215,30 @@ class MacOSBuilder extends UnixBuilderBase
if ($this->getPHPVersionID() < 80000) {
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
try {
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = $this->getMakeExtraVars();
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = $this->getMakeExtraVars();
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
$vars = SystemUtil::makeEnvVarString($vars);
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
$vars = SystemUtil::makeEnvVarString($vars);
$shell = shell()->cd(SOURCE_PATH . '/php-src');
// build
$shell->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . " {$vars} micro");
// strip
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/micro/micro.sfx')->exec('strip -S sapi/micro/micro.sfx');
}
$shell = shell()->cd(SOURCE_PATH . '/php-src');
// build
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$shell->exec("make {$concurrency} {$vars} micro");
$this->deployBinary(BUILD_TARGET_MICRO);
$this->deploySAPIBinary(BUILD_TARGET_MICRO);
} finally {
if ($this->phar_patched) {
SourcePatcher::unpatchMicroPhar();
}
if ($this->phar_patched) {
SourcePatcher::unpatchMicroPhar();
}
}
@@ -246,9 +250,11 @@ class MacOSBuilder extends UnixBuilderBase
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$shell->exec("make {$concurrency} {$vars} fpm");
$this->deploySAPIBinary(BUILD_TARGET_FPM);
$shell->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . " {$vars} fpm");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip -S sapi/fpm/php-fpm');
}
$this->deployBinary(BUILD_TARGET_FPM);
}
/**
@@ -256,31 +262,10 @@ class MacOSBuilder extends UnixBuilderBase
*/
protected function buildEmbed(): void
{
$sharedExts = array_filter($this->exts, static fn ($ext) => $ext->isBuildShared());
$sharedExts = array_filter($sharedExts, static function ($ext) {
return Config::getExt($ext->getName(), 'build-with-php') === true;
});
$install_modules = $sharedExts ? 'install-modules' : '';
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$diff = new DirDiff(BUILD_MODULES_PATH, true);
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "" "s|^EXTENSION_DIR = .*|EXTENSION_DIR = /' . basename(BUILD_MODULES_PATH) . '|" Makefile')
->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi {$install_modules} install-build install-headers install-programs");
$libphp = BUILD_LIB_PATH . '/libphp.dylib';
if (file_exists($libphp)) {
$this->deployBinary($libphp, $libphp, false);
// macOS currently have no -release option for dylib, so we just rename it here
}
// process shared extensions build-with-php
$increment_files = $diff->getChangedFiles();
foreach ($increment_files as $increment_file) {
$this->deployBinary($increment_file, $increment_file, false);
}
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') {
$AR = getenv('AR') ?: 'ar';
@@ -294,10 +279,10 @@ class MacOSBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array
{
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return array_filter([
return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => '-L' . BUILD_LIB_PATH,
'EXTRA_LIBS' => $config['libs'],
]);
];
}
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class idn2 extends MacOSLibraryBase
{
use \SPC\builder\unix\library\idn2;
public const NAME = 'idn2';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class krb5 extends MacOSLibraryBase
{
use \SPC\builder\unix\library\krb5;
public const NAME = 'krb5';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class libedit extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libedit;
public const NAME = 'libedit';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class libmaxminddb extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libmaxminddb;
public const NAME = 'libmaxminddb';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class libunistring extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libunistring;
public const NAME = 'libunistring';
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class net_snmp extends MacOSLibraryBase
{
use \SPC\builder\unix\library\net_snmp;
public const NAME = 'net-snmp';
}

View File

@@ -63,7 +63,7 @@ class openssl extends MacOSLibraryBase
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
}
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Requires.private: zlib');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
}
}

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
/**
* gmp is a template library class for unix
*/
class readline extends MacOSLibraryBase
{
use \SPC\builder\unix\library\readline;

View File

@@ -34,7 +34,7 @@ trait UnixLibraryTrait
$files = array_map(fn ($x) => "{$x}.pc", $conf_pc);
}
foreach ($files as $name) {
$realpath = realpath(BUILD_LIB_PATH . '/pkgconfig/' . $name);
$realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name);
if ($realpath === false) {
throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !');
}

View File

@@ -72,8 +72,12 @@ trait UnixSystemUtilTrait
if (!is_file($symbol_file)) {
throw new SPCInternalException("The symbol file {$symbol_file} does not exist, please check if nm command is available.");
}
// macOS/zig
if (SPCTarget::getTargetOS() !== 'Linux' || ToolchainManager::getToolchainClass() === ZigToolchain::class) {
// https://github.com/ziglang/zig/issues/24662
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
return '-Wl,--export-dynamic';
}
// macOS
if (SPCTarget::getTargetOS() !== 'Linux') {
return "-Wl,-exported_symbols_list,{$symbol_file}";
}
return "-Wl,--dynamic-list={$symbol_file}";

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\unix;
use SPC\builder\BuilderBase;
use SPC\builder\linux\SystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\exception\SPCException;
use SPC\exception\SPCInternalException;
@@ -14,7 +13,6 @@ use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\pkg\GoXcaddy;
use SPC\store\SourceManager;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\util\DependencyUtil;
@@ -80,91 +78,6 @@ abstract class UnixBuilderBase extends BuilderBase
$this->lib_list = $sorted_libraries;
}
/**
* Strip unneeded symbols from binary file.
*/
public function stripBinary(string $binary_path): void
{
shell()->exec(match (PHP_OS_FAMILY) {
'Darwin' => "strip -S {$binary_path}",
'Linux' => "strip --strip-unneeded {$binary_path}",
default => throw new SPCInternalException('stripBinary is only supported on Linux and macOS'),
});
}
/**
* Extract debug information from binary file.
*
* @param string $binary_path the path to the binary file, including executables, shared libraries, etc
*/
public function extractDebugInfo(string $binary_path): string
{
$target_dir = BUILD_ROOT_PATH . '/debug';
FileSystem::createDir($target_dir);
$basename = basename($binary_path);
$debug_file = "{$target_dir}/{$basename}" . (PHP_OS_FAMILY === 'Darwin' ? '.dwarf' : '.debug');
if (PHP_OS_FAMILY === 'Darwin') {
shell()->exec("dsymutil -f {$binary_path} -o {$debug_file}");
} elseif (PHP_OS_FAMILY === 'Linux') {
if ($eu_strip = SystemUtil::findCommand('eu-strip')) {
shell()
->exec("{$eu_strip} -f {$debug_file} {$binary_path}")
->exec("objcopy --add-gnu-debuglink={$debug_file} {$binary_path}");
} else {
shell()
->exec("objcopy --only-keep-debug {$binary_path} {$debug_file}")
->exec("objcopy --add-gnu-debuglink={$debug_file} {$binary_path}");
}
} else {
throw new SPCInternalException('extractDebugInfo is only supported on Linux and macOS');
}
return $debug_file;
}
/**
* Deploy the binary file from src to dst.
*/
public function deployBinary(string $src, string $dst, bool $executable = true): string
{
logger()->debug('Deploying binary from ' . $src . ' to ' . $dst);
// file must exists
if (!file_exists($src)) {
throw new SPCInternalException("Deploy failed. Cannot find file: {$src}");
}
// dst dir must exists
FileSystem::createDir(dirname($dst));
// ignore copy to self
if (realpath($src) !== realpath($dst)) {
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg($dst));
}
// file exist
if (!file_exists($dst)) {
throw new SPCInternalException("Deploy failed. Cannot find file after copy: {$dst}");
}
if (!$this->getOption('no-strip')) {
// extract debug info
$this->extractDebugInfo($dst);
// extra strip
$this->stripBinary($dst);
}
// UPX for linux
$upx_option = $this->getOption('with-upx-pack');
if ($upx_option && PHP_OS_FAMILY === 'Linux' && $executable) {
if ($this->getOption('no-strip')) {
logger()->warning('UPX compression is not recommended when --no-strip is enabled.');
}
logger()->info("Compressing {$dst} with UPX");
shell()->exec(getenv('UPX_EXEC') . " --best {$dst}");
}
return $dst;
}
/**
* Sanity check after build complete.
*/
@@ -235,10 +148,8 @@ abstract class UnixBuilderBase extends BuilderBase
$lens .= ' -static';
}
$dynamic_exports = '';
$embedType = 'static';
// if someone changed to EMBED_TYPE=shared, we need to add LD_LIBRARY_PATH
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
$embedType = 'shared';
if (PHP_OS_FAMILY === 'Darwin') {
$ext_path = 'DYLD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$DYLD_LIBRARY_PATH ';
} else {
@@ -257,19 +168,18 @@ abstract class UnixBuilderBase extends BuilderBase
}
}
$cc = getenv('CC');
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult("{$cc} -o embed embed.c {$lens} {$dynamic_exports}");
if ($ret !== 0) {
throw new ValidationException(
'embed failed to build. Error message: ' . implode("\n", $out),
validation_module: $embedType . ' libphp embed build sanity check'
'embed failed sanity check: build failed. Error message: ' . implode("\n", $out),
validation_module: 'static libphp.a sanity check'
);
}
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new ValidationException(
'embed failed to run. Error message: ' . implode("\n", $output),
validation_module: $embedType . ' libphp embed run sanity check'
'embed failed sanity check: run failed. Error message: ' . implode("\n", $output),
validation_module: 'static libphp.a sanity check'
);
}
}
@@ -298,20 +208,23 @@ abstract class UnixBuilderBase extends BuilderBase
}
/**
* Deploy binaries that produces executable SAPI
* Deploy the binary file to the build bin path.
*
* @param int $type Type integer, one of BUILD_TARGET_CLI, BUILD_TARGET_MICRO, BUILD_TARGET_FPM
*/
protected function deploySAPIBinary(int $type): string
protected function deployBinary(int $type): bool
{
$src = match ($type) {
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
BUILD_TARGET_CGI => SOURCE_PATH . '/php-src/sapi/cgi/php-cgi',
BUILD_TARGET_FRANKENPHP => BUILD_BIN_PATH . '/frankenphp',
default => throw new SPCInternalException("Deployment does not accept type {$type}"),
};
$dst = BUILD_BIN_PATH . '/' . basename($src);
return $this->deployBinary($src, $dst);
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_BIN_PATH);
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_BIN_PATH));
return true;
}
/**
@@ -352,75 +265,22 @@ abstract class UnixBuilderBase extends BuilderBase
}
}
/**
* Process the --with-frankenphp-app option
* Creates app.tar and app.checksum in source/frankenphp directory
*/
protected function processFrankenphpApp(): void
{
$frankenphpSourceDir = getenv('FRANKENPHP_SOURCE_PATH') ?: SOURCE_PATH . '/frankenphp';
if (!is_dir($frankenphpSourceDir)) {
SourceManager::initSource(['frankenphp'], ['frankenphp']);
}
$frankenphpAppPath = $this->getOption('with-frankenphp-app');
if ($frankenphpAppPath) {
if (!is_dir($frankenphpAppPath)) {
throw new WrongUsageException("The path provided to --with-frankenphp-app is not a valid directory: {$frankenphpAppPath}");
}
$appTarPath = $frankenphpSourceDir . '/app.tar';
logger()->info("Creating app.tar from {$frankenphpAppPath}");
shell()->exec('tar -cf ' . escapeshellarg($appTarPath) . ' -C ' . escapeshellarg($frankenphpAppPath) . ' .');
$checksum = hash_file('md5', $appTarPath);
file_put_contents($frankenphpSourceDir . '/app_checksum.txt', $checksum);
} else {
FileSystem::removeFileIfExists($frankenphpSourceDir . '/app.tar');
FileSystem::removeFileIfExists($frankenphpSourceDir . '/app_checksum.txt');
file_put_contents($frankenphpSourceDir . '/app.tar', '');
file_put_contents($frankenphpSourceDir . '/app_checksum.txt', '');
}
}
protected function getFrankenPHPVersion(): string
{
if ($version = getenv('FRANKENPHP_VERSION')) {
return $version;
}
$frankenphpSourceDir = getenv('FRANKENPHP_SOURCE_PATH') ?: SOURCE_PATH . '/frankenphp';
$goModPath = $frankenphpSourceDir . '/caddy/go.mod';
if (!file_exists($goModPath)) {
throw new SPCInternalException("FrankenPHP caddy/go.mod file not found at {$goModPath}, why did we not download FrankenPHP?");
}
$content = file_get_contents($goModPath);
if (preg_match('/github\.com\/dunglas\/frankenphp\s+v?(\d+\.\d+\.\d+)/', $content, $matches)) {
return $matches[1];
}
throw new SPCInternalException('Could not find FrankenPHP version in caddy/go.mod');
}
protected function buildFrankenphp(): void
{
GlobalEnvManager::addPathIfNotExists(GoXcaddy::getPath());
$this->processFrankenphpApp();
$nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : '';
$nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : '';
$xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES');
$frankenphpSourceDir = getenv('FRANKENPHP_SOURCE_PATH') ?: SOURCE_PATH . '/frankenphp';
$xcaddyModules = preg_replace('#--with github.com/dunglas/frankenphp\S*#', '', $xcaddyModules);
$xcaddyModules = "--with github.com/dunglas/frankenphp={$frankenphpSourceDir} " .
"--with github.com/dunglas/frankenphp/caddy={$frankenphpSourceDir}/caddy {$xcaddyModules}";
// make it possible to build from a different frankenphp directory!
if (!str_contains($xcaddyModules, '--with github.com/dunglas/frankenphp')) {
$xcaddyModules = '--with github.com/dunglas/frankenphp ' . $xcaddyModules;
}
if ($this->getLib('brotli') === null && str_contains($xcaddyModules, '--with github.com/dunglas/caddy-cbrotli')) {
logger()->warning('caddy-cbrotli module is enabled, but brotli library is not built. Disabling caddy-cbrotli.');
$xcaddyModules = str_replace('--with github.com/dunglas/caddy-cbrotli', '', $xcaddyModules);
}
$frankenPhpVersion = $this->getFrankenPHPVersion();
[, $out] = shell()->execWithResult('go list -m github.com/dunglas/frankenphp@latest');
$frankenPhpVersion = str_replace('github.com/dunglas/frankenphp v', '', $out[0]);
$libphpVersion = $this->getPHPVersion();
$dynamic_exports = '';
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
@@ -430,18 +290,20 @@ abstract class UnixBuilderBase extends BuilderBase
$dynamic_exports = ' ' . $dynamicSymbolsArgument;
}
}
$extLdFlags = "-extldflags '-pie{$dynamic_exports} {$this->arch_ld_flags}'";
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
$extLdFlags = "-extldflags '-pie{$dynamic_exports}'";
$muslTags = '';
$staticFlags = '';
if (SPCTarget::isStatic()) {
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports} {$this->arch_ld_flags}'";
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports}'";
$muslTags = 'static_build,';
$staticFlags = '-static-pie';
}
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -DFRANKENPHP_VERSION=' . $frankenPhpVersion;
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
$libs = $config['libs'];
$libs .= PHP_OS_FAMILY === 'Linux' ? ' -lrt' : '';
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||
str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) &&
@@ -454,7 +316,7 @@ abstract class UnixBuilderBase extends BuilderBase
'CGO_CFLAGS' => clean_spaces($cflags),
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs}",
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' .
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' . $debugFlags .
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .
"v{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " .
"-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}",
@@ -464,7 +326,13 @@ abstract class UnixBuilderBase extends BuilderBase
->setEnv($env)
->exec("xcaddy build --output frankenphp {$xcaddyModules}");
$this->deploySAPIBinary(BUILD_TARGET_FRANKENPHP);
if (!$this->getOption('no-strip', false) && file_exists(BUILD_BIN_PATH . '/frankenphp')) {
if (PHP_OS_FAMILY === 'Linux') {
shell()->cd(BUILD_BIN_PATH)->exec('strip --strip-unneeded frankenphp');
} else { // macOS doesn't understand strip-unneeded
shell()->cd(BUILD_BIN_PATH)->exec('strip -S frankenphp');
}
}
}
/**

View File

@@ -17,7 +17,7 @@ trait attr
->exec('libtoolize --force --copy')
->exec('./autogen.sh || autoreconf -if')
->configure('--disable-nls')
->make('install-attributes_h install-data install-libattr_h install-libLTLIBRARIES install-pkgincludeHEADERS install-pkgconfDATA', with_install: false);
->make();
$this->patchPkgconfPrefix(['libattr.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -23,8 +23,6 @@ trait curl
->optionalLib('zstd', ...cmake_boolean_args('CURL_ZSTD'))
->optionalLib('idn2', ...cmake_boolean_args('USE_LIBIDN2'))
->optionalLib('psl', ...cmake_boolean_args('CURL_USE_LIBPSL'))
->optionalLib('krb5', ...cmake_boolean_args('CURL_USE_GSSAPI'))
->optionalLib('idn2', ...cmake_boolean_args('CURL_USE_IDN2'))
->optionalLib('libcares', '-DENABLE_ARES=ON')
->addConfigureArgs(
'-DBUILD_CURL_EXE=OFF',

View File

@@ -31,7 +31,7 @@ trait gettext
$autoconf->addConfigureArgs('--disable-threads');
}
$autoconf->configure()->make(dir: $this->getSourceDir() . '/gettext-runtime/intl');
$autoconf->configure()->make();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -10,14 +10,7 @@ trait gmp
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => '-std=c17',
])
->configure(
'--enable-fat'
)
->make();
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['gmp.pc']);
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait idn2
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->configure(
'--disable-nls',
'--disable-doc',
'--enable-year2038',
'--disable-rpath'
)
->optionalLib('libiconv', "--with-libiconv-prefix={$this->getBuildRootPath()}")
->optionalLib('libunistring', "--with-libunistring-prefix={$this->getBuildRootPath()}")
->optionalLib('gettext', "--with-libnintl-prefix={$this->getBuildRootPath()}")
->make();
$this->patchPkgconfPrefix(['libidn2.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -12,11 +12,6 @@ trait imagemagick
{
protected function build(): void
{
$original_ldflags = $this->builder->arch_ld_flags;
if (str_contains($this->builder->arch_ld_flags, '-Wl,--as-needed')) {
$this->builder->arch_ld_flags = str_replace('-Wl,--as-needed', '', $original_ldflags);
}
$ac = UnixAutoconfExecutor::create($this)
->optionalLib('libzip', ...ac_with_args('zip'))
->optionalLib('libjpeg', ...ac_with_args('jpeg'))
@@ -37,7 +32,7 @@ trait imagemagick
);
// special: linux-static target needs `-static`
$ldflags = SPCTarget::isStatic() ? '-static -ldl' : '-ldl';
$ldflags = SPCTarget::isStatic() ? ('-static -ldl') : '-ldl';
// special: macOS needs -iconv
$libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
@@ -50,8 +45,6 @@ trait imagemagick
$ac->configure()->make();
$this->builder->arch_ld_flags = $original_ldflags;
$filelist = [
'ImageMagick.pc',
'ImageMagick-7.Q16HDRI.pc',

View File

@@ -1,57 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCConfigUtil;
trait krb5
{
protected function build(): void
{
$origin_source_dir = $this->source_dir;
$this->source_dir .= '/src';
shell()->cd($this->source_dir)->exec('autoreconf -if');
$libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true));
$spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]);
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
$extraEnv = [
'CFLAGS' => '-fcommon',
'LIBS' => $config['libs'],
];
if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) {
$extraEnv = [...$extraEnv, ...[
'LD_LIBRARY_PATH' => getenv('SPC_LD_LIBRARY_PATH'),
'LIBRARY_PATH' => getenv('SPC_LIBRARY_PATH'),
]];
}
$args = [
'--disable-nls',
'--disable-rpath',
'--without-system-verto',
];
if (PHP_OS_FAMILY === 'Darwin') {
$extraEnv['LDFLAGS'] = '-framework Kerberos';
$args[] = 'ac_cv_func_secure_getenv=no';
}
UnixAutoconfExecutor::create($this)
->appendEnv($extraEnv)
->optionalLib('ldap', '--with-ldap', '--without-ldap')
->optionalLib('libedit', '--with-libedit', '--without-libedit')
->configure(...$args)
->make();
$this->patchPkgconfPrefix([
'krb5-gssapi.pc',
'krb5.pc',
'kadm-server.pc',
'kadm-client.pc',
'kdb.pc',
'mit-krb5-gssapi.pc',
'mit-krb5.pc',
'gssrpc.pc',
]);
$this->source_dir = $origin_source_dir;
}
}

View File

@@ -26,7 +26,7 @@ trait libacl
->exec('libtoolize --force --copy')
->exec('./autogen.sh || autoreconf -if')
->configure('--disable-nls', '--disable-tests')
->make('install-acl_h install-libacl_h install-data install-libLTLIBRARIES install-pkgincludeHEADERS install-sysincludeHEADERS install-pkgconfDATA', with_install: false);
->make();
$this->patchPkgconfPrefix(['libacl.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait libedit
{
public function patchBeforeBuild(): bool
{
FileSystem::replaceFileRegex(
$this->source_dir . '/src/sys.h',
'|//#define\s+strl|',
'#define strl'
);
return true;
}
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->appendEnv(['CFLAGS' => '-D__STDC_ISO_10646__=201103L'])
->configure()
->make();
$this->patchPkgconfPrefix(['libedit.pc']);
}
}

View File

@@ -10,13 +10,7 @@ trait libiconv
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->configure(
'--enable-extra-encodings',
'--enable-year2038',
)
->make('install-lib', with_install: false)
->make('install-lib', with_install: false, dir: $this->getSourceDir() . '/libcharset');
UnixAutoconfExecutor::create($this)->configure('--enable-extra-encodings')->make();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -29,17 +29,13 @@ trait libjxl
);
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: '';
$has_avx512 = str_contains($cflags, '-mavx512') || str_contains($cflags, '-march=x86-64-v4');
if (!$has_avx512) {
$cmake->addConfigureArgs(
'-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE'
);
}
$cmake->addConfigureArgs(
'-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE'
);
}
$cmake->build();

View File

@@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixCMakeExecutor;
trait libmaxminddb
{
protected function build(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DBUILD_TESTING=OFF',
'-DMAXMINDDB_BUILD_BINARIES=OFF',
)
->build();
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixCMakeExecutor;
use SPC\util\executor\UnixAutoconfExecutor;
trait librdkafka
{
@@ -26,18 +26,34 @@ trait librdkafka
protected function build(): void
{
UnixCMakeExecutor::create($this)
->optionalLib('zstd', ...cmake_boolean_args('WITH_ZSTD'))
->optionalLib('curl', ...cmake_boolean_args('WITH_CURL'))
->optionalLib('openssl', ...cmake_boolean_args('WITH_SSL'))
->optionalLib('zlib', ...cmake_boolean_args('WITH_ZLIB'))
->optionalLib('liblz4', ...cmake_boolean_args('ENABLE_LZ4_EXT'))
->addConfigureArgs(
'-DWITH_SASL=OFF',
'-DRDKAFKA_BUILD_STATIC=ON',
'-DRDKAFKA_BUILD_EXAMPLES=OFF',
'-DRDKAFKA_BUILD_TESTS=OFF',
UnixAutoconfExecutor::create($this)
->appendEnv(['CFLAGS' => '-Wno-int-conversion -Wno-unused-but-set-variable -Wno-unused-variable'])
->optionalLib(
'zstd',
function ($lib) {
putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a");
return '';
},
'--disable-zstd'
)
->build();
->removeConfigureArgs(
'--with-pic',
'--enable-pic',
)
->configure(
'--disable-curl',
'--disable-sasl',
'--disable-valgrind',
'--disable-zlib',
'--disable-ssl',
)
->make();
$this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']);
// remove dynamic libs
shell()
->exec("rm -rf {$this->getLibDir()}/*.so.*")
->exec("rm -rf {$this->getLibDir()}/*.so")
->exec("rm -rf {$this->getLibDir()}/*.dylib");
}
}

View File

@@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait libunistring
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->configure('--disable-nls')
->make();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -10,26 +10,8 @@ trait libwebp
{
protected function build(): void
{
$code = '#include <immintrin.h>
int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }';
$cc = getenv('CC') ?: 'gcc';
[$ret] = shell()->execWithResult("printf '%s' '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1");
$disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64' && PHP_OS_FAMILY === 'Linux';
UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DWEBP_BUILD_EXTRAS=OFF',
'-DWEBP_BUILD_ANIM_UTILS=OFF',
'-DWEBP_BUILD_CWEBP=OFF',
'-DWEBP_BUILD_DWEBP=OFF',
'-DWEBP_BUILD_GIF2WEBP=OFF',
'-DWEBP_BUILD_IMG2WEBP=OFF',
'-DWEBP_BUILD_VWEBP=OFF',
'-DWEBP_BUILD_WEBPINFO=OFF',
'-DWEBP_BUILD_WEBPMUX=OFF',
'-DWEBP_BUILD_FUZZTEST=OFF',
$disableAvx2 ? '-DWEBP_ENABLE_SIMD=OFF' : ''
)
->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON')
->build();
// patch pkgconfig
$this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR);

View File

@@ -22,7 +22,6 @@ trait libzip
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_REGRESS=OFF',
'-DBUILD_TOOLS=OFF',
'-DBUILD_OSSFUZZ=OFF',
)
->build();
$this->patchPkgconfPrefix(['libzip.pc'], PKGCONF_PATCH_PREFIX);

View File

@@ -16,7 +16,6 @@ trait ncurses
UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => '-std=c17',
'LDFLAGS' => SPCTarget::isStatic() ? '-static' : '',
])
->configure(
@@ -30,7 +29,7 @@ trait ncurses
'--without-tests',
'--without-dlsym',
'--without-debug',
'--enable-symlinks',
'-enable-symlinks',
"--bindir={$this->getBinDir()}",
"--includedir={$this->getIncludeDir()}",
"--libdir={$this->getLibDir()}",
@@ -39,7 +38,7 @@ trait ncurses
->make();
$final = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
// Remove the new files
$new_files = array_diff($final, $filelist ?: []);
$new_files = array_diff($final, $filelist);
foreach ($new_files as $file) {
@unlink(BUILD_BIN_PATH . '/' . $file);
}

View File

@@ -1,49 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait net_snmp
{
public function patchBeforeBuild(): bool
{
if (PHP_OS_FAMILY === 'Linux') {
FileSystem::replaceFileStr("{$this->source_dir}/configure", 'LIBS="-lssl ${OPENSSL_LIBS}"', 'LIBS="-lssl ${OPENSSL_LIBS} -lpthread -ldl"');
return true;
}
return false;
}
protected function build(): void
{
// use --static for PKG_CONFIG
UnixAutoconfExecutor::create($this)
->setEnv(['PKG_CONFIG' => getenv('PKG_CONFIG') . ' --static'])
->configure(
'--disable-mibs',
'--without-nl',
'--disable-agent',
'--disable-applications',
'--disable-manuals',
'--disable-scripts',
'--disable-embedded-perl',
'--without-perl-modules',
'--with-out-mib-modules="if-mib host disman/event-mib ucd-snmp/diskio mibII"',
'--with-out-transports="Unix"',
'--with-mib-modules=""',
'--enable-mini-agent',
'--with-default-snmp-version="3"',
'--with-sys-contact="@@no.where"',
'--with-sys-location="Unknown"',
'--with-logfile="/var/log/snmpd.log"',
'--with-persistent-directory="/var/lib/net-snmp"',
'--with-openssl=' . BUILD_ROOT_PATH,
'--with-zlib=' . BUILD_ROOT_PATH,
)->make(with_install: 'installheaders installlibs install_pkgconfig');
$this->patchPkgconfPrefix();
}
}

View File

@@ -4,83 +4,93 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\exception\BuildFailureException;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\PkgConfigUtil;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
trait postgresql
{
public function patchBeforeBuild(): bool
{
// fix aarch64 build on glibc 2.17 (e.g. CentOS 7)
if (SPCTarget::getLibcVersion() === '2.17' && GNU_ARCH === 'aarch64') {
try {
FileSystem::replaceFileStr("{$this->source_dir}/src/port/pg_popcount_aarch64.c", 'HWCAP_SVE', '0');
FileSystem::replaceFileStr(
"{$this->source_dir}/src/port/pg_crc32c_armv8_choose.c",
'#if defined(__linux__) && !defined(__aarch64__) && !defined(HWCAP2_CRC32)',
'#if defined(__linux__) && !defined(HWCAP_CRC32)'
);
} catch (FileSystemException) {
// allow file not-existence to make it compatible with old and new version
}
}
// skip the test on platforms where libpq infrastructure may be provided by statically-linked libraries
FileSystem::replaceFileStr("{$this->source_dir}/src/interfaces/libpq/Makefile", 'invokes exit\'; exit 1;', 'invokes exit\';');
// disable shared libs build
FileSystem::replaceFileStr(
"{$this->source_dir}/src/Makefile.shlib",
[
'$(LINK.shared) -o $@ $(OBJS) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK)',
'$(INSTALL_SHLIB) $< \'$(DESTDIR)$(pkglibdir)/$(shlib)\'',
'$(INSTALL_SHLIB) $< \'$(DESTDIR)$(libdir)/$(shlib)\'',
'$(INSTALL_SHLIB) $< \'$(DESTDIR)$(bindir)/$(shlib)\'',
],
''
);
return true;
}
protected function build(): void
{
$libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true));
$spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]);
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
$env_vars = [
'CFLAGS' => $config['cflags'] . ' -std=c17',
'CPPFLAGS' => '-DPIC',
'LDFLAGS' => $config['ldflags'],
'LIBS' => $config['libs'],
$builddir = BUILD_ROOT_PATH;
$envs = '';
$packages = 'zlib openssl readline libxml-2.0';
$optional_packages = [
'zstd' => 'libzstd',
'ldap' => 'ldap',
'libxslt' => 'libxslt',
'icu' => 'icu-i18n',
];
$error_exec_cnt = 0;
if ($ldLibraryPath = getenv('SPC_LD_LIBRARY_PATH')) {
$env_vars['LD_LIBRARY_PATH'] = $ldLibraryPath;
foreach ($optional_packages as $lib => $pkg) {
if ($this->getBuilder()->getLib($lib)) {
$packages .= ' ' . $pkg;
$output = shell()->execWithResult("pkg-config --static {$pkg}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
logger()->info(var_export($output[1], true));
}
}
$output = shell()->execWithResult("pkg-config --cflags-only-I --static {$packages}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
$macos_15_bug_cflags = PHP_OS_FAMILY === 'Darwin' ? ' -Wno-unguarded-availability-new' : '';
$cflags = '';
if (!empty($output[1][0])) {
$cflags = $output[1][0];
$envs .= ' CPPFLAGS="-DPIC"';
$cflags = "{$cflags} -fno-ident{$macos_15_bug_cflags}";
}
$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 .= SPCTarget::isStatic() ? " LDFLAGS=\"{$ldflags} -static\" " : " LDFLAGS=\"{$ldflags}\" ";
}
$output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
if (!empty($output[1][0])) {
$libs = $output[1][0];
$libcpp = '';
if ($this->builder->getLib('icu')) {
$libcpp = $this instanceof LinuxLibraryBase ? ' -lstdc++' : ' -lc++';
}
$envs .= " LIBS=\"{$libs}{$libcpp}\" ";
}
if ($error_exec_cnt > 0) {
throw new BuildFailureException('Failed to get pkg-config information!');
}
FileSystem::resetDir($this->source_dir . '/build');
// php source relies on the non-private encoding functions in libpgcommon.a
FileSystem::replaceFileStr(
"{$this->source_dir}/src/common/Makefile",
'$(OBJS_FRONTEND): CPPFLAGS += -DUSE_PRIVATE_ENCODING_FUNCS',
'$(OBJS_FRONTEND): CPPFLAGS += -UUSE_PRIVATE_ENCODING_FUNCS -DFRONTEND',
);
$version = $this->getVersion();
// 16.1 workaround
if (version_compare($version, '16.1') >= 0) {
# 有静态链接配置 参考文件: src/interfaces/libpq/Makefile
shell()->cd($this->source_dir . '/build')
->exec('sed -i.backup "s/invokes exit\'; exit 1;/invokes exit\';/" ../src/interfaces/libpq/Makefile')
->exec('sed -i.backup "278 s/^/# /" ../src/Makefile.shlib')
->exec('sed -i.backup "402 s/^/# /" ../src/Makefile.shlib');
} else {
throw new BuildFailureException('Unsupported version for postgresql: ' . $version . ' !');
}
// configure
$shell = shell()->cd("{$this->source_dir}/build")->initializeEnv($this)
->appendEnv($env_vars)
shell()->cd($this->source_dir . '/build')->initializeEnv($this)
->appendEnv(['CFLAGS' => $cflags])
->exec(
'../configure ' .
"--prefix={$this->getBuildRootPath()} " .
"{$envs} ../configure " .
"--prefix={$builddir} " .
($this->builder->getOption('enable-zts') ? '--enable-thread-safety ' : '--disable-thread-safety ') .
'--enable-coverage=no ' .
'--with-ssl=openssl ' .
'--with-readline ' .
'--with-libxml ' .
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
($this->builder->getLib('ldap') ? '--with-ldap ' : '--without-ldap ') .
// '--without-ldap ' .
($this->builder->getLib('libxslt') ? '--with-libxslt ' : '--without-libxslt ') .
($this->builder->getLib('zstd') ? '--with-zstd ' : '--without-zstd ') .
'--without-lz4 ' .
@@ -89,29 +99,32 @@ trait postgresql
'--without-pam ' .
'--without-bonjour ' .
'--without-tcl '
);
// patch ldap lib
if ($this->builder->getLib('ldap')) {
$libs = PkgConfigUtil::getLibsArray('ldap');
$libs = clean_spaces(implode(' ', $libs));
FileSystem::replaceFileStr($this->source_dir . '/build/config.status', '-lldap', $libs);
FileSystem::replaceFileStr($this->source_dir . '/build/src/Makefile.global', '-lldap', $libs);
}
$shell
->exec('make -C src/bin/pg_config install')
->exec('make -C src/include install')
->exec('make -C src/common install')
->exec('make -C src/port install')
->exec('make -C src/interfaces/libpq install');
)
->exec($envs . ' make -C src/bin/pg_config install')
->exec($envs . ' make -C src/include install')
->exec($envs . ' make -C src/common install')
->exec($envs . ' make -C src/port install')
->exec($envs . ' make -C src/interfaces/libpq install');
// remove dynamic libs
shell()->cd($this->source_dir . '/build')
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.so.*")
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.so")
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.dylib");
->exec("rm -rf {$builddir}/lib/*.so.*")
->exec("rm -rf {$builddir}/lib/*.so")
->exec("rm -rf {$builddir}/lib/*.dylib");
FileSystem::replaceFileStr("{$this->getLibDir()}/pkgconfig/libpq.pc", '-lldap', '-lldap -llber');
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/pkgconfig/libpq.pc', '-lldap', '-lldap -llber');
}
private function getVersion(): string
{
try {
$file = FileSystem::readFile($this->source_dir . '/meson.build');
if (preg_match("/^\\s+version:\\s?'(.*)'/m", $file, $match)) {
return $match[1];
}
return 'unknown';
} catch (FileSystemException) {
return 'unknown';
}
}
}

View File

@@ -57,7 +57,6 @@ class WindowsBuilder extends BuilderBase
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
$enableCgi = ($build_target & BUILD_TARGET_CGI) === BUILD_TARGET_CGI;
SourcePatcher::patchBeforeBuildconf($this);
@@ -67,6 +66,21 @@ class WindowsBuilder extends BuilderBase
$zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no ';
// with-upx-pack for phpmicro
if ($enableMicro && version_compare($this->getMicroVersion(), '0.2.0') < 0) {
$makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32');
if ($this->getOption('with-upx-pack', false)) {
if (!file_exists($makefile . '.originfile')) {
copy($makefile, $makefile . '.originfile');
FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', '_MICRO_UPX = ' . getenv('UPX_EXEC') . " --best $(MICRO_SFX)\n$(MICRO_SFX):");
FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)");
}
} elseif (file_exists($makefile . '.originfile')) {
copy($makefile . '.originfile', $makefile);
unlink($makefile . '.originfile');
}
}
$opcache_jit = !$this->getOption('disable-opcache-jit', false);
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit=yes ' : '--enable-opcache-jit=no ';
@@ -88,13 +102,13 @@ class WindowsBuilder extends BuilderBase
->exec(
"{$this->sdk_prefix} configure.bat --task-args \"" .
'--disable-all ' .
'--disable-cgi ' .
'--with-php-build=' . BUILD_ROOT_PATH . ' ' .
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableMicro ? ('--enable-micro ' . $micro_logo . $micro_w32) : '--disable-micro ') .
($enableEmbed ? '--enable-embed ' : '--disable-embed ') .
($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
$config_file_scan_dir .
$opcache_jit_arg .
"{$this->makeStaticExtensionArgs()} " .
@@ -113,10 +127,6 @@ class WindowsBuilder extends BuilderBase
if ($enableFpm) {
logger()->warning('Windows does not support fpm SAPI, I will skip it.');
}
if ($enableCgi) {
logger()->info('building cgi');
$this->buildCgi();
}
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro();
@@ -130,7 +140,7 @@ class WindowsBuilder extends BuilderBase
}
}
public function testPHP(int $build_target = BUILD_TARGET_NONE): void
public function testPHP(int $build_target = BUILD_TARGET_NONE)
{
$this->sanityCheck($build_target);
}
@@ -141,52 +151,12 @@ class WindowsBuilder extends BuilderBase
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// Add debug symbols for release build if --no-strip is specified
// We need to modify CFLAGS to replace /Ox with /Zi and add /DEBUG to LDFLAGS
$debug_overrides = '';
if ($this->getOption('no-strip', false)) {
// Read current CFLAGS from Makefile and replace optimization flags
$makefile_content = file_get_contents(SOURCE_PATH . '\php-src\Makefile');
if (preg_match('/^CFLAGS=(.+?)$/m', $makefile_content, $matches)) {
$cflags = $matches[1];
// Replace /Ox (full optimization) with /Zi (debug info) and /Od (disable optimization)
// Keep optimization for speed: /O2 /Zi instead of /Od /Zi
$cflags = str_replace('/Ox ', '/O2 /Zi ', $cflags);
$debug_overrides = '"CFLAGS=' . $cflags . '" "LDFLAGS=/DEBUG /LTCG /INCREMENTAL:NO" "LDFLAGS_CLI=/DEBUG" ';
}
}
// add nmake wrapper
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cli_wrapper.bat', "nmake /nologo {$debug_overrides}LIBS_CLI=\"ws2_32.lib shell32.lib {$extra_libs}\" EXTRA_LD_FLAGS_PROGRAM= %*");
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cli_wrapper.bat', "nmake /nologo LIBS_CLI=\"ws2_32.lib shell32.lib {$extra_libs}\" EXTRA_LD_FLAGS_PROGRAM= %*");
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_cli_wrapper.bat --task-args php.exe");
$this->deploySAPIBinary(BUILD_TARGET_CLI);
}
public function buildCgi(): void
{
SourcePatcher::patchWindowsCGITarget();
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// Add debug symbols for release build if --no-strip is specified
$debug_overrides = '';
if ($this->getOption('no-strip', false)) {
$makefile_content = file_get_contents(SOURCE_PATH . '\php-src\Makefile');
if (preg_match('/^CFLAGS=(.+?)$/m', $makefile_content, $matches)) {
$cflags = $matches[1];
$cflags = str_replace('/Ox ', '/O2 /Zi ', $cflags);
$debug_overrides = '"CFLAGS=' . $cflags . '" "LDFLAGS=/DEBUG /LTCG /INCREMENTAL:NO" "LDFLAGS_CGI=/DEBUG" ';
}
}
// add nmake wrapper
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cgi_wrapper.bat', "nmake /nologo {$debug_overrides}LIBS_CGI=\"ws2_32.lib kernel32.lib advapi32.lib {$extra_libs}\" EXTRA_LD_FLAGS_PROGRAM= %*");
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_cgi_wrapper.bat --task-args php-cgi.exe");
$this->deploySAPIBinary(BUILD_TARGET_CGI);
$this->deployBinary(BUILD_TARGET_CLI);
}
public function buildEmbed(): void
@@ -213,20 +183,9 @@ class WindowsBuilder extends BuilderBase
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// Add debug symbols for release build if --no-strip is specified
$debug_overrides = '';
if ($this->getOption('no-strip', false) && !$this->getOption('debug', false)) {
$makefile_content = file_get_contents(SOURCE_PATH . '\php-src\Makefile');
if (preg_match('/^CFLAGS=(.+?)$/m', $makefile_content, $matches)) {
$cflags = $matches[1];
$cflags = str_replace('/Ox ', '/O2 /Zi ', $cflags);
$debug_overrides = '"CFLAGS=' . $cflags . '" "LDFLAGS=/DEBUG /LTCG /INCREMENTAL:NO" "LDFLAGS_MICRO=/DEBUG" ';
}
}
// add nmake wrapper
$fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' /DPHP_MICRO_FAKE_CLI" ' : '';
$wrapper = "nmake /nologo {$debug_overrides}LIBS_MICRO=\"ws2_32.lib shell32.lib {$extra_libs}\" CFLAGS_MICRO=\"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1{$fake_cli}\" %*";
$wrapper = "nmake /nologo LIBS_MICRO=\"ws2_32.lib shell32.lib {$extra_libs}\" CFLAGS_MICRO=\"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1{$fake_cli}\" %*";
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_micro_wrapper.bat', $wrapper);
// phar patch for micro
@@ -243,7 +202,7 @@ class WindowsBuilder extends BuilderBase
}
}
$this->deploySAPIBinary(BUILD_TARGET_MICRO);
$this->deployBinary(BUILD_TARGET_MICRO);
}
public function proveLibs(array $sorted_libraries): void
@@ -306,7 +265,7 @@ class WindowsBuilder extends BuilderBase
// sanity check for php-cli
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
logger()->info('running cli sanity check');
[$ret, $output] = cmd()->execWithResult(BUILD_BIN_PATH . '\php.exe -n -r "echo \"hello\";"');
[$ret, $output] = cmd()->execWithResult(BUILD_ROOT_PATH . '\bin\php.exe -n -r "echo \"hello\";"');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new ValidationException('cli failed sanity check', validation_module: 'php-cli function check');
}
@@ -325,7 +284,7 @@ class WindowsBuilder extends BuilderBase
if (file_exists($test_file)) {
@unlink($test_file);
}
file_put_contents($test_file, file_get_contents(BUILD_BIN_PATH . '\micro.sfx') . $task['content']);
file_put_contents($test_file, file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') . $task['content']);
chmod($test_file, 0755);
[$ret, $out] = cmd()->execWithResult($test_file);
foreach ($task['conditions'] as $condition => $closure) {
@@ -339,17 +298,6 @@ class WindowsBuilder extends BuilderBase
}
}
}
// sanity check for php-cgi
if (($build_target & BUILD_TARGET_CGI) === BUILD_TARGET_CGI) {
logger()->info('running cgi sanity check');
FileSystem::writeFile(SOURCE_PATH . '\php-cgi-test.php', '<?php echo "<h1>Hello, World!</h1>"; ?>');
[$ret, $output] = cmd()->execWithResult(BUILD_BIN_PATH . '\php-cgi.exe -n -f ' . SOURCE_PATH . '\php-cgi-test.php');
$raw_output = implode("\n", $output);
if ($ret !== 0 || !str_contains($raw_output, 'Hello, World!')) {
throw new ValidationException("cgi failed sanity check. code: {$ret}, output: {$raw_output}", validation_module: 'php-cgi sanity check');
}
}
}
/**
@@ -357,53 +305,27 @@ class WindowsBuilder extends BuilderBase
*
* @param int $type Deploy type
*/
public function deploySAPIBinary(int $type): void
public function deployBinary(int $type): bool
{
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
$debug_dir = BUILD_ROOT_PATH . '\debug';
$bin_path = BUILD_BIN_PATH;
// create dirs
FileSystem::createDir($debug_dir);
FileSystem::createDir($bin_path);
// determine source path for different SAPI
$rel_type = 'Release'; // TODO: Debug build support
$ts = $this->zts ? '_TS' : '';
$src = match ($type) {
BUILD_TARGET_CLI => [SOURCE_PATH . "\\php-src\\x64\\{$rel_type}{$ts}", 'php.exe', 'php.pdb'],
BUILD_TARGET_MICRO => [SOURCE_PATH . "\\php-src\\x64\\{$rel_type}{$ts}", 'micro.sfx', 'micro.pdb'],
BUILD_TARGET_CGI => [SOURCE_PATH . "\\php-src\\x64\\{$rel_type}{$ts}", 'php-cgi.exe', 'php-cgi.pdb'],
BUILD_TARGET_CLI => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\php.exe",
BUILD_TARGET_MICRO => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\micro.sfx",
default => throw new SPCInternalException("Deployment does not accept type {$type}"),
};
$src = "{$src[0]}\\{$src[1]}";
$dst = BUILD_BIN_PATH . '\\' . basename($src);
// file must exists
if (!file_exists($src)) {
throw new SPCInternalException("Deploy failed. Cannot find file: {$src}");
}
// dst dir must exists
FileSystem::createDir(dirname($dst));
// copy file
if (realpath($src) !== realpath($dst)) {
cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg($dst));
}
// extract debug info in buildroot/debug
if ($this->getOption('no-strip', false) && file_exists("{$src[0]}\\{$src[2]}")) {
cmd()->exec('copy ' . escapeshellarg("{$src[0]}\\{$src[2]}") . ' ' . escapeshellarg($debug_dir));
}
// with-upx-pack for cli and micro
if ($this->getOption('with-upx-pack', false)) {
if ($type === BUILD_TARGET_CLI || $type === BUILD_TARGET_CGI || ($type === BUILD_TARGET_MICRO && version_compare($this->getMicroVersion(), '0.2.0') >= 0)) {
cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($dst));
if ($type === BUILD_TARGET_CLI || ($type === BUILD_TARGET_MICRO && version_compare($this->getMicroVersion(), '0.2.0') >= 0)) {
cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src));
}
}
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_ROOT_PATH . '\bin');
cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '\bin\\'));
return true;
}
/**

View File

@@ -30,6 +30,7 @@ class curl extends WindowsLibraryBase
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DBUILD_STATIC_LIBS=ON ' .
'-DCURL_STATICLIB=ON ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
'-DBUILD_CURL_EXE=OFF ' . // disable curl.exe
'-DBUILD_TESTING=OFF ' . // disable tests
@@ -41,9 +42,9 @@ class curl extends WindowsLibraryBase
'-DCURL_USE_OPENSSL=OFF ' . // disable openssl due to certificate issue
'-DCURL_ENABLE_SSL=ON ' .
'-DUSE_NGHTTP2=ON ' . // enable nghttp2
'-DSHARE_LIB_OBJECT=OFF ' . // disable shared lib object
'-DCURL_USE_LIBSSH2=ON ' . // enable libssh2
'-DENABLE_IPV6=ON ' . // enable ipv6
'-DNGHTTP2_CFLAGS="/DNGHTTP2_STATICLIB" ' .
$alt
)
->execWithWrapper(
@@ -52,7 +53,5 @@ class curl extends WindowsLibraryBase
);
// move libcurl.lib to libcurl_a.lib
rename(BUILD_LIB_PATH . '\libcurl.lib', BUILD_LIB_PATH . '\libcurl_a.lib');
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\curl\curl.h', '#ifdef CURL_STATICLIB', '#if 1');
}
}

View File

@@ -29,16 +29,11 @@ class nghttp2 extends WindowsLibraryBase
'-DBUILD_SHARED_LIBS=OFF ' .
'-DENABLE_STATIC_CRT=ON ' .
'-DENABLE_LIB_ONLY=ON ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
'-DENABLE_STATIC_CRT=ON ' .
'-DENABLE_DOC=OFF ' .
'-DBUILD_TESTING=OFF '
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\nghttp2\nghttp2.h', '#ifdef NGHTTP2_STATICLIB', '#if 1');
}
}

View File

@@ -33,7 +33,7 @@ class BuildPHPCommand extends BuildCommand
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
$this->addOption('build-embed', null, null, 'Build embed SAPI (not available on Windows)');
$this->addOption('build-frankenphp', null, null, 'Build FrankenPHP SAPI (not available on Windows)');
$this->addOption('build-cgi', null, null, 'Build cgi SAPI');
$this->addOption('build-cgi', null, null, 'Build cgi SAPI (not available on Windows)');
$this->addOption('build-all', null, null, 'Build all SAPI');
$this->addOption('no-strip', null, null, 'build without strip, keep symbols to debug');
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
@@ -48,7 +48,6 @@ class BuildPHPCommand extends BuildCommand
$this->addOption('with-upx-pack', null, null, 'Compress / pack binary using UPX tool (linux/windows only)');
$this->addOption('with-micro-logo', null, InputOption::VALUE_REQUIRED, 'Use custom .ico for micro.sfx (windows only)');
$this->addOption('enable-micro-win32', null, null, 'Enable win32 mode for phpmicro (Windows only)');
$this->addOption('with-frankenphp-app', null, InputOption::VALUE_REQUIRED, 'Path to a folder to be embedded in FrankenPHP');
}
public function handle(): int
@@ -57,6 +56,12 @@ class BuildPHPCommand extends BuildCommand
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
// transform string to array
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
foreach ($shared_extensions as &$ext) {
if (array_key_exists($ext . '-shared', Config::getExts())) {
$ext .= '-shared';
}
}
unset($ext);
// transform string to array
$static_extensions = $this->parseExtensionList($this->getArgument('extensions'));
@@ -206,7 +211,7 @@ class BuildPHPCommand extends BuildCommand
}
// add static-php-cli.version to main.c, in order to debug php failure more easily
SourcePatcher::patchSPCVersionToPHP($this->getApplication()->getVersion());
SourcePatcher::patchSPCVersionToPHP($this->getApplication()?->getVersion());
// clean old modules that may conflict with the new php build
FileSystem::removeDir(BUILD_MODULES_PATH);
@@ -223,9 +228,11 @@ class BuildPHPCommand extends BuildCommand
// ---------- When using bin/spc-alpine-docker, the build root path is different from the host system ----------
$build_root_path = BUILD_ROOT_PATH;
$cwd = getcwd();
$fixed = '';
$build_root_path = get_display_path($build_root_path);
if (!empty(getenv('SPC_FIX_DEPLOY_ROOT'))) {
str_replace($cwd, '', $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) {
@@ -243,6 +250,7 @@ class BuildPHPCommand extends BuildCommand
}
if (!empty($shared_extensions)) {
foreach ($shared_extensions as $ext) {
$ext = str_replace('-shared', '', $ext);
$path = FileSystem::convertPath("{$build_root_path}/modules/{$ext}.so");
if (file_exists(BUILD_MODULES_PATH . "/{$ext}.so")) {
logger()->info("Shared extension [{$ext}] path{$fixed}: {$path}");

View File

@@ -106,7 +106,7 @@ class DownloadCommand extends BaseCommand
}
// retry
$retry = (int) $this->getOption('retry');
$retry = intval($this->getOption('retry'));
f_putenv('SPC_DOWNLOAD_RETRIES=' . $retry);
// Use shallow-clone can reduce git resource download
@@ -265,7 +265,7 @@ class DownloadCommand extends BaseCommand
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
}
// unzip command check
if (PHP_OS_FAMILY !== 'Windows' && !self::findCommand('unzip')) {
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
$this->output->writeln('Missing unzip command, you need to install it first !');
$this->output->writeln('You can use "bin/spc doctor" command to check and install required tools');
return static::FAILURE;
@@ -295,6 +295,11 @@ class DownloadCommand extends BaseCommand
*/
private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array
{
foreach ($extensions as $ext) {
if (array_key_exists($ext . '-shared', Config::getExts())) {
$extensions[] = $ext . '-shared';
}
}
[$extensions, $libraries] = $include_suggests ? DependencyUtil::getExtsAndLibs($extensions, [], true, true) : DependencyUtil::getExtsAndLibs($extensions);
$sources = [];
foreach ($extensions as $extension) {

View File

@@ -22,7 +22,7 @@ class LinuxMuslCheck
public static function optionalCheck(): bool
{
return getenv('SPC_TOOLCHAIN') === MuslToolchain::class ||
(getenv('SPC_TOOLCHAIN') === ZigToolchain::class && !SystemUtil::isMuslDist() && !str_contains((string) getenv('SPC_TARGET'), 'gnu'));
(getenv('SPC_TOOLCHAIN') === ZigToolchain::class && !SystemUtil::isMuslDist());
}
/** @noinspection PhpUnused */

View File

@@ -22,6 +22,7 @@ class LinuxToolCheckList
'bzip2', 'cmake', 'gcc',
'g++', 'patch', 'binutils-gold',
'libtoolize', 'which',
'patchelf',
];
public const TOOLS_DEBIAN = [
@@ -30,6 +31,7 @@ class LinuxToolCheckList
'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch',
'xz', 'libtoolize', 'which',
'patchelf',
];
public const TOOLS_RHEL = [
@@ -37,7 +39,8 @@ class LinuxToolCheckList
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch', 'which',
'xz', 'libtool', 'gettext-devel', 'file',
'xz', 'libtool', 'gettext-devel',
'patchelf',
];
public const TOOLS_ARCH = [
@@ -79,14 +82,14 @@ class LinuxToolCheckList
return CheckResult::ok();
}
#[AsCheckItem('if cmake version >= 3.22', limit_os: 'Linux')]
#[AsCheckItem('if cmake version >= 3.18', limit_os: 'Linux')]
public function checkCMakeVersion(): ?CheckResult
{
$ver = get_cmake_version();
if ($ver === null) {
return CheckResult::fail('Failed to get cmake version');
}
if (version_compare($ver, '3.22.0') < 0) {
if (version_compare($ver, '3.18.0') < 0) {
return CheckResult::fail('cmake version is too low (' . $ver . '), please update it manually!');
}
return CheckResult::ok($ver);

Some files were not shown because too many files have changed in this diff Show More