diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fa9e646fa..132b33f00 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 044de07b7..a1f149c59 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/source.json b/config/source.json index 349ba68cf..fd0301be7 100644 --- a/config/source.json +++ b/config/source.json @@ -762,7 +762,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", diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index ba2d38e0b..da143de1a 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -34,7 +34,7 @@ */ 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/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php index 3f21f639b..1892d8014 100644 --- a/src/SPC/builder/windows/WindowsBuilder.php +++ b/src/SPC/builder/windows/WindowsBuilder.php @@ -57,6 +57,7 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void $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 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void ->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 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void 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 @@ public function buildCli(): void $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 @@ public function sanityCheck(mixed $build_target): void // 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 @@ public function sanityCheck(mixed $build_target): void 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 @@ public function sanityCheck(mixed $build_target): void } } } + + // 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 @@ public function deployBinary(int $type): bool $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 a33f1e843..b608b8f06 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -33,7 +33,7 @@ public function configure(): void $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/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index c7738e92d..f628544fe 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -549,6 +549,39 @@ public static function patchWindowsCLITarget(): void 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/globals/test-extensions.php b/src/globals/test-extensions.php index 5aef4bd86..f5855dc8d 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -14,27 +14,28 @@ // 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', ]; // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - 'macos-15-intel', // bin/spc for x86_64 - 'macos-15', // bin/spc for arm64 - 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 - 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 - 'ubuntu-24.04', // bin/spc for x86_64 - 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 - 'ubuntu-24.04-arm', // bin/spc for arm64 - // 'windows-latest', // .\bin\spc.ps1 + // 'macos-15-intel', // bin/spc for x86_64 + // 'macos-15', // bin/spc for arm64 + // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 + // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 + // 'ubuntu-24.04', // bin/spc for x86_64 + // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 + // 'ubuntu-24.04-arm', // bin/spc for arm64 + // 'windows-2022', // .\bin\spc.ps1 + 'windows-2025', ]; // whether enable thread safe -$zts = false; +$zts = true; $no_strip = false; @@ -49,8 +50,8 @@ // 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', - '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', + 'Linux', 'Darwin' => 'pdo_pgsql', + 'Windows' => 'bcmath,bz2,calendar,ctype,curl,dba,dom,exif,ffi,fileinfo,filter,ftp,iconv,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_sqlite,pdo_sqlsrv,phar,session,shmop,simdjson,simplexml,soap,sockets,sqlite3,sqlsrv,ssh2,sysvshm,tokenizer,xml,xmlreader,xmlwriter,yaml,zip,zlib', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). @@ -61,7 +62,7 @@ }; // 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 @@ function quote2(string $param): string 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) {