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

Special Sponsors

+

+ Thank you to our amazing sponsors for supporting this project! +

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

Special Sponsors

+

+ Thank you to our amazing sponsors for supporting this project! +

+
+ +
- + + + 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) {