Compare commits

..

1 Commits

Author SHA1 Message Date
crazywhalecc
1a6c044ee9 Add google analytics for docs 2025-11-04 09:45:25 +08:00
50 changed files with 472 additions and 1291 deletions

View File

@@ -1,24 +1,24 @@
# StaticPHP
# static-php-cli
[![Chinese readme](https://img.shields.io/badge/README-%E4%B8%AD%E6%96%87%20%F0%9F%87%A8%F0%9F%87%B3-moccasin?style=flat-square)](README-zh.md)
[![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
[![Chinese readme](https://img.shields.io/badge/README-%E4%B8%AD%E6%96%87%20%F0%9F%87%A8%F0%9F%87%B3-moccasin?style=flat-square)](README-zh.md)
[![Releases](https://img.shields.io/packagist/v/crazywhalecc/static-php-cli?include_prereleases&label=Release&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/releases)
[![CI](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/tests.yml?branch=main&label=Build%20Test&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
**StaticPHP**(原名 **static-php-cli**是一个用于构建静态、独立 PHP 运行时的强大工具,支持众多流行扩展。
**static-php-cli** 是一个用于构建静态、独立 PHP 运行时的强大工具,支持众多流行扩展。
## 特性
- :elephant: **支持多 PHP 版本** - 支持 PHP 8.1, 8.2, 8.3, 8.4, 8.5
- :handbag: **单文件 PHP 可执行文件** - 构建零依赖的独立 PHP
- :hamburger: **phpmicro 集成** - 构建 **[phpmicro](https://github.com/static-php/phpmicro)** 自解压可执行文件(将 PHP 二进制文件和源代码合并为一个文件)
- :hamburger: **phpmicro 集成** - 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自解压可执行文件(将 PHP 二进制文件和源代码合并为一个文件)
- :pill: **智能环境检查器** - 自动构建环境检查器,具备自动修复功能
- :zap: **跨平台支持** - 支持 Linux、macOS、FreeBSD 和 Windows
- :wrench: **可配置补丁** - 可自定义的源代码补丁系统
- :books: **智能依赖管理** - 自动处理构建依赖
- 📦 **自包含工具** - 提供使用 [box](https://github.com/box-project/box) 构建的 `spc` 可执行文件
- :fire: **广泛的扩展支持** - 支持 100+ 流行 [扩展](https://static-php.dev/zh/guide/extensions.html)
- :fire: **广泛的扩展支持** - 支持 75+ 流行 [扩展](https://static-php.dev/zh/guide/extensions.html)
- :floppy_disk: **UPX 压缩** - 减小二进制文件大小 30-50%(仅 Linux/Windows
**单文件独立 php-cli**
@@ -33,8 +33,6 @@
### 1. 下载 spc 二进制文件
`spc` 二进制文件是 StaticPHP 项目的 CLI 工具,打包为单个可执行文件。
```bash
# Linux x86_64
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
@@ -109,7 +107,7 @@ buildroot/bin/php-fpm -v
以下是几个具有不同扩展组合的预编译静态 PHP 二进制文件,
您可以根据需要直接下载。
| 组合名称 | 扩展数量 | 系统 | 备注 |
| 组合名称 | 扩展数量 | 系统 | 备注 |
|----------------------------------------------------------------------|----------------------------------------------------------------------------|--------------|--------------------|
| [common](https://dl.static-php.dev/static-php-cli/common/) | [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) | Linux, macOS | 二进制文件大小约为 7.5MB |
| [bulk](https://dl.static-php.dev/static-php-cli/bulk/) | [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) | Linux, macOS | 二进制文件大小约为 25MB |

View File

@@ -1,4 +1,4 @@
# StaticPHP
# static-php-cli
[![Chinese readme](https://img.shields.io/badge/README-%E4%B8%AD%E6%96%87%20%F0%9F%87%A8%F0%9F%87%B3-moccasin?style=flat-square)](README-zh.md)
[![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
@@ -6,13 +6,14 @@
[![CI](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/tests.yml?branch=main&label=Build%20Test&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
**StaticPHP** (formerly **static-php-cli**) is a powerful tool designed for building static, standalone PHP runtime with popular extensions.
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
with popular extensions.
## Features
- :elephant: Support multiple PHP versions - PHP 8.1, 8.2, 8.3, 8.4, 8.5
- :handbag: Build single-file PHP executable with zero dependencies
- :hamburger:Build **[phpmicro](https://github.com/static-php/phpmicro)** self-extracting executables (combines PHP binary and source code into one file)
- :hamburger:Build **[phpmicro](https://github.com/dixyes/phpmicro)** self-extracting executables (combines PHP binary and source code into one file)
- :pill: Automatic build environment checker with auto-fix capabilities
- :zap: `Linux`, `macOS`, `FreeBSD`, `Windows` support
- :wrench: Configurable source code patching
@@ -33,8 +34,6 @@
### 1. Download spc binary
`spc` binary is StaticPHP CLI tool packaged as a single executable file.
```bash
# For Linux x86_64
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
@@ -54,7 +53,7 @@ For macOS and Linux, add execute permission first:
chmod +x ./spc
```
### 2. Build standalone PHP binaries
### 2. Build Static PHP
First, create a `craft.yml` file and specify which extensions you want to include from [extension list](https://static-php.dev/en/guide/extensions.html) or [command generator](https://static-php.dev/en/guide/cli-generator.html):
@@ -80,7 +79,7 @@ Run command:
./spc craft --debug
```
### 3. Using the built binaries
### 3. Static PHP usage
Now you can copy binaries built by static-php-cli to another machine and run with no dependencies:
@@ -106,7 +105,7 @@ see <https://static-php.dev> .
If you don't want to build or want to test first, you can download example pre-compiled artifact from [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml), or from self-hosted server.
Below are several precompiled statically built php binaries with different extension combinations,
Below are several precompiled static-php binaries with different extension combinations,
which can be downloaded directly according to your needs.
| Combination | Extension Count | OS | Comment |

View File

@@ -162,47 +162,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
@@ -224,5 +183,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

@@ -174,47 +174,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
@@ -237,5 +196,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

176
composer.lock generated
View File

@@ -416,16 +416,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.6",
"version": "v7.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
"shasum": ""
},
"require": {
@@ -490,7 +490,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.6"
"source": "https://github.com/symfony/console/tree/v7.3.4"
},
"funding": [
{
@@ -510,7 +510,7 @@
"type": "tidelift"
}
],
"time": "2025-11-04T01:21:42+00:00"
"time": "2025-09-22T15:31:00+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -981,16 +981,16 @@
},
{
"name": "symfony/service-contracts",
"version": "v3.6.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"shasum": ""
},
"require": {
@@ -1044,7 +1044,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
"source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -1055,16 +1055,12 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-07-15T11:30:57+00:00"
"time": "2025-04-25T09:37:31+00:00"
},
{
"name": "symfony/string",
@@ -1158,16 +1154,16 @@
},
{
"name": "symfony/yaml",
"version": "v7.3.5",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc"
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc",
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc",
"url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d",
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d",
"shasum": ""
},
"require": {
@@ -1210,7 +1206,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v7.3.5"
"source": "https://github.com/symfony/yaml/tree/v7.3.3"
},
"funding": [
{
@@ -1230,20 +1226,20 @@
"type": "tidelift"
}
],
"time": "2025-09-27T09:00:46+00:00"
"time": "2025-08-27T11:34:33+00:00"
},
{
"name": "zhamao/logger",
"version": "1.1.4",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/zhamao-robot/zhamao-logger.git",
"reference": "b28c0c26d59d58f153c764f224c21c5901213e25"
"reference": "2551b3e1dbbb1db81794d5c3a666c66804a9dca9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zhamao-robot/zhamao-logger/zipball/b28c0c26d59d58f153c764f224c21c5901213e25",
"reference": "b28c0c26d59d58f153c764f224c21c5901213e25",
"url": "https://api.github.com/repos/zhamao-robot/zhamao-logger/zipball/2551b3e1dbbb1db81794d5c3a666c66804a9dca9",
"reference": "2551b3e1dbbb1db81794d5c3a666c66804a9dca9",
"shasum": ""
},
"require": {
@@ -1297,9 +1293,9 @@
"description": "Another Console Logger for CLI Applications",
"support": {
"issues": "https://github.com/zhamao-robot/zhamao-logger/issues",
"source": "https://github.com/zhamao-robot/zhamao-logger/tree/1.1.4"
"source": "https://github.com/zhamao-robot/zhamao-logger/tree/1.1.3"
},
"time": "2025-11-08T15:38:01+00:00"
"time": "2025-08-02T13:44:27+00:00"
}
],
"packages-dev": [
@@ -2864,16 +2860,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.89.2",
"version": "v3.89.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "7569658f91e475ec93b99bd5964b059ad1336dcf"
"reference": "4dd6768cb7558440d27d18f54909eee417317ce9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7569658f91e475ec93b99bd5964b059ad1336dcf",
"reference": "7569658f91e475ec93b99bd5964b059ad1336dcf",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4dd6768cb7558440d27d18f54909eee417317ce9",
"reference": "4dd6768cb7558440d27d18f54909eee417317ce9",
"shasum": ""
},
"require": {
@@ -2909,7 +2905,7 @@
"justinrainbow/json-schema": "^6.5",
"keradus/cli-executor": "^2.2",
"mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.9",
"php-coveralls/php-coveralls": "^2.8",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
@@ -2955,7 +2951,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.2"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.0"
},
"funding": [
{
@@ -2963,20 +2959,20 @@
"type": "github"
}
],
"time": "2025-11-06T21:12:50+00:00"
"time": "2025-10-18T19:30:16+00:00"
},
{
"name": "humbug/box",
"version": "4.6.10",
"version": "4.6.8",
"source": {
"type": "git",
"url": "https://github.com/box-project/box.git",
"reference": "6dc6a1314d63e9d75c8195c996e1081e68514c36"
"reference": "05d205d99ddb72f3729658a0115db02cfc08912e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/box-project/box/zipball/6dc6a1314d63e9d75c8195c996e1081e68514c36",
"reference": "6dc6a1314d63e9d75c8195c996e1081e68514c36",
"url": "https://api.github.com/repos/box-project/box/zipball/05d205d99ddb72f3729658a0115db02cfc08912e",
"reference": "05d205d99ddb72f3729658a0115db02cfc08912e",
"shasum": ""
},
"require": {
@@ -3005,7 +3001,7 @@
"symfony/process": "^6.4.0 || ^7.0.0",
"symfony/var-dumper": "^6.4.0 || ^7.0.0",
"thecodingmachine/safe": "^2.5 || ^3.0",
"webmozart/assert": "^1.12"
"webmozart/assert": "^1.11"
},
"conflict": {
"marc-mabe/php-enum": "<4.4"
@@ -3075,9 +3071,9 @@
],
"support": {
"issues": "https://github.com/box-project/box/issues",
"source": "https://github.com/box-project/box/tree/4.6.10"
"source": "https://github.com/box-project/box/tree/4.6.8"
},
"time": "2025-10-31T18:38:02+00:00"
"time": "2025-10-13T17:13:17+00:00"
},
{
"name": "humbug/php-scoper",
@@ -3212,16 +3208,16 @@
},
{
"name": "justinrainbow/json-schema",
"version": "6.6.1",
"version": "6.6.0",
"source": {
"type": "git",
"url": "https://github.com/jsonrainbow/json-schema.git",
"reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396"
"reference": "68ba7677532803cc0c5900dd5a4d730537f2b2f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fd8e5c6b1badb998844ad34ce0abcd71a0aeb396",
"reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396",
"url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/68ba7677532803cc0c5900dd5a4d730537f2b2f3",
"reference": "68ba7677532803cc0c5900dd5a4d730537f2b2f3",
"shasum": ""
},
"require": {
@@ -3281,9 +3277,9 @@
],
"support": {
"issues": "https://github.com/jsonrainbow/json-schema/issues",
"source": "https://github.com/jsonrainbow/json-schema/tree/6.6.1"
"source": "https://github.com/jsonrainbow/json-schema/tree/6.6.0"
},
"time": "2025-11-07T18:30:29+00:00"
"time": "2025-10-10T11:34:09+00:00"
},
{
"name": "kelunik/certificate",
@@ -3704,16 +3700,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.6.2",
"version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"shasum": ""
},
"require": {
@@ -3756,9 +3752,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
},
"time": "2025-10-21T19:32:17+00:00"
"time": "2025-08-13T20:13:15+00:00"
},
{
"name": "phar-io/composer-distributor",
@@ -6780,16 +6776,16 @@
},
{
"name": "symfony/filesystem",
"version": "v7.3.6",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "e9bcfd7837928ab656276fe00464092cc9e1826a"
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a",
"reference": "e9bcfd7837928ab656276fe00464092cc9e1826a",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
"shasum": ""
},
"require": {
@@ -6826,7 +6822,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v7.3.6"
"source": "https://github.com/symfony/filesystem/tree/v7.3.2"
},
"funding": [
{
@@ -6846,20 +6842,20 @@
"type": "tidelift"
}
],
"time": "2025-11-05T09:52:27+00:00"
"time": "2025-07-07T08:17:47+00:00"
},
{
"name": "symfony/finder",
"version": "v7.3.5",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"shasum": ""
},
"require": {
@@ -6894,7 +6890,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v7.3.5"
"source": "https://github.com/symfony/finder/tree/v7.3.2"
},
"funding": [
{
@@ -6914,7 +6910,7 @@
"type": "tidelift"
}
],
"time": "2025-10-15T18:45:57+00:00"
"time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/options-resolver",
@@ -7215,16 +7211,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.3.5",
"version": "v7.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
"shasum": ""
},
"require": {
@@ -7278,7 +7274,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
"source": "https://github.com/symfony/var-dumper/tree/v7.3.4"
},
"funding": [
{
@@ -7298,7 +7294,7 @@
"type": "tidelift"
}
],
"time": "2025-09-27T09:00:46+00:00"
"time": "2025-09-11T10:12:26+00:00"
},
{
"name": "thecodingmachine/safe",
@@ -7441,16 +7437,16 @@
},
{
"name": "theseer/tokenizer",
"version": "1.3.0",
"version": "1.2.3",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb"
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"shasum": ""
},
"require": {
@@ -7479,7 +7475,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.3.0"
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
},
"funding": [
{
@@ -7487,32 +7483,32 @@
"type": "github"
}
],
"time": "2025-11-13T13:44:09+00:00"
"time": "2024-03-03T12:36:25+00:00"
},
{
"name": "webmozart/assert",
"version": "1.12.1",
"version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-filter": "*",
"php": "^7.2 || ^8.0"
},
"suggest": {
"ext-intl": "",
"ext-simplexml": "",
"ext-spl": ""
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.13"
},
"type": "library",
"extra": {
@@ -7543,9 +7539,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.12.1"
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
},
"time": "2025-10-29T15:56:20+00:00"
"time": "2022-06-03T18:03:27+00:00"
}
],
"aliases": [],

View File

@@ -1,41 +1,40 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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`)
; SPC_EXTRA_PHP_VARS: the extra vars for building php, used in `configure` and `make` command.
[global]
; Build concurrency for make -jN, default is CPU_COUNT, this value are used in every libs.
@@ -45,7 +44,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}"
@@ -110,7 +109,9 @@ SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable
; *** 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=""
@@ -140,8 +141,10 @@ SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-
; *** 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}"
; 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

@@ -358,18 +358,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",

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",
@@ -236,24 +228,6 @@
"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,
@@ -301,26 +275,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": [
@@ -506,16 +460,6 @@
"liblz4.a"
]
},
"libmaxminddb": {
"source": "libmaxminddb",
"static-libs-unix": [
"libmaxminddb.a"
],
"headers": [
"maxminddb.h",
"maxminddb_config.h"
]
},
"libmemcached": {
"source": "libmemcached",
"cpp-library": true,
@@ -562,16 +506,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"
]
},
@@ -618,16 +559,6 @@
"zstd"
]
},
"libunistring": {
"source": "libunistring",
"static-libs-unix": [
"libunistring.a"
],
"headers": [
"unistr.h",
"unistring/"
]
},
"liburing": {
"source": "liburing",
"pkg-configs": [

View File

@@ -184,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",
@@ -310,19 +301,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"
@@ -439,16 +421,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/",
@@ -607,15 +579,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",
@@ -650,16 +613,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",
@@ -727,16 +680,6 @@
"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",
@@ -750,7 +693,6 @@
"type": "git",
"url": "https://github.com/static-php/libuuid.git",
"rev": "master",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"

View File

@@ -1,10 +1,11 @@
import sidebarEn from "./sidebar.en";
import sidebarZh from "./sidebar.zh";
import sidebarJa from "./sidebar.ja";
// https://vitepress.dev/reference/site-config
export default {
title: "StaticPHP",
title: "Static PHP",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
locales: {
en: {
@@ -61,5 +62,19 @@ export default {
indexName: 'static-php docs',
},
},
}
},
head: [
[
'script',
{ async: '', src: 'https://www.googletagmanager.com/gtag/js?id=G-0MBJ29BD7F' }
],
[
'script',
{},
`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-0MBJ29BD7F');`
]
]
}

View File

@@ -1,6 +1,6 @@
# Guide
StaticPHP is a tool used to build statically compiled PHP binaries,
Static php cli is a tool used to build statically compiled PHP binaries,
currently supporting Linux and macOS systems.
In the guide section, you will learn how to use static php cli to build standalone PHP programs.
@@ -14,14 +14,12 @@ In the guide section, you will learn how to use static php cli to build standalo
The following is the architecture support situation, where :gear: represents support for GitHub Action build,
:computer: represents support for local manual build, and empty represents temporarily not supported.
| | x86_64 | aarch64 |
|---------|------------------------|------------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: (:warning:) | :computer: (:warning:) |
> Due to lack of users and testing, FreeBSD is no longer supported in latest StaticPHP project.
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
Current supported PHP versions for compilation:
@@ -31,17 +29,17 @@ Current supported PHP versions for compilation:
>
> :x: Not supported
| PHP Version | Status | Comment |
|-------------|--------------------|--------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 | :heavy_check_mark: | |
| PHP Version | Status | Comment |
|-------------|--------------------|-------------------------------------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1, we no longer handle 8.1 related backport support after 8.5 release |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 is currently in beta stage |
> This table shows the support status of static-php-cli for building corresponding versions, not the PHP official support status for that version.

View File

@@ -3,7 +3,7 @@
layout: home
hero:
name: "StaticPHP"
name: "Static PHP"
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
@@ -14,9 +14,9 @@ hero:
link: ./guide/
features:
- title: Static PHP Binary
- title: Static CLI Binary
details: You can easily compile a standalone php binary for general use. Including CLI, FPM sapi.
- title: PHP micro Self-Extracted Executable
- title: Micro Self-Extracted Executable
details: You can compile a self-extracted executable and build with your php source code.
- title: Dependency Management
details: static-php-cli comes with dependency management and supports installation of different types of PHP extensions.

View File

@@ -3,7 +3,7 @@
layout: home
hero:
name: "StaticPHP"
name: "Static PHP"
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

BIN
docs/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -12,14 +12,12 @@ static-php-cli 是一个用于构建静态编译的 PHP 二进制的工具,目
下面是架构支持情况,:gear: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。
| | x86_64 | aarch64 |
|---------|------------------------|------------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: (:warning:) | :computer: (:warning:) |
> 由于缺乏用户和测试FreeBSD 在最新的 StaticPHP 项目中不再受支持。
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
当前支持编译的 PHP 版本:
@@ -29,17 +27,17 @@ static-php-cli 是一个用于构建静态编译的 PHP 二进制的工具,目
>
> :x: 不支持
| PHP Version | Status | Comment |
|-------------|--------------------|----------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :warning: | PHP 官方已停止 8.0 的维护,我们不再处理 8.0 相关的 backport 支持 |
| 8.1 | :warning: | PHP 官方仅对 8.1 提供安全更新 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 | :heavy_check_mark: | |
| PHP Version | Status | Comment |
|-------------|--------------------|---------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :warning: | PHP 官方已停止 8.0 的维护,我们不再处理 8.0 相关的 backport 支持 |
| 8.1 | :warning: | PHP 官方仅对 8.1 提供安全更新,在 8.5 发布后我们不再处理 8.1 相关的 backport 支持 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 目前处于 beta 阶段 |
> 这个表格的支持状态是 static-php-cli 对构建对应版本的支持情况,不是 PHP 官方对该版本的支持情况。

View File

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

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\builder;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\EnvironmentException;
use SPC\exception\SPCException;
use SPC\exception\ValidationException;
@@ -221,7 +220,7 @@ class Extension
*/
public function patchBeforeSharedMake(): bool
{
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
$lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
@@ -449,15 +448,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';
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, $soFile, false);
}
/**
@@ -496,46 +486,18 @@ 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);
$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 ';
@@ -557,7 +519,7 @@ class Extension
}
logger()->info("enabling {$this->name} without library {$name}");
} else {
$this->dependencies[$name] = $depLib;
$this->dependencies[] = $depLib;
}
}
@@ -570,7 +532,7 @@ class Extension
}
logger()->info("enabling {$this->name} without extension {$name}");
} else {
$this->dependencies[$name] = $depExt;
$this->dependencies[] = $depExt;
}
}
@@ -605,4 +567,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 (!array_key_exists($depdepName, $deps)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!array_key_exists($depName, $deps)) {
$deps[$depName] = $dep;
}
}
}
if (array_key_exists(0, $deps)) {
$zero = [0 => $deps[0]];
unset($deps[0]);
return $zero + $deps;
}
return $deps;
}
}

View File

@@ -43,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;

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

@@ -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

@@ -70,7 +70,7 @@ class swoole extends Extension
$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'));
$config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']);
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}

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

@@ -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

@@ -8,7 +8,6 @@ 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,7 +90,7 @@ 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!
@@ -195,7 +194,15 @@ class LinuxBuilder extends UnixBuilderBase
SourcePatcher::patchFile('musl_static_readline.patch', SOURCE_PATH . '/php-src', true);
}
$this->deploySAPIBinary(BUILD_TARGET_CLI);
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->deployBinary(BUILD_TARGET_CLI);
}
protected function buildCgi(): void
@@ -206,7 +213,15 @@ class LinuxBuilder extends UnixBuilderBase
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$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 +232,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);
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
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("make {$concurrency} {$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();
}
}
@@ -258,7 +269,14 @@ class LinuxBuilder extends UnixBuilderBase
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make {$concurrency} {$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);
}
/**
@@ -271,9 +289,6 @@ class LinuxBuilder extends UnixBuilderBase
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')
@@ -281,54 +296,10 @@ class LinuxBuilder extends UnixBuilderBase
->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");
// process libphp.so for shared embed
$libphpSo = BUILD_LIB_PATH . '/libphp.so';
if (file_exists($libphpSo)) {
// post actions: rename libphp.so to libphp-<release>.so if -release is set in LDFLAGS
$this->processLibphpSoFile($libphpSo);
// deploy libphp.so
$this->deployBinary($libphpSo, $libphpSo, false);
}
// process shared extensions build-with-php
$increment_files = $diff->getChangedFiles();
foreach ($increment_files as $increment_file) {
$this->deployBinary($increment_file, $increment_file, false);
}
// 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');
// export dynamic symbols
SystemUtil::exportDynamicSymbols(BUILD_LIB_PATH . '/libphp.a');
}
// patch embed php scripts
$this->patchPhpScripts();
}
/**
* Return extra variables for php make command.
*/
private function getMakeExtraVars(): array
{
$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([
'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",
]);
}
private function processLibphpSoFile(string $libphpSo): void
{
$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();
@@ -390,29 +361,60 @@ class LinuxBuilder extends UnixBuilderBase
}
}
}
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');
// export dynamic symbols
SystemUtil::exportDynamicSymbols(BUILD_LIB_PATH . '/libphp.a');
}
if (!$this->getOption('no-strip', false) && file_exists(BUILD_LIB_PATH . '/' . $realLibName)) {
shell()->cd(BUILD_LIB_PATH)->exec("strip --strip-unneeded {$realLibName}");
}
$this->patchPhpScripts();
}
/**
* 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
* Return extra variables for php make command.
*/
private function processUpxedMicroSfx(string $dst): void
private function getMakeExtraVars(): array
{
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');
$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([
'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",
]);
}
/**
* 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 processMicroUPX(): void
{
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 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

@@ -8,7 +8,6 @@ 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 +105,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,
]);
@@ -190,7 +189,10 @@ class MacOSBuilder extends UnixBuilderBase
$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);
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
@@ -200,7 +202,10 @@ class MacOSBuilder extends UnixBuilderBase
$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);
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 +216,31 @@ 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
$concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : '';
$shell->exec("make {$concurrency} {$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();
}
}
@@ -248,7 +254,10 @@ class MacOSBuilder extends UnixBuilderBase
$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);
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);
}
/**
@@ -263,25 +272,9 @@ class MacOSBuilder extends UnixBuilderBase
$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);
}
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');

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 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

@@ -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,92 +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}");
}
// extract debug info
$this->extractDebugInfo($dst);
// strip
if (!$this->getOption('no-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.
*/
@@ -296,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;
}
/**
@@ -350,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') {
@@ -428,6 +290,7 @@ abstract class UnixBuilderBase extends BuilderBase
$dynamic_exports = ' ' . $dynamicSymbolsArgument;
}
}
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
$extLdFlags = "-extldflags '-pie{$dynamic_exports} {$this->arch_ld_flags}'";
$muslTags = '';
$staticFlags = '';
@@ -438,7 +301,7 @@ abstract class UnixBuilderBase extends BuilderBase
}
$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'];
// 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') ||
@@ -452,7 +315,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}",
@@ -462,7 +325,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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -47,7 +47,7 @@ trait postgresql
{
$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));
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs'));
$env_vars = [
'CFLAGS' => $config['cflags'],

View File

@@ -67,6 +67,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 ';
@@ -130,7 +145,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,27 +156,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);
$this->deployBinary(BUILD_TARGET_CLI);
}
public function buildCgi(): void
@@ -170,23 +170,12 @@ 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)) {
$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= %*");
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cgi_wrapper.bat', "nmake /nologo 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_CGI);
}
public function buildEmbed(): void
@@ -213,20 +202,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 +221,7 @@ class WindowsBuilder extends BuilderBase
}
}
$this->deploySAPIBinary(BUILD_TARGET_MICRO);
$this->deployBinary(BUILD_TARGET_MICRO);
}
public function proveLibs(array $sorted_libraries): void
@@ -357,53 +335,28 @@ 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",
BUILD_TARGET_CGI => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\php-cgi.exe",
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));
cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src));
}
}
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_BIN_PATH);
cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_BIN_PATH . '\\'));
return true;
}
/**

View File

@@ -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

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

@@ -159,9 +159,7 @@ class ExceptionHandler
public static function handleDefaultException(\Throwable $e): void
{
$class = get_class($e);
$file = $e->getFile();
$line = $e->getLine();
self::logError("✗ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n");
self::logError("✗ Unhandled exception {$class}:\n\t{$e->getMessage()}\n");
self::logError('Stack trace:');
self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4);
self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues');

View File

@@ -1,95 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\store;
/**
* A util class to diff directory file increments.
*/
class DirDiff
{
protected array $before = [];
protected array $before_file_hashes = [];
public function __construct(protected string $dir, protected bool $track_content_changes = false)
{
$this->reset();
}
/**
* Reset the baseline to current state.
*/
public function reset(): void
{
$this->before = FileSystem::scanDirFiles($this->dir, relative: true) ?: [];
if ($this->track_content_changes) {
$this->before_file_hashes = [];
foreach ($this->before as $file) {
$this->before_file_hashes[$file] = md5_file($this->dir . DIRECTORY_SEPARATOR . $file);
}
}
}
/**
* Get the list of incremented files.
*
* @param bool $relative Return relative paths or absolute paths
* @return array<string> List of incremented files
*/
public function getIncrementFiles(bool $relative = false): array
{
$after = FileSystem::scanDirFiles($this->dir, relative: true) ?: [];
$diff = array_diff($after, $this->before);
if ($relative) {
return $diff;
}
return array_map(fn ($f) => $this->dir . DIRECTORY_SEPARATOR . $f, $diff);
}
/**
* Get the list of changed files (including new files).
*
* @param bool $relative Return relative paths or absolute paths
* @param bool $include_new_files Include new files as changed files
* @return array<string> List of changed files
*/
public function getChangedFiles(bool $relative = false, bool $include_new_files = true): array
{
$after = FileSystem::scanDirFiles($this->dir, relative: true) ?: [];
$changed = [];
foreach ($after as $file) {
if (isset($this->before_file_hashes[$file])) {
$after_hash = md5_file($this->dir . DIRECTORY_SEPARATOR . $file);
if ($after_hash !== $this->before_file_hashes[$file]) {
$changed[] = $file;
}
} elseif ($include_new_files) {
// New file, consider as changed
$changed[] = $file;
}
}
if ($relative) {
return $changed;
}
return array_map(fn ($f) => $this->dir . DIRECTORY_SEPARATOR . $f, $changed);
}
/**
* Get the list of removed files.
*
* @param bool $relative Return relative paths or absolute paths
* @return array<string> List of removed files
*/
public function getRemovedFiles(bool $relative = false): array
{
$after = FileSystem::scanDirFiles($this->dir, relative: true) ?: [];
$removed = array_diff($this->before, $after);
if ($relative) {
return $removed;
}
return array_map(fn ($f) => $this->dir . DIRECTORY_SEPARATOR . $f, $removed);
}
}

