Compare commits

...

13 Commits

Author SHA1 Message Date
Jerry Ma
b4ed673261 feat(windows): replace php-sdk-binary-tools with MSYS2 + 7za-win (#1193) 2026-06-23 14:36:28 +08:00
crazywhalecc
db2d9a909f feat(gmssl): add patch for pbkdf2_hmac_sm3_genkey rename and update build process 2026-06-22 16:44:44 +08:00
crazywhalecc
38e01a9b88 feat(tests): enhance label information for triggering extension build tests 2026-06-22 13:33:25 +08:00
crazywhalecc
2b210f9403 feat(logging): synchronize logger level and debug mode with output verbosity 2026-06-22 13:33:02 +08:00
crazywhalecc
be329c1d56 feat(build): add patch to Makefile for include order to resolve zip.h conflict 2026-06-22 11:14:14 +08:00
crazywhalecc
c88041b7e0 feat(build): add UPX as an optional package for compression 2026-06-21 20:08:27 +08:00
crazywhalecc
3bb84f3b94 feat(build): add zlib as a dependency for Windows 2026-06-21 19:35:07 +08:00
crazywhalecc
c31bf73685 feat(build): add bison and re2c to required packages; bypass phpsdk_version check for MSVC + msys2 2026-06-21 19:28:15 +08:00
crazywhalecc
c4d7ca819b fix(openssl): update perl path for Windows compatibility 2026-06-21 19:27:47 +08:00
crazywhalecc
fd8ab71d80 feat(build): use WinCNG as crypto backend for libssh2 windows 2026-06-21 19:27:32 +08:00
crazywhalecc
2a7966aa4b Fix curl zstd build bug 2026-06-21 19:26:55 +08:00
crazywhalecc
ef83ff074e 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.
2026-06-21 17:33:48 +08:00
crazywhalecc
06864fc3f6 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.
2026-06-21 16:56:40 +08:00
34 changed files with 267 additions and 50 deletions

View File

@@ -3,6 +3,10 @@ ncurses:
license-files:
- COPYING
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/ncurses/'
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/ncurses/'
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'

View File

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

View File

@@ -2,6 +2,10 @@ gettext:
type: library
artifact:
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/gettext/'
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/gettext/'
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'

View File

@@ -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="(?<file>gmp-(?<version>[^"]+)\.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="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/'
metadata:
license-files: ['@/gmp.txt']
license: Custom

View File

@@ -2,6 +2,10 @@ idn2:
type: library
artifact:
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libidn/'
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libidn/'
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -2,6 +2,10 @@ libiconv:
type: library
artifact:
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libiconv/'
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libiconv/'
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -9,8 +9,10 @@ libssh2:
metadata:
license-files: [COPYING]
license: BSD-3-Clause
depends:
depends@unix:
- openssl
depends@windows:
- zlib
headers:
- libssh2.h
- libssh2_publickey.h

View File

@@ -2,6 +2,10 @@ libunistring:
type: library
artifact:
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libunistring/'
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libunistring/'
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -2,6 +2,10 @@ readline:
type: library
artifact:
source:
type: filelist
url: 'https://ftp.gnu.org/gnu/readline/'
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist
url: 'https://ftpmirror.gnu.org/gnu/readline/'
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -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' }

View File

@@ -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'

View File

@@ -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' } }

View File

@@ -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}' }

View File

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

View File

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

View File

@@ -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 包类型

View File

@@ -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 构建环境的配置。
:::
## 已重命名 / 已弃用的选项

View File

@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Package\Artifact;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Artifact\Downloader\DownloadResult;
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
use StaticPHP\Attribute\Artifact\BinaryExtract;
use StaticPHP\Attribute\Artifact\CustomBinary;
use StaticPHP\Exception\DownloaderException;
use StaticPHP\Util\FileSystem;
use StaticPHP\Util\GlobalEnvManager;
class msys2_build_essentials
{
// MSYS subsystem packages required for autotools-based builds.
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
{
// MSYS2 nightly self-extracting archive; running it with `-y -oTARGET` extracts to TARGET\msys64\.
$url = 'https://github.com/msys2/msys2-installer/releases/download/nightly-x86_64/msys2-base-x86_64-latest.sfx.exe';
$filename = 'msys2-base-x86_64-latest.sfx.exe';
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . $filename;
default_shell()->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");
}
}

View File

@@ -27,6 +27,18 @@ class gmssl extends PhpExtensionPackage
);
}
#[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

View File

@@ -45,13 +45,13 @@ class gmssl
->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 gmssl XCFLAGS=/MT');
cmd()->cd($buildDir)->exec('nmake install 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);
}
}

View File

@@ -18,6 +18,7 @@ class libssh2
{
WindowsCMakeExecutor::create($lib)
->addConfigureArgs(
'-DCRYPTO_BACKEND=WinCNG',
'-DENABLE_ZLIB_COMPRESSION=ON',
'-DBUILD_TESTING=OFF'
)

View File

@@ -24,7 +24,7 @@ class openssl
{
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(

View File

@@ -40,7 +40,7 @@ class curl
->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',

View File

@@ -255,6 +255,11 @@ class php extends TargetPackage
$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];
}

View File

@@ -39,6 +39,13 @@ trait windows
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 {
@@ -88,6 +95,17 @@ trait windows
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

View File

@@ -644,7 +644,7 @@ class Artifact
'{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,

View File

@@ -614,7 +614,7 @@ class ArtifactExtractor
'{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);
}

View File

@@ -76,9 +76,10 @@ class DownloadResult
?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);
}
/**

View File

@@ -36,6 +36,15 @@ class CraftCommand extends BaseCommand
// 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}"));

View File

@@ -253,6 +253,13 @@ class TestBotCommand extends BaseCommand
$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 @@ class TestBotCommand extends BaseCommand
'',
$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 @@ class TestBotCommand extends BaseCommand
'',
$detected,
'**Active labels**: ' . $labels_str,
'**Available labels**: ' . $available_labels,
'**Config**: ' . implode(' + ', $platform_parts) . ' | ' . $php_str,
]);
}

View File

@@ -54,13 +54,24 @@ class WindowsToolCheck
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 @@ class WindowsToolCheck
return true;
}
#[FixItem('install-php-sdk')]
public function installSDK(): bool
#[FixItem('install-msys2-build-essentials')]
public function installMsys2(): bool
{
FileSystem::removeDir(getenv('PHP_SDK_PATH'));
$installer = new PackageInstaller(interactive: false);
$installer->addInstallPackage('php-sdk-binary-tools');
$installer->addInstallPackage('msys2-build-essentials');
$installer->run(true);
return true;
}
#[FixItem('install-7za-win')]
public function install7zaWin(): bool
{
$installer = new PackageInstaller(interactive: false);
$installer->addInstallPackage('7za-win');
$installer->run(true);
return true;
}

View File

@@ -184,12 +184,14 @@ class DefaultShell extends Shell
*/
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));

View File

@@ -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')) {

View File

@@ -411,7 +411,7 @@ class FileSystem
$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,