From abd7d3cfb42907f995fadc5748ab1ac1accf1c03 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 24 Jul 2025 00:42:30 +0800 Subject: [PATCH 1/5] Add --no-alt and --skip-extract option to install-pkg command --- src/SPC/command/DownloadCommand.php | 27 ++---------------------- src/SPC/command/InstallPkgCommand.php | 16 ++++++++++++-- src/SPC/store/Downloader.php | 23 ++++++++++++++++++++ src/SPC/store/PackageManager.php | 30 +++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index f77c80f9..c1b0903a 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -248,9 +248,9 @@ class DownloadCommand extends BaseCommand $alt_sources = Config::getSource($source)['alt'] ?? null; if ($alt_sources === null) { logger()->warning("No alternative sources found for {$source}, using default alternative source"); - $alt_config = array_merge($config, $this->getDefaultAlternativeSource($source)); + $alt_config = array_merge($config, Downloader::getDefaultAlternativeSource($source)); } elseif ($alt_sources === false) { - logger()->warning("No alternative sources found for {$source}, skipping alternative download"); + logger()->error("No alternative sources found for {$source}, skipping alternative download"); throw $e; } else { logger()->notice("Trying to download alternative sources for {$source}"); @@ -399,27 +399,4 @@ class DownloadCommand extends BaseCommand } return static::FAILURE; } - - private function getDefaultAlternativeSource(string $source_name): array - { - return [ - 'type' => 'custom', - 'func' => function (bool $force, array $source, int $download_as) use ($source_name) { - logger()->debug("Fetching alternative source for {$source_name}"); - // get from dl.static-php.dev - $url = "https://dl.static-php.dev/static-php-cli/deps/spc-download-mirror/{$source_name}/?format=json"; - $json = json_decode(Downloader::curlExec(url: $url, retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)), true); - if (!is_array($json)) { - throw new RuntimeException('failed http fetch'); - } - $item = $json[0] ?? null; - if ($item === null) { - throw new RuntimeException('failed to parse json'); - } - $full_url = 'https://dl.static-php.dev' . $item['full_path']; - $filename = basename($item['full_path']); - Downloader::downloadFile($source_name, $full_url, $filename, $source['path'] ?? null, $download_as); - }, - ]; - } } diff --git a/src/SPC/command/InstallPkgCommand.php b/src/SPC/command/InstallPkgCommand.php index b1ea3cd5..19d1532b 100644 --- a/src/SPC/command/InstallPkgCommand.php +++ b/src/SPC/command/InstallPkgCommand.php @@ -24,6 +24,8 @@ class InstallPkgCommand extends BaseCommand $this->addArgument('packages', InputArgument::REQUIRED, 'The packages will be installed, comma separated'); $this->addOption('shallow-clone', null, null, 'Clone shallow'); $this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"'); + $this->addOption('no-alt', null, null, 'Do not download alternative packages'); + $this->addOption('skip-extract', null, null, 'Skip package extraction, just download the package archive'); } /** @@ -66,10 +68,20 @@ class InstallPkgCommand extends BaseCommand $new_config['filename'] = $config['filename']; } logger()->info("Installing source {$pkg} from custom url [{$ni}/{$cnt}]"); - PackageManager::installPackage($pkg, $new_config); + PackageManager::installPackage( + $pkg, + $new_config, + allow_alt: false, + extract: !$this->getOption('skip-extract') + ); } else { logger()->info("Fetching package {$pkg} [{$ni}/{$cnt}]"); - PackageManager::installPackage($pkg, Config::getPkg($pkg)); + PackageManager::installPackage( + $pkg, + Config::getPkg($pkg), + allow_alt: !$this->getOption('no-alt'), + extract: !$this->getOption('skip-extract') + ); } } $time = round(microtime(true) - START_TIME, 3); diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index 12881ae7..ed462489 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -608,6 +608,29 @@ class Downloader return "{$source}-{$os_family}-{$gnu_arch}-{$libc}-{$libc_version}"; } + public static function getDefaultAlternativeSource(string $source_name): array + { + return [ + 'type' => 'custom', + 'func' => function (bool $force, array $source, int $download_as) use ($source_name) { + logger()->debug("Fetching alternative source for {$source_name}"); + // get from dl.static-php.dev + $url = "https://dl.static-php.dev/static-php-cli/deps/spc-download-mirror/{$source_name}/?format=json"; + $json = json_decode(Downloader::curlExec(url: $url, retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)), true); + if (!is_array($json)) { + throw new RuntimeException('failed http fetch'); + } + $item = $json[0] ?? null; + if ($item === null) { + throw new RuntimeException('failed to parse json'); + } + $full_url = 'https://dl.static-php.dev' . $item['full_path']; + $filename = basename($item['full_path']); + Downloader::downloadFile($source_name, $full_url, $filename, $source['path'] ?? null, $download_as); + }, + ]; + } + /** * Register CTRL+C event for different OS. * diff --git a/src/SPC/store/PackageManager.php b/src/SPC/store/PackageManager.php index d5c1043d..14f6bbcf 100644 --- a/src/SPC/store/PackageManager.php +++ b/src/SPC/store/PackageManager.php @@ -4,13 +4,14 @@ declare(strict_types=1); namespace SPC\store; +use SPC\exception\DownloaderException; use SPC\exception\FileSystemException; use SPC\exception\WrongUsageException; use SPC\store\pkg\CustomPackage; class PackageManager { - public static function installPackage(string $pkg_name, ?array $config = null, bool $force = false): void + public static function installPackage(string $pkg_name, ?array $config = null, bool $force = false, bool $allow_alt = true, bool $extract = true): void { if ($config === null) { $config = Config::getPkg($pkg_name); @@ -32,7 +33,32 @@ class PackageManager } // Download package - Downloader::downloadPackage($pkg_name, $config, $force); + try { + Downloader::downloadPackage($pkg_name, $config, $force); + } catch (\Throwable $e) { + if (!$allow_alt) { + logger()->error("Download package {$pkg_name} failed: " . $e->getMessage()); + throw new DownloaderException("Download package {$pkg_name} failed: " . $e->getMessage()); + } + // if download failed, we will try to download alternative packages + logger()->warning("Download package {$pkg_name} failed: " . $e->getMessage()); + $alt = $config['alt'] ?? null; + if ($alt === null) { + logger()->warning("No alternative package found for {$pkg_name}, using default mirror."); + $alt_config = array_merge($config, Downloader::getDefaultAlternativeSource($pkg_name)); + } elseif ($alt === false) { + logger()->error("No alternative package found for {$pkg_name}."); + throw $e; + } else { + logger()->notice("Trying alternative package for {$pkg_name}."); + $alt_config = array_merge($config, $alt); + } + Downloader::downloadPackage($pkg_name, $alt_config, $force); + } + if (!$extract) { + logger()->info("Package [{$pkg_name}] downloaded, but extraction is skipped."); + return; + } if (Config::getPkg($pkg_name)['type'] === 'custom') { // Custom extract function $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); From 52a623f31e9e0b8ac7d0f1755e7acc5f08ac39e8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 24 Jul 2025 12:00:17 +0800 Subject: [PATCH 2/5] Suggestions --- src/SPC/command/DownloadCommand.php | 3 +-- src/SPC/store/PackageManager.php | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index c1b0903a..dfa4c9ee 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -250,8 +250,7 @@ class DownloadCommand extends BaseCommand logger()->warning("No alternative sources found for {$source}, using default alternative source"); $alt_config = array_merge($config, Downloader::getDefaultAlternativeSource($source)); } elseif ($alt_sources === false) { - logger()->error("No alternative sources found for {$source}, skipping alternative download"); - throw $e; + throw new DownloaderException("No alternative sources found for {$source}, skipping alternative download"); } else { logger()->notice("Trying to download alternative sources for {$source}"); $alt_config = array_merge($config, $alt_sources); diff --git a/src/SPC/store/PackageManager.php b/src/SPC/store/PackageManager.php index 14f6bbcf..dc662a5b 100644 --- a/src/SPC/store/PackageManager.php +++ b/src/SPC/store/PackageManager.php @@ -37,7 +37,6 @@ class PackageManager Downloader::downloadPackage($pkg_name, $config, $force); } catch (\Throwable $e) { if (!$allow_alt) { - logger()->error("Download package {$pkg_name} failed: " . $e->getMessage()); throw new DownloaderException("Download package {$pkg_name} failed: " . $e->getMessage()); } // if download failed, we will try to download alternative packages From f47c3a2d20c6bff51b6a0687a874b5b131392ec6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 25 Jul 2025 10:58:58 +0800 Subject: [PATCH 3/5] Fix macOS missing lib when linking --- config/env.ini | 2 ++ src/SPC/builder/macos/MacOSBuilder.php | 1 + 2 files changed, 3 insertions(+) diff --git a/config/env.ini b/config/env.ini index 375ee13c..cf24967f 100644 --- a/config/env.ini +++ b/config/env.ini @@ -155,6 +155,8 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}" SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; EXTRA_CFLAGS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie ${SPC_DEFAULT_C_FLAGS}" +; EXTRA_LDFLAGS_PROGRAM for `make` php +SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-L${BUILD_LIB_PATH}" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv" ; embed type for php, static (libphp.a) or shared (libphp.dylib) diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 50efa013..03abedef 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -280,6 +280,7 @@ class MacOSBuilder extends UnixBuilderBase $config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs')); return [ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), + 'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'), 'EXTRA_LIBS' => $config['libs'], ]; } From a375ab97805fb219c7adaaafb99521a87eecec98 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 25 Jul 2025 11:29:53 +0800 Subject: [PATCH 4/5] Fix custom pkg download callable not working bug --- src/SPC/store/Downloader.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index ed462489..c9b71c86 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -368,6 +368,11 @@ class Downloader break; case 'custom': // Custom download method, like API-based download or other $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); + if (isset($pkg['func']) && is_callable($pkg['func'])) { + $pkg['name'] = $name; + $pkg['func']($force, $pkg, SPC_DOWNLOAD_PACKAGE); + break; + } foreach ($classes as $class) { if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) { $cls = new $class(); From 6c3ff7da32f658f534fd783d667d6a9890370e37 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 25 Jul 2025 12:44:22 +0800 Subject: [PATCH 5/5] Change LDFLAGS_PROGRAM to hard-coded --- config/env.ini | 23 ++++++++--------------- src/SPC/builder/linux/LinuxBuilder.php | 8 +++++--- src/SPC/builder/macos/MacOSBuilder.php | 4 ++-- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/config/env.ini b/config/env.ini index cf24967f..c4c27c50 100644 --- a/config/env.ini +++ b/config/env.ini @@ -34,7 +34,6 @@ ; SPC_LINUX_DEFAULT_CXX: the default c++ compiler for linux. (For alpine linux: `g++`, default: `$GNU_ARCH-linux-musl-g++`) ; SPC_LINUX_DEFAULT_AR: the default archiver for linux. (For alpine linux: `ar`, default: `$GNU_ARCH-linux-musl-ar`) - [global] ; Build concurrency for make -jN, default is CPU_COUNT, this value are used in every libs. SPC_CONCURRENCY=${CPU_COUNT} @@ -101,11 +100,11 @@ SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" ; configure command SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --disable-shared --enable-static --disable-all --disable-cgi --disable-phpdbg --with-pic" ; make command -SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" -; embed type for php, static (libphp.a) or shared (libphp.so) -SPC_CMD_VAR_PHP_EMBED_TYPE="static" +SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}" ; *** default build vars for building php *** +; embed type for php, static (libphp.a) or shared (libphp.so) +SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; CFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -fPIE" ; CPPFLAGS for configuring php @@ -115,13 +114,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; LIBS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE ${SPC_DEFAULT_C_FLAGS}" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_DEFAULT_C_FLAGS} -g -fstack-protector-strong -fno-ident -fPIE" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm" -; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so -SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS="-L${BUILD_LIB_PATH}" -; EXTRA_LDFLAGS_PROGRAM for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie" [macos] ; build target: macho or macho (possibly we could support macho-universal in the future) @@ -144,9 +139,11 @@ SPC_CMD_PREFIX_PHP_BUILDCONF="./buildconf --force" ; configure command SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-shared=no --enable-static=yes --disable-all --disable-cgi --disable-phpdbg" ; make command -SPC_CMD_PREFIX_PHP_MAKE="make -j${CPU_COUNT}" +SPC_CMD_PREFIX_PHP_MAKE="make -j${SPC_CONCURRENCY}" ; *** default build vars for building php *** +; embed type for php, static (libphp.a) or shared (libphp.dylib) +SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; CFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS="${SPC_DEFAULT_C_FLAGS} -Werror=unknown-warning-option" ; CPPFLAGS for configuring php @@ -154,13 +151,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}" ; LDFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie ${SPC_DEFAULT_C_FLAGS}" -; EXTRA_LDFLAGS_PROGRAM for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-L${BUILD_LIB_PATH}" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_DEFAULT_C_FLAGS} -g -fstack-protector-strong -fpic -fpie" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv" -; embed type for php, static (libphp.a) or shared (libphp.dylib) -SPC_CMD_VAR_PHP_EMBED_TYPE="static" [freebsd] ; compiler environments diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 869f088f..7628f667 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -12,6 +12,7 @@ use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\GlobalEnvManager; use SPC\util\SPCConfigUtil; +use SPC\util\SPCTarget; class LinuxBuilder extends UnixBuilderBase { @@ -96,7 +97,7 @@ class LinuxBuilder extends UnixBuilderBase $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), - 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), + 'LDFLAGS' => '-L' . BUILD_LIB_PATH, 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); @@ -299,11 +300,12 @@ class LinuxBuilder extends UnixBuilderBase private function getMakeExtraVars(): array { $config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs')); + $static = SPCTarget::isStatic() ? '-all-static' : ''; + $lib = BUILD_LIB_PATH; return [ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), 'EXTRA_LIBS' => $config['libs'], - 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), - 'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'), + 'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie", ]; } diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 03abedef..9b131b9d 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -116,7 +116,7 @@ class MacOSBuilder extends UnixBuilderBase $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), - 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), + 'LDFLAGS' => '-L' . BUILD_LIB_PATH, 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); @@ -280,7 +280,7 @@ class MacOSBuilder extends UnixBuilderBase $config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs')); return [ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), - 'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'), + 'EXTRA_LDFLAGS_PROGRAM' => '-L' . BUILD_LIB_PATH, 'EXTRA_LIBS' => $config['libs'], ]; }