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 7d770426..1f17797e 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 09779cf9..d74658a6 100644
--- a/config/lib.json
+++ b/config/lib.json
@@ -507,13 +507,16 @@
},
"librdkafka": {
"source": "librdkafka",
- "static-libs-unix": [
- "librdkafka.a",
- "librdkafka++.a",
- "librdkafka-static.a"
+ "pkg-configs": [
+ "rdkafka++-static",
+ "rdkafka-static"
],
"cpp-library": true,
"lib-suggests": [
+ "curl",
+ "liblz4",
+ "openssl",
+ "zlib",
"zstd"
]
},
@@ -608,8 +611,8 @@
},
"libxml2": {
"source": "libxml2",
- "static-libs-unix": [
- "libxml2.a"
+ "pkg-configs": [
+ "libxml-2.0"
],
"static-libs-windows": [
"libxml2s.lib",
@@ -698,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 77e5a5cf..4a199081 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",
@@ -772,7 +782,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",
@@ -820,6 +830,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.php b/src/SPC/builder/Extension.php
index 5b6a3329..c9cd0657 100644
--- a/src/SPC/builder/Extension.php
+++ b/src/SPC/builder/Extension.php
@@ -220,7 +220,7 @@ class Extension
*/
public function patchBeforeSharedMake(): bool
{
- $config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
+ $config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
$lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
@@ -486,18 +486,46 @@ class Extension
return $this->build_static;
}
+ /**
+ * Get the library dependencies that current extension depends on.
+ *
+ * @param bool $recursive Whether it includes dependencies recursively
+ */
+ public function getLibraryDependencies(bool $recursive = false): array
+ {
+ $ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
+ if (!$recursive) {
+ return $ret;
+ }
+
+ $deps = [];
+
+ $added = 1;
+ while ($added !== 0) {
+ $added = 0;
+ foreach ($ret as $depName => $dep) {
+ foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
+ if (!array_key_exists($depdepName, $deps)) {
+ $deps[$depdepName] = $depdep;
+ ++$added;
+ }
+ }
+ if (!array_key_exists($depName, $deps)) {
+ $deps[$depName] = $dep;
+ }
+ }
+ }
+
+ return $deps;
+ }
+
/**
* Returns the environment variables a shared extension needs to be built.
* CFLAGS, CXXFLAGS, LDFLAGS and so on.
*/
protected function getSharedExtensionEnv(): array
{
- $config = (new SPCConfigUtil($this->builder))->config(
- [$this->getName()],
- array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
- $this->builder->getOption('with-suggested-exts'),
- $this->builder->getOption('with-suggested-libs'),
- );
+ $config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
@@ -519,7 +547,7 @@ class Extension
}
logger()->info("enabling {$this->name} without library {$name}");
} else {
- $this->dependencies[] = $depLib;
+ $this->dependencies[$name] = $depLib;
}
}
@@ -532,7 +560,7 @@ class Extension
}
logger()->info("enabling {$this->name} without extension {$name}");
} else {
- $this->dependencies[] = $depExt;
+ $this->dependencies[$name] = $depExt;
}
}
@@ -567,37 +595,4 @@ class Extension
}
return [trim($staticLibString), trim($sharedLibString)];
}
-
- private function getLibraryDependencies(bool $recursive = false): array
- {
- $ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
- if (!$recursive) {
- return $ret;
- }
-
- $deps = [];
-
- $added = 1;
- while ($added !== 0) {
- $added = 0;
- foreach ($ret as $depName => $dep) {
- foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
- if (!array_key_exists($depdepName, $deps)) {
- $deps[$depdepName] = $depdep;
- ++$added;
- }
- }
- if (!array_key_exists($depName, $deps)) {
- $deps[$depName] = $dep;
- }
- }
- }
-
- if (array_key_exists(0, $deps)) {
- $zero = [0 => $deps[0]];
- unset($deps[0]);
- return $zero + $deps;
- }
- return $deps;
- }
}
diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php
index 7388eaff..fb31c85f 100644
--- a/src/SPC/builder/extension/grpc.php
+++ b/src/SPC/builder/extension/grpc.php
@@ -43,7 +43,7 @@ class grpc extends Extension
public function patchBeforeConfigure(): bool
{
$util = new SPCConfigUtil($this->builder, ['libs_only_deps' => true]);
- $config = $util->config(['grpc']);
+ $config = $util->getExtensionConfig($this);
$libs = $config['libs'];
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lgrpc', $libs);
return true;
diff --git a/src/SPC/builder/extension/rdkafka.php b/src/SPC/builder/extension/rdkafka.php
index 575ab309..58af50ff 100644
--- a/src/SPC/builder/extension/rdkafka.php
+++ b/src/SPC/builder/extension/rdkafka.php
@@ -7,6 +7,7 @@ namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
+use SPC\util\SPCConfigUtil;
#[CustomExt('rdkafka')]
class rdkafka extends Extension
@@ -15,6 +16,7 @@ class rdkafka extends Extension
{
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\n", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm \$RDKAFKA_LIBS\n");
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\"\n", '-L$RDKAFKA_DIR/$PHP_LIBDIR -lm $RDKAFKA_LIBS"');
+ FileSystem::replaceFileStr("{$this->source_dir}/config.m4", 'PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,', 'AC_CHECK_LIB([$LIBNAME], [$LIBSYMBOL],');
return true;
}
@@ -37,8 +39,7 @@ class rdkafka extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
- $pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1];
- $pkgconf_libs = trim(implode('', $pkgconf_libs));
- return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"';
+ $pkgconf_libs = (new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]))->getExtensionConfig($this);
+ return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . " RDKAFKA_LIBS=\"{$pkgconf_libs['libs']}\"";
}
}
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/extension/swoole.php b/src/SPC/builder/extension/swoole.php
index 7ff4b331..f6ff5931 100644
--- a/src/SPC/builder/extension/swoole.php
+++ b/src/SPC/builder/extension/swoole.php
@@ -70,7 +70,7 @@ class swoole extends Extension
$arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd';
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite';
if ($this->builder->getExt('swoole-hook-odbc')) {
- $config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']);
+ $config = (new SPCConfigUtil($this->builder))->getLibraryConfig($this->builder->getLib('unixodbc'));
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}
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 @@
+appendEnv(['CFLAGS' => '-Wno-int-conversion -Wno-unused-but-set-variable -Wno-unused-variable'])
- ->optionalLib(
- 'zstd',
- function ($lib) {
- putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a");
- return '';
- },
- '--disable-zstd'
+ UnixCMakeExecutor::create($this)
+ ->optionalLib('zstd', ...cmake_boolean_args('WITH_ZSTD'))
+ ->optionalLib('curl', ...cmake_boolean_args('WITH_CURL'))
+ ->optionalLib('openssl', ...cmake_boolean_args('WITH_SSL'))
+ ->optionalLib('zlib', ...cmake_boolean_args('WITH_ZLIB'))
+ ->optionalLib('liblz4', ...cmake_boolean_args('ENABLE_LZ4_EXT'))
+ ->addConfigureArgs(
+ '-DWITH_SASL=OFF',
+ '-DRDKAFKA_BUILD_STATIC=ON',
+ '-DRDKAFKA_BUILD_EXAMPLES=OFF',
+ '-DRDKAFKA_BUILD_TESTS=OFF',
)
- ->removeConfigureArgs(
- '--with-pic',
- '--enable-pic',
- )
- ->configure(
- '--disable-curl',
- '--disable-sasl',
- '--disable-valgrind',
- '--disable-zlib',
- '--disable-ssl',
- )
- ->make();
-
- $this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']);
- // remove dynamic libs
- shell()
- ->exec("rm -rf {$this->getLibDir()}/*.so.*")
- ->exec("rm -rf {$this->getLibDir()}/*.so")
- ->exec("rm -rf {$this->getLibDir()}/*.dylib");
+ ->build();
}
}
diff --git a/src/SPC/builder/unix/library/net_snmp.php b/src/SPC/builder/unix/library/net_snmp.php
new file mode 100644
index 00000000..df464d52
--- /dev/null
+++ b/src/SPC/builder/unix/library/net_snmp.php
@@ -0,0 +1,49 @@
+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..6e0cb606 100644
--- a/src/SPC/builder/unix/library/postgresql.php
+++ b/src/SPC/builder/unix/library/postgresql.php
@@ -45,9 +45,9 @@ 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]);
- $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs'));
+ $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true));
+ $spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]);
+ $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
$env_vars = [
'CFLAGS' => $config['cflags'],
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 c5c60d26..ad884b3b 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/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php
index d784be71..df5e4bf0 100644
--- a/src/SPC/exception/ExceptionHandler.php
+++ b/src/SPC/exception/ExceptionHandler.php
@@ -159,7 +159,9 @@ class ExceptionHandler
public static function handleDefaultException(\Throwable $e): void
{
$class = get_class($e);
- self::logError("✗ Unhandled exception {$class}:\n\t{$e->getMessage()}\n");
+ $file = $e->getFile();
+ $line = $e->getLine();
+ self::logError("✗ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n");
self::logError('Stack trace:');
self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4);
self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues');
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/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php
index f321ca10..a74d6a24 100644
--- a/src/SPC/util/SPCConfigUtil.php
+++ b/src/SPC/util/SPCConfigUtil.php
@@ -7,6 +7,7 @@ namespace SPC\util;
use SPC\builder\BuilderBase;
use SPC\builder\BuilderProvider;
use SPC\builder\Extension;
+use SPC\builder\LibraryBase;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use Symfony\Component\Console\Input\ArgvInput;
@@ -53,6 +54,9 @@ class SPCConfigUtil
*/
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
{
+ logger()->debug('config extensions: ' . implode(',', $extensions));
+ logger()->debug('config libs: ' . implode(',', $libraries));
+ logger()->debug('config suggest for [ext, lib]: ' . ($include_suggest_ext ? 'true' : 'false') . ',' . ($include_suggest_lib ? 'true' : 'false'));
$extra_exts = [];
foreach ($extensions as $ext) {
$extra_exts = array_merge($extra_exts, Config::getExt($ext, 'ext-suggests', []));
@@ -124,6 +128,63 @@ class SPCConfigUtil
];
}
+ /**
+ * [Helper function]
+ * Get configuration for a specific extension(s) dependencies.
+ *
+ * @param Extension|Extension[] $extension Extension instance or list
+ * @param bool $include_suggest_ext Whether to include suggested extensions
+ * @param bool $include_suggest_lib Whether to include suggested libraries
+ * @return array{
+ * cflags: string,
+ * ldflags: string,
+ * libs: string
+ * }
+ */
+ public function getExtensionConfig(array|Extension $extension, bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
+ {
+ if (!is_array($extension)) {
+ $extension = [$extension];
+ }
+ $libs = array_map(fn ($y) => $y->getName(), array_merge(...array_map(fn ($x) => $x->getLibraryDependencies(true), $extension)));
+ return $this->config(
+ extensions: array_map(fn ($x) => $x->getName(), $extension),
+ libraries: $libs,
+ include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false,
+ include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
+ );
+ }
+
+ /**
+ * [Helper function]
+ * Get configuration for a specific library(s) dependencies.
+ *
+ * @param LibraryBase|LibraryBase[] $lib Library instance or list
+ * @param bool $include_suggest_lib Whether to include suggested libraries
+ * @return array{
+ * cflags: string,
+ * ldflags: string,
+ * libs: string
+ * }
+ */
+ public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_lib = false): array
+ {
+ if (!is_array($lib)) {
+ $lib = [$lib];
+ }
+ $save_no_php = $this->no_php;
+ $this->no_php = true;
+ $save_libs_only_deps = $this->libs_only_deps;
+ $this->libs_only_deps = true;
+ $ret = $this->config(
+ libraries: array_map(fn ($x) => $x->getName(), $lib),
+ include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
+ );
+ $this->no_php = $save_no_php;
+ $this->libs_only_deps = $save_libs_only_deps;
+ return $ret;
+ }
+
private function hasCpp(array $extensions, array $libraries): bool
{
// judge cpp-extension
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 5aef4bd8..43ce5d15 100644
--- a/src/globals/test-extensions.php
+++ b/src/globals/test-extensions.php
@@ -13,11 +13,11 @@ declare(strict_types=1);
// test php version (8.1 ~ 8.4 available, multiple for matrix)
$test_php_version = [
- '8.1',
+ // '8.1',
// '8.2',
// '8.3',
- // '8.4',
- '8.5',
+ '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;
@@ -49,7 +50,7 @@ $prefer_pre_built = false;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
- 'Linux', 'Darwin' => 'gettext',
+ 'Linux', 'Darwin' => 'rdkafka',
'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',
};
@@ -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) {