mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-07 08:45:40 +08:00
Separate unix and windows build for php
This commit is contained in:
228
src/Package/Target/php/windows.php
Normal file
228
src/Package/Target/php/windows.php
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Target\php;
|
||||
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\BuildFor;
|
||||
use StaticPHP\Attribute\Package\Stage;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Exception\PatchException;
|
||||
use StaticPHP\Exception\SPCInternalException;
|
||||
use StaticPHP\Package\PackageBuilder;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\TargetPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\InteractiveTerm;
|
||||
use StaticPHP\Util\SourcePatcher;
|
||||
use StaticPHP\Util\System\WindowsUtil;
|
||||
use StaticPHP\Util\V2CompatLayer;
|
||||
use ZM\Logger\ConsoleColor;
|
||||
|
||||
trait windows
|
||||
{
|
||||
#[Stage]
|
||||
public function buildconfForWindows(TargetPackage $package): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf.bat'));
|
||||
V2CompatLayer::emitPatchPoint('before-php-buildconf');
|
||||
cmd()->cd($package->getSourceDir())->exec('.\buildconf.bat');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function configureForWindows(TargetPackage $package, PackageInstaller $installer): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./configure.bat'));
|
||||
V2CompatLayer::emitPatchPoint('before-php-configure');
|
||||
$args = [
|
||||
'--disable-all',
|
||||
"--with-php-build={$package->getBuildRootPath()}",
|
||||
"--with-extra-includes={$package->getIncludeDir()}",
|
||||
"--with-extra-libs={$package->getLibDir()}",
|
||||
];
|
||||
// sapis
|
||||
$cli = $installer->isPackageResolved('php-cli');
|
||||
$cgi = $installer->isPackageResolved('php-cgi');
|
||||
$micro = $installer->isPackageResolved('php-micro');
|
||||
$args[] = $cli ? '--enable-cli=yes' : '--enable-cli=no';
|
||||
$args[] = $cgi ? '--enable-cgi=yes' : '--enable-cgi=no';
|
||||
$args[] = $micro ? '--enable-micro=yes' : '--enable-micro=no';
|
||||
|
||||
// zts
|
||||
$args[] = $package->getBuildOption('enable-zts', false) ? '--enable-zts=yes' : '--enable-zts=no';
|
||||
// opcache-jit
|
||||
$args[] = !$package->getBuildOption('disable-opcache-jit', false) ? '--enable-opcache-jit=yes' : '--enable-opcache-jit=no';
|
||||
// micro win32
|
||||
if ($micro && $package->getBuildOption('enable-micro-win32', false)) {
|
||||
$args[] = '--enable-micro-win32=yes';
|
||||
}
|
||||
// config-file-scan-dir
|
||||
if ($option = $package->getBuildOption('with-config-file-scan-dir', false)) {
|
||||
$args[] = "--with-config-file-scan-dir={$option}";
|
||||
}
|
||||
// micro logo
|
||||
if ($micro && ($logo = $this->getBuildOption('with-micro-logo')) !== null) {
|
||||
$args[] = "--enable-micro-logo={$logo}";
|
||||
copy($logo, SOURCE_PATH . '\php-src\\' . $logo);
|
||||
}
|
||||
$args = implode(' ', $args);
|
||||
$static_extension_str = $this->makeStaticExtensionString($installer);
|
||||
cmd()->cd($package->getSourceDir())->exec(".\\configure.bat {$args} {$static_extension_str}");
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [self::class, 'makeCliForWindows'])]
|
||||
#[PatchDescription('Patch Windows Makefile for CLI target')]
|
||||
public function patchCLITarget(TargetPackage $package): void
|
||||
{
|
||||
// search Makefile code line contains "$(BUILD_DIR)\php.exe:"
|
||||
$content = FileSystem::readFile("{$package->getSourceDir()}\\Makefile");
|
||||
$lines = explode("\r\n", $content);
|
||||
$line_num = 0;
|
||||
$found = false;
|
||||
foreach ($lines as $v) {
|
||||
if (str_contains($v, '$(BUILD_DIR)\php.exe:')) {
|
||||
$found = $line_num;
|
||||
break;
|
||||
}
|
||||
++$line_num;
|
||||
}
|
||||
if ($found === false) {
|
||||
throw new PatchException('Windows Makefile patching for php.exe target', 'Cannot patch windows CLI Makefile, Makefile does not contain "$(BUILD_DIR)\php.exe:" line');
|
||||
}
|
||||
$lines[$line_num] = '$(BUILD_DIR)\php.exe: generated_files $(DEPS_CLI) $(PHP_GLOBAL_OBJS) $(CLI_GLOBAL_OBJS) $(STATIC_EXT_OBJS) $(ASM_OBJS) $(BUILD_DIR)\php.exe.res $(BUILD_DIR)\php.exe.manifest';
|
||||
$lines[$line_num + 1] = "\t" . '"$(LINK)" /nologo $(PHP_GLOBAL_OBJS_RESP) $(CLI_GLOBAL_OBJS_RESP) $(STATIC_EXT_OBJS_RESP) $(STATIC_EXT_LIBS) $(ASM_OBJS) $(LIBS) $(LIBS_CLI) $(BUILD_DIR)\php.exe.res /out:$(BUILD_DIR)\php.exe $(LDFLAGS) $(LDFLAGS_CLI) /ltcg /nodefaultlib:msvcrt /nodefaultlib:msvcrtd /ignore:4286';
|
||||
FileSystem::writeFile("{$package->getSourceDir()}\\Makefile", implode("\r\n", $lines));
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeCliForWindows(TargetPackage $package, PackageBuilder $builder): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('nmake php-cli'));
|
||||
|
||||
// extra lib
|
||||
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
|
||||
|
||||
// Add debug symbols for release build if --no-strip is specified
|
||||
// We need to modify CFLAGS to replace /Ox with /Zi and add /DEBUG to LDFLAGS
|
||||
$debug_overrides = '';
|
||||
if ($package->getBuildOption('no-strip', false)) {
|
||||
// Read current CFLAGS from Makefile and replace optimization flags
|
||||
$makefile_content = file_get_contents("{$package->getSourceDir()}\\Makefile");
|
||||
if (preg_match('/^CFLAGS=(.+?)$/m', $makefile_content, $matches)) {
|
||||
$cflags = $matches[1];
|
||||
// Replace /Ox (full optimization) with /Zi (debug info) and /Od (disable optimization)
|
||||
// Keep optimization for speed: /O2 /Zi instead of /Od /Zi
|
||||
$cflags = str_replace('/Ox ', '/O2 /Zi ', $cflags);
|
||||
$debug_overrides = '"CFLAGS=' . $cflags . '" "LDFLAGS=/DEBUG /LTCG /INCREMENTAL:NO" "LDFLAGS_CLI=/DEBUG" ';
|
||||
}
|
||||
}
|
||||
|
||||
cmd()->cd($package->getSourceDir())
|
||||
->exec("nmake /nologo {$debug_overrides}LIBS_CLI=\"ws2_32.lib shell32.lib {$extra_libs}\" EXTRA_LD_FLAGS_PROGRAM= php.exe");
|
||||
|
||||
$this->deployWindowsBinary($builder, $package, 'php-cli');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeForWindows(TargetPackage $package, PackageInstaller $installer): void
|
||||
{
|
||||
V2CompatLayer::emitPatchPoint('before-php-make');
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('nmake clean'));
|
||||
cmd()->cd($package->getSourceDir())->exec('nmake clean');
|
||||
|
||||
if ($installer->isPackageResolved('php-cli')) {
|
||||
$package->runStage([$this, 'makeCliForWindows']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-cgi')) {
|
||||
$package->runStage([$this, 'makeCgiForWindows']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-micro')) {
|
||||
$package->runStage([$this, 'makeMicroForWindows']);
|
||||
}
|
||||
}
|
||||
|
||||
#[BuildFor('Windows')]
|
||||
public function buildWin(TargetPackage $package): void
|
||||
{
|
||||
if ($package->getName() !== 'php') {
|
||||
return;
|
||||
}
|
||||
|
||||
$package->runStage([$this, 'buildconfForWindows']);
|
||||
$package->runStage([$this, 'configureForWindows']);
|
||||
$package->runStage([$this, 'makeForWindows']);
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [self::class, 'buildconfForWindows'])]
|
||||
#[PatchDescription('Patch SPC_MICRO_PATCHES defined patches')]
|
||||
#[PatchDescription('Fix PHP 8.1 static build bug on Windows')]
|
||||
#[PatchDescription('Fix PHP Visual Studio version detection')]
|
||||
public function patchBeforeBuildconfForWindows(TargetPackage $package): void
|
||||
{
|
||||
// php-src patches from micro
|
||||
SourcePatcher::patchPhpSrc();
|
||||
|
||||
// php 8.1 bug
|
||||
if ($this->getPHPVersionID() >= 80100 && $this->getPHPVersionID() < 80200) {
|
||||
logger()->info('Patching PHP 8.1 windows Fiber bug');
|
||||
FileSystem::replaceFileStr(
|
||||
"{$package->getSourceDir()}\\win32\\build\\config.w32",
|
||||
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
|
||||
"ADD_FLAG('ASM_OBJS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj $(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');"
|
||||
);
|
||||
FileSystem::replaceFileStr(
|
||||
"{$package->getSourceDir()}\\win32\\build\\config.w32",
|
||||
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
// Fix PHP VS version
|
||||
// get vs version
|
||||
$vc = WindowsUtil::findVisualStudio();
|
||||
$vc_matches = match ($vc['major_version']) {
|
||||
'17' => ['VS17', 'Visual C++ 2022'],
|
||||
'16' => ['VS16', 'Visual C++ 2019'],
|
||||
default => ['unknown', 'unknown'],
|
||||
};
|
||||
// patch php-src/win32/build/confutils.js
|
||||
FileSystem::replaceFileStr(
|
||||
"{$package->getSourceDir()}\\win32\\build\\confutils.js",
|
||||
'var name = "unknown";',
|
||||
"var name = short ? \"{$vc_matches[0]}\" : \"{$vc_matches[1]}\";return name;"
|
||||
);
|
||||
|
||||
// patch micro win32
|
||||
if ($package->getBuildOption('enable-micro-win32') && !file_exists("{$package->getSourceDir()}\\sapi\\micro\\php_micro.c.win32bak")) {
|
||||
copy("{$package->getSourceDir()}\\sapi\\micro\\php_micro.c", "{$package->getSourceDir()}\\php-src\\sapi\\micro\\php_micro.c.win32bak");
|
||||
FileSystem::replaceFileStr("{$package->getSourceDir()}\\sapi\\micro\\php_micro.c", '#include "php_variables.h"', '#include "php_variables.h"' . "\n#define PHP_MICRO_WIN32_NO_CONSOLE 1");
|
||||
} else {
|
||||
if (file_exists("{$package->getSourceDir()}\\sapi\\micro\\php_micro.c.win32bak")) {
|
||||
rename("{$package->getSourceDir()}\\sapi\\micro\\php_micro.c.win32bak", "{$package->getSourceDir()}\\sapi\\micro\\php_micro.c");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function deployWindowsBinary(PackageBuilder $builder, TargetPackage $package, string $sapi): void
|
||||
{
|
||||
$rel_type = 'Release'; // TODO: Debug build support
|
||||
$ts = $builder->getOption('enable-zts') ? '_TS' : '';
|
||||
$debug_dir = BUILD_ROOT_PATH . '\debug';
|
||||
$src = match ($sapi) {
|
||||
'php-cli' => ["{$package->getSourceDir()}\\x64\\{$rel_type}{$ts}", 'php.exe', 'php.pdb'],
|
||||
'php-micro' => ["{$package->getSourceDir()}\\x64\\{$rel_type}{$ts}", 'micro.sfx', 'micro.pdb'],
|
||||
'php-cgi' => ["{$package->getSourceDir()}\\x64\\{$rel_type}{$ts}", 'php-cgi.exe', 'php-cgi.pdb'],
|
||||
default => throw new SPCInternalException("Deployment does not accept type {$sapi}"),
|
||||
};
|
||||
$src = "{$src[0]}\\{$src[1]}";
|
||||
$dst = BUILD_BIN_PATH . '\\' . basename($src);
|
||||
|
||||
$builder->deployBinary($src, $dst);
|
||||
|
||||
// make debug info file path
|
||||
if ($builder->getOption('no-strip', false) && file_exists("{$src[0]}\\{$src[2]}")) {
|
||||
cmd()->exec('copy ' . escapeshellarg("{$src[0]}\\{$src[2]}") . ' ' . escapeshellarg($debug_dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user