Compare commits

...

82 Commits

Author SHA1 Message Date
Jerry Ma
085abd635e Merge pull request #819 from crazywhalecc/php-85
Add PHP 8.5 initial support
2025-08-05 12:01:47 +08:00
DubbleClick
3789c7c335 only enable one of password-argon2 or openssl-argon2 2025-08-04 10:14:48 +07:00
crazywhalecc
4fb4e42896 Revert 2025-08-04 01:10:08 +08:00
crazywhalecc
81e7a0c554 Add without argon2 option 2025-08-03 23:01:24 +08:00
crazywhalecc
4cbe4ea82d Revert corrupted revert 2025-08-03 23:01:09 +08:00
crazywhalecc
ea4905cd0d Add argon2 support for PHP-NTS < 8.5 2025-08-03 22:59:40 +08:00
crazywhalecc
3c09ba59d7 Merge remote-tracking branch 'origin/php-85' into php-85 2025-08-03 22:55:17 +08:00
Jerry Ma
430f436b79 Update src/SPC/builder/macos/MacOSBuilder.php
Co-authored-by: Marc <m@pyc.ac>
2025-08-03 22:48:09 +08:00
Jerry Ma
93001dce88 Update src/SPC/builder/macos/MacOSBuilder.php
Co-authored-by: Marc <m@pyc.ac>
2025-08-03 22:47:02 +08:00
Jerry Ma
2d6d25cadf Update src/SPC/builder/linux/LinuxBuilder.php
Co-authored-by: Marc <m@pyc.ac>
2025-08-03 22:46:47 +08:00
crazywhalecc
b644da8210 Remove redundant patches for openssl 2025-08-03 22:45:24 +08:00
crazywhalecc
f1a9a28ed7 Use backup file function to avoid multiple build conflict 2025-08-03 02:06:08 +08:00
crazywhalecc
643926886c Test original 2025-08-03 02:00:19 +08:00
crazywhalecc
9a5a59d876 Test 2025-08-03 01:49:15 +08:00
crazywhalecc
e7fe91faef Fix patch, use pure socket client directly 2025-08-03 01:23:47 +08:00
crazywhalecc
e6cf05ddff Test 2025-08-03 01:12:28 +08:00
crazywhalecc
c3e9a2816b Test 2025-08-03 00:29:13 +08:00
Marc
0bb8e83d68 Merge pull request #844 from crazywhalecc/swoole-v6
change swoole to version 6.x because 5.x is not compatible with php 8.4+
2025-08-02 23:06:35 +07:00
crazywhalecc
d0053534ab tmate 2025-08-02 23:06:16 +08:00
crazywhalecc
38725c2bb4 Update ca certificates 2025-08-02 22:22:09 +08:00
DubbleClick
b8fe70e5ee change swoole to version 6.x because 5.x is not compatible with php 8.4+ 2025-08-02 20:23:26 +07:00
crazywhalecc
3960a21e05 Use full domain test list 2025-08-02 18:40:55 +08:00
crazywhalecc
e14301d991 Symbol workaround for cross toolchain 2025-08-02 18:07:32 +08:00
Jerry Ma
65f74044d8 Update tests.yml 2025-08-02 03:03:20 +08:00
Jerry Ma
f6eba32be5 Update tests.yml 2025-08-02 02:38:24 +08:00
crazywhalecc
af62e55da8 Add missing space 2025-08-02 01:38:32 +08:00
crazywhalecc
22a8191b97 Fix opcache jit option parsing in builder 2025-08-02 01:29:20 +08:00
Jerry Ma
17ff5f63bf Update tests.yml 2025-08-02 00:58:36 +08:00
crazywhalecc
48a7d814f8 Test jit 2025-08-01 17:00:35 +08:00
crazywhalecc
2c5cf07e9c cs fix, fix file name 2025-08-01 15:45:33 +08:00
crazywhalecc
cace504a63 Workaround for windows openssl temporarily 2025-08-01 15:42:34 +08:00
crazywhalecc
efa47af347 Add git source test 2025-08-01 15:17:13 +08:00
crazywhalecc
1c9fbdb032 Use none base combination 2025-08-01 15:01:55 +08:00
crazywhalecc
ac2eb3adae Remove redis test 2025-08-01 14:21:38 +08:00
crazywhalecc
d6081ee10f Support alpha4 2025-08-01 13:00:12 +08:00
crazywhalecc
8b9b72958e Add PHP_BUILD_COMPILER for different toolchain 2025-08-01 12:48:48 +08:00
crazywhalecc
34edb6e329 Add PHP_BUILD_PROVIDER to env.ini 2025-08-01 10:58:31 +08:00
crazywhalecc
9487051796 Add PHP_BUILD_PROVIDER for PHP >= 8.4 2025-08-01 02:25:12 +08:00
crazywhalecc
7d0577460f cs-fix 2025-08-01 02:05:46 +08:00
crazywhalecc
6b23f4b34a Fix PHPUnit test on Windows, ignore calling linux system util for other OS 2025-08-01 01:53:38 +08:00
crazywhalecc
451de4a6f6 Fix ConfigValidator and sort config 2025-08-01 01:50:32 +08:00
crazywhalecc
33d587ee9e Remove redis test (https://github.com/phpredis/phpredis/pull/2676) 2025-08-01 01:32:37 +08:00
crazywhalecc
6b381238fe Remove collision, it's useless at all 2025-08-01 01:29:35 +08:00
crazywhalecc
07d66ade85 Add separated patchedBeforeWindowsConfigure 2025-08-01 01:28:56 +08:00
crazywhalecc
e1c9240698 README update 2025-08-01 00:51:04 +08:00
crazywhalecc
d3e8af23bc Whoops 2025-08-01 00:50:51 +08:00
crazywhalecc
5f9fe2948c Fix missing SPC_EXTRA_LIBS with type error bug 2025-08-01 00:09:05 +08:00
crazywhalecc
4c54d99621 Remove pcntl 2025-07-31 23:49:53 +08:00
crazywhalecc
72beba76c3 Merge remote-tracking branch 'origin/php-85' into php-85 2025-07-31 23:46:43 +08:00
crazywhalecc
1047d471ed Merge branch 'main' into php-85
# Conflicts:
#	src/SPC/builder/linux/LinuxBuilder.php
#	src/SPC/store/source/PhpSource.php
#	src/globals/test-extensions.php
2025-07-31 23:46:34 +08:00
crazywhalecc
0496af47df Fix windows PHP 8.5 build 2025-07-31 23:43:44 +08:00
crazywhalecc
96a7aabda0 Don't show shell log 2025-07-31 21:31:48 +08:00
crazywhalecc
be857913cd Add alt for re2c 2025-07-31 01:54:28 +08:00
crazywhalecc
601444d0a5 Add re2c build for spc-gnu-docker 2025-07-31 01:44:44 +08:00
crazywhalecc
3c972ac905 Add re2c build 2025-07-31 00:55:25 +08:00
crazywhalecc
6984c29a3a suggestion 2025-07-31 00:11:49 +08:00
crazywhalecc
cb0ea67a28 Fix x86_64 macOS bison finder path 2025-07-31 00:09:13 +08:00
crazywhalecc
fcdb029b10 Install re2c manually in gnu docker 2025-07-31 00:07:23 +08:00
crazywhalecc
5f33a07f4c Fix windows builds when unix configure does not exist 2025-07-30 23:57:52 +08:00
crazywhalecc
357c04def0 Merge branch 'main' into php-85
# Conflicts:
#	src/SPC/util/PkgConfigUtil.php
2025-07-30 23:25:49 +08:00
crazywhalecc
0dfa6e63bd Fix dev:lib-version command with dependencies 2025-07-30 23:23:27 +08:00
crazywhalecc
af10cacdff Add openssl version getter for Windows, test openssl 2025-07-30 23:23:12 +08:00
crazywhalecc
5f5d934d58 Add openssl argon2 password hash support for PHP 8.5 2025-07-30 23:02:28 +08:00
crazywhalecc
9ed3c8b498 phpstan 2025-07-29 11:25:06 +08:00
crazywhalecc
ed67393d33 Move opcache JIT handling from Linux and MacOS builders to Extension 2025-07-29 11:22:58 +08:00
crazywhalecc
e9dbeb1e34 Refactor opcache JIT handling and version checks in Linux and MacOS builders 2025-07-29 10:59:36 +08:00
crazywhalecc
4efb3dfc9a Add check for Bison version in MacOS tool checklist, trigger extension test 2025-07-28 16:47:04 +08:00
crazywhalecc
b9bec5b526 Whoops, extension test 2025-07-28 16:00:32 +08:00
crazywhalecc
1ae0752933 Trigger full extension test 2025-07-28 15:58:07 +08:00
crazywhalecc
0696acb9c5 Add support for re2c in tool checklists and environment setup 2025-07-28 15:54:55 +08:00
crazywhalecc
973c8f082f Add php-src git version support 2025-07-28 15:36:53 +08:00
crazywhalecc
85e89e4326 alpha2 2025-07-28 10:17:14 +08:00
crazywhalecc
fb106a3d41 Merge branch 'refs/heads/main' into php-85
# Conflicts:
#	src/globals/test-extensions.php
2025-07-28 10:12:13 +08:00
crazywhalecc
f0612591be Test bulk (without amqp, swoole) and spc-max 2025-07-15 23:31:26 +08:00
crazywhalecc
5838c87140 Merge remote-tracking branch 'origin/php-85' into php-85 2025-07-15 22:08:16 +08:00
crazywhalecc
1ce3ba0f30 Update docs and READMEs 2025-07-15 22:08:10 +08:00
Jerry Ma
dc8f7de75a Merge branch 'main' into php-85 2025-07-15 21:59:48 +08:00
crazywhalecc
d3f8e94fe9 Use new branch of micro, extension test 2025-07-15 21:57:49 +08:00
crazywhalecc
88cf0184cc extension test 2025-07-15 21:57:06 +08:00
crazywhalecc
b9e096abfa Download alpha version for 8.5 2025-07-15 21:14:15 +08:00
crazywhalecc
ec959f6239 Add 8.5 patch support for phpmicro 2025-07-15 21:14:02 +08:00
crazywhalecc
5f2459ae43 Avoid useless exception on startup version mismatch 2025-07-15 21:11:38 +08:00
62 changed files with 716 additions and 452 deletions

View File

@@ -82,7 +82,7 @@ jobs:
- zlib
- zstd
php-version:
- "8.4"
- "git"
operating-system:
- "ubuntu-latest"
#- "macos-13"

View File

@@ -145,6 +145,10 @@ jobs:
os: ${{ fromJSON(needs.define-matrix.outputs.os) }}
fail-fast: false
steps:
- name: "Update runner packages"
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
run: sudo apt-get update && sudo apt-get install -y ca-certificates
- name: "Checkout"
uses: actions/checkout@v4

View File

@@ -76,22 +76,23 @@ static-php-cli简称 `spc`)有许多特性:
当前支持编译的 PHP 版本:
> :warning: 支持,但 static-php-cli 作者可能不再提供补丁修复
> :warning: 部分支持,对于新的测试版和旧版本可能存在问题。
>
> :heavy_check_mark: 支持
>
> :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 | :heavy_check_mark: | PHP 官方仅对 8.1 提供安全更新 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :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 | :heavy_check_mark: | 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 (alpha) | :warning: | PHP 8.5 目前处于 alpha 阶段 |
> 这个表格的支持状态是 static-php-cli 对构建对应版本的支持情况,不是 PHP 官方对该版本的支持情况。

