mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-10 02:15:36 +08:00
Merge remote-tracking branch 'origin/fable-v3-windows' into fable-v3-windows
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "bin/spc dev:lint-config --check",
|
||||
"action": "php bin/spc dev:lint-config --check",
|
||||
"conditions": [
|
||||
{
|
||||
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\InDirectory",
|
||||
|
||||
@@ -9,5 +9,4 @@ libiconv-win:
|
||||
license-files: [source/COPYING]
|
||||
license: GPL-3.0-or-later
|
||||
static-libs@windows:
|
||||
- libiconv.lib
|
||||
- libiconv_a.lib
|
||||
|
||||
@@ -27,4 +27,5 @@ openssl:
|
||||
- libcrypto.lib
|
||||
tools@windows:
|
||||
- jom
|
||||
- nasm
|
||||
- strawberry-perl
|
||||
|
||||
@@ -28,3 +28,9 @@ postgresql:
|
||||
- libpq.lib
|
||||
- libpgport.lib
|
||||
- libpgcommon.lib
|
||||
tools@windows:
|
||||
- python-win
|
||||
- meson
|
||||
- ninja
|
||||
- winflexbison
|
||||
- strawberry-perl
|
||||
|
||||
11
config/pkg/tool/meson.yml
Normal file
11
config/pkg/tool/meson.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
meson:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/mesonbuild/meson/releases/download/1.11.1/meson-1.11.1-py3-none-any.whl', extract: '{pkg_root_path}/meson/meson-1.11.1-py3-none-any.whl' }
|
||||
path@windows:
|
||||
- '{pkg_root_path}\meson'
|
||||
tool:
|
||||
provides:
|
||||
- meson.bat
|
||||
binary-subdir: meson
|
||||
9
config/pkg/tool/ninja.yml
Normal file
9
config/pkg/tool/ninja.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
ninja:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/ninja-build/ninja/releases/download/v1.13.2/ninja-win.zip', extract: { ninja.exe: '{pkg_root_path}/bin/ninja.exe' } }
|
||||
tool:
|
||||
provides:
|
||||
- ninja.exe
|
||||
binary-subdir: bin
|
||||
8
config/pkg/tool/python-win.yml
Normal file
8
config/pkg/tool/python-win.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
python-win:
|
||||
type: tool
|
||||
artifact:
|
||||
binary: custom
|
||||
tool:
|
||||
provides:
|
||||
- python.exe
|
||||
binary-subdir: python-win/tools
|
||||
12
config/pkg/tool/winflexbison.yml
Normal file
12
config/pkg/tool/winflexbison.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
winflexbison:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip', extract: '{pkg_root_path}/winflexbison' }
|
||||
path@windows:
|
||||
- '{pkg_root_path}\winflexbison'
|
||||
tool:
|
||||
provides:
|
||||
- win_flex.exe
|
||||
- win_bison.exe
|
||||
binary-subdir: winflexbison
|
||||
48
src/Package/Artifact/meson_win.php
Normal file
48
src/Package/Artifact/meson_win.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Artifact;
|
||||
|
||||
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
|
||||
use StaticPHP\Exception\EnvironmentException;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
class meson_win
|
||||
{
|
||||
/**
|
||||
* Meson 1.11 dropped the Windows MSI, so the artifact is the wheel, installed offline
|
||||
* into a private venv. The venv is not just packaging hygiene: pip generates a real
|
||||
* meson.exe launcher there, and PostgreSQL needs one because its build re-invokes meson
|
||||
* through find_program(), which rejects non-executables like the meson.pyz zipapp.
|
||||
*/
|
||||
#[AfterBinaryExtract('meson', ['windows-x86_64'])]
|
||||
public function afterExtract(string $target_path): void
|
||||
{
|
||||
$dir = dirname($target_path);
|
||||
$venv = "{$dir}\\venv";
|
||||
|
||||
// Prefer the python-win tool package (installed alongside via tools@windows),
|
||||
// fall back to whatever Python the machine already has.
|
||||
$candidates = ['"' . PKG_ROOT_PATH . '\python-win\tools\python.exe"', 'python', 'py -3'];
|
||||
$python = null;
|
||||
foreach ($candidates as $candidate) {
|
||||
[$code] = cmd()->execWithResult("{$candidate} --version", false);
|
||||
if ($code === 0) {
|
||||
$python = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($python === null) {
|
||||
throw new EnvironmentException('meson needs Python 3; the python-win tool package did not install and no system Python was found.');
|
||||
}
|
||||
|
||||
if (is_dir($venv)) {
|
||||
FileSystem::removeDir($venv);
|
||||
}
|
||||
cmd()->exec("{$python} -m venv \"{$venv}\"")
|
||||
->exec("\"{$venv}\\Scripts\\python.exe\" -m pip install --no-index --no-deps \"{$target_path}\"");
|
||||
|
||||
FileSystem::writeFile("{$dir}\\meson.bat", "@echo off\r\n\"%~dp0venv\\Scripts\\meson.exe\" %*\r\n");
|
||||
}
|
||||
}
|
||||
66
src/Package/Artifact/python_win.php
Normal file
66
src/Package/Artifact/python_win.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Artifact;
|
||||
|
||||
use StaticPHP\Artifact\ArtifactDownloader;
|
||||
use StaticPHP\Artifact\Downloader\DownloadResult;
|
||||
use StaticPHP\Artifact\Downloader\Type\CheckUpdateResult;
|
||||
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
|
||||
use StaticPHP\Attribute\Artifact\CustomBinary;
|
||||
use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate;
|
||||
use StaticPHP\Exception\DownloaderException;
|
||||
|
||||
/**
|
||||
* Full CPython for Windows from the official python.org nuget package. It is a plain zip
|
||||
* (python.exe plus stdlib under tools/, venv and ensurepip included), so it installs into
|
||||
* the pkgroot without touching the system. Used by the meson tool package.
|
||||
*/
|
||||
class python_win
|
||||
{
|
||||
#[CustomBinary('python-win', [
|
||||
'windows-x86_64',
|
||||
])]
|
||||
public function downBinary(ArtifactDownloader $downloader): DownloadResult
|
||||
{
|
||||
$version = $this->getLatestVersion($downloader->getRetry());
|
||||
|
||||
$url = "https://api.nuget.org/v3-flatcontainer/python/{$version}/python.{$version}.nupkg";
|
||||
// .nupkg is a zip; name the cache file .zip so the extractor treats it as one
|
||||
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . "python-win-{$version}.zip";
|
||||
default_shell()->executeCurlDownload($url, $path, retries: $downloader->getRetry());
|
||||
|
||||
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $version], extract: '{pkg_root_path}/python-win', version: $version);
|
||||
}
|
||||
|
||||
#[CustomBinaryCheckUpdate('python-win', ['windows-x86_64'])]
|
||||
public function checkUpdateBinary(?string $old_version): CheckUpdateResult
|
||||
{
|
||||
$version = $this->getLatestVersion();
|
||||
return new CheckUpdateResult(
|
||||
old: $old_version,
|
||||
new: $version,
|
||||
needUpdate: $old_version === null || $version !== $old_version,
|
||||
);
|
||||
}
|
||||
|
||||
#[AfterBinaryExtract('python-win', ['windows-x86_64'])]
|
||||
public function afterExtract(string $target_path): void
|
||||
{
|
||||
if (!file_exists("{$target_path}\\tools\\python.exe")) {
|
||||
throw new DownloaderException("Python installation appears incomplete: python.exe not found at {$target_path}\\tools\\python.exe");
|
||||
}
|
||||
}
|
||||
|
||||
private function getLatestVersion(int $retries = 0): string
|
||||
{
|
||||
$index = default_shell()->executeCurl('https://api.nuget.org/v3-flatcontainer/python/index.json', retries: $retries);
|
||||
$versions = $index ? (json_decode($index, true)['versions'] ?? []) : [];
|
||||
$stable = array_filter($versions, fn ($v) => preg_match('/^\d+\.\d+\.\d+$/', $v));
|
||||
if ($stable === []) {
|
||||
throw new DownloaderException('Failed to get Python versions from the nuget index');
|
||||
}
|
||||
return end($stable);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,15 @@ declare(strict_types=1);
|
||||
namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageBuilder;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Package\TargetPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\SPCConfigUtil;
|
||||
|
||||
#[Extension('pgsql')]
|
||||
@@ -39,6 +43,27 @@ class pgsql extends PhpExtensionPackage
|
||||
return "--with-pgsql={$builder->getBuildRootPath()}";
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-pgsql')]
|
||||
#[PatchDescription('Link the Win32 system libraries the static libpq needs')]
|
||||
public function patchConfigW32ForWindows(TargetPackage $package): void
|
||||
{
|
||||
$config = "{$package->getSourceDir()}\\ext\\pgsql\\config.w32";
|
||||
|
||||
if (str_contains(FileSystem::readFile($config), 'LIBS_PGSQL')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// libpq uses SSPI for Windows auth (secur32) and the static libcrypto behind it
|
||||
// reads the system cert store (crypt32). Nothing else puts these on the link line
|
||||
// when the openssl extension itself is not part of the build.
|
||||
FileSystem::replaceFileStr(
|
||||
$config,
|
||||
'EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");',
|
||||
'EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");' . "\n\t\t" .
|
||||
'ADD_FLAG("LIBS_PGSQL", "secur32.lib crypt32.lib");'
|
||||
);
|
||||
}
|
||||
|
||||
public function getSharedExtensionEnv(): array
|
||||
{
|
||||
$parent = parent::getSharedExtensionEnv();
|
||||
|
||||
@@ -98,7 +98,8 @@ class postgresql extends LibraryPackage
|
||||
. ' -Dextra_lib_dirs=' . escapeshellarg($lib_dir);
|
||||
|
||||
// Build only the three frontend static libs (not the server) — keeps it fast and avoids
|
||||
// needing every backend dependency. meson/ninja/win_bison/win_flex/perl come from PATH.
|
||||
// needing every backend dependency. meson/ninja/win_bison/win_flex/perl come from the
|
||||
// tool packages declared in the package config (tools@windows).
|
||||
$targets = 'src/interfaces/libpq/libpq.a src/common/libpgcommon.a src/port/libpgport.a';
|
||||
|
||||
cmd()->cd($src)
|
||||
|
||||
@@ -59,7 +59,7 @@ trait unix
|
||||
}
|
||||
|
||||
if (self::getPHPVersionID() >= 80300 && self::getPHPVersionID() < 80400) {
|
||||
SourcePatcher::patchFile('spc_fix_avx512_cache_before_80400.patch', $this->getSourceDir());
|
||||
SourcePatcher::patchFile('spc_fix_avx512_cache_before_80400.patch', $package->getSourceDir());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,10 @@ trait windows
|
||||
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');
|
||||
}
|
||||
$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';
|
||||
$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';
|
||||
// /FORCE:MULTIPLE /ignore:4006: same reason as the php.exe target above. Without it the
|
||||
// CGI link fails with LNK2005 (e.g. imagick's MagickCore defines gettimeofday, which
|
||||
// php's time.obj also defines).
|
||||
$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 /FORCE:MULTIPLE /ignore:4006';
|
||||
FileSystem::writeFile("{$package->getSourceDir()}\\Makefile", implode("\r\n", $lines));
|
||||
|
||||
// Patch cgi-static, comment ZEND_TSRMLS_CACHE_DEFINE()
|
||||
@@ -268,6 +271,19 @@ trait windows
|
||||
}
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [self::class, 'makeMicroForWindows'])]
|
||||
#[PatchDescription('Add /FORCE:MULTIPLE to the micro.sfx link, matching the CLI and CGI targets')]
|
||||
public function patchMicroTarget(TargetPackage $package): void
|
||||
{
|
||||
$makefile = "{$package->getSourceDir()}\\Makefile";
|
||||
if (str_contains(FileSystem::readFile($makefile), 'LDFLAGS_MICRO=/FORCE:MULTIPLE')) {
|
||||
return;
|
||||
}
|
||||
// Same reason as the php.exe and php-cgi.exe targets: extension-bundled libs duplicate
|
||||
// symbols from php's own objects and the link fails with LNK2005.
|
||||
FileSystem::replaceFileStr($makefile, "\r\nLDFLAGS_MICRO=", "\r\nLDFLAGS_MICRO=/FORCE:MULTIPLE /ignore:4006 ");
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeMicroForWindows(TargetPackage $package, PackageBuilder $builder, PackageInstaller $installer): void
|
||||
{
|
||||
|
||||
@@ -12,7 +12,6 @@ use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use StaticPHP\Toolchain\ToolchainManager;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\GlobalEnvManager;
|
||||
use StaticPHP\Util\System\WindowsUtil;
|
||||
|
||||
#[OptionalCheck([self::class, 'optional'])]
|
||||
@@ -74,27 +73,6 @@ class WindowsToolCheck
|
||||
return CheckResult::ok($path);
|
||||
}
|
||||
|
||||
#[CheckItem('if nasm installed', level: 995)]
|
||||
public function checkNasm(): ?CheckResult
|
||||
{
|
||||
if (($a = WindowsUtil::findCommand('nasm.exe')) === null) {
|
||||
return CheckResult::fail('nasm.exe not found in path.', 'install-nasm');
|
||||
}
|
||||
return CheckResult::ok($a);
|
||||
}
|
||||
|
||||
#[CheckItem('if perl(strawberry) installed', limit_os: 'Windows', level: 994)]
|
||||
public function checkPerl(): ?CheckResult
|
||||
{
|
||||
if (($path = WindowsUtil::findCommand('perl.exe')) === null) {
|
||||
return CheckResult::fail('perl not found in path.', 'install-perl');
|
||||
}
|
||||
if (!str_contains(implode('', cmd()->execWithResult(quote($path) . ' -v', false)[1]), 'MSWin32')) {
|
||||
return CheckResult::fail($path . ' is not built for msvc.', 'install-perl');
|
||||
}
|
||||
return CheckResult::ok($path);
|
||||
}
|
||||
|
||||
#[CheckItem('if environment is properly set up', level: 1)]
|
||||
public function checkenv(): ?CheckResult
|
||||
{
|
||||
@@ -113,16 +91,6 @@ class WindowsToolCheck
|
||||
return CheckResult::ok();
|
||||
}
|
||||
|
||||
#[FixItem('install-perl')]
|
||||
public function installPerl(): bool
|
||||
{
|
||||
$installer = new PackageInstaller();
|
||||
$installer->addInstallPackage('strawberry-perl');
|
||||
$installer->run(true);
|
||||
GlobalEnvManager::addPathIfNotExists(PKG_ROOT_PATH . '\strawberry-perl');
|
||||
return true;
|
||||
}
|
||||
|
||||
#[FixItem('install-msys2-build-essentials')]
|
||||
public function installMsys2(): bool
|
||||
{
|
||||
@@ -141,15 +109,6 @@ class WindowsToolCheck
|
||||
return true;
|
||||
}
|
||||
|
||||
#[FixItem('install-nasm')]
|
||||
public function installNasm(): bool
|
||||
{
|
||||
$installer = new PackageInstaller(interactive: false);
|
||||
$installer->addInstallPackage('nasm');
|
||||
$installer->run(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
#[FixItem('install-vswhere')]
|
||||
public function installVSWhere(): bool
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user