mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-19 13:24:51 +08:00
Add windows php cli builds, support micro patches
This commit is contained in:
parent
48fbeab7e4
commit
7c8b40a49a
@ -4,19 +4,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Package\Target;
|
||||
|
||||
use Package\Target\php\unix;
|
||||
use Package\Target\php\windows;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\BuildFor;
|
||||
use StaticPHP\Attribute\Package\Info;
|
||||
use StaticPHP\Attribute\Package\InitPackage;
|
||||
use StaticPHP\Attribute\Package\ResolveBuild;
|
||||
use StaticPHP\Attribute\Package\Stage;
|
||||
use StaticPHP\Attribute\Package\Target;
|
||||
use StaticPHP\Attribute\Package\Validate;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Config\PackageConfig;
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Exception\EnvironmentException;
|
||||
use StaticPHP\Exception\SPCException;
|
||||
use StaticPHP\Exception\WrongUsageException;
|
||||
use StaticPHP\Package\Package;
|
||||
use StaticPHP\Package\PackageBuilder;
|
||||
@ -28,16 +25,11 @@ use StaticPHP\Registry\PackageLoader;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use StaticPHP\Toolchain\Interface\ToolchainInterface;
|
||||
use StaticPHP\Toolchain\ToolchainManager;
|
||||
use StaticPHP\Util\DirDiff;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\InteractiveTerm;
|
||||
use StaticPHP\Util\SourcePatcher;
|
||||
use StaticPHP\Util\SPCConfigUtil;
|
||||
use StaticPHP\Util\System\UnixUtil;
|
||||
use StaticPHP\Util\V2CompatLayer;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use ZM\Logger\ConsoleColor;
|
||||
|
||||
#[Target('php')]
|
||||
#[Target('php-cli')]
|
||||
@ -48,6 +40,9 @@ use ZM\Logger\ConsoleColor;
|
||||
#[Target('frankenphp')]
|
||||
class php extends TargetPackage
|
||||
{
|
||||
use unix;
|
||||
use windows;
|
||||
|
||||
public static function getPHPVersionID(): int
|
||||
{
|
||||
$artifact = ArtifactLoader::getArtifactInstance('php-src');
|
||||
@ -242,343 +237,6 @@ class php extends TargetPackage
|
||||
FileSystem::removeDir(BUILD_MODULES_PATH);
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [self::class, 'buildconfForUnix'], 'php')]
|
||||
#[PatchDescription('Patch configure.ac for musl and musl-toolchain')]
|
||||
#[PatchDescription('Let php m4 tools use static pkg-config')]
|
||||
public function patchBeforeBuildconf(TargetPackage $package): void
|
||||
{
|
||||
// patch configure.ac for musl and musl-toolchain
|
||||
$musl = SystemTarget::getTargetOS() === 'Linux' && SystemTarget::getLibc() === 'musl';
|
||||
FileSystem::backupFile(SOURCE_PATH . '/php-src/configure.ac');
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/configure.ac',
|
||||
'if command -v ldd >/dev/null && ldd --version 2>&1 | grep ^musl >/dev/null 2>&1',
|
||||
'if ' . ($musl ? 'true' : 'false')
|
||||
);
|
||||
|
||||
// let php m4 tools use static pkg-config
|
||||
FileSystem::replaceFileStr("{$package->getSourceDir()}/build/php.m4", 'PKG_CHECK_MODULES(', 'PKG_CHECK_MODULES_STATIC(');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function buildconfForUnix(TargetPackage $package): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf'));
|
||||
V2CompatLayer::emitPatchPoint('before-php-buildconf');
|
||||
shell()->cd($package->getSourceDir())->exec(getenv('SPC_CMD_PREFIX_PHP_BUILDCONF'));
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function configureForUnix(TargetPackage $package, PackageInstaller $installer): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./configure'));
|
||||
V2CompatLayer::emitPatchPoint('before-php-configure');
|
||||
$cmd = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
|
||||
|
||||
$args = [];
|
||||
$version_id = self::getPHPVersionID();
|
||||
// PHP JSON extension is built-in since PHP 8.0
|
||||
if ($version_id < 80000) {
|
||||
$args[] = '--enable-json';
|
||||
}
|
||||
// zts
|
||||
if ($package->getBuildOption('enable-zts', false)) {
|
||||
$args[] = '--enable-zts --disable-zend-signals';
|
||||
if ($version_id >= 80100 && SystemTarget::getTargetOS() === 'Linux') {
|
||||
$args[] = '--enable-zend-max-execution-timers';
|
||||
}
|
||||
}
|
||||
// config-file-path and config-file-scan-dir
|
||||
if ($option = $package->getBuildOption('with-config-file-path', false)) {
|
||||
$args[] = "--with-config-file-path={$option}";
|
||||
}
|
||||
if ($option = $package->getBuildOption('with-config-file-scan-dir', false)) {
|
||||
$args[] = "--with-config-file-scan-dir={$option}";
|
||||
}
|
||||
// perform enable cli options
|
||||
$args[] = $installer->isPackageResolved('php-cli') ? '--enable-cli' : '--disable-cli';
|
||||
$args[] = $installer->isPackageResolved('php-fpm') ? '--enable-fpm' : '--disable-fpm';
|
||||
$args[] = $installer->isPackageResolved('php-micro') ? match (SystemTarget::getTargetOS()) {
|
||||
'Linux' => '--enable-micro=all-static',
|
||||
default => '--enable-micro',
|
||||
} : null;
|
||||
$args[] = $installer->isPackageResolved('php-cgi') ? '--enable-cgi' : '--disable-cgi';
|
||||
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
|
||||
$args[] = $installer->isPackageResolved('php-embed') ? "--enable-embed={$embed_type}" : '--disable-embed';
|
||||
$args[] = getenv('SPC_EXTRA_PHP_VARS') ?: null;
|
||||
$args = implode(' ', array_filter($args));
|
||||
|
||||
$static_extension_str = $this->makeStaticExtensionString($installer);
|
||||
|
||||
// run ./configure with args
|
||||
$this->seekPhpSrcLogFileOnException(fn () => shell()->cd($package->getSourceDir())->setEnv([
|
||||
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
|
||||
'CPPFLAGS' => "-I{$package->getIncludeDir()}",
|
||||
'LDFLAGS' => "-L{$package->getLibDir()} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
|
||||
])->exec("{$cmd} {$args} {$static_extension_str}"), $package->getSourceDir());
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeForUnix(TargetPackage $package, PackageInstaller $installer): void
|
||||
{
|
||||
V2CompatLayer::emitPatchPoint('before-php-make');
|
||||
|
||||
logger()->info('cleaning up php-src build files');
|
||||
shell()->cd($package->getSourceDir())->exec('make clean');
|
||||
|
||||
if ($installer->isPackageResolved('php-cli')) {
|
||||
$package->runStage([self::class, 'makeCliForUnix']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-cgi')) {
|
||||
$package->runStage([self::class, 'makeCgiForUnix']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-fpm')) {
|
||||
$package->runStage([self::class, 'makeFpmForUnix']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-micro')) {
|
||||
$package->runStage([self::class, 'makeMicroForUnix']);
|
||||
}
|
||||
if ($installer->isPackageResolved('php-embed')) {
|
||||
$package->runStage([self::class, 'makeEmbedForUnix']);
|
||||
}
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeCliForUnix(TargetPackage $package, PackageInstaller $installer, PackageBuilder $builder): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make cli'));
|
||||
$concurrency = $builder->concurrency;
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($this->makeVars($installer))
|
||||
->exec("make -j{$concurrency} cli");
|
||||
|
||||
$builder->deployBinary("{$package->getSourceDir()}/sapi/cli/php", BUILD_BIN_PATH . '/php');
|
||||
$package->setOutput('Binary path for cli SAPI', BUILD_BIN_PATH . '/php');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeCgiForUnix(TargetPackage $package, PackageInstaller $installer, PackageBuilder $builder): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make cgi'));
|
||||
$concurrency = $builder->concurrency;
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($this->makeVars($installer))
|
||||
->exec("make -j{$concurrency} cgi");
|
||||
|
||||
$builder->deployBinary("{$package->getSourceDir()}/sapi/cgi/php-cgi", BUILD_BIN_PATH . '/php-cgi');
|
||||
$package->setOutput('Binary path for cgi SAPI', BUILD_BIN_PATH . '/php-cgi');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeFpmForUnix(TargetPackage $package, PackageInstaller $installer, PackageBuilder $builder): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make fpm'));
|
||||
$concurrency = $builder->concurrency;
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($this->makeVars($installer))
|
||||
->exec("make -j{$concurrency} fpm");
|
||||
|
||||
$builder->deployBinary("{$package->getSourceDir()}/sapi/fpm/php-fpm", BUILD_BIN_PATH . '/php-fpm');
|
||||
$package->setOutput('Binary path for fpm SAPI', BUILD_BIN_PATH . '/php-fpm');
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
#[PatchDescription('Patch phar extension for micro SAPI to support compressed phar')]
|
||||
public function makeMicroForUnix(TargetPackage $package, PackageInstaller $installer, PackageBuilder $builder): void
|
||||
{
|
||||
$phar_patched = false;
|
||||
try {
|
||||
if ($installer->isPackageResolved('ext-phar')) {
|
||||
$phar_patched = true;
|
||||
SourcePatcher::patchMicroPhar(self::getPHPVersionID());
|
||||
}
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make micro'));
|
||||
// apply --with-micro-fake-cli option
|
||||
$vars = $this->makeVars($installer);
|
||||
$vars['EXTRA_CFLAGS'] .= $package->getBuildOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
|
||||
// build
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($vars)
|
||||
->exec("make -j{$builder->concurrency} micro");
|
||||
|
||||
$builder->deployBinary($package->getSourceDir() . '/sapi/micro/micro.sfx', BUILD_BIN_PATH . '/micro.sfx');
|
||||
$package->setOutput('Binary path for micro SAPI', BUILD_BIN_PATH . '/micro.sfx');
|
||||
} finally {
|
||||
if ($phar_patched) {
|
||||
SourcePatcher::unpatchMicroPhar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function makeEmbedForUnix(TargetPackage $package, PackageInstaller $installer, PackageBuilder $builder): void
|
||||
{
|
||||
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make embed'));
|
||||
$shared_exts = array_filter(
|
||||
$installer->getResolvedPackages(),
|
||||
static fn ($x) => $x instanceof PhpExtensionPackage && $x->isBuildShared() && $x->isBuildWithPhp()
|
||||
);
|
||||
$install_modules = $shared_exts ? 'install-modules' : '';
|
||||
|
||||
// detect changes in module path
|
||||
$diff = new DirDiff(BUILD_MODULES_PATH, true);
|
||||
|
||||
$root = BUILD_ROOT_PATH;
|
||||
$sed_prefix = SystemTarget::getTargetOS() === 'Darwin' ? 'sed -i ""' : 'sed -i';
|
||||
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($this->makeVars($installer))
|
||||
->exec("{$sed_prefix} \"s|^EXTENSION_DIR = .*|EXTENSION_DIR = /" . basename(BUILD_MODULES_PATH) . '|" Makefile')
|
||||
->exec("make -j{$builder->concurrency} INSTALL_ROOT={$root} install-sapi {$install_modules} install-build install-headers install-programs");
|
||||
|
||||
// ------------- SPC_CMD_VAR_PHP_EMBED_TYPE=shared -------------
|
||||
|
||||
// process libphp.so for shared embed
|
||||
$suffix = SystemTarget::getTargetOS() === 'Darwin' ? 'dylib' : 'so';
|
||||
$libphp_so = "{$package->getLibDir()}/libphp.{$suffix}";
|
||||
if (file_exists($libphp_so)) {
|
||||
// rename libphp.so if -release is set
|
||||
if (SystemTarget::getTargetOS() === 'Linux') {
|
||||
$this->processLibphpSoFile($libphp_so, $installer);
|
||||
}
|
||||
// deploy
|
||||
$builder->deployBinary($libphp_so, $libphp_so, false);
|
||||
$package->setOutput('Library path for embed SAPI', $libphp_so);
|
||||
}
|
||||
|
||||
// process shared extensions that built-with-php
|
||||
$increment_files = $diff->getChangedFiles();
|
||||
$files = [];
|
||||
foreach ($increment_files as $increment_file) {
|
||||
$builder->deployBinary($increment_file, $increment_file, false);
|
||||
$files[] = basename($increment_file);
|
||||
}
|
||||
if (!empty($files)) {
|
||||
$package->setOutput('Built shared extensions', implode(', ', $files));
|
||||
}
|
||||
|
||||
// ------------- SPC_CMD_VAR_PHP_EMBED_TYPE=static -------------
|
||||
|
||||
// process libphp.a for static embed
|
||||
if (!file_exists("{$package->getLibDir()}/libphp.a")) {
|
||||
return;
|
||||
}
|
||||
$ar = getenv('AR') ?: 'ar';
|
||||
$libphp_a = "{$package->getLibDir()}/libphp.a";
|
||||
shell()->exec("{$ar} -t {$libphp_a} | grep '\\.a$' | xargs -n1 {$ar} d {$libphp_a}");
|
||||
UnixUtil::exportDynamicSymbols($libphp_a);
|
||||
|
||||
// deploy embed php scripts
|
||||
$package->runStage([$this, 'patchEmbedScripts']);
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
public function unixBuildSharedExt(PackageInstaller $installer, ToolchainInterface $toolchain): void
|
||||
{
|
||||
// collect shared extensions
|
||||
/** @var PhpExtensionPackage[] $shared_extensions */
|
||||
$shared_extensions = array_filter(
|
||||
$installer->getResolvedPackages(PhpExtensionPackage::class),
|
||||
fn ($x) => $x->isBuildShared() && !$x->isBuildWithPhp()
|
||||
);
|
||||
if (!empty($shared_extensions)) {
|
||||
if ($toolchain->isStatic()) {
|
||||
throw new WrongUsageException(
|
||||
"You're building against musl libc statically (the default on Linux), but you're trying to build shared extensions.\n" .
|
||||
'Static musl libc does not implement `dlopen`, so your php binary is not able to load shared extensions.' . "\n" .
|
||||
'Either use SPC_LIBC=glibc to link against glibc on a glibc OS, or use SPC_TARGET="native-native-musl -dynamic" to link against musl libc dynamically using `zig cc`.'
|
||||
);
|
||||
}
|
||||
FileSystem::createDir(BUILD_MODULES_PATH);
|
||||
|
||||
// backup
|
||||
FileSystem::backupFile(BUILD_BIN_PATH . '/php-config');
|
||||
FileSystem::backupFile(BUILD_LIB_PATH . '/php/build/phpize.m4');
|
||||
|
||||
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', 'extension_dir="' . BUILD_MODULES_PATH . '"');
|
||||
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/php/build/phpize.m4', 'test "[$]$1" = "no" && $1=yes', '# test "[$]$1" = "no" && $1=yes');
|
||||
}
|
||||
|
||||
try {
|
||||
logger()->debug('Building shared extensions...');
|
||||
foreach ($shared_extensions as $extension) {
|
||||
InteractiveTerm::setMessage('Building shared PHP extension: ' . ConsoleColor::yellow($extension->getName()));
|
||||
$extension->buildShared();
|
||||
}
|
||||
} finally {
|
||||
// restore php-config
|
||||
if (!empty($shared_extensions)) {
|
||||
FileSystem::restoreBackupFile(BUILD_BIN_PATH . '/php-config');
|
||||
FileSystem::restoreBackupFile(BUILD_LIB_PATH . '/php/build/phpize.m4');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[BuildFor('Darwin')]
|
||||
#[BuildFor('Linux')]
|
||||
public function build(TargetPackage $package): void
|
||||
{
|
||||
// virtual target, do nothing
|
||||
if ($package->getName() !== 'php') {
|
||||
return;
|
||||
}
|
||||
|
||||
$package->runStage([$this, 'buildconfForUnix']);
|
||||
$package->runStage([$this, 'configureForUnix']);
|
||||
$package->runStage([$this, 'makeForUnix']);
|
||||
|
||||
$package->runStage([$this, 'unixBuildSharedExt']);
|
||||
}
|
||||
|
||||
#[BuildFor('Windows')]
|
||||
public function buildWin(TargetPackage $package): void
|
||||
{
|
||||
throw new EnvironmentException('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch phpize and php-config if needed
|
||||
*/
|
||||
#[Stage]
|
||||
public function patchEmbedScripts(): void
|
||||
{
|
||||
// patch phpize
|
||||
if (file_exists(BUILD_BIN_PATH . '/phpize')) {
|
||||
logger()->debug('Patching phpize prefix');
|
||||
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
|
||||
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
|
||||
$this->setOutput('phpize script path for embed SAPI', BUILD_BIN_PATH . '/phpize');
|
||||
}
|
||||
// patch php-config
|
||||
if (file_exists(BUILD_BIN_PATH . '/php-config')) {
|
||||
logger()->debug('Patching php-config prefix and libs order');
|
||||
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
|
||||
$php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
|
||||
// move mimalloc to the beginning of libs
|
||||
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
|
||||
// move lstdc++ to the end of libs
|
||||
$php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
|
||||
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
|
||||
$this->setOutput('php-config script path for embed SAPI', BUILD_BIN_PATH . '/php-config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek php-src/config.log when building PHP, add it to exception.
|
||||
*/
|
||||
protected function seekPhpSrcLogFileOnException(callable $callback, string $source_dir): void
|
||||
{
|
||||
try {
|
||||
$callback();
|
||||
} catch (SPCException $e) {
|
||||
if (file_exists("{$source_dir}/config.log")) {
|
||||
$e->addExtraLogFile('php-src config.log', 'php-src.config.log');
|
||||
copy("{$source_dir}/config.log", SPC_LOGS_DIR . '/php-src.config.log');
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function makeStaticExtensionString(PackageInstaller $installer): string
|
||||
{
|
||||
$arg = [];
|
||||
@ -599,93 +257,4 @@ class php extends TargetPackage
|
||||
logger()->debug("Static extension configure args: {$str}");
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make environment variables for php make.
|
||||
* This will call SPCConfigUtil to generate proper LDFLAGS and LIBS for static linking.
|
||||
*/
|
||||
private function makeVars(PackageInstaller $installer): array
|
||||
{
|
||||
$config = (new SPCConfigUtil(['libs_only_deps' => true]))->config(array_map(fn ($x) => $x->getName(), $installer->getResolvedPackages()));
|
||||
$static = ApplicationContext::get(ToolchainInterface::class)->isStatic() ? '-all-static' : '';
|
||||
$pie = SystemTarget::getTargetOS() === 'Linux' ? '-pie' : '';
|
||||
|
||||
return array_filter([
|
||||
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
|
||||
'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') . "{$config['ldflags']} {$static} {$pie}",
|
||||
'EXTRA_LDFLAGS' => $config['ldflags'],
|
||||
'EXTRA_LIBS' => $config['libs'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename libphp.so to libphp-<release>.so if -release is set in LDFLAGS.
|
||||
*/
|
||||
private function processLibphpSoFile(string $libphpSo, PackageInstaller $installer): void
|
||||
{
|
||||
$ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: '';
|
||||
$libDir = BUILD_LIB_PATH;
|
||||
$modulesDir = BUILD_MODULES_PATH;
|
||||
$realLibName = 'libphp.so';
|
||||
$cwd = getcwd();
|
||||
|
||||
if (preg_match('/-release\s+(\S+)/', $ldflags, $matches)) {
|
||||
$release = $matches[1];
|
||||
$realLibName = "libphp-{$release}.so";
|
||||
$libphpRelease = "{$libDir}/{$realLibName}";
|
||||
if (!file_exists($libphpRelease) && file_exists($libphpSo)) {
|
||||
rename($libphpSo, $libphpRelease);
|
||||
}
|
||||
if (file_exists($libphpRelease)) {
|
||||
chdir($libDir);
|
||||
if (file_exists($libphpSo)) {
|
||||
unlink($libphpSo);
|
||||
}
|
||||
symlink($realLibName, 'libphp.so');
|
||||
shell()->exec(sprintf(
|
||||
'patchelf --set-soname %s %s',
|
||||
escapeshellarg($realLibName),
|
||||
escapeshellarg($libphpRelease)
|
||||
));
|
||||
}
|
||||
if (is_dir($modulesDir)) {
|
||||
chdir($modulesDir);
|
||||
foreach ($installer->getResolvedPackages(PhpExtensionPackage::class) as $ext) {
|
||||
if (!$ext->isBuildShared()) {
|
||||
continue;
|
||||
}
|
||||
$name = $ext->getName();
|
||||
$versioned = "{$name}-{$release}.so";
|
||||
$unversioned = "{$name}.so";
|
||||
$src = "{$modulesDir}/{$versioned}";
|
||||
$dst = "{$modulesDir}/{$unversioned}";
|
||||
if (is_file($src)) {
|
||||
rename($src, $dst);
|
||||
shell()->exec(sprintf(
|
||||
'patchelf --set-soname %s %s',
|
||||
escapeshellarg($unversioned),
|
||||
escapeshellarg($dst)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
chdir($cwd);
|
||||
}
|
||||
|
||||
$target = "{$libDir}/{$realLibName}";
|
||||
if (file_exists($target)) {
|
||||
[, $output] = shell()->execWithResult('readelf -d ' . escapeshellarg($target));
|
||||
$output = implode("\n", $output);
|
||||
if (preg_match('/SONAME.*\[(.+)]/', $output, $sonameMatch)) {
|
||||
$currentSoname = $sonameMatch[1];
|
||||
if ($currentSoname !== basename($target)) {
|
||||
shell()->exec(sprintf(
|
||||
'patchelf --set-soname %s %s',
|
||||
escapeshellarg(basename($target)),
|
||||
escapeshellarg($target)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ class PackageBuilder
|
||||
|
||||
// ignore copy to self
|
||||
if (realpath($src) !== realpath($dst)) {
|
||||
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg($dst));
|
||||
FileSystem::copy($src, $dst);
|
||||
}
|
||||
|
||||
// file exist
|
||||
@ -111,7 +111,7 @@ class PackageBuilder
|
||||
$this->extractDebugInfo($dst);
|
||||
|
||||
// strip
|
||||
if (!$this->getOption('no-strip')) {
|
||||
if (!$this->getOption('no-strip') && SystemTarget::isUnix()) {
|
||||
$this->stripBinary($dst);
|
||||
}
|
||||
|
||||
@ -123,6 +123,9 @@ class PackageBuilder
|
||||
}
|
||||
logger()->info("Compressing {$dst} with UPX");
|
||||
shell()->exec(getenv('UPX_EXEC') . " --best {$dst}");
|
||||
} elseif ($upx_option && SystemTarget::getTargetOS() === 'Windows' && $executable) {
|
||||
logger()->info("Compressing {$dst} with UPX");
|
||||
shell()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($dst));
|
||||
}
|
||||
|
||||
return $dst;
|
||||
@ -136,12 +139,13 @@ class PackageBuilder
|
||||
public function extractDebugInfo(string $binary_path): string
|
||||
{
|
||||
$target_dir = BUILD_ROOT_PATH . '/debug';
|
||||
FileSystem::createDir($target_dir);
|
||||
$basename = basename($binary_path);
|
||||
$debug_file = "{$target_dir}/{$basename}" . (SystemTarget::getTargetOS() === 'Darwin' ? '.dwarf' : '.debug');
|
||||
if (SystemTarget::getTargetOS() === 'Darwin') {
|
||||
FileSystem::createDir($target_dir);
|
||||
shell()->exec("dsymutil -f {$binary_path} -o {$debug_file}");
|
||||
} elseif (SystemTarget::getTargetOS() === 'Linux') {
|
||||
FileSystem::createDir($target_dir);
|
||||
if ($eu_strip = LinuxUtil::findCommand('eu-strip')) {
|
||||
shell()
|
||||
->exec("{$eu_strip} -f {$debug_file} {$binary_path}")
|
||||
@ -152,7 +156,8 @@ class PackageBuilder
|
||||
->exec("objcopy --add-gnu-debuglink={$debug_file} {$binary_path}");
|
||||
}
|
||||
} else {
|
||||
throw new SPCInternalException('extractDebugInfo is only supported on Linux and macOS');
|
||||
logger()->debug('extractDebugInfo is only supported on Linux and macOS');
|
||||
return '';
|
||||
}
|
||||
return $debug_file;
|
||||
}
|
||||
|
||||
@ -151,9 +151,6 @@ abstract class Shell
|
||||
bool $throw_on_error = true,
|
||||
?string $cwd = null
|
||||
): array {
|
||||
if ($cwd !== null) {
|
||||
$cwd = $cwd;
|
||||
}
|
||||
$file_res = null;
|
||||
if ($this->enable_log_file) {
|
||||
// write executed command to the log file using fwrite
|
||||
|
||||
@ -6,6 +6,7 @@ namespace StaticPHP\Util;
|
||||
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Exception\PatchException;
|
||||
use StaticPHP\Registry\PackageLoader;
|
||||
|
||||
/**
|
||||
* SourcePatcher provides static utility methods for patching source files.
|
||||
@ -194,4 +195,69 @@ class SourcePatcher
|
||||
{
|
||||
FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c');
|
||||
}
|
||||
|
||||
public static function patchPhpSrc(?array $items = null): bool
|
||||
{
|
||||
$patch_dir = ROOT_DIR . '/src/globals/patch/php-src-patches';
|
||||
// in phar mode, we need to extract all the patch files
|
||||
if (str_starts_with($patch_dir, 'phar://')) {
|
||||
$tmp_dir = sys_get_temp_dir() . '/php-src-patches';
|
||||
FileSystem::createDir($tmp_dir);
|
||||
foreach (FileSystem::scanDirFiles($patch_dir) as $file) {
|
||||
FileSystem::writeFile("{$tmp_dir}/" . basename($file), file_get_contents($file));
|
||||
}
|
||||
$patch_dir = $tmp_dir;
|
||||
}
|
||||
$php_package = PackageLoader::getTargetPackage('php');
|
||||
if (!file_exists("{$php_package->getSourceDir()}/sapi/micro/php_micro.c")) {
|
||||
return false;
|
||||
}
|
||||
$ver_file = "{$php_package->getSourceDir()}/main/php_version.h";
|
||||
if (!file_exists($ver_file)) {
|
||||
throw new PatchException('php-src patcher (original micro patches)', 'Patch failed, cannot find php source files');
|
||||
}
|
||||
$version_h = FileSystem::readFile("{$php_package->getSourceDir()}/main/php_version.h");
|
||||
preg_match('/#\s*define\s+PHP_MAJOR_VERSION\s+(\d+)\s+#\s*define\s+PHP_MINOR_VERSION\s+(\d+)\s+/m', $version_h, $match);
|
||||
// $ver = "{$match[1]}.{$match[2]}";
|
||||
|
||||
$major_ver = $match[1] . $match[2];
|
||||
if ($major_ver === '74') {
|
||||
return false;
|
||||
}
|
||||
// $check = !defined('DEBUG_MODE') ? ' -q' : '';
|
||||
// f_passthru('cd ' . SOURCE_PATH . '/php-src && git checkout' . $check . ' HEAD');
|
||||
|
||||
if ($items !== null) {
|
||||
$spc_micro_patches = $items;
|
||||
} else {
|
||||
$spc_micro_patches = getenv('SPC_MICRO_PATCHES');
|
||||
$spc_micro_patches = $spc_micro_patches === false ? [] : explode(',', $spc_micro_patches);
|
||||
}
|
||||
$spc_micro_patches = array_filter($spc_micro_patches, fn ($item) => trim((string) $item) !== '');
|
||||
$patch_list = $spc_micro_patches;
|
||||
$patches = [];
|
||||
$serial = ['80', '81', '82', '83', '84', '85'];
|
||||
foreach ($patch_list as $patchName) {
|
||||
if (file_exists("{$patch_dir}/{$patchName}.patch")) {
|
||||
$patches[] = "{$patch_dir}/{$patchName}.patch";
|
||||
continue;
|
||||
}
|
||||
for ($i = array_search($major_ver, $serial, true); $i >= 0; --$i) {
|
||||
$tryMajMin = $serial[$i];
|
||||
if (!file_exists("{$patch_dir}/{$patchName}_{$tryMajMin}.patch")) {
|
||||
continue;
|
||||
}
|
||||
$patches[] = "{$patch_dir}/{$patchName}_{$tryMajMin}.patch";
|
||||
continue 2;
|
||||
}
|
||||
throw new PatchException('phpmicro patches', "Failed finding patch file or versioned file {$patchName} !");
|
||||
}
|
||||
|
||||
foreach ($patches as $patch) {
|
||||
logger()->info("Patching micro with {$patch}");
|
||||
self::patchFile($patch, $php_package->getSourceDir());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user