diff --git a/config/ext.json b/config/ext.json index d5c70793..e5aa0ce3 100644 --- a/config/ext.json +++ b/config/ext.json @@ -341,6 +341,7 @@ "ext-depends": [ "xml" ], + "build-with-php": true, "target": [ "static" ] @@ -461,6 +462,7 @@ "mysqli": { "type": "builtin", "arg-type": "with", + "build-with-php": true, "ext-depends": [ "mysqlnd" ] @@ -468,6 +470,7 @@ "mysqlnd": { "type": "builtin", "arg-type-windows": "with", + "build-with-php": true, "lib-depends": [ "zlib" ] @@ -797,6 +800,7 @@ "type": "builtin", "arg-type": "with-path", "arg-type-windows": "with", + "build-with-php": true, "lib-depends": [ "sqlite" ] @@ -1177,6 +1181,7 @@ "lib-depends": [ "zlib" ], + "build-with-php": true, "target": [ "static" ] diff --git a/config/lib.json b/config/lib.json index 39e47613..c3d864f4 100644 --- a/config/lib.json +++ b/config/lib.json @@ -795,7 +795,7 @@ "libxml2", "openssl", "zlib", - "readline" + "libedit" ], "lib-suggests": [ "icu", diff --git a/config/source.json b/config/source.json index da58158c..349ba68c 100644 --- a/config/source.json +++ b/config/source.json @@ -47,7 +47,7 @@ "provide-pre-built": true, "license": { "type": "file", - "path": "doc/COPYING" + "path": "doc/COPYING.LGPL" } }, "brotli": { @@ -306,16 +306,17 @@ "regex": "/href=\"(?gettext-(?[^\"]+)\\.tar\\.xz)\"/", "license": { "type": "file", - "path": "COPYING" + "path": "gettext-runtime/intl/COPYING.LIB" } }, "gmp": { - "type": "url", - "url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz", + "type": "filelist", + "url": "https://gmplib.org/download/gmp/", + "regex": "/href=\"(?gmp-(?[^\"]+)\\.tar\\.xz)\"/", "provide-pre-built": true, "alt": { - "type": "ghtagtar", - "repo": "alisw/GMP" + "type": "url", + "url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz" }, "license": { "type": "text", @@ -439,7 +440,7 @@ "provide-pre-built": true, "license": { "type": "file", - "path": "doc/COPYING" + "path": "doc/COPYING.LGPL" } }, "libaom": { diff --git a/src/SPC/builder/extension/gettext.php b/src/SPC/builder/extension/gettext.php index dc4f58aa..303cc389 100644 --- a/src/SPC/builder/extension/gettext.php +++ b/src/SPC/builder/extension/gettext.php @@ -15,7 +15,11 @@ class gettext extends Extension public function patchBeforeBuildconf(): bool { if ($this->builder instanceof MacOSBuilder) { - FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gettext/config.m4', 'AC_CHECK_LIB($GETTEXT_CHECK_IN_LIB', 'AC_CHECK_LIB(intl'); + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/gettext/config.m4', + ['AC_CHECK_LIB($GETTEXT_CHECK_IN_LIB', 'AC_CHECK_LIB([$GETTEXT_CHECK_IN_LIB'], + ['AC_CHECK_LIB(intl', 'AC_CHECK_LIB([intl'] // new php versions use a bracket + ); } return true; } diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index a4a531cf..7ff4b331 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -69,12 +69,15 @@ class swoole extends Extension $arg .= $this->builder->getExt('swoole-hook-pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql'; $arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd'; $arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite'; - if ($this->builder->getExt('swoole-hook-odbc')) { $config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']); $arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"'; } + if ($this->getExtVersion() >= '6.1.0') { + $arg .= ' --enable-swoole-stdext'; + } + if (SPCTarget::getTargetOS() === 'Darwin') { $arg .= ' ac_cv_lib_pthread_pthread_barrier_init=no'; } diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 41b1545d..3995c3a8 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -7,6 +7,7 @@ namespace SPC\builder\linux; use SPC\builder\unix\UnixBuilderBase; use SPC\exception\PatchException; use SPC\exception\WrongUsageException; +use SPC\store\Config; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\GlobalEnvManager; @@ -283,12 +284,17 @@ class LinuxBuilder extends UnixBuilderBase */ protected function buildEmbed(): void { + $sharedExts = array_filter($this->exts, static fn ($ext) => $ext->isBuildShared()); + $sharedExts = array_filter($sharedExts, static function ($ext) { + return Config::getExt($ext->getName(), 'build-with-php') === true; + }); + $install_modules = $sharedExts ? 'install-modules' : ''; $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); $concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : ''; shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') ->exec('sed -i "s|^EXTENSION_DIR = .*|EXTENSION_DIR = /' . basename(BUILD_MODULES_PATH) . '|" Makefile') - ->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi install-build install-headers install-programs"); + ->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi {$install_modules} install-build install-headers install-programs"); $ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: ''; $libDir = BUILD_LIB_PATH; diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index d144457e..bcfaf6cf 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -7,6 +7,7 @@ namespace SPC\builder\macos; use SPC\builder\macos\library\MacOSLibraryBase; use SPC\builder\unix\UnixBuilderBase; use SPC\exception\WrongUsageException; +use SPC\store\Config; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\GlobalEnvManager; @@ -264,10 +265,15 @@ class MacOSBuilder extends UnixBuilderBase */ protected function buildEmbed(): void { + $sharedExts = array_filter($this->exts, static fn ($ext) => $ext->isBuildShared()); + $sharedExts = array_filter($sharedExts, static function ($ext) { + return Config::getExt($ext->getName(), 'build-with-php') === true; + }); + $install_modules = $sharedExts ? 'install-modules' : ''; $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); $concurrency = getenv('SPC_CONCURRENCY') ? '-j' . getenv('SPC_CONCURRENCY') : ''; shell()->cd(SOURCE_PATH . '/php-src') - ->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi install-build install-headers install-programs"); + ->exec("make {$concurrency} INSTALL_ROOT=" . BUILD_ROOT_PATH . " {$vars} install-sapi {$install_modules} install-build install-headers install-programs"); if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { $AR = getenv('AR') ?: 'ar'; diff --git a/src/SPC/builder/unix/library/attr.php b/src/SPC/builder/unix/library/attr.php index b33cf987..67ac5feb 100644 --- a/src/SPC/builder/unix/library/attr.php +++ b/src/SPC/builder/unix/library/attr.php @@ -17,7 +17,7 @@ trait attr ->exec('libtoolize --force --copy') ->exec('./autogen.sh || autoreconf -if') ->configure('--disable-nls') - ->make(); + ->make('install-attributes_h install-data install-libattr_h install-libLTLIBRARIES install-pkgincludeHEADERS install-pkgconfDATA', with_install: false); $this->patchPkgconfPrefix(['libattr.pc'], PKGCONF_PATCH_PREFIX); } } diff --git a/src/SPC/builder/unix/library/gettext.php b/src/SPC/builder/unix/library/gettext.php index f0fdae54..332e25c9 100644 --- a/src/SPC/builder/unix/library/gettext.php +++ b/src/SPC/builder/unix/library/gettext.php @@ -31,7 +31,7 @@ trait gettext $autoconf->addConfigureArgs('--disable-threads'); } - $autoconf->configure()->make(); + $autoconf->configure()->make(dir: $this->getSourceDir() . '/gettext-runtime/intl'); $this->patchLaDependencyPrefix(); } } diff --git a/src/SPC/builder/unix/library/libacl.php b/src/SPC/builder/unix/library/libacl.php index 223e09fc..8c5d699d 100644 --- a/src/SPC/builder/unix/library/libacl.php +++ b/src/SPC/builder/unix/library/libacl.php @@ -26,7 +26,7 @@ trait libacl ->exec('libtoolize --force --copy') ->exec('./autogen.sh || autoreconf -if') ->configure('--disable-nls', '--disable-tests') - ->make(); + ->make('install-acl_h install-libacl_h install-data install-libLTLIBRARIES install-pkgincludeHEADERS install-sysincludeHEADERS install-pkgconfDATA', with_install: false); $this->patchPkgconfPrefix(['libacl.pc'], PKGCONF_PATCH_PREFIX); } } diff --git a/src/SPC/builder/unix/library/libedit.php b/src/SPC/builder/unix/library/libedit.php index e436ee8b..2de9077f 100644 --- a/src/SPC/builder/unix/library/libedit.php +++ b/src/SPC/builder/unix/library/libedit.php @@ -4,10 +4,21 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\store\FileSystem; use SPC\util\executor\UnixAutoconfExecutor; trait libedit { + public function patchBeforeBuild(): bool + { + FileSystem::replaceFileRegex( + $this->source_dir . '/src/sys.h', + '|//#define\s+strl|', + '#define strl' + ); + return true; + } + protected function build(): void { UnixAutoconfExecutor::create($this) diff --git a/src/SPC/builder/unix/library/libiconv.php b/src/SPC/builder/unix/library/libiconv.php index fd68e309..5ccc9484 100644 --- a/src/SPC/builder/unix/library/libiconv.php +++ b/src/SPC/builder/unix/library/libiconv.php @@ -10,7 +10,13 @@ trait libiconv { protected function build(): void { - UnixAutoconfExecutor::create($this)->configure('--enable-extra-encodings')->make(); + UnixAutoconfExecutor::create($this) + ->configure( + '--enable-extra-encodings', + '--enable-year2038', + ) + ->make('install-lib', with_install: false) + ->make('install-lib', with_install: false, dir: $this->getSourceDir() . '/libcharset'); $this->patchLaDependencyPrefix(); } } diff --git a/src/SPC/builder/unix/library/libzip.php b/src/SPC/builder/unix/library/libzip.php index 931bfcc3..ad0befea 100644 --- a/src/SPC/builder/unix/library/libzip.php +++ b/src/SPC/builder/unix/library/libzip.php @@ -22,6 +22,7 @@ trait libzip '-DBUILD_EXAMPLES=OFF', '-DBUILD_REGRESS=OFF', '-DBUILD_TOOLS=OFF', + '-DBUILD_OSSFUZZ=OFF', ) ->build(); $this->patchPkgconfPrefix(['libzip.pc'], PKGCONF_PATCH_PREFIX); diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index 2f6e866d..a23ad6d5 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -82,14 +82,14 @@ class LinuxToolCheckList return CheckResult::ok(); } - #[AsCheckItem('if cmake version >= 3.18', limit_os: 'Linux')] + #[AsCheckItem('if cmake version >= 3.22', limit_os: 'Linux')] public function checkCMakeVersion(): ?CheckResult { $ver = get_cmake_version(); if ($ver === null) { return CheckResult::fail('Failed to get cmake version'); } - if (version_compare($ver, '3.18.0') < 0) { + if (version_compare($ver, '3.22.0') < 0) { return CheckResult::fail('cmake version is too low (' . $ver . '), please update it manually!'); } return CheckResult::ok($ver); diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index e66aee0a..f6ce371e 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -645,6 +645,36 @@ class FileSystem }; } + /** + * Move file or directory, handling cross-device scenarios + * Uses rename() if possible, falls back to copy+delete for cross-device moves + * + * @param string $source Source path + * @param string $dest Destination path + */ + private static function moveFileOrDir(string $source, string $dest): void + { + $source = self::convertPath($source); + $dest = self::convertPath($dest); + + // Try rename first (fast, atomic) + if (@rename($source, $dest)) { + return; + } + + if (is_dir($source)) { + self::copyDir($source, $dest); + self::removeDir($source); + } else { + if (!copy($source, $dest)) { + throw new FileSystemException("Failed to copy file from {$source} to {$dest}"); + } + if (!unlink($source)) { + throw new FileSystemException("Failed to remove source file: {$source}"); + } + } + } + /** * Unzip file with stripping top-level directory */ @@ -675,10 +705,10 @@ class FileSystem if (is_dir($extract_path)) { self::removeDir($extract_path); } - // if only one dir, move its contents to extract_path using rename + // if only one dir, move its contents to extract_path $subdir = self::convertPath("{$temp_dir}/{$contents[0]}"); if (count($contents) === 1 && is_dir($subdir)) { - rename($subdir, $extract_path); + self::moveFileOrDir($subdir, $extract_path); } else { // else, if it contains only one dir, strip dir and copy other files $dircount = 0; @@ -701,17 +731,20 @@ class FileSystem throw new FileSystemException("Cannot scan unzip temp sub-dir: {$dir[0]}"); } foreach ($sub_contents as $sub_item) { - rename(self::convertPath("{$temp_dir}/{$dir[0]}/{$sub_item}"), self::convertPath("{$extract_path}/{$sub_item}")); + self::moveFileOrDir(self::convertPath("{$temp_dir}/{$dir[0]}/{$sub_item}"), self::convertPath("{$extract_path}/{$sub_item}")); } } else { foreach ($dir as $item) { - rename(self::convertPath("{$temp_dir}/{$item}"), self::convertPath("{$extract_path}/{$item}")); + self::moveFileOrDir(self::convertPath("{$temp_dir}/{$item}"), self::convertPath("{$extract_path}/{$item}")); } } // move top-level files to extract_path foreach ($top_files as $top_file) { - rename(self::convertPath("{$temp_dir}/{$top_file}"), self::convertPath("{$extract_path}/{$top_file}")); + self::moveFileOrDir(self::convertPath("{$temp_dir}/{$top_file}"), self::convertPath("{$extract_path}/{$top_file}")); } } + + // Clean up temp directory + self::removeDir($temp_dir); } } diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 694d87ef..7b72ad1b 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -44,7 +44,7 @@ class SourcePatcher } foreach ($builder->getLibs() as $lib) { if ($lib->patchBeforeBuildconf() === true) { - logger()->info("Library [{$lib->getName()}]patched before buildconf"); + logger()->info("Library [{$lib->getName()}] patched before buildconf"); } } // patch windows php 8.1 bug diff --git a/src/SPC/store/source/PhpSource.php b/src/SPC/store/source/PhpSource.php index ca6b6b6f..1c0be85f 100644 --- a/src/SPC/store/source/PhpSource.php +++ b/src/SPC/store/source/PhpSource.php @@ -16,7 +16,7 @@ class PhpSource extends CustomSourceBase { $major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.4'; if ($major === '8.5') { - Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://github.com/php/php-src/archive/refs/tags/php-8.5.0RC2.tar.gz'], $force); + Downloader::downloadSource('php-src', ['type' => 'url', 'url' => 'https://downloads.php.net/~daniels/php-8.5.0RC3.tar.xz'], $force); } elseif ($major === 'git') { Downloader::downloadSource('php-src', ['type' => 'git', 'url' => 'https://github.com/php/php-src.git', 'rev' => 'master'], $force); } else { diff --git a/src/SPC/util/executor/UnixAutoconfExecutor.php b/src/SPC/util/executor/UnixAutoconfExecutor.php index 075d7fd3..f196cb1c 100644 --- a/src/SPC/util/executor/UnixAutoconfExecutor.php +++ b/src/SPC/util/executor/UnixAutoconfExecutor.php @@ -50,18 +50,22 @@ class UnixAutoconfExecutor extends Executor * @param bool $with_clean Whether to clean before building * @param array $after_env_vars Environment variables postfix */ - public function make(string $target = '', false|string $with_install = 'install', bool $with_clean = true, array $after_env_vars = []): static + public function make(string $target = '', false|string $with_install = 'install', bool $with_clean = true, array $after_env_vars = [], ?string $dir = null): static { - return $this->seekLogFileOnException(function () use ($target, $with_install, $with_clean, $after_env_vars) { + return $this->seekLogFileOnException(function () use ($target, $with_install, $with_clean, $after_env_vars, $dir) { + $shell = $this->shell; + if ($dir) { + $shell = $shell->cd($dir); + } if ($with_clean) { - $this->shell->exec('make clean'); + $shell->exec('make clean'); } $after_env_vars_str = $after_env_vars !== [] ? shell()->setEnv($after_env_vars)->getEnvString() : ''; - $this->shell->exec("make -j{$this->library->getBuilder()->concurrency} {$target} {$after_env_vars_str}"); + $shell->exec("make -j{$this->library->getBuilder()->concurrency} {$target} {$after_env_vars_str}"); if ($with_install !== false) { - $this->shell->exec("make {$with_install}"); + $shell->exec("make {$with_install}"); } - return $this->shell; + return $shell; }); } diff --git a/src/SPC/util/executor/UnixCMakeExecutor.php b/src/SPC/util/executor/UnixCMakeExecutor.php index 3e29addf..eceab901 100644 --- a/src/SPC/util/executor/UnixCMakeExecutor.php +++ b/src/SPC/util/executor/UnixCMakeExecutor.php @@ -205,7 +205,7 @@ SET(CMAKE_INSTALL_PREFIX "{$root}") SET(CMAKE_INSTALL_LIBDIR "lib") set(PKG_CONFIG_EXECUTABLE "{$pkgConfigExecutable}") -list(APPEND PKG_CONFIG_EXECUTABLE "--static") +set(PKG_CONFIG_ARGN "--static" CACHE STRING "Extra arguments for pkg-config" FORCE) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/src/SPC/util/shell/UnixShell.php b/src/SPC/util/shell/UnixShell.php index 75a0be3d..2fdc1b07 100644 --- a/src/SPC/util/shell/UnixShell.php +++ b/src/SPC/util/shell/UnixShell.php @@ -8,6 +8,7 @@ use SPC\builder\freebsd\library\BSDLibraryBase; use SPC\builder\linux\library\LinuxLibraryBase; use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\SPCInternalException; +use SPC\util\SPCTarget; use ZM\Logger\ConsoleColor; /** @@ -28,6 +29,7 @@ class UnixShell extends Shell public function exec(string $cmd): static { + $cmd = clean_spaces($cmd); /* @phpstan-ignore-next-line */ logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd)); $original_command = $cmd; @@ -48,7 +50,7 @@ class UnixShell extends Shell 'CFLAGS' => $library->getLibExtraCFlags(), 'CXXFLAGS' => $library->getLibExtraCXXFlags(), 'LDFLAGS' => $library->getLibExtraLdFlags(), - 'LIBS' => $library->getLibExtraLibs(), + 'LIBS' => $library->getLibExtraLibs() . SPCTarget::getRuntimeLibs(), ]); return $this; }