View File

@@ -83,7 +83,7 @@ Here is the supported OS and arch, where :octocat: represents support for GitHub
Currently supported PHP versions for compilation:
> :warning: supported but not maintained by static-php-cli authors
> :warning: Partial support, there may be issues with newer test versions or older versions.
>
> :heavy_check_mark: supported
>
@@ -95,10 +95,11 @@ Currently supported PHP versions for compilation:
| 7.3 | :x: | phpmicro and some extensions not supported on 7.x |
| 7.4 | :x: | phpmicro and some extensions not supported on 7.x |
| 8.0 | :warning: | PHP official has stopped maintenance of 8.0, we no longer provide backport support for version 8.0 |
| 8.1 | :heavy_check_mark: | PHP official has security fixes only |
| 8.1 | :heavy_check_mark: | PHP official has security fixes only, we no longer provide backport support when 8.5 released |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (alpha) | :warning: | PHP 8.5 is in alpha |
> This table shows the support status for static-php-cli in building the corresponding version,
> not the official PHP support status for that version.

View File

@@ -104,6 +104,7 @@ RUN apk update; \
m4 \
make \
pkgconfig \
re2c \
wget \
xz \
gettext-dev \

View File

@@ -3,7 +3,7 @@
set -e
# This file is using docker to run commands
SPC_DOCKER_VERSION=v4
SPC_DOCKER_VERSION=v5
# Detect docker can run
if ! which docker >/dev/null; then
@@ -102,17 +102,20 @@ RUN curl -o cmake.tgz -#fSL https://github.com/Kitware/CMake/releases/download/v
tar -xzf cmake.tgz -C /cmake --strip-components 1
WORKDIR /app
ADD ./src /app/src
COPY ./composer.* /app/
ADD ./bin/setup-runtime /app/bin/setup-runtime
ADD ./bin/spc /app/bin/spc
RUN /app/bin/setup-runtime
ADD ./src /app/src
RUN /app/bin/php /app/bin/composer install --no-dev
ENV SPC_LIBC=glibc
ENV PATH="/app/bin:/cmake/bin:/opt/rh/devtoolset-10/root/usr/bin:\$PATH"
ADD ./config/env.ini /app/config/env.ini
ADD ./config /app/config
RUN CC=gcc bin/spc doctor --auto-fix --debug
RUN if [ -f /app/buildroot/bin/re2c ]; then \
cp /app/buildroot/bin/re2c /usr/local/bin/re2c ;\
fi
RUN curl -o make.tgz -fsSL https://ftp.gnu.org/gnu/make/make-4.4.tar.gz && \
tar -zxvf make.tgz && \

View File

@@ -23,7 +23,6 @@
"captainhook/hook-installer": "^1.0",
"friendsofphp/php-cs-fixer": "^3.60",
"humbug/box": "^4.5.0 || ^4.6.0",
"nunomaduro/collision": "^7.8",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.3 || ^9.5"
},

