From 06864fc3f69dc2befd8eec059b9e501f7e9d7050 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 16:56:40 +0800 Subject: [PATCH 01/12] feat(windows): replace php-sdk-binary-tools with MSYS2 + 7za-win - Add msys2-build-essentials target: downloads the MSYS2 nightly sfx, extracts it, disables PGP keyring (CI-safe), runs two-pass pacman update, and installs autotools build essentials (make, autoconf, automake, libtool, pkgconf, perl). - Add 7za-win target: downloads 7za.exe to PKG_ROOT_PATH\bin. - Remove php-sdk-binary-tools target and all PHP_SDK_PATH references; replace with SPC_MSYS2_PATH throughout Artifact, ArtifactExtractor, FileSystem, DefaultShell and MSVCToolchain. - Replace {php_sdk_path} path placeholder with {spc_msys2_path}. - WindowsToolCheck: replace checkSDK/installSDK with checkMsys2, installMsys2 and check7zaWin/install7zaWin fix items. - nasm.yml: extract nasm.exe/ndisasm.exe to {pkg_root_path}/bin. - env.ini: rename PHP_SDK_PATH to SPC_MSYS2_PATH. - Docs: update Windows migration guide and package-model placeholder docs. --- config/env.ini | 4 +- config/pkg/target/7za-win.yml | 5 + config/pkg/target/msys2-build-essentials.yml | 8 ++ config/pkg/target/nasm.yml | 2 +- config/pkg/target/php-sdk-binary-tools.yml | 5 - docs/en/develop/package-model.md | 2 +- docs/en/guide/migrate-from-v2.md | 8 +- docs/zh/develop/package-model.md | 2 +- docs/zh/guide/migrate-from-v2.md | 8 +- .../Artifact/msys2_build_essentials.php | 93 +++++++++++++++++++ src/StaticPHP/Artifact/Artifact.php | 2 +- src/StaticPHP/Artifact/ArtifactExtractor.php | 2 +- .../Artifact/Downloader/DownloadResult.php | 3 +- .../Doctor/Item/WindowsToolCheck.php | 37 ++++++-- src/StaticPHP/Runtime/Shell/DefaultShell.php | 10 +- src/StaticPHP/Toolchain/MSVCToolchain.php | 12 ++- src/StaticPHP/Util/FileSystem.php | 2 +- 17 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 config/pkg/target/7za-win.yml create mode 100644 config/pkg/target/msys2-build-essentials.yml delete mode 100644 config/pkg/target/php-sdk-binary-tools.yml create mode 100644 src/Package/Artifact/msys2_build_essentials.php diff --git a/config/env.ini b/config/env.ini index 483ae4083..a3e9aa706 100644 --- a/config/env.ini +++ b/config/env.ini @@ -68,8 +68,8 @@ SPC_PRESERVE_LOGS="no" [windows] ; build target: win7-static SPC_TARGET=native-windows -; php-sdk-binary-tools path -PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools" +; MSYS2 root directory (msys64 subfolder), used by the Windows toolchain +SPC_MSYS2_PATH="${PKG_ROOT_PATH}\msys2-build-essentials\msys64" ; 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 diff --git a/config/pkg/target/7za-win.yml b/config/pkg/target/7za-win.yml new file mode 100644 index 000000000..351fad8c2 --- /dev/null +++ b/config/pkg/target/7za-win.yml @@ -0,0 +1,5 @@ +7za-win: + type: target + artifact: + binary: + windows-x86_64: { type: url, url: 'https://dl.static-php.dev/v3/tools/7zip/7za.exe', extract: '{pkg_root_path}/bin/7za.exe' } diff --git a/config/pkg/target/msys2-build-essentials.yml b/config/pkg/target/msys2-build-essentials.yml new file mode 100644 index 000000000..39f10fe00 --- /dev/null +++ b/config/pkg/target/msys2-build-essentials.yml @@ -0,0 +1,8 @@ +msys2-build-essentials: + type: target + artifact: + binary: custom + env: + SPC_MSYS2_PATH: '{pkg_root_path}/msys2-build-essentials/msys64' + path@windows: + - '{pkg_root_path}/msys2-build-essentials/msys64/usr/bin' diff --git a/config/pkg/target/nasm.yml b/config/pkg/target/nasm.yml index 3f483e8bb..3e6d9e439 100644 --- a/config/pkg/target/nasm.yml +++ b/config/pkg/target/nasm.yml @@ -2,4 +2,4 @@ nasm: type: target artifact: binary: - windows-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip', extract: { nasm.exe: '{php_sdk_path}/bin/nasm.exe', ndisasm.exe: '{php_sdk_path}/bin/ndisasm.exe' } } + windows-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip', extract: { nasm.exe: '{pkg_root_path}/bin/nasm.exe', ndisasm.exe: '{pkg_root_path}/bin/ndisasm.exe' } } diff --git a/config/pkg/target/php-sdk-binary-tools.yml b/config/pkg/target/php-sdk-binary-tools.yml deleted file mode 100644 index 81180007e..000000000 --- a/config/pkg/target/php-sdk-binary-tools.yml +++ /dev/null @@ -1,5 +0,0 @@ -php-sdk-binary-tools: - type: target - artifact: - binary: - windows-x86_64: { type: git, rev: master, url: 'https://github.com/php/php-sdk-binary-tools.git', extract: '{php_sdk_path}' } diff --git a/docs/en/develop/package-model.md b/docs/en/develop/package-model.md index 2e9a290d7..4bac3de20 100644 --- a/docs/en/develop/package-model.md +++ b/docs/en/develop/package-model.md @@ -229,7 +229,7 @@ The following path placeholders are supported in string values of the `path`, `e | `{working_dir}` | Working directory (project root) | | `{download_path}` | Download cache directory (`downloads/`) | | `{source_path}` | Extracted source directory (`source/`) | -| `{php_sdk_path}` | Windows PHP SDK directory | +| `{spc_msys2_path}` | MSYS2 root directory (`msys64/`) — Windows only | ## target Package Type diff --git a/docs/en/guide/migrate-from-v2.md b/docs/en/guide/migrate-from-v2.md index 54bfa1636..3fee7bd32 100644 --- a/docs/en/guide/migrate-from-v2.md +++ b/docs/en/guide/migrate-from-v2.md @@ -58,7 +58,13 @@ A single-file hook API for lightweight patches may be provided in a future relea ### Windows-only: `--with-sdk-binary-dir` and `--vs-ver` -These options are no longer accepted on the command line. Instead, set the `PHP_SDK_PATH` environment variable to point to your PHP SDK binary tools directory. The Visual Studio version is now managed by the toolchain configuration. +These options are no longer accepted on the command line. In v3, the `php-sdk-binary-tools` dependency has been completely removed. v3 now manages its own **MSYS2** environment to support autotools-based library builds on Windows. Run `spc doctor --install` to download and configure MSYS2 automatically. + +If you need to point to a custom MSYS2 installation, set the `SPC_MSYS2_PATH` environment variable to the `msys64` directory (e.g. `C:\msys64`). Visual Studio is now auto-detected by the toolchain — no manual version flag needed. + +::: warning Migrating from v2 +v2 relied on `php-sdk-binary-tools` and required `--with-sdk-binary-dir` and `--vs-ver` on every build invocation. In v3 these options are gone. Remove them from all CI scripts and run `spc doctor --install` once to set up the Windows build environment. +::: ## Renamed / Deprecated Options diff --git a/docs/zh/develop/package-model.md b/docs/zh/develop/package-model.md index c7fa9dff5..af87a8daf 100644 --- a/docs/zh/develop/package-model.md +++ b/docs/zh/develop/package-model.md @@ -223,7 +223,7 @@ openssl: | `{working_dir}` | 工作目录(项目根目录) | | `{download_path}` | 下载缓存目录(`downloads/`) | | `{source_path}` | 解压源码目录(`source/`) | -| `{php_sdk_path}` | Windows PHP SDK 目录 | +| `{spc_msys2_path}` | MSYS2 根目录(`msys64/`)——仅 Windows | ## target 包类型 diff --git a/docs/zh/guide/migrate-from-v2.md b/docs/zh/guide/migrate-from-v2.md index 81297acf8..805a8549d 100644 --- a/docs/zh/guide/migrate-from-v2.md +++ b/docs/zh/guide/migrate-from-v2.md @@ -58,7 +58,13 @@ curl -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-x86_64 ### Windows 专有:`--with-sdk-binary-dir` 和 `--vs-ver` -这两个选项已不再被命令行接受。请改为设置 `PHP_SDK_PATH` 环境变量,指向你的 PHP SDK binary tools 目录。Visual Studio 版本现在由工具链配置统一管理。 +这两个选项已不再被命令行接受。在 v3 中,`php-sdk-binary-tools` 依赖已被完全移除。v3 现在通过管理自己的 **MSYS2** 环境来支持 Windows 上基于 autotools 的库构建。运行 `spc doctor --install` 即可自动下载并配置 MSYS2。 + +如需指向自定义 MSYS2 安装目录,请设置 `SPC_MSYS2_PATH` 环境变量,值为 `msys64` 目录路径(例如 `C:\msys64`)。Visual Studio 版本现在由工具链自动检测,无需手动指定版本号。 + +::: warning 从 v2 迁移 +v2 依赖 `php-sdk-binary-tools`,并在每次构建时需要传入 `--with-sdk-binary-dir` 和 `--vs-ver` 参数。在 v3 中这些选项已被移除。请从所有 CI 脚本中删除这些参数,并使用 `spc doctor --install` 一次性完成 Windows 构建环境的配置。 +::: ## 已重命名 / 已弃用的选项 diff --git a/src/Package/Artifact/msys2_build_essentials.php b/src/Package/Artifact/msys2_build_essentials.php new file mode 100644 index 000000000..920927bfc --- /dev/null +++ b/src/Package/Artifact/msys2_build_essentials.php @@ -0,0 +1,93 @@ +executeCurlDownload($url, $path, retries: $downloader->getRetry()); + + return DownloadResult::file( + $filename, + ['url' => $url, 'version' => 'nightly'], + version: 'nightly', + extract: '{pkg_root_path}/msys2-build-essentials', + ); + } + + #[BinaryExtract('msys2-build-essentials', ['windows-x86_64'])] + public function extractBinary(string $source_file, string $target_path): void + { + $target_path = FileSystem::convertPath($target_path); + $source_file = FileSystem::convertPath($source_file); + + // Guard: skip re-extraction if already initialized (marker written at end of this method). + $marker = "{$target_path}\\.spc-msys2-initialized"; + if (file_exists($marker)) { + return; + } + + if (!is_dir($target_path)) { + FileSystem::createDir($target_path); + } + + cmd()->exec("\"{$source_file}\" -y -o\"{$target_path}\""); + + $msys2_bin = "{$target_path}\\msys64\\usr\\bin"; + if (!file_exists("{$msys2_bin}\\bash.exe")) { + throw new DownloaderException("MSYS2 extraction failed: bash.exe not found at {$msys2_bin}\\bash.exe"); + } + + // Add MSYS2 usr\bin to PATH so pacman.exe can load msys-2.0.dll. + GlobalEnvManager::addPathIfNotExists($msys2_bin); + GlobalEnvManager::putenv('CHERE_INVOKING=yes'); + GlobalEnvManager::putenv('MSYSTEM=MSYS'); + + // Disable PGP signature checking: pacman-key --init requires a pseudo-TTY which is unavailable + // from PHP. Patching pacman.conf is the standard approach for CI pipelines. + $pacman_conf = "{$target_path}\\msys64\\etc\\pacman.conf"; + FileSystem::replaceFileRegex($pacman_conf, '/^SigLevel\s*=.*$/m', 'SigLevel = Never'); + + $pacman = "{$target_path}\\msys64\\usr\\bin\\pacman.exe"; + + // Two-pass update as recommended by MSYS2 CI docs. + cmd()->exec("\"{$pacman}\" --noconfirm -Syuu"); + cmd()->exec("\"{$pacman}\" --noconfirm -Syuu"); + + $pkgs = implode(' ', self::REQUIRED_PACKAGES); + cmd()->exec("\"{$pacman}\" --noconfirm -S --needed {$pkgs}"); + + FileSystem::writeFile($marker, date('Y-m-d H:i:s')); + } + + #[AfterBinaryExtract('msys2-build-essentials', ['windows-x86_64'])] + public function afterExtract(string $target_path): void + { + $target_path = FileSystem::convertPath($target_path); + $msys2_root = "{$target_path}\\msys64"; + + GlobalEnvManager::putenv("SPC_MSYS2_PATH={$msys2_root}"); + GlobalEnvManager::addPathIfNotExists("{$msys2_root}\\usr\\bin"); + } +} diff --git a/src/StaticPHP/Artifact/Artifact.php b/src/StaticPHP/Artifact/Artifact.php index 224bcff30..666939fef 100644 --- a/src/StaticPHP/Artifact/Artifact.php +++ b/src/StaticPHP/Artifact/Artifact.php @@ -644,7 +644,7 @@ private function replaceExtractPathVariables(string $extract): string '{artifact_name}' => $this->name, '{pkg_root_path}' => PKG_ROOT_PATH, '{build_root_path}' => BUILD_ROOT_PATH, - '{php_sdk_path}' => getenv('PHP_SDK_PATH') ?: WORKING_DIR . '/php-sdk-binary-tools', + '{spc_msys2_path}' => getenv('SPC_MSYS2_PATH'), '{working_dir}' => WORKING_DIR, '{download_path}' => DOWNLOAD_PATH, '{source_path}' => SOURCE_PATH, diff --git a/src/StaticPHP/Artifact/ArtifactExtractor.php b/src/StaticPHP/Artifact/ArtifactExtractor.php index 987ec554e..3630981ad 100644 --- a/src/StaticPHP/Artifact/ArtifactExtractor.php +++ b/src/StaticPHP/Artifact/ArtifactExtractor.php @@ -614,7 +614,7 @@ protected function replacePathVariables(string $path): string '{source_path}' => SOURCE_PATH, '{download_path}' => DOWNLOAD_PATH, '{working_dir}' => WORKING_DIR, - '{php_sdk_path}' => getenv('PHP_SDK_PATH') ?: '', + '{spc_msys2_path}' => getenv('SPC_MSYS2_PATH') ?: '', ]; return str_replace(array_keys($replacement), array_values($replacement), $path); } diff --git a/src/StaticPHP/Artifact/Downloader/DownloadResult.php b/src/StaticPHP/Artifact/Downloader/DownloadResult.php index 2efe6945e..9115fb593 100644 --- a/src/StaticPHP/Artifact/Downloader/DownloadResult.php +++ b/src/StaticPHP/Artifact/Downloader/DownloadResult.php @@ -76,9 +76,10 @@ public static function file( ?string $version = null, array $metadata = [], ?string $downloader = null, + mixed $extract = null, ): DownloadResult { $cache_type = self::isArchiveFile($filename) ? 'archive' : 'file'; - return new self($cache_type, config: $config, filename: $filename, verified: $verified, version: $version, metadata: $metadata, downloader: $downloader); + return new self($cache_type, config: $config, filename: $filename, extract: $extract, verified: $verified, version: $version, metadata: $metadata, downloader: $downloader); } /** diff --git a/src/StaticPHP/Doctor/Item/WindowsToolCheck.php b/src/StaticPHP/Doctor/Item/WindowsToolCheck.php index 08e140f47..3fe1d3127 100644 --- a/src/StaticPHP/Doctor/Item/WindowsToolCheck.php +++ b/src/StaticPHP/Doctor/Item/WindowsToolCheck.php @@ -54,13 +54,24 @@ public function checkGitPatch(): ?CheckResult return CheckResult::ok(); } - #[CheckItem('if php-sdk-binary-tools are downloaded', limit_os: 'Windows', level: 996)] - public function checkSDK(): ?CheckResult + #[CheckItem('if msys2-build-essentials is installed', limit_os: 'Windows', level: 996)] + public function checkMsys2(): ?CheckResult { - if (!file_exists(getenv('PHP_SDK_PATH') . DIRECTORY_SEPARATOR . 'phpsdk-starter.bat')) { - return CheckResult::fail('php-sdk-binary-tools not downloaded', 'install-php-sdk'); + $marker = PKG_ROOT_PATH . '\msys2-build-essentials\.spc-msys2-initialized'; + if (!file_exists($marker)) { + return CheckResult::fail('msys2-build-essentials not installed', 'install-msys2-build-essentials'); } - return CheckResult::ok(getenv('PHP_SDK_PATH')); + return CheckResult::ok(PKG_ROOT_PATH . '\msys2-build-essentials\msys64'); + } + + #[CheckItem('if 7za.exe is installed', limit_os: 'Windows', level: 999)] + public function check7zaWin(): ?CheckResult + { + $path = FileSystem::convertPath(PKG_ROOT_PATH . '\bin\7za.exe'); + if (!file_exists($path)) { + return CheckResult::fail('7za.exe not found', 'install-7za-win'); + } + return CheckResult::ok($path); } #[CheckItem('if nasm installed', level: 995)] @@ -112,12 +123,20 @@ public function installPerl(): bool return true; } - #[FixItem('install-php-sdk')] - public function installSDK(): bool + #[FixItem('install-msys2-build-essentials')] + public function installMsys2(): bool + { + $installer = new PackageInstaller(interactive: false); + $installer->addInstallPackage('msys2-build-essentials'); + $installer->run(true); + return true; + } + + #[FixItem('install-7za-win')] + public function install7zaWin(): bool { - FileSystem::removeDir(getenv('PHP_SDK_PATH')); $installer = new PackageInstaller(interactive: false); - $installer->addInstallPackage('php-sdk-binary-tools'); + $installer->addInstallPackage('7za-win'); $installer->run(true); return true; } diff --git a/src/StaticPHP/Runtime/Shell/DefaultShell.php b/src/StaticPHP/Runtime/Shell/DefaultShell.php index f20fca339..2761f32fc 100644 --- a/src/StaticPHP/Runtime/Shell/DefaultShell.php +++ b/src/StaticPHP/Runtime/Shell/DefaultShell.php @@ -184,12 +184,14 @@ public function executeUnzip(string $zip_path, string $target_path): void */ public function execute7zExtract(string $archive_path, string $target_path): bool { - $sdk_path = getenv('PHP_SDK_PATH'); - if ($sdk_path === false) { - throw new SPCInternalException('PHP_SDK_PATH environment variable is not set'); + // 7za.exe is installed by the 7za-win target package into PKG_ROOT_PATH\bin, + // which is added to PATH by MSVCToolchain::initEnv(). + $_7z_path = FileSystem::convertPath(PKG_ROOT_PATH . '\bin\7za.exe'); + if (!file_exists($_7z_path)) { + throw new SPCInternalException('7za.exe not found. Please install the 7za-win target package.'); } - $_7z = escapeshellarg(FileSystem::convertPath($sdk_path . '/bin/7za.exe')); + $_7z = escapeshellarg(FileSystem::convertPath($_7z_path)); $archive_arg = escapeshellarg(FileSystem::convertPath($archive_path)); $target_arg = escapeshellarg(FileSystem::convertPath($target_path)); diff --git a/src/StaticPHP/Toolchain/MSVCToolchain.php b/src/StaticPHP/Toolchain/MSVCToolchain.php index 1449db70d..646564fa1 100644 --- a/src/StaticPHP/Toolchain/MSVCToolchain.php +++ b/src/StaticPHP/Toolchain/MSVCToolchain.php @@ -14,10 +14,14 @@ class MSVCToolchain implements ToolchainInterface public function initEnv(): void { GlobalEnvManager::addPathIfNotExists(PKG_ROOT_PATH . '\bin'); - $sdk = getenv('PHP_SDK_PATH'); - if ($sdk !== false) { - GlobalEnvManager::addPathIfNotExists($sdk . '\bin'); - GlobalEnvManager::addPathIfNotExists($sdk . '\msys2\usr\bin'); + // msys2-build-essentials: add MSYS2 usr\bin to PATH so that 7za.exe, make, autoconf, etc. are available. + // This must be done here because msys2-build-essentials is not a dependency of any library package, + // so its path@windows entries are not automatically applied by the package installer at runtime. + $msys2_path = getenv('SPC_MSYS2_PATH') ?: (PKG_ROOT_PATH . '\msys2-build-essentials\msys64'); + if (is_dir($msys2_path)) { + GlobalEnvManager::putenv("SPC_MSYS2_PATH={$msys2_path}"); + GlobalEnvManager::addPathIfNotExists($msys2_path . '\usr\bin'); + GlobalEnvManager::addPathIfNotExists("{$msys2_path}\\usr\\lib\\p7zip"); } // strawberry-perl if (is_dir(PKG_ROOT_PATH . '\strawberry-perl')) { diff --git a/src/StaticPHP/Util/FileSystem.php b/src/StaticPHP/Util/FileSystem.php index 28a4facd7..ad41425c0 100644 --- a/src/StaticPHP/Util/FileSystem.php +++ b/src/StaticPHP/Util/FileSystem.php @@ -411,7 +411,7 @@ public static function replacePathVariable(string $path): string $replacement = [ '{build_root_path}' => BUILD_ROOT_PATH, '{pkg_root_path}' => PKG_ROOT_PATH, - '{php_sdk_path}' => getenv('PHP_SDK_PATH') ? getenv('PHP_SDK_PATH') : WORKING_DIR . '/php-sdk-binary-tools', + '{spc_msys2_path}' => getenv('SPC_MSYS2_PATH') ?: (PKG_ROOT_PATH . DIRECTORY_SEPARATOR . 'msys2-build-essentials' . DIRECTORY_SEPARATOR . 'msys64'), '{working_dir}' => WORKING_DIR, '{download_path}' => DOWNLOAD_PATH, '{source_path}' => SOURCE_PATH, From ef83ff074ec5e136572ad8e73c06de2c374e7316 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 17:33:48 +0800 Subject: [PATCH 02/12] fix(source): use ftp.gnu.org as primary, ftpmirror.gnu.org as fallback All GNU packages now use ftp.gnu.org (stable canonical server) as the primary filelist source, with ftpmirror.gnu.org configured as source-mirror fallback. ftpmirror uses DNS round-robin across many mirrors of varying reliability; this setup eliminates random CI failures caused by unreachable mirror nodes while preserving a fallback path. --- config/artifact/ncurses.yml | 4 ++++ config/pkg/lib/gettext.yml | 4 ++++ config/pkg/lib/gmp.yml | 7 ++++--- config/pkg/lib/idn2.yml | 4 ++++ config/pkg/lib/libiconv.yml | 4 ++++ config/pkg/lib/libunistring.yml | 4 ++++ config/pkg/lib/readline.yml | 4 ++++ 7 files changed, 28 insertions(+), 3 deletions(-) diff --git a/config/artifact/ncurses.yml b/config/artifact/ncurses.yml index 8d39e81b0..c13e8787d 100644 --- a/config/artifact/ncurses.yml +++ b/config/artifact/ncurses.yml @@ -3,6 +3,10 @@ ncurses: license-files: - COPYING source: + type: filelist + url: 'https://ftp.gnu.org/gnu/ncurses/' + regex: '/href="(?ncurses-(?[^"]+)\.tar\.gz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/ncurses/' regex: '/href="(?ncurses-(?[^"]+)\.tar\.gz)"/' diff --git a/config/pkg/lib/gettext.yml b/config/pkg/lib/gettext.yml index 047430331..5e81f795a 100644 --- a/config/pkg/lib/gettext.yml +++ b/config/pkg/lib/gettext.yml @@ -2,6 +2,10 @@ gettext: type: library artifact: source: + type: filelist + url: 'https://ftp.gnu.org/gnu/gettext/' + regex: '/href="(?gettext-(?[^"]+)\.tar\.xz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/gettext/' regex: '/href="(?gettext-(?[^"]+)\.tar\.xz)"/' diff --git a/config/pkg/lib/gmp.yml b/config/pkg/lib/gmp.yml index 803030566..2d70c7ee4 100644 --- a/config/pkg/lib/gmp.yml +++ b/config/pkg/lib/gmp.yml @@ -3,11 +3,12 @@ gmp: artifact: source: type: filelist - url: 'https://ftpmirror.gnu.org/gnu/gmp/' + url: 'https://ftp.gnu.org/gnu/gmp/' regex: '/href="(?gmp-(?[^"]+)\.tar\.xz)"/' source-mirror: - type: url - url: 'https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz' + type: filelist + url: 'https://ftpmirror.gnu.org/gnu/gmp/' + regex: '/href="(?gmp-(?[^"]+)\.tar\.xz)"/' metadata: license-files: ['@/gmp.txt'] license: Custom diff --git a/config/pkg/lib/idn2.yml b/config/pkg/lib/idn2.yml index 3b597b4d6..6a1524677 100644 --- a/config/pkg/lib/idn2.yml +++ b/config/pkg/lib/idn2.yml @@ -2,6 +2,10 @@ idn2: type: library artifact: source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libidn/' + regex: '/href="(?libidn2-(?[^"]+)\.tar\.gz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/libidn/' regex: '/href="(?libidn2-(?[^"]+)\.tar\.gz)"/' diff --git a/config/pkg/lib/libiconv.yml b/config/pkg/lib/libiconv.yml index 2893679c9..5b21f603a 100644 --- a/config/pkg/lib/libiconv.yml +++ b/config/pkg/lib/libiconv.yml @@ -2,6 +2,10 @@ libiconv: type: library artifact: source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libiconv/' + regex: '/href="(?libiconv-(?[^"]+)\.tar\.gz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/libiconv/' regex: '/href="(?libiconv-(?[^"]+)\.tar\.gz)"/' diff --git a/config/pkg/lib/libunistring.yml b/config/pkg/lib/libunistring.yml index 5a78fa141..47530c6aa 100644 --- a/config/pkg/lib/libunistring.yml +++ b/config/pkg/lib/libunistring.yml @@ -2,6 +2,10 @@ libunistring: type: library artifact: source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libunistring/' + regex: '/href="(?libunistring-(?[^"]+)\.tar\.gz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/libunistring/' regex: '/href="(?libunistring-(?[^"]+)\.tar\.gz)"/' diff --git a/config/pkg/lib/readline.yml b/config/pkg/lib/readline.yml index 2dd25e49d..9b6045717 100644 --- a/config/pkg/lib/readline.yml +++ b/config/pkg/lib/readline.yml @@ -2,6 +2,10 @@ readline: type: library artifact: source: + type: filelist + url: 'https://ftp.gnu.org/gnu/readline/' + regex: '/href="(?readline-(?[^"]+)\.tar\.gz)"/' + source-mirror: type: filelist url: 'https://ftpmirror.gnu.org/gnu/readline/' regex: '/href="(?readline-(?[^"]+)\.tar\.gz)"/' From 2a7966aa4b42119cfe3aa4ac9023f06fddf7baa4 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 19:26:55 +0800 Subject: [PATCH 03/12] Fix curl zstd build bug --- src/Package/Target/curl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Package/Target/curl.php b/src/Package/Target/curl.php index 3117a8cd1..a707fb7c1 100644 --- a/src/Package/Target/curl.php +++ b/src/Package/Target/curl.php @@ -40,7 +40,7 @@ public function buildWin(LibraryPackage $lib): void ->optionalPackage('brotli', ...cmake_boolean_args('CURL_BROTLI')) ->addConfigureArgs( '-DBUILD_CURL_EXE=ON', - '-DZSTD_LIBRARY=zstd_static.lib', + '-DZSTD_LIBRARY=' . BUILD_LIB_PATH . '/zstd_static.lib', '-DBUILD_TESTING=OFF', '-DBUILD_EXAMPLES=OFF', '-DUSE_LIBIDN2=OFF', From fd8ab71d809504c7287076b72145dbbc3416686a Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 19:27:32 +0800 Subject: [PATCH 04/12] feat(build): use WinCNG as crypto backend for libssh2 windows --- config/pkg/lib/libssh2.yml | 2 +- src/Package/Library/libssh2.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/pkg/lib/libssh2.yml b/config/pkg/lib/libssh2.yml index 724474162..54fa2a5e1 100644 --- a/config/pkg/lib/libssh2.yml +++ b/config/pkg/lib/libssh2.yml @@ -9,7 +9,7 @@ libssh2: metadata: license-files: [COPYING] license: BSD-3-Clause - depends: + depends@unix: - openssl headers: - libssh2.h diff --git a/src/Package/Library/libssh2.php b/src/Package/Library/libssh2.php index b41434e09..27761d7f4 100644 --- a/src/Package/Library/libssh2.php +++ b/src/Package/Library/libssh2.php @@ -18,6 +18,7 @@ public function buildWin(LibraryPackage $lib): void { WindowsCMakeExecutor::create($lib) ->addConfigureArgs( + '-DCRYPTO_BACKEND=WinCNG', '-DENABLE_ZLIB_COMPRESSION=ON', '-DBUILD_TESTING=OFF' ) From c4d7ca819b4f55280202bd7727c46702b0235d76 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 19:27:47 +0800 Subject: [PATCH 05/12] fix(openssl): update perl path for Windows compatibility --- src/Package/Library/openssl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Package/Library/openssl.php b/src/Package/Library/openssl.php index 69297198d..2f59da225 100644 --- a/src/Package/Library/openssl.php +++ b/src/Package/Library/openssl.php @@ -24,7 +24,7 @@ public function validate(): void { if (SystemTarget::getTargetOS() === 'Windows') { global $argv; - $perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe'; + $perl_path_native = PKG_ROOT_PATH . '\strawberry-perl\perl\bin\perl.exe'; $perl = file_exists($perl_path_native) ? ($perl_path_native) : WindowsUtil::findCommand('perl.exe'); if ($perl === null) { throw new EnvironmentException( From c31bf73685267bdbcf11516486bbf8dc034cfbbd Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 19:28:15 +0800 Subject: [PATCH 06/12] feat(build): add bison and re2c to required packages; bypass phpsdk_version check for MSVC + msys2 --- src/Package/Artifact/msys2_build_essentials.php | 2 +- src/Package/Target/php/windows.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Package/Artifact/msys2_build_essentials.php b/src/Package/Artifact/msys2_build_essentials.php index 920927bfc..87d522185 100644 --- a/src/Package/Artifact/msys2_build_essentials.php +++ b/src/Package/Artifact/msys2_build_essentials.php @@ -16,7 +16,7 @@ class msys2_build_essentials { // MSYS subsystem packages required for autotools-based builds. - private const REQUIRED_PACKAGES = ['make', 'autoconf', 'automake', 'libtool', 'pkgconf', 'perl']; + private const REQUIRED_PACKAGES = ['make', 'autoconf', 'automake', 'libtool', 'pkgconf', 'perl', 'bison', 're2c']; #[CustomBinary('msys2-build-essentials', ['windows-x86_64'])] public function downBinary(ArtifactDownloader $downloader): DownloadResult diff --git a/src/Package/Target/php/windows.php b/src/Package/Target/php/windows.php index a38da5b43..57a9e3ae0 100644 --- a/src/Package/Target/php/windows.php +++ b/src/Package/Target/php/windows.php @@ -39,6 +39,13 @@ public function buildconfForWindows(TargetPackage $package, PackageInstaller $in InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf.bat')); cmd()->cd($package->getSourceDir())->exec('.\buildconf.bat'); + // Bypass the phpsdk_version check in configure.js: we use MSVC + msys2 instead of PHP SDK, so phpsdk_version is not available and the check would always fail. + FileSystem::replaceFileStr( + "{$package->getSourceDir()}\\configure.js", + 'check_binary_tools_sdk();', + '/* check_binary_tools_sdk(); skipped: using MSVC + msys2 without PHP SDK */' + ); + if ($package->getBuildOption('enable-micro-win32') && $installer->isPackageResolved('php-micro')) { SourcePatcher::patchMicroWin32(); } else { From 3bb84f3b94a21f337c4a195f42310e74883b79e3 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 19:35:07 +0800 Subject: [PATCH 07/12] feat(build): add zlib as a dependency for Windows --- config/pkg/lib/libssh2.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/pkg/lib/libssh2.yml b/config/pkg/lib/libssh2.yml index 54fa2a5e1..fa43fb274 100644 --- a/config/pkg/lib/libssh2.yml +++ b/config/pkg/lib/libssh2.yml @@ -11,6 +11,8 @@ libssh2: license: BSD-3-Clause depends@unix: - openssl + depends@windows: + - zlib headers: - libssh2.h - libssh2_publickey.h From c88041b7e0f1a3b8d5237cee1ae3e6bdbd9aad35 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 21 Jun 2026 20:08:27 +0800 Subject: [PATCH 08/12] feat(build): add UPX as an optional package for compression --- src/Package/Target/php.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Package/Target/php.php b/src/Package/Target/php.php index a4ae5c56a..d1f5a54e7 100644 --- a/src/Package/Target/php.php +++ b/src/Package/Target/php.php @@ -255,6 +255,11 @@ public function resolveBuild(TargetPackage $package, PackageInstaller $installer $installer->addBuildPackage('php-embed'); } + // UPX compression: ensure the upx binary package is installed when requested + if ($package->getBuildOption('with-upx-pack')) { + $additional_packages[] = 'upx'; + } + return [...$extensions_pkg, ...$additional_packages]; } From be329c1d567ee0179f5a5206fb9b5062e5e74131 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 22 Jun 2026 11:14:14 +0800 Subject: [PATCH 09/12] feat(build): add patch to Makefile for include order to resolve zip.h conflict --- src/Package/Target/php/windows.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Package/Target/php/windows.php b/src/Package/Target/php/windows.php index 57a9e3ae0..7697ce4b6 100644 --- a/src/Package/Target/php/windows.php +++ b/src/Package/Target/php/windows.php @@ -95,6 +95,17 @@ public function configureForWindows(TargetPackage $package, PackageInstaller $in cmd()->cd($package->getSourceDir())->exec(".\\configure.bat {$args} {$static_extension_str}"); } + #[BeforeStage('php', [self::class, 'makeCliForWindows'])] + #[PatchDescription('Patch Makefile to ensure buildroot/include comes before extension CFLAGS (fixes zip.h conflict with minizip)')] + public function patchMakefileIncludeOrder(TargetPackage $package): void + { + FileSystem::replaceFileStr( + "{$package->getSourceDir()}\\Makefile", + '$(CFLAGS_PHP_OBJ) $(CFLAGS)', + '$(CFLAGS) $(CFLAGS_PHP_OBJ)' + ); + } + #[BeforeStage('php', [self::class, 'makeCliForWindows'])] #[PatchDescription('Patch Windows Makefile for CLI target')] public function patchCLITarget(TargetPackage $package): void From 2b210f940365885f9765a6b7913504fc7322f66d Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 22 Jun 2026 13:33:02 +0800 Subject: [PATCH 10/12] feat(logging): synchronize logger level and debug mode with output verbosity --- src/StaticPHP/Command/CraftCommand.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/StaticPHP/Command/CraftCommand.php b/src/StaticPHP/Command/CraftCommand.php index 864949020..4ec67e6bf 100644 --- a/src/StaticPHP/Command/CraftCommand.php +++ b/src/StaticPHP/Command/CraftCommand.php @@ -36,6 +36,15 @@ public function handle(): int // set verbosity $this->output->setVerbosity($craft['verbosity']); + // sync logger level and ApplicationContext debug mode to match the new verbosity + $level = match ($this->output->getVerbosity()) { + OutputInterface::VERBOSITY_VERBOSE => 'info', + OutputInterface::VERBOSITY_VERY_VERBOSE, OutputInterface::VERBOSITY_DEBUG => 'debug', + default => 'warning', + }; + logger()->setLevel($level); + ApplicationContext::setDebug($this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG); + // apply env array_walk($craft['extra-env'], fn ($v, $k) => f_putenv("{$k}={$v}")); From 38e01a9b88fba3db82525c2cd4547b963ca2fc37 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 22 Jun 2026 13:33:25 +0800 Subject: [PATCH 11/12] feat(tests): enhance label information for triggering extension build tests --- src/StaticPHP/Command/Dev/TestBotCommand.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/StaticPHP/Command/Dev/TestBotCommand.php b/src/StaticPHP/Command/Dev/TestBotCommand.php index e5739a727..6ee1e1e3d 100644 --- a/src/StaticPHP/Command/Dev/TestBotCommand.php +++ b/src/StaticPHP/Command/Dev/TestBotCommand.php @@ -253,6 +253,13 @@ private function buildCommentBody( $fmt($targets), ); + $available_labels = implode(', ', [ + '`need-test` (gate)', + '`test/linux` `test/windows` `test/macos` (platform)', + '`test/tier2` (extra arch)', + '`test/php-83` `test/php-84` (PHP version)', + ]); + // Case 1: need-test absent → invite the author to add it if (!$need_test) { return implode("\n", [ @@ -261,11 +268,9 @@ private function buildCommentBody( '', $detected, '', - 'To trigger extension build tests on this PR, add the `need-test` label:', + 'To trigger extension build tests on this PR, add the `need-test` label.', '', - '**Gate**: `need-test`', - '**Platform filter** (optional, default all): `test/linux` `test/windows` `test/macos` · `test/tier2`', - '**PHP version** (optional, default 8.5): `test/php-83` `test/php-84`', + '**Available labels**: ' . $available_labels, ]); } @@ -307,6 +312,7 @@ private function buildCommentBody( '', $detected, '**Active labels**: ' . $labels_str, + '**Available labels**: ' . $available_labels, '**Config**: ' . implode(' + ', $platform_parts) . ' | ' . $php_str, ]); } From db2d9a909fab4a988b164d34f9bf626640bfefd3 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 22 Jun 2026 16:44:44 +0800 Subject: [PATCH 12/12] feat(gmssl): add patch for pbkdf2_hmac_sm3_genkey rename and update build process --- src/Package/Extension/gmssl.php | 12 ++++++++++++ src/Package/Library/gmssl.php | 16 ++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Package/Extension/gmssl.php b/src/Package/Extension/gmssl.php index 372e7d7c4..a230f407f 100644 --- a/src/Package/Extension/gmssl.php +++ b/src/Package/Extension/gmssl.php @@ -27,6 +27,18 @@ public function patchSm2VerifyCtx(): void ); } + #[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-gmssl')] + #[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-gmssl')] + #[PatchDescription('Fix ext-gmssl v1.1.1: pbkdf2_hmac_sm3_genkey was renamed to sm3_pbkdf2 in GmSSL >= 3.2.0')] + public function patchPbkdf2Rename(): void + { + FileSystem::replaceFileStr( + "{$this->getSourceDir()}/gmssl.c", + 'pbkdf2_hmac_sm3_genkey', + 'sm3_pbkdf2' + ); + } + #[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-gmssl')] #[PatchDescription('Add CHECK_LIB to config.w32 for static Windows builds')] public function patchBeforeBuildconfWin(): bool diff --git a/src/Package/Library/gmssl.php b/src/Package/Library/gmssl.php index 8887b64fe..eff598a32 100644 --- a/src/Package/Library/gmssl.php +++ b/src/Package/Library/gmssl.php @@ -45,13 +45,13 @@ public function buildWin(LibraryPackage $lib): void ->toStep(1) ->build(); - // fix cmake_install.cmake install prefix (GmSSL overrides it internally) - $installCmake = "{$buildDir}\\cmake_install.cmake"; - FileSystem::writeFile( - $installCmake, - 'set(CMAKE_INSTALL_PREFIX "' . str_replace('\\', '/', $lib->getBuildRootPath()) . '")' . PHP_EOL . FileSystem::readFile($installCmake) - ); - - cmd()->cd($buildDir)->exec('nmake install XCFLAGS=/MT'); + cmd()->cd($buildDir)->exec('nmake gmssl XCFLAGS=/MT'); + + $libPath = "{$lib->getBuildRootPath()}/lib"; + $incPath = "{$lib->getBuildRootPath()}/include/gmssl"; + FileSystem::createDir($libPath); + FileSystem::createDir($incPath); + FileSystem::copy("{$buildDir}\\bin\\gmssl.lib", "{$libPath}/gmssl.lib"); + FileSystem::copyDir("{$lib->getSourceDir()}\\include\\gmssl", $incPath); } }