View File

@@ -174,9 +174,6 @@ class FileSystem
logger()->debug("Copying file from {$from} to {$to}");
$dst_path = FileSystem::convertPath($to);
$src_path = FileSystem::convertPath($from);
if ($src_path === $dst_path) {
return;
}
if (!copy($src_path, $dst_path)) {
throw new FileSystemException('Cannot copy file from ' . $src_path . ' to ' . $dst_path);
}
@@ -660,19 +657,11 @@ class FileSystem
$source = self::convertPath($source);
$dest = self::convertPath($dest);
// Check if source and dest are on the same device to avoid cross-device rename errors
$source_stat = @stat($source);
$dest_parent = dirname($dest);
$dest_stat = @stat($dest_parent);
// Only use rename if on same device
if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) {
if (@rename($source, $dest)) {
return;
}
// Try rename first (fast, atomic)
if (@rename($source, $dest)) {
return;
}
// Fall back to copy + delete for cross-device moves or if rename failed
if (is_dir($source)) {
self::copyDir($source, $dest);
self::removeDir($source);

View File

@@ -15,7 +15,9 @@ class PhpSource extends CustomSourceBase
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
{
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.4';
if ($major === 'git') {
if ($major === '8.5') {
Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://downloads.php.net/~daniels/php-8.5.0RC3.tar.xz'], $force);
} elseif ($major === 'git') {
Downloader::downloadSource('php-src', ['type' => 'git', 'url' => 'https://github.com/php/php-src.git', 'rev' => 'master'], $force);
} else {
Downloader::downloadSource('php-src', $this->getLatestPHPInfo($major), $force);

View File

@@ -7,7 +7,6 @@ namespace SPC\util;
use SPC\builder\BuilderBase;
use SPC\builder\BuilderProvider;
use SPC\builder\Extension;
use SPC\builder\LibraryBase;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use Symfony\Component\Console\Input\ArgvInput;
@@ -54,9 +53,6 @@ class SPCConfigUtil
*/
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
{
logger()->debug('config extensions: ' . implode(',', $extensions));
logger()->debug('config libs: ' . implode(',', $libraries));
logger()->debug('config suggest for [ext, lib]: ' . ($include_suggest_ext ? 'true' : 'false') . ',' . ($include_suggest_lib ? 'true' : 'false'));
$extra_exts = [];
foreach ($extensions as $ext) {
$extra_exts = array_merge($extra_exts, Config::getExt($ext, 'ext-suggests', []));
@@ -128,63 +124,6 @@ class SPCConfigUtil
];
}
/**
* [Helper function]
* Get configuration for a specific extension(s) dependencies.
*
* @param Extension|Extension[] $extension Extension instance or list
* @param bool $include_suggest_ext Whether to include suggested extensions
* @param bool $include_suggest_lib Whether to include suggested libraries
* @return array{
* cflags: string,
* ldflags: string,
* libs: string
* }
*/
public function getExtensionConfig(array|Extension $extension, bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
{
if (!is_array($extension)) {
$extension = [$extension];
}
$libs = array_map(fn ($y) => $y->getName(), array_merge(...array_map(fn ($x) => $x->getLibraryDependencies(true), $extension)));
return $this->config(
extensions: array_map(fn ($x) => $x->getName(), $extension),
libraries: $libs,
include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false,
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
);
}
/**
* [Helper function]
* Get configuration for a specific library(s) dependencies.
*
* @param LibraryBase|LibraryBase[] $lib Library instance or list
* @param bool $include_suggest_lib Whether to include suggested libraries
* @return array{
* cflags: string,
* ldflags: string,
* libs: string
* }
*/
public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_lib = false): array
{
if (!is_array($lib)) {
$lib = [$lib];
}
$save_no_php = $this->no_php;
$this->no_php = true;
$save_libs_only_deps = $this->libs_only_deps;
$this->libs_only_deps = true;
$ret = $this->config(
libraries: array_map(fn ($x) => $x->getName(), $lib),
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
);
$this->no_php = $save_no_php;
$this->libs_only_deps = $save_libs_only_deps;
return $ret;
}
private function hasCpp(array $extensions, array $libraries): bool
{
// judge cpp-extension

View File

@@ -35,7 +35,7 @@ $test_os = [
];
// whether enable thread safe
$zts = false;
$zts = true;
$no_strip = false;
@@ -50,8 +50,8 @@ $prefer_pre_built = false;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'maxminddb',
'Windows' => 'bcmath',
'Linux', 'Darwin' => 'trader',
'Windows' => 'bcmath,bz2,calendar,ctype,curl,dba,dom,exif,ffi,fileinfo,filter,ftp,iconv,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_sqlite,pdo_sqlsrv,phar,session,shmop,simdjson,simplexml,soap,sockets,sqlite3,sqlsrv,ssh2,sysvshm,tokenizer,xml,xmlreader,xmlwriter,yaml,zip,zlib',
};
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
@@ -74,7 +74,7 @@ $with_libs = match (PHP_OS_FAMILY) {
// You can use `common`, `bulk`, `minimal` or `none`.
// note: combination is only available for *nix platform. Windows must use `none` combination
$base_combination = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'minimal',
'Linux', 'Darwin' => 'none',
'Windows' => 'none',
};