437
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d705cec8270679a463d9e04310208967",
"content-hash": "dbefe1ee5c584f6f0cc64c26fb83451c",
"packages": [
{
"name": "illuminate/collections",
@@ -416,47 +416,47 @@
},
{
"name": "symfony/console",
"version": "v6.4.23",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93"
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/9056771b8eca08d026cd3280deeec3cfd99c4d93",
"reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93",
"url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0|^7.0"
"symfony/string": "^7.2"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
"symfony/dotenv": "<5.4",
"symfony/event-dispatcher": "<5.4",
"symfony/lock": "<5.4",
"symfony/process": "<5.4"
"symfony/dependency-injection": "<6.4",
"symfony/dotenv": "<6.4",
"symfony/event-dispatcher": "<6.4",
"symfony/lock": "<6.4",
"symfony/process": "<6.4"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/event-dispatcher": "^5.4|^6.0|^7.0",
"symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/lock": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0",
"symfony/stopwatch": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
"symfony/lock": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/stopwatch": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -490,7 +490,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.4.23"
"source": "https://github.com/symfony/console/tree/v7.3.2"
},
"funding": [
{
@@ -501,12 +501,16 @@
"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-06-27T19:37:22+00:00"
"time": "2025-07-30T17:13:41+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1040,16 +1044,16 @@
},
{
"name": "symfony/string",
"version": "v7.3.0",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125"
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125",
"reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125",
"url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
"shasum": ""
},
"require": {
@@ -1107,7 +1111,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v7.3.0"
"source": "https://github.com/symfony/string/tree/v7.3.2"
},
"funding": [
{
@@ -1118,25 +1122,29 @@
"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-04-20T20:19:01+00:00"
"time": "2025-07-10T08:47:49+00:00"
},
{
"name": "symfony/yaml",
"version": "v7.3.1",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "0c3555045a46ab3cd4cc5a69d161225195230edb"
"reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/0c3555045a46ab3cd4cc5a69d161225195230edb",
"reference": "0c3555045a46ab3cd4cc5a69d161225195230edb",
"url": "https://api.github.com/repos/symfony/yaml/zipball/b8d7d868da9eb0919e99c8830431ea087d6aae30",
"reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30",
"shasum": ""
},
"require": {
@@ -1179,7 +1187,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v7.3.1"
"source": "https://github.com/symfony/yaml/tree/v7.3.2"
},
"funding": [
{
@@ -1190,12 +1198,16 @@
"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-06-03T06:57:57+00:00"
"time": "2025-07-10T08:47:49+00:00"
},
{
"name": "zhamao/logger",
@@ -2078,7 +2090,7 @@
},
{
"name": "captainhook/captainhook-phar",
"version": "5.25.6",
"version": "5.25.10",
"source": {
"type": "git",
"url": "https://github.com/captainhook-git/captainhook-phar.git",
@@ -2132,7 +2144,7 @@
],
"support": {
"issues": "https://github.com/captainhook-git/captainhook/issues",
"source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.6"
"source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.10"
},
"funding": [
{
@@ -2831,93 +2843,22 @@
],
"time": "2025-02-13T23:05:19+00:00"
},
{
"name": "filp/whoops",
"version": "2.18.3",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "59a123a3d459c5a23055802237cb317f609867e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5",
"reference": "59a123a3d459c5a23055802237cb317f609867e5",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3",
"symfony/var-dumper": "^4.0 || ^5.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool kids",
"homepage": "https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.18.3"
},
"funding": [
{
"url": "https://github.com/denis-sokolov",
"type": "github"
}
],
"time": "2025-06-16T00:02:10+00:00"
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.84.0",
"version": "v3.85.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "38dad0767bf2a9b516b976852200ae722fe984ca"
"reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca",
"reference": "38dad0767bf2a9b516b976852200ae722fe984ca",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba",
"reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba",
"shasum": ""
},
"require": {
"clue/ndjson-react": "^1.0",
"clue/ndjson-react": "^1.3",
"composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.5",
"ext-filter": "*",
@@ -2927,12 +2868,12 @@
"fidry/cpu-core-counter": "^1.2",
"php": "^7.4 || ^8.0",
"react/child-process": "^0.6.6",
"react/event-loop": "^1.0",
"react/promise": "^2.11 || ^3.0",
"react/socket": "^1.0",
"react/stream": "^1.0",
"react/event-loop": "^1.5",
"react/promise": "^3.2",
"react/socket": "^1.16",
"react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"symfony/console": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/console": "^5.4.47 || ^6.4.13 || ^7.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0",
@@ -2997,7 +2938,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.84.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1"
},
"funding": [
{
@@ -3005,7 +2946,7 @@
"type": "github"
}
],
"time": "2025-07-15T18:21:57+00:00"
"time": "2025-07-29T22:22:50+00:00"
},
{
"name": "humbug/box",
@@ -3660,16 +3601,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.5.0",
"version": "v5.6.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56",
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56",
"shasum": ""
},
"require": {
@@ -3712,190 +3653,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0"
},
"time": "2025-05-31T08:24:38+00:00"
},
{
"name": "nunomaduro/collision",
"version": "v7.12.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
"reference": "995245421d3d7593a6960822063bdba4f5d7cf1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/995245421d3d7593a6960822063bdba4f5d7cf1a",
"reference": "995245421d3d7593a6960822063bdba4f5d7cf1a",
"shasum": ""
},
"require": {
"filp/whoops": "^2.17.0",
"nunomaduro/termwind": "^1.17.0",
"php": "^8.1.0",
"symfony/console": "^6.4.17"
},
"conflict": {
"laravel/framework": ">=11.0.0"
},
"require-dev": {
"brianium/paratest": "^7.4.8",
"laravel/framework": "^10.48.29",
"laravel/pint": "^1.21.2",
"laravel/sail": "^1.41.0",
"laravel/sanctum": "^3.3.3",
"laravel/tinker": "^2.10.1",
"nunomaduro/larastan": "^2.10.0",
"orchestra/testbench-core": "^8.35.0",
"pestphp/pest": "^2.36.0",
"phpunit/phpunit": "^10.5.36",
"sebastian/environment": "^6.1.0",
"spatie/laravel-ignition": "^2.9.1"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider"
]
}
},
"autoload": {
"files": [
"./src/Adapters/Phpunit/Autoload.php"
],
"psr-4": {
"NunoMaduro\\Collision\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"description": "Cli error handling for console/command-line PHP applications.",
"keywords": [
"artisan",
"cli",
"command-line",
"console",
"error",
"handling",
"laravel",
"laravel-zero",
"php",
"symfony"
],
"support": {
"issues": "https://github.com/nunomaduro/collision/issues",
"source": "https://github.com/nunomaduro/collision"
},
"funding": [
{
"url": "https://www.paypal.com/paypalme/enunomaduro",
"type": "custom"
},
{
"url": "https://github.com/nunomaduro",
"type": "github"
},
{
"url": "https://www.patreon.com/nunomaduro",
"type": "patreon"
}
],
"time": "2025-03-14T22:35:49+00:00"
},
{
"name": "nunomaduro/termwind",
"version": "v1.17.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
"reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/5369ef84d8142c1d87e4ec278711d4ece3cbf301",
"reference": "5369ef84d8142c1d87e4ec278711d4ece3cbf301",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.1",
"symfony/console": "^6.4.15"
},
"require-dev": {
"illuminate/console": "^10.48.24",
"illuminate/support": "^10.48.24",
"laravel/pint": "^1.18.2",
"pestphp/pest": "^2.36.0",
"pestphp/pest-plugin-mock": "2.0.0",
"phpstan/phpstan": "^1.12.11",
"phpstan/phpstan-strict-rules": "^1.6.1",
"symfony/var-dumper": "^6.4.15",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Termwind\\Laravel\\TermwindServiceProvider"
]
}
},
"autoload": {
"files": [
"src/Functions.php"
],
"psr-4": {
"Termwind\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"description": "Its like Tailwind CSS, but for the console.",
"keywords": [
"cli",
"console",
"css",
"package",
"php",
"style"
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
"source": "https://github.com/nunomaduro/termwind/tree/v1.17.0"
},
"funding": [
{
"url": "https://www.paypal.com/paypalme/enunomaduro",
"type": "custom"
},
{
"url": "https://github.com/nunomaduro",
"type": "github"
},
{
"url": "https://github.com/xiCO2k",
"type": "github"
}
],
"time": "2024-11-21T10:36:35+00:00"
"time": "2025-07-27T20:03:57+00:00"
},
{
"name": "phar-io/composer-distributor",
@@ -6881,16 +6641,16 @@
},
{
"name": "symfony/filesystem",
"version": "v7.3.0",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
"shasum": ""
},
"require": {
@@ -6927,7 +6687,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v7.3.0"
"source": "https://github.com/symfony/filesystem/tree/v7.3.2"
},
"funding": [
{
@@ -6938,25 +6698,29 @@
"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": "2024-10-25T15:15:23+00:00"
"time": "2025-07-07T08:17:47+00:00"
},
{
"name": "symfony/finder",
"version": "v7.3.0",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d"
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d",
"reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d",
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"shasum": ""
},
"require": {
@@ -6991,7 +6755,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.0"
"source": "https://github.com/symfony/finder/tree/v7.3.2"
},
"funding": [
{
@@ -7002,25 +6766,29 @@
"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": "2024-12-30T19:00:26+00:00"
"time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v7.3.0",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "afb9a8038025e5dbc657378bfab9198d75f10fca"
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/afb9a8038025e5dbc657378bfab9198d75f10fca",
"reference": "afb9a8038025e5dbc657378bfab9198d75f10fca",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
"shasum": ""
},
"require": {
@@ -7058,7 +6826,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.3.0"
"source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
},
"funding": [
{
@@ -7069,12 +6837,16 @@
"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-04-04T13:12:05+00:00"
"time": "2025-07-15T11:36:08+00:00"
},
{
"name": "symfony/polyfill-iconv",
@@ -7296,16 +7068,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.3.1",
"version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42"
"reference": "53205bea27450dc5c65377518b3275e126d45e75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75",
"reference": "53205bea27450dc5c65377518b3275e126d45e75",
"shasum": ""
},
"require": {
@@ -7317,7 +7089,6 @@
"symfony/console": "<6.4"
},
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
@@ -7360,7 +7131,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.1"
"source": "https://github.com/symfony/var-dumper/tree/v7.3.2"
},
"funding": [
{
@@ -7371,12 +7142,16 @@
"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-06-27T19:55:54+00:00"
"time": "2025-07-29T20:02:46+00:00"
},
{
"name": "thecodingmachine/safe",

View File

@@ -10,6 +10,7 @@
;
; 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`)
@@ -43,6 +44,8 @@ SPC_SKIP_PHP_VERSION_CHECK="no"
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/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}"
; EXTENSION_DIR where the built php will look for extension when a .ini instructs to load them
; only useful for builds targeting not pure-static linking

View File

@@ -488,6 +488,7 @@
"opcache": {
"type": "builtin",
"arg-type-unix": "custom",
"arg-type-windows": "enable",
"zend-extension": true
},
"openssl": {
@@ -530,9 +531,10 @@
},
"notes": true,
"type": "builtin",
"arg-type": "with-path",
"arg-type": "custom",
"lib-depends": [
"libargon2"
"libargon2",
"openssl"
]
},
"pcntl": {

View File

@@ -797,6 +797,12 @@
"depot.h"
]
},
"re2c": {
"source": "re2c",
"bin-unix": [
"re2c"
]
},
"readline": {
"source": "readline",
"static-libs-unix": [

View File

@@ -733,7 +733,7 @@
"micro": {
"type": "git",
"path": "php-src/sapi/micro",
"rev": "84beta",
"rev": "php-85-win",
"url": "https://github.com/static-php/phpmicro",
"license": {
"type": "file",
@@ -932,6 +932,20 @@
"path": "LICENSE"
}
},
"re2c": {
"type": "ghrel",
"repo": "skvadrik/re2c",
"match": "re2c.+\\.tar\\.xz",
"prefer-stable": true,
"alt": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/re2c/re2c-4.3.tar.xz"
},
"license": {
"type": "file",
"path": "LICENSE"
}
},
"readline": {
"type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/readline/",
@@ -998,6 +1012,7 @@
"path": "php-src/ext/swoole",
"type": "ghtar",
"repo": "swoole/swoole-src",
"match": "v6\\.+",
"prefer-stable": true,
"license": {
"type": "file",

View File

@@ -238,6 +238,7 @@ const availablePhpVersions = [
'8.2',
'8.3',
'8.4',
'8.5',
];
const I18N = {

View File

@@ -32,7 +32,7 @@ Windows currently only supports the x86_64 architecture, and does not support 32
## Supported PHP Version
Currently, static php cli supports PHP versions 8.1 to 8.4, and theoretically supports PHP 8.0 and earlier versions.
Currently, static php cli supports PHP versions 8.1 to 8.5, and theoretically supports PHP 8.0 and earlier versions.
Simply select the earlier version when downloading.
However, due to some extensions and special components that have stopped supporting earlier versions of PHP,
static-php-cli will not explicitly support earlier versions.

View File

@@ -242,8 +242,8 @@ Also, it is available when downloading with the `--for-extensions` option.
```bash
# Specifying to download a beta version of PHP8.3
bin/spc download --all -U "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"
# Specifying to download a alpha version of PHP 8.5
bin/spc download --all -U "php-src:https://downloads.php.net/~edorian/php-8.5.0alpha2.tar.xz"
# Specifying to download an older version of the curl library
bin/spc download --all -U "curl:https://curl.se/download/curl-7.88.1.tar.gz"

View File

@@ -29,6 +29,6 @@ Windows 目前只支持 x86_64 架构,不支持 32 位 x86、不支持 arm64
## PHP 支持版本
目前static-php-cli 对 PHP 8.1 ~ 8.4 版本是支持的,对于 PHP 8.0 及更早版本理论上支持,只需下载时选择早期版本即可。
目前static-php-cli 对 PHP 8.1 ~ 8.5 版本是支持的,对于 PHP 8.0 及更早版本理论上支持,只需下载时选择早期版本即可。
但由于部分扩展和特殊组件已对早期版本的 PHP 停止了支持,所以 static-php-cli 不会明确支持早期版本。
我们推荐你编译尽可能新的 PHP 版本,以获得更好的体验。

View File

@@ -209,8 +209,8 @@ bin/spc download --from-zip=/path/to/your/download.zip
让下载器强制使用你指定的链接下载此 source 的包。使用方法为 `{source-name}:{url}` 即可,可同时重写多个库的下载地址。在使用 `--for-extensions` 选项下载时同样可用。
```bash
# 例如:指定下载测试版的 PHP8.3
bin/spc download --all -U "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"
# 例如:指定下载 Alpha 版的 PHP8.5
bin/spc download --all -U "php-src:https://downloads.php.net/~edorian/php-8.5.0alpha2.tar.xz"
# 指定下载旧版本的 curl 库
bin/spc download --all -U "curl:https://curl.se/download/curl-7.88.1.tar.gz"

View File

@@ -339,16 +339,21 @@ abstract class BuilderBase
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
}
public function getPHPVersion(): string
public function getPHPVersion(bool $exception_on_failure = true): string
{
if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
if (!$exception_on_failure) {
return 'unknown';
}
throw new WrongUsageException('PHP source files are not available, you need to download them first');
}
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION "(.*)"/', $file, $match) !== 0) {
return $match[1];
}
if (!$exception_on_failure) {
return 'unknown';
}
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
}
@@ -366,7 +371,7 @@ abstract class BuilderBase
}
$file = LockFile::getLockFullPath($lock);
}
if (preg_match('/php-(\d+\.\d+\.\d+(?:RC\d+)?)\.tar\.(?:gz|bz2|xz)/', $file, $match)) {
if (preg_match('/php-(\d+\.\d+\.\d+(?:RC\d+|alpha\d+|beta\d+)?)\.tar\.(?:gz|bz2|xz)/', $file, $match)) {
return $match[1];
}
return false;

View File

@@ -183,6 +183,14 @@ class Extension
return false;
}
/**
* Patch code before ./configure.bat for Windows
*/
public function patchBeforeWindowsConfigure(): bool
{
return false;
}
/**
* Patch code before make
* If you need to patch some code, overwrite this

View File

@@ -288,6 +288,16 @@ abstract class LibraryBase
return false;
}
/**
* Patch code before windows configure.bat
* If you need to patch some code, overwrite this
* return true if you patched something, false if not
*/
public function patchBeforeWindowsConfigure(): bool
{
return false;
}
/**
* Patch code before make
* If you need to patch some code, overwrite this

View File

@@ -61,7 +61,7 @@ class curl extends Extension
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
$extra_libs = getenv('SPC_EXTRA_LIBS');
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
if ($this->builder instanceof WindowsBuilder && !str_contains($extra_libs, 'secur32.lib')) {
$extra_libs .= ' secur32.lib';
putenv('SPC_EXTRA_LIBS=' . trim($extra_libs));

View File

@@ -49,7 +49,7 @@ class imap extends Extension
if (PHP_OS_FAMILY !== 'Linux' || SystemUtil::isMuslDist()) {
return $patched;
}
$extra_libs = trim(getenv('SPC_EXTRA_LIBS') . ' -lcrypt');
$extra_libs = trim((getenv('SPC_EXTRA_LIBS') ?: '') . ' -lcrypt');
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
return true;
}

View File

@@ -26,19 +26,26 @@ class opcache extends Extension
public function patchBeforeBuildconf(): bool
{
$version = $this->builder->getPHPVersion();
if (file_exists(SOURCE_PATH . '/php-src/.opcache_patched')) {
return false;
}
// if 8.2.0 <= PHP_VERSION < 8.2.23, we need to patch from legacy patch file
if (version_compare($this->builder->getPHPVersion(), '8.2.0', '>=') && version_compare($this->builder->getPHPVersion(), '8.2.23', '<')) {
if (version_compare($version, '8.2.0', '>=') && version_compare($version, '8.2.23', '<')) {
SourcePatcher::patchFile('spc_fix_static_opcache_before_80222.patch', SOURCE_PATH . '/php-src');
}
// if 8.3.0 <= PHP_VERSION < 8.3.11, we need to patch from legacy patch file
elseif (version_compare($this->builder->getPHPVersion(), '8.3.0', '>=') && version_compare($this->builder->getPHPVersion(), '8.3.11', '<')) {
elseif (version_compare($version, '8.3.0', '>=') && version_compare($version, '8.3.11', '<')) {
SourcePatcher::patchFile('spc_fix_static_opcache_before_80310.patch', SOURCE_PATH . '/php-src');
} else {
}
// if 8.3.12 <= PHP_VERSION < 8.5.0-dev, we need to patch from legacy patch file
elseif (version_compare($version, '8.5.0-dev', '<')) {
SourcePatcher::patchMicro(items: ['static_opcache']);
}
// PHP 8.5.0-dev and later supports static opcache without patching
else {
return false;
}
return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false;
}

View File

@@ -27,6 +27,19 @@ class openssl extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH;
return '--with-openssl=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $openssl_dir;
$args = '--with-openssl=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $openssl_dir;
if ($this->builder->getPHPVersionID() >= 80500 || ($this->builder->getPHPVersionID() >= 80400 && !$this->builder->getOption('enable-zts'))) {
$args .= ' --with-openssl-argon2 OPENSSL_LIBS="-lz"';
}
return $args;
}
public function getWindowsConfigureArg(bool $shared = false): string
{
$args = '--with-openssl';
if ($this->builder->getPHPVersionID() >= 80500 || ($this->builder->getPHPVersionID() >= 80400 && !$this->builder->getOption('enable-zts'))) {
$args .= ' --with-openssl-argon2';
}
return $args;
}
}

View File

@@ -42,4 +42,14 @@ class password_argon2 extends Extension
}
return $patched;
}
public function getConfigureArg(bool $shared = false): string
{
if ($this->builder->getLib('openssl') !== null) {
if ($this->builder->getPHPVersionID() >= 80500 || ($this->builder->getPHPVersionID() >= 80400 && !$this->builder->getOption('enable-zts'))) {
return '--without-password-argon2'; // use --with-openssl-argon2 in openssl extension instead
}
}
return '--with-password-argon2';
}
}

View File

@@ -24,7 +24,7 @@ class sqlsrv extends Extension
return false;
}
public function patchBeforeConfigure(): bool
public function patchBeforeWindowsConfigure(): bool
{
if ($this->pdo_sqlsrv_patched) {
// revert pdo_sqlsrv patch

View File

@@ -66,6 +66,17 @@ class LinuxBuilder extends UnixBuilderBase
$phpVersionID = $this->getPHPVersionID();
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '';
$opcache_jit = !$this->getOption('disable-opcache-jit', false);
if ($opcache_jit && ($phpVersionID >= 80500 || $this->getExt('opcache'))) {
// php 8.5 contains opcache extension by default,
// if opcache_jit is enabled for 8.5 or opcache enabled,
// we need to disable undefined behavior sanitizer.
f_putenv('SPC_COMPILER_EXTRA=-fno-sanitize=undefined');
} elseif ($opcache_jit) {
$opcache_jit = false;
}
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit ' : '--disable-opcache-jit ';
if ($this->getOption('enable-zts', false)) {
$maxExecutionTimers = $phpVersionID >= 80100 ? '--enable-zend-max-execution-timers ' : '';
$zts = '--enable-zts --disable-zend-signals ';
@@ -73,10 +84,7 @@ class LinuxBuilder extends UnixBuilderBase
$maxExecutionTimers = '';
$zts = '';
}
$disable_jit = $this->getOption('disable-opcache-jit', false) ? '--disable-opcache-jit ' : '';
if (!$disable_jit && $this->getExt('opcache')) {
f_putenv('SPC_COMPILER_EXTRA=-fno-sanitize=undefined');
}
$config_file_path = $this->getOption('with-config-file-path', false) ?
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
@@ -89,9 +97,10 @@ class LinuxBuilder extends UnixBuilderBase
$enableFrankenphp = ($build_target & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP;
// prepare build php envs
// $musl_flag = SPCTarget::getLibc() === 'musl' ? ' -D__MUSL__' : ' -U__MUSL__';
$php_configure_env = SystemUtil::makeEnvVarString([
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH,
'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!
]);
@@ -114,7 +123,7 @@ class LinuxBuilder extends UnixBuilderBase
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
$config_file_path .
$config_file_scan_dir .
$disable_jit .
$opcache_jit_arg .
$json_74 .
$zts .
$maxExecutionTimers .
@@ -335,6 +344,15 @@ class LinuxBuilder extends UnixBuilderBase
$this->patchPhpScripts();
}
/**
* Return extra variables for php make command.
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
* @throws \ReflectionException
* @throws \Throwable
*/
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'));

View File

@@ -28,6 +28,8 @@ use SPC\store\FileSystem;
class openssl extends LinuxLibraryBase
{
use \SPC\builder\traits\openssl;
public const NAME = 'openssl';
/**
@@ -37,8 +39,6 @@ class openssl extends LinuxLibraryBase
*/
public function build(): void
{
[,,$destdir] = SEPARATED_PATH;
$extra = '';
$ex_lib = '-ldl -pthread';
$arch = getenv('SPC_ARCH');

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* a template library class for unix
*/
class re2c extends LinuxLibraryBase
{
use \SPC\builder\unix\library\re2c;
public const NAME = 're2c';
}

View File

@@ -98,9 +98,17 @@ class MacOSBuilder extends UnixBuilderBase
$this->emitPatchPoint('before-php-configure');
SourcePatcher::patchBeforeConfigure($this);
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
$phpVersionID = $this->getPHPVersionID();
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '';
$zts = $this->getOption('enable-zts', false) ? '--enable-zts --disable-zend-signals ' : '';
$opcache_jit = !$this->getOption('disable-opcache-jit', false);
// disable opcache jit for PHP < 8.5.0 when opcache is not enabled
if ($opcache_jit && $phpVersionID < 80500 && !$this->getExt('opcache')) {
$opcache_jit = false;
}
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit ' : '--disable-opcache-jit ';
$config_file_path = $this->getOption('with-config-file-path', false) ?
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
@@ -135,6 +143,7 @@ class MacOSBuilder extends UnixBuilderBase
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
$opcache_jit_arg .
$config_file_path .
$config_file_scan_dir .
$json_74 .

View File

@@ -28,6 +28,8 @@ use SPC\store\FileSystem;
class openssl extends MacOSLibraryBase
{
use \SPC\builder\traits\openssl;
public const NAME = 'openssl';
/**

View File

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

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace SPC\builder\traits;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\PkgConfigUtil;
trait openssl
{
public function getLibVersion(): ?string
{
// get openssl version from source directory
if (file_exists("{$this->source_dir}/VERSION.dat")) {
// parse as INI
$version = parse_ini_file("{$this->source_dir}/VERSION.dat");
if ($version !== false) {
return "{$version['MAJOR']}.{$version['MINOR']}.{$version['PATCH']}";
}
}
// get openssl version from pkg-config
if (PHP_OS_FAMILY !== 'Windows') {
try {
return PkgConfigUtil::getModuleVersion('openssl');
} catch (RuntimeException) {
}
}
// get openssl version from header openssl/opensslv.h
if (file_exists(BUILD_INCLUDE_PATH . '/openssl/opensslv.h')) {
if (preg_match('/OPENSSL_VERSION_STR "(.*)"/', FileSystem::readFile(BUILD_INCLUDE_PATH . '/openssl/opensslv.h'), $match)) {
return $match[1];
}
}
return null;
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixCMakeExecutor;
trait re2c
{
protected function build(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DRE2C_BUILD_TESTS=OFF',
'-DRE2C_BUILD_EXAMPLES=OFF',
'-DRE2C_BUILD_DOCS=OFF',
'-DRE2C_BUILD_RE2D=OFF',
'-DRE2C_BUILD_RE2GO=OFF',
'-DRE2C_BUILD_RE2HS=OFF',
'-DRE2C_BUILD_RE2JAVA=OFF',
'-DRE2C_BUILD_RE2JS=OFF',
'-DRE2C_BUILD_RE2OCAML=OFF',
'-DRE2C_BUILD_RE2PY=OFF',
'-DRE2C_BUILD_RE2RUST=OFF',
'-DRE2C_BUILD_RE2SWIFT=OFF',
'-DRE2C_BUILD_RE2V=OFF',
'-DRE2C_BUILD_RE2ZIG=OFF',
)
->build();
}
}

View File

@@ -89,6 +89,9 @@ class WindowsBuilder extends BuilderBase
}
}
$opcache_jit = !$this->getOption('disable-opcache-jit', false);
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit=yes ' : '--enable-opcache-jit=no ';
if (($logo = $this->getOption('with-micro-logo')) !== null) {
// realpath
// $logo = realpath($logo);
@@ -115,6 +118,7 @@ class WindowsBuilder extends BuilderBase
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
$config_file_scan_dir .
$opcache_jit_arg .
"{$this->makeStaticExtensionArgs()} " .
$zts .
'"'

View File

@@ -159,7 +159,7 @@ class BuildPHPCommand extends BuildCommand
$indent_texts['UPX Pack'] = 'enabled';
}
$ver = $builder->getPHPVersionFromArchive() ?: $builder->getPHPVersion();
$ver = $builder->getPHPVersionFromArchive() ?: $builder->getPHPVersion(false);
$indent_texts['PHP Version'] = $ver;
if (!empty($not_included)) {
@@ -269,6 +269,7 @@ class BuildPHPCommand extends BuildCommand
} catch (WrongUsageException $e) {
// WrongUsageException is not an exception, it's a user error, so we just print the error message
logger()->critical($e->getMessage());
logger()->error($e->getTraceAsString());
return static::FAILURE;
} catch (\Throwable $e) {
if ($this->getOption('debug')) {

View File

@@ -108,12 +108,9 @@ class DownloadCommand extends BaseCommand
// Define PHP major version
$ver = $this->php_major_ver = $this->getOption('with-php');
define('SPC_BUILD_PHP_VERSION', $ver);
// match x.y
preg_match('/^\d+\.\d+$/', $ver, $matches);
if (!$matches) {
// match x.y.z
preg_match('/^\d+\.\d+\.\d+$/', $ver, $matches);
if (!$matches) {
if ($ver !== 'git' && !preg_match('/^\d+\.\d+$/', $ver)) {
// If not git, we need to check the version format
if (!preg_match('/^\d+\.\d+(\.\d+)?$/', $ver)) {
logger()->error("bad version arg: {$ver}, x.y or x.y.z required!");
return static::FAILURE;
}

View File

@@ -8,6 +8,7 @@ use SPC\builder\BuilderProvider;
use SPC\command\BaseCommand;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -41,7 +42,10 @@ class LibVerCommand extends BaseCommand
return static::FAILURE;
}
$builder->proveLibs([$this->getArgument('library')]);
// parse the dependencies
[, $libs] = DependencyUtil::getExtsAndLibs([], [$this->getArgument('library')]);
$builder->proveLibs($libs);
// Check whether lib is extracted
if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
@@ -51,7 +55,7 @@ class LibVerCommand extends BaseCommand
$version = $builder->getLib($this->getArgument('library'))->getLibVersion();
if ($version === null) {
$this->output->writeln("<error>Failed to get version of library {$this->getArgument('library')}</error>");
$this->output->writeln("<error>Failed to get version of library {$this->getArgument('library')}. The version getter for [{$this->getArgument('library')}] is not implemented.</error>");
return static::FAILURE;
}
$this->output->writeln("<info>{$version}</info>");

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace SPC\doctor;
#[\Attribute(\Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsCheckItem
{
public mixed $callback = null;

View File

@@ -16,7 +16,7 @@ class LinuxToolCheckList
use UnixSystemUtilTrait;
public const TOOLS_ALPINE = [
'make', 'bison', 'flex',
'make', 'bison', 're2c', 'flex',
'git', 'autoconf', 'automake', 'gettext-dev',
'tar', 'unzip', 'gzip',
'bzip2', 'cmake', 'gcc',
@@ -26,7 +26,7 @@ class LinuxToolCheckList
];
public const TOOLS_DEBIAN = [
'make', 'bison', 'flex',
'make', 'bison', 're2c', 'flex',
'git', 'autoconf', 'automake', 'autopoint',
'tar', 'unzip', 'gzip',
'bzip2', 'cmake', 'patch',
@@ -35,7 +35,7 @@ class LinuxToolCheckList
];
public const TOOLS_RHEL = [
'perl', 'make', 'bison', 'flex',
'perl', 'make', 'bison', 're2c', 'flex',
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip', 'gcc',
'bzip2', 'cmake', 'patch', 'which',

View File

@@ -19,6 +19,7 @@ class MacOSToolCheckList
'curl',
'make',
'bison',
're2c',
'flex',
'pkg-config',
'git',
@@ -61,6 +62,30 @@ class MacOSToolCheckList
return CheckResult::ok();
}
#[AsCheckItem('if bison version is 3.0 or later', limit_os: 'Darwin')]
public function checkBisonVersion(array $command_path = []): ?CheckResult
{
// if the bison command is /usr/bin/bison, it is the system bison that may be too old
if (($bison = $this->findCommand('bison', $command_path)) === null) {
return CheckResult::fail('bison is not installed or too old', 'build-tools', [['bison']]);
}
// check version: bison (GNU Bison) x.y(.z)
$version = shell()->execWithResult("{$bison} --version", false);
if (preg_match('/bison \(GNU Bison\) (\d+)\.(\d+)(?:\.(\d+))?/', $version[1][0], $matches)) {
$major = (int) $matches[1];
// major should be 3 or later
if ($major < 3) {
// find homebrew keg-only bison
if ($command_path !== []) {
return CheckResult::fail("Current {$bison} version is too old: " . $matches[0]);
}
return $this->checkBisonVersion(['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin']);
}
return CheckResult::ok($matches[0]);
}
return CheckResult::fail('bison version cannot be determined');
}
#[AsFixItem('brew')]
public function fixBrew(): bool
{

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace SPC\doctor\item;
use SPC\builder\BuilderProvider;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
use SPC\exception\DownloaderException;
use SPC\store\Config;
use SPC\store\Downloader;
use Symfony\Component\Console\Input\ArgvInput;
class Re2cVersionCheck
{
use UnixSystemUtilTrait;
#[AsCheckItem('if re2c version >= 1.0.3', limit_os: 'Linux', level: 20)]
#[AsCheckItem('if re2c version >= 1.0.3', limit_os: 'Darwin', level: 20)]
public function checkRe2cVersion(): ?CheckResult
{
$ver = shell(false)->execWithResult('re2c --version', false);
// match version: re2c X.X(.X)
if ($ver[0] !== 0 || !preg_match('/re2c\s+(\d+\.\d+(\.\d+)?)/', $ver[1][0], $matches)) {
return CheckResult::fail('Failed to get re2c version', 'build-re2c');
}
$version_string = $matches[1];
if (version_compare($version_string, '1.0.3') < 0) {
return CheckResult::fail('re2c version is too low (' . $version_string . ')', 'build-re2c');
}
return CheckResult::ok($version_string);
}
#[AsFixItem('build-re2c')]
public function buildRe2c(): bool
{
try {
Downloader::downloadSource('re2c');
} catch (DownloaderException) {
logger()->warning('Failed to download re2c version, trying alternative');
$alt = Config::getSource('re2c');
$alt = [...$alt, ...$alt['alt'] ?? []];
Downloader::downloadSource('re2c', $alt);
}
$builder = BuilderProvider::makeBuilderByInput(new ArgvInput([]));
$builder->proveLibs(['re2c']);
$builder->setupLibs();
return true;
}
}

View File

@@ -10,20 +10,6 @@ class ExceptionHandler
private static ?ExceptionHandler $obj = null;
private function __construct()
{
$whoops_class = 'Whoops\Run';
$collision_class = 'NunoMaduro\Collision\Handler';
if (class_exists($collision_class) && class_exists($whoops_class)) {
/* @phpstan-ignore-next-line */
$this->whoops = new $whoops_class();
$this->whoops->allowQuit(false);
$this->whoops->writeToOutput(false);
$this->whoops->pushHandler(new $collision_class());
$this->whoops->register();
}
}
public static function getInstance(): ExceptionHandler
{
if (self::$obj === null) {
@@ -34,13 +20,8 @@ class ExceptionHandler
public function handle(\Throwable $e): void
{
if (is_null($this->whoops)) {
logger()->error('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')');
logger()->error($e->getTraceAsString());
return;
}
$this->whoops->handleException($e);
logger()->error('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')');
logger()->error($e->getTraceAsString());
logger()->critical('You can report this exception to static-php-cli GitHub repo.');
}
}

View File

@@ -7,6 +7,7 @@ namespace SPC\store;
use SPC\builder\BuilderBase;
use SPC\builder\linux\SystemUtil;
use SPC\builder\unix\UnixBuilderBase;
use SPC\builder\windows\WindowsBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
@@ -68,6 +69,35 @@ class SourcePatcher
);
}
// Fix PHP VS version
if ($builder instanceof WindowsBuilder) {
// get vs version
$vc = \SPC\builder\windows\SystemUtil::findVisualStudio();
$vc_matches = match ($vc['version']) {
'vs17' => ['VS17', 'Visual C++ 2022'],
'vs16' => ['VS16', 'Visual C++ 2019'],
default => ['unknown', 'unknown'],
};
// patch php-src/win32/build/confutils.js
FileSystem::replaceFileStr(
SOURCE_PATH . '\php-src\win32\build\confutils.js',
'var name = "unknown";',
"var name = short ? \"{$vc_matches[0]}\" : \"{$vc_matches[1]}\";return name;"
);
}
// patch configure.ac
$musl = SPCTarget::getLibc() === 'musl';
FileSystem::backupFile(SOURCE_PATH . '/php-src/configure.ac');
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/configure.ac',
'if command -v ldd >/dev/null && ldd --version 2>&1 | grep ^musl >/dev/null 2>&1',
'if ' . ($musl ? 'true' : 'false')
);
if (getenv('SPC_LIBC') === false && ($libc = SPCTarget::getLibc()) !== null) {
putenv("SPC_LIBC={$libc}");
}
// patch php-src/build/php.m4 PKG_CHECK_MODULES -> PKG_CHECK_MODULES_STATIC
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/build/php.m4', 'PKG_CHECK_MODULES(', 'PKG_CHECK_MODULES_STATIC(');
@@ -87,7 +117,8 @@ class SourcePatcher
public static function patchBeforeConfigure(BuilderBase $builder): void
{
foreach ($builder->getExts() as $ext) {
if ($ext->patchBeforeConfigure() === true) {
$patch = $builder instanceof WindowsBuilder ? $ext->patchBeforeWindowsConfigure() : $ext->patchBeforeConfigure();
if ($patch === true) {
logger()->info("Extension [{$ext->getName()}] patched before configure");
}
}
@@ -97,7 +128,14 @@ class SourcePatcher
}
}
// patch capstone
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"');
if (is_unix()) {
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"');
}
if (file_exists(SOURCE_PATH . '/php-src/configure.ac.bak')) {
// restore configure.ac
FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/configure.ac');
}
}
/**
@@ -132,7 +170,7 @@ class SourcePatcher
}
$patch_list = $spc_micro_patches;
$patches = [];
$serial = ['80', '81', '82', '83', '84'];
$serial = ['80', '81', '82', '83', '84', '85'];
foreach ($patch_list as $patchName) {
if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) {
$patches[] = "sapi/micro/patches/{$patchName}.patch";
@@ -584,7 +622,7 @@ class SourcePatcher
*/
public static function patchSPCVersionToPHP(string $version = 'unknown'): void
{
// detect patch
// detect patch (remove this when 8.3 deprecated)
$file = FileSystem::readFile(SOURCE_PATH . '/php-src/main/main.c');
if (!str_contains($file, 'static-php-cli.version')) {
logger()->debug('Inserting static-php-cli.version to php-src');

View File

@@ -21,8 +21,14 @@ 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.3';
Downloader::downloadSource('php-src', $this->getLatestPHPInfo($major), $force);
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.4';
if ($major === '8.5') {
Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://downloads.php.net/~daniels/php-8.5.0alpha4.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', self::getLatestPHPInfo($major), $force);
}
}
/**
@@ -36,7 +42,7 @@ class PhpSource extends CustomSourceBase
// 查找最新的小版本号
$info = json_decode(Downloader::curlExec(
url: "https://www.php.net/releases/index.php?json&version={$major_version}",
retries: (int) getenv('SPC_DOWNLOAD_RETRIES')
retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)
), true);
if (!isset($info['version'])) {
throw new DownloaderException("Version {$major_version} not found.");

View File

@@ -7,6 +7,7 @@ namespace SPC\toolchain;
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
@@ -37,8 +38,19 @@ class ClangNativeToolchain implements ToolchainInterface
'Linux' => LinuxSystemUtil::findCommand($command) ?? throw new WrongUsageException("{$command} not found, please install it or set {$env} to a valid path."),
'Darwin' => MacOSSystemUtil::findCommand($command) ?? throw new WrongUsageException("{$command} not found, please install it or set {$env} to a valid path."),
'BSD' => FreeBSDSystemUtil::findCommand($command) ?? throw new WrongUsageException("{$command} not found, please install it or set {$env} to a valid path."),
default => throw new \RuntimeException(__CLASS__ . ' is not supported on ' . PHP_OS_FAMILY . '.'),
default => throw new RuntimeException(__CLASS__ . ' is not supported on ' . PHP_OS_FAMILY . '.'),
};
}
}
public function getCompilerInfo(): ?string
{
$compiler = getenv('CC') ?: 'clang';
$version = shell(false)->execWithResult("{$compiler} --version", false);
$head = pathinfo($compiler, PATHINFO_BASENAME);
if ($version[0] === 0 && preg_match('/clang version (\d+.\d+.\d+)/', $version[1][0], $match)) {
return "{$head} {$match[1]}";
}
return $head;
}
}

View File

@@ -35,4 +35,15 @@ class GccNativeToolchain implements ToolchainInterface
};
}
}
public function getCompilerInfo(): ?string
{
$compiler = getenv('CC') ?: 'gcc';
$version = shell(false)->execWithResult("{$compiler} --version", false);
$head = pathinfo($compiler, PATHINFO_BASENAME);
if ($version[0] === 0 && preg_match('/gcc.*(\d+.\d+.\d+)/', $version[1][0], $match)) {
return "{$head} {$match[1]}";
}
return $head;
}
}

View File

@@ -9,4 +9,9 @@ class MSVCToolchain implements ToolchainInterface
public function initEnv(): void {}
public function afterInit(): void {}
public function getCompilerInfo(): ?string
{
return null;
}
}

View File

@@ -36,4 +36,15 @@ class MuslToolchain implements ToolchainInterface
throw new WrongUsageException('You are building with musl-libc target in glibc distro, but musl-toolchain is not installed, please install musl-toolchain first. (You can use `doctor` command to install it)');
}
}
public function getCompilerInfo(): ?string
{
$compiler = getenv('CC') ?: getenv('SPC_LINUX_DEFAULT_CC');
$version = shell(false)->execWithResult("{$compiler} --version", false);
$head = pathinfo($compiler, PATHINFO_BASENAME);
if ($version[0] === 0 && preg_match('/linux-musl-cc.*(\d+.\d+.\d+)/', $version[1][0], $match)) {
return "{$head} {$match[1]}";
}
return $head;
}
}

View File

@@ -27,4 +27,12 @@ interface ToolchainInterface
* post-initialization setup or validation.
*/
public function afterInit(): void;
/**
* Returns the compiler name and version for toolchains.
*
* If the toolchain does not support compiler information,
* this method can return null.
*/
public function getCompilerInfo(): ?string;
}

View File

@@ -61,6 +61,10 @@ class ToolchainManager
}
$toolchain = getenv('SPC_TOOLCHAIN');
/* @var ToolchainInterface $toolchain */
(new $toolchain())->afterInit();
$instance = new $toolchain();
$instance->afterInit();
if (getenv('PHP_BUILD_COMPILER') === false && ($compiler_info = $instance->getCompilerInfo())) {
GlobalEnvManager::putenv("PHP_BUILD_COMPILER={$compiler_info}");
}
}
}

View File

@@ -68,4 +68,10 @@ class ZigToolchain implements ToolchainInterface
GlobalEnvManager::putenv("SPC_EXTRA_LIBS={$extra_libs}");
}
}
public function getCompilerInfo(): ?string
{
$version = shell(false)->execWithResult('zig version', false)[1][0] ?? '';
return trim("zig {$version}");
}
}

View File

@@ -47,20 +47,20 @@ class ConfigValidator
// check if license is valid
if (isset($src['license'])) {
if (!is_assoc_array($src['license'])) {
throw new ValidationException("source {$name} license must be object");
if (!is_array($src['license'])) {
throw new ValidationException("source {$name} license must be an object or array");
}
if (!isset($src['license']['type'])) {
throw new ValidationException("source {$name} license must have type");
}
if (!in_array($src['license']['type'], ['file', 'text'])) {
throw new ValidationException("source {$name} license type is invalid");
}
if ($src['license']['type'] === 'file' && !isset($src['license']['path'])) {
throw new ValidationException("source {$name} license file must have path");
}
if ($src['license']['type'] === 'text' && !isset($src['license']['text'])) {
throw new ValidationException("source {$name} license text must have text");
if (is_assoc_array($src['license'])) {
self::checkSingleLicense($src['license'], $name);
} elseif (is_list_array($src['license'])) {
foreach ($src['license'] as $license) {
if (!is_assoc_array($license)) {
throw new ValidationException("source {$name} license must be an object or array");
}
self::checkSingleLicense($license, $name);
}
} else {
throw new ValidationException("source {$name} license must be an object or array");
}
}
}
@@ -415,6 +415,31 @@ class ConfigValidator
return $craft;
}
/**
* @throws ValidationException
*/
private static function checkSingleLicense(array $license, string $name): void
{
if (!is_assoc_array($license)) {
throw new ValidationException("source {$name} license must be an object");
}
if (!isset($license['type'])) {
throw new ValidationException("source {$name} license must have type");
}
if (!in_array($license['type'], ['file', 'text'])) {
throw new ValidationException("source {$name} license type is invalid");
}
if (!in_array($license['type'], ['file', 'text'])) {
throw new ValidationException("source {$name} license type is invalid");
}
if ($license['type'] === 'file' && !isset($license['path'])) {
throw new ValidationException("source {$name} license file must have path");
}
if ($license['type'] === 'text' && !isset($license['text'])) {
throw new ValidationException("source {$name} license text must have text");
}
}
/**
* Validate source type configuration (shared between source.json and pkg.json)
*

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\util;
use SPC\builder\macos\SystemUtil;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\toolchain\ToolchainManager;
@@ -117,6 +118,15 @@ class GlobalEnvManager
if (!filter_var(getenv('SPC_SKIP_TOOLCHAIN_CHECK'), FILTER_VALIDATE_BOOL)) {
ToolchainManager::afterInitToolchain();
}
// test bison
if (PHP_OS_FAMILY === 'Darwin') {
if ($bison = SystemUtil::findCommand('bison', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin'])) {
self::putenv("BISON={$bison}");
}
if ($yacc = SystemUtil::findCommand('yacc', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin'])) {
self::putenv("YACC={$yacc}");
}
}
}
/**

View File

@@ -14,6 +14,21 @@ use SPC\exception\RuntimeException;
*/
class PkgConfigUtil
{
/**
* Returns the version of a module.
* This method uses `pkg-config --modversion` to get the version of the specified module.
* If the module is not found, it will throw a RuntimeException.
*
* @param string $pkg_config_str .pc file str, accepts multiple files
* @return string version string, e.g. "1.2.3"
* @throws RuntimeException
*/
public static function getModuleVersion(string $pkg_config_str): string
{
$result = self::execWithResult("pkg-config --modversion {$pkg_config_str}");
return trim($result);
}
/**
* Get CFLAGS from pkg-config
*

View File

@@ -99,8 +99,11 @@ class SPCTarget
*/
public static function getLibcVersion(): ?string
{
$libc = self::getLibc();
return SystemUtil::getLibcVersionIfExists($libc);
if (PHP_OS_FAMILY === 'Linux') {
$libc = self::getLibc();
return SystemUtil::getLibcVersionIfExists($libc);
}
return null;
}
/**

View File

@@ -6,13 +6,27 @@ assert(function_exists('curl_init'));
assert(function_exists('curl_setopt'));
assert(function_exists('curl_exec'));
assert(function_exists('curl_close'));
assert(function_exists('curl_version'));
$curl_version = curl_version();
if (stripos($curl_version['ssl_version'], 'schannel') !== false) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://captive.apple.com/');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
$data = curl_exec($curl);
curl_close($curl);
assert($data !== false);
$domain_list = [
'https://captive.apple.com/',
'https://detectportal.firefox.com/',
'https://static-php.dev/',
'https://www.example.com/',
];
$valid = false;
foreach ($domain_list as $domain) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $domain);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
$data = curl_exec($curl);
curl_close($curl);
if ($data !== false) {
$valid = true;
break;
}
}
assert($valid);
}

View File

@@ -5,5 +5,32 @@ declare(strict_types=1);
assert(function_exists('openssl_digest'));
assert(openssl_digest('123456', 'md5') === 'e10adc3949ba59abbe56e057f20f883e');
if (file_exists('/etc/ssl/openssl.cnf')) {
assert(file_get_contents('https://captive.apple.com/') !== false);
$domain_list = [
'captive.apple.com',
'detectportal.firefox.com',
'static-php.dev',
'www.example.com',
];
$valid = false;
foreach ($domain_list as $domain) {
$ssloptions = [
'capture_peer_cert' => true,
'capture_peer_cert_chain' => true,
'allow_self_signed' => false,
'CN_match' => $domain,
'verify_peer' => true,
'SNI_enabled' => true,
'SNI_server_name' => $domain,
];
$context = stream_context_create(['ssl' => $ssloptions]);
$result = stream_socket_client("ssl://{$domain}:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
if ($result !== false) {
$valid = true;
break;
}
}
assert($valid);
}
if (PHP_VERSION_ID >= 80500 && defined('OPENSSL_VERSION_NUMBER') && OPENSSL_VERSION_NUMBER >= 0x30200000) {
assert(function_exists('openssl_password_hash'));
}

View File

@@ -6,9 +6,12 @@ use SPC\builder\freebsd\SystemUtil as BSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\builder\windows\SystemUtil as WindowsSystemUtil;
use SPC\ConsoleApplication;
use SPC\store\FileSystem;
use SPC\util\GlobalEnvManager;
// static-php-cli version string
const SPC_VERSION = ConsoleApplication::VERSION;
// output path for everything, other paths are defined relative to this by default
define('BUILD_ROOT_PATH', FileSystem::convertPath(is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot')));
// output path for header files for development
@@ -44,6 +47,7 @@ define('SEPARATED_PATH', [
]);
// add these to env vars with same name
GlobalEnvManager::putenv('SPC_VERSION=' . SPC_VERSION);
GlobalEnvManager::putenv('BUILD_ROOT_PATH=' . BUILD_ROOT_PATH);
GlobalEnvManager::putenv('BUILD_INCLUDE_PATH=' . BUILD_INCLUDE_PATH);
GlobalEnvManager::putenv('BUILD_LIB_PATH=' . BUILD_LIB_PATH);

View File

@@ -17,15 +17,17 @@ $test_php_version = [
// '8.2',
// '8.3',
'8.4',
// '8.5',
'git',
];
// test os (macos-13, macos-14, macos-15, ubuntu-latest, windows-latest are available)
$test_os = [
'macos-13', // bin/spc for x86_64
// 'macos-13', // bin/spc for x86_64
// 'macos-14', // bin/spc for arm64
'macos-15', // bin/spc for arm64
// 'ubuntu-latest', // bin/spc-alpine-docker for x86_64
'ubuntu-22.04', // bin/spc-gnu-docker for x86_64
// 'macos-15', // bin/spc for arm64
'ubuntu-latest', // bin/spc-alpine-docker for x86_64
// 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64
'ubuntu-24.04', // bin/spc for x86_64
'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64
'ubuntu-24.04-arm', // bin/spc for arm64
@@ -41,15 +43,15 @@ $no_strip = false;
$upx = false;
// whether to test frankenphp build, only available for macos and linux
$frankenphp = true;
$frankenphp = false;
// prefer downloading pre-built packages to speed up the build process
$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' => 'ast,bcmath,calendar,ctype,dba,dom,exif,fileinfo,filter,libxml,mbregex,mbstring,pcntl,phar,posix,session,simplexml,sockets,sodium,tokenizer,xml,xmlreader,xmlwriter,zlib',
'Windows' => 'intl',
'Linux', 'Darwin' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pdo,pdo_mysql,pdo_sqlite,phar,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip',
'Windows' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pdo,pdo_mysql,pdo_sqlite,phar,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip',
};
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
@@ -60,7 +62,7 @@ $shared_extensions = match (PHP_OS_FAMILY) {
};
// If you want to test lib-suggests for all extensions and libraries, set it to true.
$with_suggested_libs = true;
$with_suggested_libs = false;
// If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true.
$with_libs = match (PHP_OS_FAMILY) {
@@ -72,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',
};

View File

@@ -19,6 +19,10 @@ final class PkgConfigUtilTest extends TestCase
public static function setUpBeforeClass(): void
{
if (PHP_OS_FAMILY === 'Windows') {
// Skip tests on Windows as pkg-config is not typically available
self::markTestSkipped('PkgConfigUtil tests are not applicable on Windows.');
}
parent::setUpBeforeClass();
// Save original PATH

View File

@@ -21,6 +21,10 @@ class SPCConfigUtilTest extends TestCase
*/
public static function setUpBeforeClass(): void
{
if (PHP_OS_FAMILY === 'Windows') {
// Skip tests on Windows as SPCConfigUtil is not applicable
self::markTestSkipped('SPCConfigUtil tests are not applicable on Windows.');
}
$testdir = WORKING_DIR . '/.configtest';
FileSystem::createDir($testdir);
FileSystem::writeFile($testdir . '/lib.json', file_get_contents(ROOT_DIR . '/config/lib.json'));