diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fa9e646f..132b33f0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -175,7 +175,7 @@ jobs:
key: php-dependencies-${{ matrix.os }}
- name: "Install Dependencies"
- run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
+ run: composer update -vvv --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-plugins
- name: "Run Build Tests (doctor)"
run: php src/globals/test-extensions.php doctor_cmd ${{ matrix.os }} ${{ matrix.php }}
diff --git a/config/env.ini b/config/env.ini
index 044de07b..a1f149c5 100644
--- a/config/env.ini
+++ b/config/env.ini
@@ -65,7 +65,7 @@ PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools"
; upx executable path
UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe"
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
-SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static
+SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static,win32_api
[linux]
; Linux can use different build toolchains.
diff --git a/config/ext.json b/config/ext.json
index e5aa0ce3..303e0dde 100644
--- a/config/ext.json
+++ b/config/ext.json
@@ -756,6 +756,18 @@
"apcu"
]
},
+ "snmp": {
+ "support": {
+ "Windows": "wip",
+ "BSD": "wip"
+ },
+ "type": "builtin",
+ "arg-type-unix": "with",
+ "arg-type-windows": "with",
+ "lib-depends": [
+ "net-snmp"
+ ]
+ },
"soap": {
"support": {
"BSD": "wip"
@@ -988,6 +1000,14 @@
"type": "builtin",
"build-with-php": true
},
+ "trader": {
+ "support": {
+ "BSD": "wip",
+ "Windows": "wip"
+ },
+ "type": "external",
+ "source": "ext-trader"
+ },
"uuid": {
"support": {
"Windows": "wip",
diff --git a/config/lib.json b/config/lib.json
index 4a01ad49..8d1da464 100644
--- a/config/lib.json
+++ b/config/lib.json
@@ -611,8 +611,8 @@
},
"libxml2": {
"source": "libxml2",
- "static-libs-unix": [
- "libxml2.a"
+ "pkg-configs": [
+ "libxml-2.0"
],
"static-libs-windows": [
"libxml2s.lib",
@@ -701,6 +701,17 @@
"libncurses.a"
]
},
+ "net-snmp": {
+ "source": "net-snmp",
+ "pkg-configs": [
+ "netsnmp",
+ "netsnmp-agent"
+ ],
+ "lib-depends": [
+ "openssl",
+ "zlib"
+ ]
+ },
"nghttp2": {
"source": "nghttp2",
"static-libs-unix": [
diff --git a/config/source.json b/config/source.json
index 349ba68c..ee3f8948 100644
--- a/config/source.json
+++ b/config/source.json
@@ -233,6 +233,16 @@
"path": "LICENSE"
}
},
+ "ext-trader": {
+ "type": "url",
+ "url": "https://pecl.php.net/get/trader",
+ "path": "php-src/ext/trader",
+ "filename": "trader.tgz",
+ "license": {
+ "type": "file",
+ "path": "LICENSE"
+ }
+ },
"ext-uuid": {
"type": "url",
"url": "https://pecl.php.net/get/uuid",
@@ -762,7 +772,7 @@
"micro": {
"type": "git",
"path": "php-src/sapi/micro",
- "rev": "php-85-win",
+ "rev": "master",
"url": "https://github.com/static-php/phpmicro",
"license": {
"type": "file",
@@ -810,6 +820,14 @@
"path": "COPYING"
}
},
+ "net-snmp": {
+ "type": "ghtagtar",
+ "repo": "net-snmp/net-snmp",
+ "license": {
+ "type": "file",
+ "path": "COPYING"
+ }
+ },
"nghttp2": {
"type": "ghrel",
"repo": "nghttp2/nghttp2",
diff --git a/docs/.vitepress/components/CliGenerator.vue b/docs/.vitepress/components/CliGenerator.vue
index 430dec24..378f6eae 100644
--- a/docs/.vitepress/components/CliGenerator.vue
+++ b/docs/.vitepress/components/CliGenerator.vue
@@ -744,10 +744,26 @@ h2 {
}
select {
- border-radius: 4px;
+ border-radius: 8px;
border: 1px solid var(--vp-c-divider);
- padding: 0 4px;
+ padding: 8px 12px;
width: 300px;
+ background-color: var(--vp-c-bg-soft);
+ color: var(--vp-c-text-1);
+ font-size: 14px;
+ transition: all 0.2s ease;
+ cursor: pointer;
+ outline: none;
+}
+
+select:hover {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-bg);
+}
+
+select:focus {
+ border-color: var(--vp-c-brand-1);
+ box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
}
.my-btn {
@@ -781,17 +797,160 @@ select {
.textarea {
border: 1px solid var(--vp-c-divider);
- border-radius: 4px;
- width: calc(100% - 12px);
- padding: 4px 8px;
+ border-radius: 8px;
+ width: calc(100% - 24px);
+ padding: 12px;
+ background-color: var(--vp-c-bg-soft);
+ color: var(--vp-c-text-1);
+ font-size: 14px;
+ font-family: var(--vp-font-family-mono);
+ line-height: 1.5;
+ transition: all 0.2s ease;
+ outline: none;
+ resize: vertical;
+}
+
+.textarea:hover {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-bg);
+}
+
+.textarea:focus {
+ border-color: var(--vp-c-brand-1);
+ box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
}
.input {
display: block;
border: 1px solid var(--vp-c-divider);
- border-radius: 4px;
+ border-radius: 8px;
width: 100%;
- padding: 4px 8px;
+ padding: 10px 12px;
+ background-color: var(--vp-c-bg-soft);
+ color: var(--vp-c-text-1);
+ font-size: 14px;
+ transition: all 0.2s ease;
+ outline: none;
+ box-sizing: border-box;
+}
+
+.input:hover {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-bg);
+}
+
+.input:focus {
+ border-color: var(--vp-c-brand-1);
+ box-shadow: 0 0 0 3px var(--vp-c-brand-soft);
+}
+
+/* Radio button styles */
+input[type="radio"] {
+ appearance: none;
+ width: 18px;
+ height: 18px;
+ border: 2px solid var(--vp-c-border);
+ border-radius: 50%;
+ background-color: var(--vp-c-bg);
+ cursor: pointer;
+ position: relative;
+ vertical-align: middle;
+ margin-right: 6px;
+ transition: all 0.2s ease;
+}
+
+input[type="radio"]:hover {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-bg-soft);
+}
+
+input[type="radio"]:checked {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-brand-1);
+}
+
+input[type="radio"]:checked::after {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: var(--vp-c-bg);
+}
+
+input[type="radio"]:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+/* Checkbox styles */
+input[type="checkbox"] {
+ appearance: none;
+ width: 18px;
+ height: 18px;
+ border: 2px solid var(--vp-c-border);
+ border-radius: 4px;
+ background-color: var(--vp-c-bg);
+ cursor: pointer;
+ position: relative;
+ vertical-align: middle;
+ margin-right: 6px;
+ transition: all 0.2s ease;
+}
+
+input[type="checkbox"]:hover {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-bg-soft);
+}
+
+input[type="checkbox"]:checked {
+ border-color: var(--vp-c-brand-1);
+ background-color: var(--vp-c-brand-1);
+}
+
+input[type="checkbox"]:checked::after {
+ content: '';
+ position: absolute;
+ top: 2px;
+ left: 5px;
+ width: 4px;
+ height: 8px;
+ border: solid var(--vp-c-bg);
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+}
+
+input[type="checkbox"]:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+/* Label styles */
+label {
+ cursor: pointer;
+ user-select: none;
+ color: var(--vp-c-text-1);
+ font-size: 14px;
+ line-height: 1.5;
+ transition: color 0.2s ease;
+}
+
+label:hover {
+ color: var(--vp-c-brand-1);
+}
+
+input[type="radio"]:disabled + label,
+input[type="checkbox"]:disabled + label {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+input[type="radio"]:disabled + label:hover,
+input[type="checkbox"]:disabled + label:hover {
+ color: var(--vp-c-text-1);
}
.command-container {
diff --git a/docs/.vitepress/components/Contributors.vue b/docs/.vitepress/components/Contributors.vue
new file mode 100644
index 00000000..c1f474b0
--- /dev/null
+++ b/docs/.vitepress/components/Contributors.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
Loading contributors...
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index bf210a99..8ddc9c1f 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -4,7 +4,7 @@ import sidebarZh from "./sidebar.zh";
// https://vitepress.dev/reference/site-config
export default {
- title: "static-php-cli",
+ title: "Static PHP",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
locales: {
en: {
@@ -44,6 +44,7 @@ export default {
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
+ logo: '/images/static-php_nobg.png',
nav: [],
socialLinks: [
{icon: 'github', link: 'https://github.com/crazywhalecc/static-php-cli'}
diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css
index b09fc682..ccf44074 100644
--- a/docs/.vitepress/theme/style.css
+++ b/docs/.vitepress/theme/style.css
@@ -4,3 +4,21 @@
max-width: 1000px !important;
}
+
+.vp-doc .contributors-header h2 {
+ padding-top: 0;
+ border-top: none;
+}
+
+.vp-doc .sponsors-header h2 {
+ padding-top: 0;
+ border-top: none;
+}
+
+.dark .VPImage.logo {
+ filter: contrast(0.7);
+}
+
+.dark .VPImage.image-src {
+ filter: contrast(0.7);
+}
diff --git a/docs/en/faq/index.md b/docs/en/faq/index.md
index a942244c..b65dca46 100644
--- a/docs/en/faq/index.md
+++ b/docs/en/faq/index.md
@@ -44,6 +44,11 @@ So on macOS, you can **directly** use SPC to build statically compiled PHP binar
2. You will get `buildroot/modules/xdebug.so` and `buildroot/bin/php`.
3. The `xdebug.so` file could be used for php that version and thread-safe are the same.
+For the Windows platform, since officially built extensions (such as `php_yaml.dll`) force the use of the `php8.dll` dynamic library as a link, and statically built PHP does not include any dynamic libraries other than system libraries,
+php.exe built by static-php cannot load officially built dynamic extensions. Since static-php-cli does not yet support building dynamic extensions, there is currently no way to load dynamic extensions with static-php.
+
+However, Windows can normally use the `FFI` extension to load other dll files and call them.
+
## Can it support Oracle database extension?
Some extensions that rely on closed source libraries, such as `oci8`, `sourceguardian`, etc.,
diff --git a/docs/en/index.md b/docs/en/index.md
index 3aee0612..7d80bf2f 100644
--- a/docs/en/index.md
+++ b/docs/en/index.md
@@ -3,11 +3,14 @@
layout: home
hero:
- name: "static-php-cli"
+ 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
+ alt: Static PHP CLI Logo
actions:
- theme: brand
- text: Guide
+ text: Get Started
link: ./guide/
features:
@@ -19,3 +22,121 @@ features:
details: static-php-cli comes with dependency management and supports installation of different types of PHP extensions.
---
+
+
+
+
+
+
+
diff --git a/docs/index.md b/docs/index.md
index f667ce44..b2b25ded 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -3,8 +3,11 @@
layout: home
hero:
- name: "static-php-cli"
+ 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
+ alt: Static PHP CLI Logo
actions:
- theme: brand
text: Get Started
@@ -24,13 +27,121 @@ features:
-## Special Sponsors
+
-
+
+
+
diff --git a/docs/public/images/static-php_nobg.png b/docs/public/images/static-php_nobg.png
new file mode 100644
index 00000000..64b6695c
Binary files /dev/null and b/docs/public/images/static-php_nobg.png differ
diff --git a/docs/zh/faq/index.md b/docs/zh/faq/index.md
index 27611a50..142a1503 100644
--- a/docs/zh/faq/index.md
+++ b/docs/zh/faq/index.md
@@ -41,6 +41,11 @@ buildroot/bin/php -d "zend_extension=/path/to/php{PHP_VER}-{ts/nts}/xdebug.so" -
2. 你将获得 `buildroot/modules/xdebug.so` 和 `buildroot/bin/php`。
3. `xdebug.so` 文件可用于版本和线程安全相同的 php。
+对于 Windows 平台,由于官方构建的扩展(如 `php_yaml.dll`)强制使用了 `php8.dll` 动态库作为链接,静态构建的 PHP 不包含任何系统库以外的动态库,
+所以 Windows 下无法加载官方构建的动态扩展。 由于 static-php-cli 还暂未支持构建动态扩展,所以目前还没有让 static-php 加载动态扩展的方法。
+
+不过,Windows 可以正常使用 `FFI` 扩展加载其他的 dll 文件并调用。
+
## 可以支持 Oracle 数据库扩展吗?
部分依赖库闭源的扩展,如 `oci8`、`sourceguardian` 等,它们没有提供纯静态编译的依赖库文件(`.a`),仅提供了动态依赖库文件(`.so`),
diff --git a/docs/zh/index.md b/docs/zh/index.md
index bfa81cf4..265d3974 100644
--- a/docs/zh/index.md
+++ b/docs/zh/index.md
@@ -3,18 +3,140 @@
layout: home
hero:
- name: "static-php-cli"
+ name: "Static PHP"
tagline: "在 Linux、macOS、FreeBSD、Windows 上与 PHP 项目一起构建独立的 PHP 二进制文件,并包含流行的扩展。"
+ image:
+ src: /images/static-php_nobg.png
+ alt: Static PHP CLI Logo
actions:
- theme: brand
- text: 指南
+ text: 开始使用
link: ./guide/
features:
-- title: 静态二进制
- details: 您可以轻松地编译一个独立的 PHP 二进制文件以供嵌入程序使用。包括 cli、fpm、micro。
-- title: phpmicro 自执行二进制
- details: 您可以使用 micro SAPI 编译一个自解压的可执行文件,并将 PHP 代码与二进制文件打包为一个文件。
-- title: 依赖管理
- details: static-php-cli 附带依赖项管理,支持安装不同类型的 PHP 扩展和不同的依赖库。
+ - title: 静态 CLI 二进制
+ details: 您可以轻松地编译一个独立的 PHP 二进制文件以供通用使用,包括 CLI、FPM SAPI。
+ - title: Micro 自解压可执行文件
+ details: 您可以编译一个自解压的可执行文件,并将 PHP 源代码与二进制文件打包在一起。
+ - title: 依赖管理
+ details: static-php-cli 附带依赖项管理,支持安装不同类型的 PHP 扩展。
---
+
+
+
+
+
+
+
+
diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php
index ba2d38e0..da143de1 100644
--- a/src/SPC/ConsoleApplication.php
+++ b/src/SPC/ConsoleApplication.php
@@ -34,7 +34,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
- public const string VERSION = '2.7.5';
+ public const string VERSION = '2.7.6';
public function __construct()
{
diff --git a/src/SPC/builder/extension/snmp.php b/src/SPC/builder/extension/snmp.php
new file mode 100644
index 00000000..488fc81e
--- /dev/null
+++ b/src/SPC/builder/extension/snmp.php
@@ -0,0 +1,29 @@
+builder->getPHPVersionID() < 80400) {
+ FileSystem::copy(ROOT_DIR . '/src/globals/extra/snmp-ext-config-old.m4', "{$this->source_dir}/config.m4");
+ }
+ $libs = implode(' ', PkgConfigUtil::getLibsArray('netsnmp'));
+ FileSystem::replaceFileStr(
+ "{$this->source_dir}/config.m4",
+ 'PHP_EVAL_LIBLINE([$SNMP_LIBS], [SNMP_SHARED_LIBADD])',
+ "SNMP_LIBS=\"{$libs}\"\nPHP_EVAL_LIBLINE([\$SNMP_LIBS], [SNMP_SHARED_LIBADD])"
+ );
+ return true;
+ }
+}
diff --git a/src/SPC/builder/linux/library/net_snmp.php b/src/SPC/builder/linux/library/net_snmp.php
new file mode 100644
index 00000000..249b28aa
--- /dev/null
+++ b/src/SPC/builder/linux/library/net_snmp.php
@@ -0,0 +1,12 @@
+source_dir}/configure", 'LIBS="-lssl ${OPENSSL_LIBS}"', 'LIBS="-lssl ${OPENSSL_LIBS} -lpthread -ldl"');
+ return true;
+ }
+ return false;
+ }
+
+ protected function build(): void
+ {
+ // use --static for PKG_CONFIG
+ UnixAutoconfExecutor::create($this)
+ ->setEnv(['PKG_CONFIG' => getenv('PKG_CONFIG') . ' --static'])
+ ->configure(
+ '--disable-mibs',
+ '--without-nl',
+ '--disable-agent',
+ '--disable-applications',
+ '--disable-manuals',
+ '--disable-scripts',
+ '--disable-embedded-perl',
+ '--without-perl-modules',
+ '--with-out-mib-modules="if-mib host disman/event-mib ucd-snmp/diskio mibII"',
+ '--with-out-transports="Unix"',
+ '--with-mib-modules=""',
+ '--enable-mini-agent',
+ '--with-default-snmp-version="3"',
+ '--with-sys-contact="@@no.where"',
+ '--with-sys-location="Unknown"',
+ '--with-logfile="/var/log/snmpd.log"',
+ '--with-persistent-directory="/var/lib/net-snmp"',
+ '--with-openssl=' . BUILD_ROOT_PATH,
+ '--with-zlib=' . BUILD_ROOT_PATH,
+ )->make(with_install: 'installheaders installlibs install_pkgconfig');
+ $this->patchPkgconfPrefix();
+ }
+}
diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php
index 67935d14..e55b6e93 100644
--- a/src/SPC/builder/unix/library/postgresql.php
+++ b/src/SPC/builder/unix/library/postgresql.php
@@ -45,8 +45,8 @@ trait postgresql
protected function build(): void
{
- $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies());
- $spc = new SPCConfigUtil($this->getBuilder(), ['no_php' => true, 'libs_only_deps' => true]);
+ $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'));
$env_vars = [
diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php
index 3f21f639..1892d801 100644
--- a/src/SPC/builder/windows/WindowsBuilder.php
+++ b/src/SPC/builder/windows/WindowsBuilder.php
@@ -57,6 +57,7 @@ class WindowsBuilder extends BuilderBase
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
+ $enableCgi = ($build_target & BUILD_TARGET_CGI) === BUILD_TARGET_CGI;
SourcePatcher::patchBeforeBuildconf($this);
@@ -102,13 +103,13 @@ class WindowsBuilder extends BuilderBase
->exec(
"{$this->sdk_prefix} configure.bat --task-args \"" .
'--disable-all ' .
- '--disable-cgi ' .
'--with-php-build=' . BUILD_ROOT_PATH . ' ' .
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
- ($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
- ($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
- ($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
+ ($enableCli ? '--enable-cli ' : '--disable-cli ') .
+ ($enableMicro ? ('--enable-micro ' . $micro_logo . $micro_w32) : '--disable-micro ') .
+ ($enableEmbed ? '--enable-embed ' : '--disable-embed ') .
+ ($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
$config_file_scan_dir .
$opcache_jit_arg .
"{$this->makeStaticExtensionArgs()} " .
@@ -127,6 +128,10 @@ class WindowsBuilder extends BuilderBase
if ($enableFpm) {
logger()->warning('Windows does not support fpm SAPI, I will skip it.');
}
+ if ($enableCgi) {
+ logger()->info('building cgi');
+ $this->buildCgi();
+ }
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro();
@@ -159,6 +164,20 @@ class WindowsBuilder extends BuilderBase
$this->deployBinary(BUILD_TARGET_CLI);
}
+ public function buildCgi(): void
+ {
+ SourcePatcher::patchWindowsCGITarget();
+
+ $extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
+
+ // add nmake wrapper
+ 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->deployBinary(BUILD_TARGET_CGI);
+ }
+
public function buildEmbed(): void
{
// TODO: add embed support for windows
@@ -265,7 +284,7 @@ class WindowsBuilder extends BuilderBase
// sanity check for php-cli
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
logger()->info('running cli sanity check');
- [$ret, $output] = cmd()->execWithResult(BUILD_ROOT_PATH . '\bin\php.exe -n -r "echo \"hello\";"');
+ [$ret, $output] = cmd()->execWithResult(BUILD_BIN_PATH . '\php.exe -n -r "echo \"hello\";"');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new ValidationException('cli failed sanity check', validation_module: 'php-cli function check');
}
@@ -284,7 +303,7 @@ class WindowsBuilder extends BuilderBase
if (file_exists($test_file)) {
@unlink($test_file);
}
- file_put_contents($test_file, file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') . $task['content']);
+ file_put_contents($test_file, file_get_contents(BUILD_BIN_PATH . '\micro.sfx') . $task['content']);
chmod($test_file, 0755);
[$ret, $out] = cmd()->execWithResult($test_file);
foreach ($task['conditions'] as $condition => $closure) {
@@ -298,6 +317,17 @@ class WindowsBuilder extends BuilderBase
}
}
}
+
+ // sanity check for php-cgi
+ if (($build_target & BUILD_TARGET_CGI) === BUILD_TARGET_CGI) {
+ logger()->info('running cgi sanity check');
+ FileSystem::writeFile(SOURCE_PATH . '\php-cgi-test.php', 'Hello, World!"; ?>');
+ [$ret, $output] = cmd()->execWithResult(BUILD_BIN_PATH . '\php-cgi.exe -n -f ' . SOURCE_PATH . '\php-cgi-test.php');
+ $raw_output = implode("\n", $output);
+ if ($ret !== 0 || !str_contains($raw_output, 'Hello, World!')) {
+ throw new ValidationException("cgi failed sanity check. code: {$ret}, output: {$raw_output}", validation_module: 'php-cgi sanity check');
+ }
+ }
}
/**
@@ -311,20 +341,21 @@ class WindowsBuilder extends BuilderBase
$src = match ($type) {
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}"),
};
// with-upx-pack for cli and micro
if ($this->getOption('with-upx-pack', false)) {
- if ($type === BUILD_TARGET_CLI || ($type === BUILD_TARGET_MICRO && version_compare($this->getMicroVersion(), '0.2.0') >= 0)) {
+ 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($src));
}
}
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
- FileSystem::createDir(BUILD_ROOT_PATH . '\bin');
+ FileSystem::createDir(BUILD_BIN_PATH);
- cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '\bin\\'));
+ cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_BIN_PATH . '\\'));
return true;
}
diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php
index a33f1e84..b608b8f0 100644
--- a/src/SPC/command/BuildPHPCommand.php
+++ b/src/SPC/command/BuildPHPCommand.php
@@ -33,7 +33,7 @@ class BuildPHPCommand extends BuildCommand
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
$this->addOption('build-embed', null, null, 'Build embed SAPI (not available on Windows)');
$this->addOption('build-frankenphp', null, null, 'Build FrankenPHP SAPI (not available on Windows)');
- $this->addOption('build-cgi', null, null, 'Build cgi SAPI (not available on Windows)');
+ $this->addOption('build-cgi', null, null, 'Build cgi SAPI');
$this->addOption('build-all', null, null, 'Build all SAPI');
$this->addOption('no-strip', null, null, 'build without strip, keep symbols to debug');
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php
index a23ad6d5..ab8144a2 100644
--- a/src/SPC/doctor/item/LinuxToolCheckList.php
+++ b/src/SPC/doctor/item/LinuxToolCheckList.php
@@ -40,7 +40,7 @@ class LinuxToolCheckList
'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch', 'which',
'xz', 'libtool', 'gettext-devel',
- 'patchelf',
+ 'patchelf', 'file',
];
public const TOOLS_ARCH = [
diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php
index c7738e92..f628544f 100644
--- a/src/SPC/store/SourcePatcher.php
+++ b/src/SPC/store/SourcePatcher.php
@@ -549,6 +549,39 @@ class SourcePatcher
FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines));
}
+ /**
+ * Patch cgi SAPI Makefile for Windows.
+ */
+ public static function patchWindowsCGITarget(): void
+ {
+ // search Makefile code line contains "$(BUILD_DIR)\php-cgi.exe:"
+ $content = FileSystem::readFile(SOURCE_PATH . '/php-src/Makefile');
+ $lines = explode("\r\n", $content);
+ $line_num = 0;
+ $found = false;
+ foreach ($lines as $v) {
+ if (str_contains($v, '$(BUILD_DIR)\php-cgi.exe:')) {
+ $found = $line_num;
+ break;
+ }
+ ++$line_num;
+ }
+ if ($found === false) {
+ throw new PatchException('Windows Makefile patching for php-cgi.exe target', 'Cannot patch windows CGI Makefile, Makefile does not contain "$(BUILD_DIR)\php-cgi.exe:" line');
+ }
+ // cli: $(BUILD_DIR)\php.exe: $(DEPS_CLI) $(CLI_GLOBAL_OBJS) $(BUILD_DIR)\$(PHPLIB) $(BUILD_DIR)\php.exe.res $(BUILD_DIR)\php.exe.manifest
+ // $lines[$line_num] = '$(BUILD_DIR)\php.exe: generated_files $(DEPS_CLI) $(CLI_GLOBAL_OBJS) $(PHP_GLOBAL_OBJS) $(STATIC_EXT_OBJS) $(ASM_OBJS) $(BUILD_DIR)\php.exe.res $(BUILD_DIR)\php.exe.manifest';
+ // cgi: $(BUILD_DIR)\php-cgi.exe: $(DEPS_CGI) $(CGI_GLOBAL_OBJS) $(BUILD_DIR)\$(PHPLIB) $(BUILD_DIR)\php-cgi.exe.res $(BUILD_DIR)\php-cgi.exe.manifest
+ $lines[$line_num] = '$(BUILD_DIR)\php-cgi.exe: $(DEPS_CGI) $(CGI_GLOBAL_OBJS) $(PHP_GLOBAL_OBJS) $(STATIC_EXT_OBJS) $(ASM_OBJS) $(BUILD_DIR)\php-cgi.exe.res $(BUILD_DIR)\php-cgi.exe.manifest';
+
+ // cli: @"$(LINK)" /nologo $(CGI_GLOBAL_OBJS_RESP) $(BUILD_DIR)\$(PHPLIB) $(LIBS_CGI) $(BUILD_DIR)\php-cgi.exe.res /out:$(BUILD_DIR)\php-cgi.exe $(LDFLAGS) $(LDFLAGS_CGI)
+ $lines[$line_num + 1] = "\t" . '@"$(LINK)" /nologo $(PHP_GLOBAL_OBJS_RESP) $(CGI_GLOBAL_OBJS_RESP) $(STATIC_EXT_OBJS_RESP) $(STATIC_EXT_LIBS) $(ASM_OBJS) $(LIBS) $(LIBS_CGI) $(BUILD_DIR)\php-cgi.exe.res /out:$(BUILD_DIR)\php-cgi.exe $(LDFLAGS) $(LDFLAGS_CGI) /ltcg /nodefaultlib:msvcrt /nodefaultlib:msvcrtd /ignore:4286';
+ FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines));
+
+ // Patch cgi-static, comment ZEND_TSRMLS_CACHE_DEFINE()
+ FileSystem::replaceFileRegex(SOURCE_PATH . '\php-src\sapi\cgi\cgi_main.c', '/^ZEND_TSRMLS_CACHE_DEFINE\(\)/m', '// ZEND_TSRMLS_CACHE_DEFINE()');
+ }
+
public static function patchPhpLibxml212(): bool
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
diff --git a/src/SPC/util/executor/UnixAutoconfExecutor.php b/src/SPC/util/executor/UnixAutoconfExecutor.php
index f196cb1c..e04fe4f9 100644
--- a/src/SPC/util/executor/UnixAutoconfExecutor.php
+++ b/src/SPC/util/executor/UnixAutoconfExecutor.php
@@ -115,6 +115,12 @@ class UnixAutoconfExecutor extends Executor
return $this;
}
+ public function setEnv(array $env): static
+ {
+ $this->shell->setEnv($env);
+ return $this;
+ }
+
public function appendEnv(array $env): static
{
$this->shell->appendEnv($env);
diff --git a/src/globals/extra/snmp-ext-config-old.m4 b/src/globals/extra/snmp-ext-config-old.m4
new file mode 100644
index 00000000..22cab40a
--- /dev/null
+++ b/src/globals/extra/snmp-ext-config-old.m4
@@ -0,0 +1,92 @@
+PHP_ARG_WITH([snmp],
+ [for SNMP support],
+ [AS_HELP_STRING([[--with-snmp[=DIR]]],
+ [Include SNMP support. Use PKG_CONFIG_PATH (or SNMP_CFLAGS and SNMP_LIBS)
+ environment variables, or alternatively the optional DIR argument to
+ customize where to look for the net-snmp-config utility of the NET-SNMP
+ library.])])
+
+if test "$PHP_SNMP" != "no"; then
+ snmp_found=no
+ AS_VAR_IF([PHP_SNMP], [yes],
+ [PKG_CHECK_MODULES([SNMP], [netsnmp >= 5.3], [snmp_found=yes], [:])])
+
+ AS_VAR_IF([snmp_found], [no], [
+ AS_VAR_IF([PHP_SNMP], [yes],
+ [AC_PATH_PROG([SNMP_CONFIG], [net-snmp-config],, [/usr/local/bin:$PATH])],
+ [SNMP_CONFIG="$PHP_SNMP/bin/net-snmp-config"])
+
+ AS_IF([test ! -x "$SNMP_CONFIG"],
+ [AC_MSG_ERROR(m4_text_wrap([
+ Could not find net-snmp-config binary. Please check your net-snmp
+ installation.
+ ]))])
+
+ snmp_version=$($SNMP_CONFIG --version)
+ AS_VERSION_COMPARE([$snmp_version], [5.3],
+ [AC_MSG_ERROR(m4_text_wrap([
+ Net-SNMP version 5.3 or greater required (detected $snmp_version).
+ ]))])
+
+ SNMP_PREFIX=$($SNMP_CONFIG --prefix)
+ SNMP_CFLAGS="-I${SNMP_PREFIX}/include"
+ SNMP_LIBS=$($SNMP_CONFIG --netsnmp-libs)
+ SNMP_LIBS="$SNMP_LIBS $($SNMP_CONFIG --external-libs)"
+
+ AS_IF([test -z "$SNMP_LIBS" || test -z "$SNMP_PREFIX"],
+ [AC_MSG_ERROR(m4_text_wrap([
+ Could not find the required paths. Please check your net-snmp
+ installation.
+ ]))])
+ ])
+
+ PHP_EVAL_INCLINE([$SNMP_CFLAGS])
+ PHP_EVAL_LIBLINE([$SNMP_LIBS], [SNMP_SHARED_LIBADD])
+ SNMP_LIBNAME=netsnmp
+
+ dnl Test build.
+ PHP_CHECK_LIBRARY([$SNMP_LIBNAME], [init_snmp],
+ [AC_DEFINE([HAVE_SNMP], [1],
+ [Define to 1 if the PHP extension 'snmp' is available.])],
+ [AC_MSG_FAILURE([SNMP sanity check failed.])],
+ [$SNMP_SHARED_LIBADD])
+
+ dnl Check whether shutdown_snmp_logging() exists.
+ PHP_CHECK_LIBRARY([$SNMP_LIBNAME], [shutdown_snmp_logging],
+ [AC_DEFINE([HAVE_SHUTDOWN_SNMP_LOGGING], [1],
+ [Define to 1 if SNMP library has the 'shutdown_snmp_logging' function.])],
+ [],
+ [$SNMP_SHARED_LIBADD])
+
+ CFLAGS_SAVE=$CFLAGS
+ LIBS_SAVE=$LIBS
+ CFLAGS="$CFLAGS $SNMP_CFLAGS"
+ LIBS="$LIBS $SNMP_LIBS"
+
+ AC_CHECK_DECL([usmHMAC192SHA256AuthProtocol],
+ [AC_DEFINE([HAVE_SNMP_SHA256], [1],
+ [Define to 1 if SNMP library has the 'usmHMAC192SHA256AuthProtocol'
+ array.])],
+ [],
+ [
+ #include
+ #include
+ ])
+
+ AC_CHECK_DECL([usmHMAC384SHA512AuthProtocol],
+ [AC_DEFINE([HAVE_SNMP_SHA512], [1],
+ [Define to 1 if SNMP library has the 'usmHMAC384SHA512AuthProtocol'
+ array.])],
+ [],
+ [
+ #include
+ #include
+ ])
+
+ CFLAGS=$CFLAGS_SAVE
+ LIBS=$LIBS_SAVE
+
+ PHP_NEW_EXTENSION([snmp], [snmp.c], [$ext_shared])
+ PHP_ADD_EXTENSION_DEP(snmp, spl)
+ PHP_SUBST([SNMP_SHARED_LIBADD])
+fi
diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php
index 7797367d..391c401b 100644
--- a/src/globals/test-extensions.php
+++ b/src/globals/test-extensions.php
@@ -14,9 +14,9 @@ declare(strict_types=1);
// test php version (8.1 ~ 8.4 available, multiple for matrix)
$test_php_version = [
'8.1',
- // '8.2',
- // '8.3',
- // '8.4',
+ '8.2',
+ '8.3',
+ '8.4',
'8.5',
// 'git',
];
@@ -30,11 +30,12 @@ $test_os = [
'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
- // 'windows-latest', // .\bin\spc.ps1
+ // 'windows-2022', // .\bin\spc.ps1
+ // 'windows-2025',
];
// whether enable thread safe
-$zts = false;
+$zts = true;
$no_strip = false;
@@ -61,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) {
@@ -208,7 +209,7 @@ switch ($argv[1] ?? null) {
passthru($prefix . $down_cmd, $retcode);
break;
case 'build_cmd':
- passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode);
+ passthru($prefix . $build_cmd . ' --build-cli --build-micro --build-cgi', $retcode);
break;
case 'build_embed_cmd':
if ($frankenphp) {