From 5a0fd40dc49ffca1a5889f0bed98105e1fc843de Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 1 Dec 2025 09:55:46 +0100 Subject: [PATCH 01/73] update libwebp and libxml2 --- config/source.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/config/source.json b/config/source.json index 9a80cd059..689594a76 100644 --- a/config/source.json +++ b/config/source.json @@ -771,8 +771,9 @@ ] }, "libwebp": { - "type": "url", - "url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz", + "type": "ghtagtar", + "repo": "webmproject/libwebp", + "match": "v1\\.\\d+\\.\\d+$", "provide-pre-built": true, "license": { "type": "file", @@ -780,8 +781,10 @@ } }, "libxml2": { - "type": "url", - "url": "https://github.com/GNOME/libxml2/archive/refs/tags/v2.12.5.tar.gz", + "type": "ghtagtar", + "repo": "GNOME/libxml2", + "match": "v2\\.\\d+\\.\\d+$", + "provide-pre-built": false, "license": { "type": "file", "path": "Copyright" From 7204d277b4f3e92b3b3dd9fe030b1ae7bc9b7cb5 Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 1 Dec 2025 11:39:56 +0100 Subject: [PATCH 02/73] Update PHP extensions for Linux and Darwin --- src/globals/test-extensions.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index f44914ece..8a30b008e 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -50,14 +50,14 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'bcmath', + 'Linux', 'Darwin' => 'bcmath,xsl,xml', 'Windows' => 'bcmath', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => 'pcov', - 'Darwin' => 'pcov', + 'Linux' => '', + 'Darwin' => '', 'Windows' => '', }; From 14b822a185379b62c9daae3259bccd320942fcd7 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 16:55:52 +0100 Subject: [PATCH 03/73] don't build avx2 if we don't have it --- src/SPC/builder/unix/library/libjxl.php | 18 +++++++++++------- src/SPC/builder/unix/library/libwebp.php | 7 ++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/SPC/builder/unix/library/libjxl.php b/src/SPC/builder/unix/library/libjxl.php index 13f8481b1..4c922d9df 100644 --- a/src/SPC/builder/unix/library/libjxl.php +++ b/src/SPC/builder/unix/library/libjxl.php @@ -29,13 +29,17 @@ protected function build(): void ); if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { - $cmake->addConfigureArgs( - '-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE', - '-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE', - '-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE', - '-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE', - '-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE' - ); + $cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: ''; + $has_avx512 = str_contains($cflags, '-mavx512') || str_contains($cflags, '-march=x86-64-v4'); + if (!$has_avx512) { + $cmake->addConfigureArgs( + '-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE', + '-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE', + '-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE', + '-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE', + '-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE' + ); + } } $cmake->build(); diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 46a88af49..788d069fb 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -10,8 +10,13 @@ trait libwebp { protected function build(): void { + $cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: ''; + $has_avx2 = str_contains($cflags, '-mavx2') || str_contains($cflags, '-march=x86-64-v2') || str_contains($cflags, '-march=x86-64-v3'); UnixCMakeExecutor::create($this) - ->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON') + ->addConfigureArgs( + '-DWEBP_BUILD_EXTRAS=ON', + '-DWEBP_ENABLE_SIMD=' . ($has_avx2 ? 'ON' : 'OFF'), + ) ->build(); // patch pkgconfig $this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR); From d1041c57dcc12adef278fe592ba7e1edb5b998bd Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 17:05:50 +0100 Subject: [PATCH 04/73] remove openssl source/test dir (4.1gb?!) --- src/SPC/builder/linux/library/openssl.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index d9e04b323..7a4681976 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -80,5 +80,6 @@ public function build(): void } FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Requires.private: zlib'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); + FileSystem::removeDir($this->source_dir . '/test'); } } From 7f863d182f80811792da2eac9edf4f43eaed7677 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 17:10:56 +0100 Subject: [PATCH 05/73] don't remove dir, just don't build tests --- src/SPC/builder/linux/library/openssl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index 7a4681976..a78b6a642 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -62,6 +62,7 @@ public function build(): void "{$zlib_extra}" . 'enable-pie ' . 'no-legacy ' . + 'no-tests ' . "linux-{$arch}" ) ->exec('make clean') @@ -80,6 +81,5 @@ public function build(): void } FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Requires.private: zlib'); FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")'); - FileSystem::removeDir($this->source_dir . '/test'); } } From b965ffcd820cfc3c319b7f41ae6170fe7ca82616 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 17:16:59 +0100 Subject: [PATCH 06/73] don't build extra programs --- src/SPC/builder/unix/library/libwebp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 788d069fb..2ad616e0b 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -14,7 +14,7 @@ protected function build(): void $has_avx2 = str_contains($cflags, '-mavx2') || str_contains($cflags, '-march=x86-64-v2') || str_contains($cflags, '-march=x86-64-v3'); UnixCMakeExecutor::create($this) ->addConfigureArgs( - '-DWEBP_BUILD_EXTRAS=ON', + '-DWEBP_BUILD_EXTRAS=OFF', '-DWEBP_ENABLE_SIMD=' . ($has_avx2 ? 'ON' : 'OFF'), ) ->build(); From c051a48d56ee79e855ebc188bf2550167c28e374 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 17:28:59 +0100 Subject: [PATCH 07/73] don't add -l:libstdc++.a if we're not actually using gcc/clang --- src/SPC/builder/extension/imagick.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php index bef772ee6..0fda41ea8 100644 --- a/src/SPC/builder/extension/imagick.php +++ b/src/SPC/builder/extension/imagick.php @@ -5,6 +5,8 @@ namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\toolchain\ToolchainManager; +use SPC\toolchain\ZigToolchain; use SPC\util\CustomExt; #[CustomExt('imagick')] @@ -19,7 +21,7 @@ public function getUnixConfigureArg(bool $shared = false): string protected function splitLibsIntoStaticAndShared(string $allLibs): array { [$static, $shared] = parent::splitLibsIntoStaticAndShared($allLibs); - if (str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) { + if (ToolchainManager::getToolchainClass() !== ZigToolchain::class && str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) { $static .= ' -l:libstdc++.a'; $shared = str_replace('-lstdc++', '', $shared); } From 150d866c1504a3a8928b1b763f980f672ea826a5 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 19:12:43 +0100 Subject: [PATCH 08/73] revert turning off sse for libwebp, need to check why debian fails building --- src/SPC/builder/extension/imagick.php | 4 +++- src/SPC/builder/unix/library/libwebp.php | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php index 0fda41ea8..a548a8a3d 100644 --- a/src/SPC/builder/extension/imagick.php +++ b/src/SPC/builder/extension/imagick.php @@ -21,7 +21,9 @@ public function getUnixConfigureArg(bool $shared = false): string protected function splitLibsIntoStaticAndShared(string $allLibs): array { [$static, $shared] = parent::splitLibsIntoStaticAndShared($allLibs); - if (ToolchainManager::getToolchainClass() !== ZigToolchain::class && str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) { + if (ToolchainManager::getToolchainClass() !== ZigToolchain::class && + (str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) + ) { $static .= ' -l:libstdc++.a'; $shared = str_replace('-lstdc++', '', $shared); } diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 2ad616e0b..88a07f8c3 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -10,12 +10,9 @@ trait libwebp { protected function build(): void { - $cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: ''; - $has_avx2 = str_contains($cflags, '-mavx2') || str_contains($cflags, '-march=x86-64-v2') || str_contains($cflags, '-march=x86-64-v3'); UnixCMakeExecutor::create($this) ->addConfigureArgs( - '-DWEBP_BUILD_EXTRAS=OFF', - '-DWEBP_ENABLE_SIMD=' . ($has_avx2 ? 'ON' : 'OFF'), + '-DWEBP_BUILD_EXTRAS=OFF' ) ->build(); // patch pkgconfig From 22d263c0a85ccb5e99a8a19dfcae7e8532a7ac63 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 19:27:44 +0100 Subject: [PATCH 09/73] maybe explicit mavx2?! --- src/SPC/builder/unix/library/libwebp.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 88a07f8c3..ad00259a6 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -11,6 +11,9 @@ trait libwebp protected function build(): void { UnixCMakeExecutor::create($this) + ->appendEnv([ + 'CFLAGS' => GNU_ARCH === 'x86_64' ? '-mavx2' : '', + ]) ->addConfigureArgs( '-DWEBP_BUILD_EXTRAS=OFF' ) From 5b4f4f8e55d4716cc222652376d42c3522f7b3df Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 19:55:51 +0100 Subject: [PATCH 10/73] maybe? --- src/SPC/builder/unix/library/libwebp.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index ad00259a6..54f9e7847 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -5,17 +5,25 @@ namespace SPC\builder\unix\library; use SPC\util\executor\UnixCMakeExecutor; +use SPC\util\SPCTarget; trait libwebp { protected function build(): void { UnixCMakeExecutor::create($this) - ->appendEnv([ - 'CFLAGS' => GNU_ARCH === 'x86_64' ? '-mavx2' : '', - ]) ->addConfigureArgs( - '-DWEBP_BUILD_EXTRAS=OFF' + '-DWEBP_BUILD_EXTRAS=OFF', + '-DWEBP_BUILD_ANIM_UTILS=OFF', + '-DWEBP_BUILD_CWEBP=OFF', + '-DWEBP_BUILD_DWEBP=OFF', + '-DWEBP_BUILD_GIF2WEBP=OFF', + '-DWEBP_BUILD_IMG2WEBP=OFF', + '-DWEBP_BUILD_VWEBP=OFF', + '-DWEBP_BUILD_WEBPINFO=OFF', + '-DWEBP_BUILD_WEBPMUX=OFF', + '-DWEBP_BUILD_FUZZTEST=OFF', + SPCTarget::getLibcVersion() === '2.31' && GNU_ARCH === 'x86_64' ? '-DWEBP_ENABLE_SIMD=OFF' : '' // fix an edge bug for debian 11 with gcc 10 ) ->build(); // patch pkgconfig From b8444070eea11ca75bd29764a5dfd159580e01d8 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 1 Dec 2025 20:41:58 +0100 Subject: [PATCH 11/73] update go-xcaddy version automatically --- src/SPC/store/pkg/GoXcaddy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/store/pkg/GoXcaddy.php b/src/SPC/store/pkg/GoXcaddy.php index 0c1c6f8c6..93821aaa9 100644 --- a/src/SPC/store/pkg/GoXcaddy.php +++ b/src/SPC/store/pkg/GoXcaddy.php @@ -48,10 +48,10 @@ public function fetch(string $name, bool $force = false, ?array $config = null): 'macos' => 'darwin', default => throw new \InvalidArgumentException('Unsupported OS: ' . $name), }; - $go_version = '1.25.0'; + [$go_version] = explode("\n", Downloader::curlExec('https://go.dev/VERSION?m=text')); $config = [ 'type' => 'url', - 'url' => "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz", + 'url' => "https://go.dev/dl/{$go_version}.{$os}-{$arch}.tar.gz", ]; Downloader::downloadPackage($name, $config, $force); } From 719d818fd1e75be83a9b34c90551c7b1ed0bb0a8 Mon Sep 17 00:00:00 2001 From: henderkes Date: Tue, 2 Dec 2025 21:34:32 +0100 Subject: [PATCH 12/73] we need to check for structure of pdo_sqlsrv extension --- src/SPC/builder/extension/pdo_sqlsrv.php | 26 ++++++++ src/SPC/store/FileSystem.php | 76 ++++++++++++------------ 2 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 src/SPC/builder/extension/pdo_sqlsrv.php diff --git a/src/SPC/builder/extension/pdo_sqlsrv.php b/src/SPC/builder/extension/pdo_sqlsrv.php new file mode 100644 index 000000000..32697b169 --- /dev/null +++ b/src/SPC/builder/extension/pdo_sqlsrv.php @@ -0,0 +1,26 @@ +source_dir . '/config.m4') && is_dir($this->source_dir . '/source/pdo_sqlsrv')) { + FileSystem::moveFileOrDir($this->source_dir . '/LICENSE', $this->source_dir . '/source/pdo_sqlsrv/LICENSE'); + FileSystem::moveFileOrDir($this->source_dir . '/source/shared', $this->source_dir . '/source/pdo_sqlsrv/shared'); + FileSystem::moveFileOrDir($this->source_dir . '/source/pdo_sqlsrv', SOURCE_PATH . '/pdo_sqlsrv'); + FileSystem::removeDir($this->source_dir); + FileSystem::moveFileOrDir(SOURCE_PATH . '/pdo_sqlsrv', $this->source_dir); + return true; + } + return false; + } +} diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 3b88a2bce..f6c538bdf 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -572,6 +572,44 @@ public static function replaceFileLineContainsString(string $file, string $find, return file_put_contents($file, implode('', $lines)); } + /** + * 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 + */ + public static function moveFileOrDir(string $source, string $dest): void + { + $source = self::convertPath($source); + $dest = self::convertPath($dest); + + // Check if source and dest are on the same device to avoid cross-device rename errors + $source_stat = @stat($source); + $dest_parent = dirname($dest); + $dest_stat = @stat($dest_parent); + + // Only use rename if on same device + if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) { + if (@rename($source, $dest)) { + return; + } + } + + // Fall back to copy + delete for cross-device moves or if rename failed + 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}"); + } + } + } + private static function extractArchive(string $filename, string $target): void { // Create base dir @@ -648,44 +686,6 @@ private static function extractWithType(string $source_type, string $filename, s }; } - /** - * 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); - - // Check if source and dest are on the same device to avoid cross-device rename errors - $source_stat = @stat($source); - $dest_parent = dirname($dest); - $dest_stat = @stat($dest_parent); - - // Only use rename if on same device - if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) { - if (@rename($source, $dest)) { - return; - } - } - - // Fall back to copy + delete for cross-device moves or if rename failed - 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 */ From 98773ee5a6fab2c7366cf9e8c4024ff7043ca92e Mon Sep 17 00:00:00 2001 From: henderkes Date: Wed, 3 Dec 2025 15:02:14 +0100 Subject: [PATCH 13/73] zig toolchain can always use libc --- src/SPC/builder/linux/library/liburing.php | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/SPC/builder/linux/library/liburing.php b/src/SPC/builder/linux/library/liburing.php index 82249cf80..9a67f50c4 100644 --- a/src/SPC/builder/linux/library/liburing.php +++ b/src/SPC/builder/linux/library/liburing.php @@ -6,6 +6,8 @@ use SPC\builder\linux\SystemUtil; use SPC\store\FileSystem; +use SPC\toolchain\GccNativeToolchain; +use SPC\toolchain\ToolchainManager; use SPC\util\executor\UnixAutoconfExecutor; use SPC\util\SPCTarget; @@ -15,26 +17,19 @@ class liburing extends LinuxLibraryBase public function patchBeforeBuild(): bool { - if (!SystemUtil::isMuslDist()) { - return false; + if (SystemUtil::isMuslDist()) { + FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath'); + return true; } - FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath'); - return true; + return false; } protected function build(): void { - $use_libc = SPCTarget::getLibc() !== 'glibc' || version_compare(SPCTarget::getLibcVersion(), '2.30', '>='); + $use_libc = ToolchainManager::getToolchainClass() !== GccNativeToolchain::class || version_compare(SPCTarget::getLibcVersion(), '2.30', '>='); $make = UnixAutoconfExecutor::create($this); - if (!$use_libc) { - $make->appendEnv([ - 'CC' => 'gcc', // libc-less version fails to compile with clang or zig - 'CXX' => 'g++', - 'AR' => 'ar', - 'LD' => 'ld', - ]); - } else { + if ($use_libc) { $make->appendEnv([ 'CFLAGS' => '-D_GNU_SOURCE', ]); @@ -51,7 +46,7 @@ protected function build(): void $use_libc ? '--use-libc' : '', ) ->configure() - ->make('library', 'install ENABLE_SHARED=0', with_clean: false); + ->make('library ENABLE_SHARED=0', 'install ENABLE_SHARED=0', with_clean: false); $this->patchPkgconfPrefix(); } From 66840a8eed896b8d3769861394198ff336d7336e Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 09:15:22 +0100 Subject: [PATCH 14/73] update xdebug to use pie sources --- config/source.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/source.json b/config/source.json index 689594a76..c96822d6b 100644 --- a/config/source.json +++ b/config/source.json @@ -1172,9 +1172,8 @@ } }, "xdebug": { - "type": "url", - "url": "https://pecl.php.net/get/xdebug", - "filename": "xdebug.tgz", + "type": "pie", + "repo": "xdebug/xdebug", "license": { "type": "file", "path": "LICENSE" From 7bdcda1d626fa6c1b935168c3741079908630230 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 11:37:35 +0100 Subject: [PATCH 15/73] gmp can't build with std=c23 (default with gcc 15) --- src/SPC/builder/unix/library/gmp.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index f09976d8c..cb5d76f9c 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -10,7 +10,12 @@ trait gmp { protected function build(): void { - UnixAutoconfExecutor::create($this)->configure()->make(); + UnixAutoconfExecutor::create($this) + ->appendEnv([ + 'CFLAGS' => '-std=gnu99', + ]) + ->configure() + ->make(); $this->patchPkgconfPrefix(['gmp.pc']); } } From 6b5f7027196a6e36e9ca1c755177fe71282a2638 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 11:43:51 +0100 Subject: [PATCH 16/73] ncurses can't build with std=c23 (default with gcc 15) --- src/SPC/builder/unix/library/ncurses.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SPC/builder/unix/library/ncurses.php b/src/SPC/builder/unix/library/ncurses.php index 27725c3d5..31e61b1e7 100644 --- a/src/SPC/builder/unix/library/ncurses.php +++ b/src/SPC/builder/unix/library/ncurses.php @@ -16,6 +16,7 @@ protected function build(): void UnixAutoconfExecutor::create($this) ->appendEnv([ + 'CFLAGS' => '-std=gnu99', 'LDFLAGS' => SPCTarget::isStatic() ? '-static' : '', ]) ->configure( From 1d5aec037b6f4bae508a2a679cf25c4eb0076023 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 12:14:57 +0100 Subject: [PATCH 17/73] c17 instead --- src/SPC/builder/extension/mongodb.php | 5 +++++ src/SPC/builder/unix/library/gmp.php | 2 +- src/SPC/builder/unix/library/ncurses.php | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php index 745417bb1..1c22f2899 100644 --- a/src/SPC/builder/extension/mongodb.php +++ b/src/SPC/builder/extension/mongodb.php @@ -24,4 +24,9 @@ public function getUnixConfigureArg(bool $shared = false): string $arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled '; return clean_spaces($arg); } + + protected function getExtraEnv(): array + { + return ['CFLAGS' => '-std=c17']; + } } diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index cb5d76f9c..f625274f6 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -12,7 +12,7 @@ protected function build(): void { UnixAutoconfExecutor::create($this) ->appendEnv([ - 'CFLAGS' => '-std=gnu99', + 'CFLAGS' => '-std=c17', ]) ->configure() ->make(); diff --git a/src/SPC/builder/unix/library/ncurses.php b/src/SPC/builder/unix/library/ncurses.php index 31e61b1e7..2859f556d 100644 --- a/src/SPC/builder/unix/library/ncurses.php +++ b/src/SPC/builder/unix/library/ncurses.php @@ -16,7 +16,7 @@ protected function build(): void UnixAutoconfExecutor::create($this) ->appendEnv([ - 'CFLAGS' => '-std=gnu99', + 'CFLAGS' => '-std=c17', 'LDFLAGS' => SPCTarget::isStatic() ? '-static' : '', ]) ->configure( From b2182b4fe1d0278c1efcdbfce7a5b0268fb4aae0 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 12:20:14 +0100 Subject: [PATCH 18/73] use source extract hook for pdo_sqlsrv --- src/SPC/builder/extension/pdo_sqlsrv.php | 26 ------------------------ src/SPC/store/SourcePatcher.php | 18 ++++++++++++++++ 2 files changed, 18 insertions(+), 26 deletions(-) delete mode 100644 src/SPC/builder/extension/pdo_sqlsrv.php diff --git a/src/SPC/builder/extension/pdo_sqlsrv.php b/src/SPC/builder/extension/pdo_sqlsrv.php deleted file mode 100644 index 32697b169..000000000 --- a/src/SPC/builder/extension/pdo_sqlsrv.php +++ /dev/null @@ -1,26 +0,0 @@ -source_dir . '/config.m4') && is_dir($this->source_dir . '/source/pdo_sqlsrv')) { - FileSystem::moveFileOrDir($this->source_dir . '/LICENSE', $this->source_dir . '/source/pdo_sqlsrv/LICENSE'); - FileSystem::moveFileOrDir($this->source_dir . '/source/shared', $this->source_dir . '/source/pdo_sqlsrv/shared'); - FileSystem::moveFileOrDir($this->source_dir . '/source/pdo_sqlsrv', SOURCE_PATH . '/pdo_sqlsrv'); - FileSystem::removeDir($this->source_dir); - FileSystem::moveFileOrDir(SOURCE_PATH . '/pdo_sqlsrv', $this->source_dir); - return true; - } - return false; - } -} diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index f628544fe..0068f53e3 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -25,6 +25,7 @@ public static function init(): void FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchFfiCentos7FixO3strncmp']); FileSystem::addSourceExtractHook('sqlsrv', [__CLASS__, 'patchSQLSRVWin32']); FileSystem::addSourceExtractHook('pdo_sqlsrv', [__CLASS__, 'patchSQLSRVWin32']); + FileSystem::addSourceExtractHook('pdo_sqlsrv', [__CLASS__, 'patchSQLSRVPhp85']); FileSystem::addSourceExtractHook('yaml', [__CLASS__, 'patchYamlWin32']); FileSystem::addSourceExtractHook('libyaml', [__CLASS__, 'patchLibYaml']); FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchImapLicense']); @@ -432,6 +433,23 @@ public static function patchSQLSRVWin32(string $source_name): bool return false; } + /** + * Fix the compilation issue of pdo_sqlsrv with php 8.5 + */ + public static function patchSQLSRVPhp85(): bool + { + $source_dir = SOURCE_PATH . '/php-src/ext/pdo_sqlsrv'; + if (!file_exists($source_dir . '/config.m4') && is_dir($source_dir . '/source/pdo_sqlsrv')) { + FileSystem::moveFileOrDir($source_dir . '/LICENSE', $source_dir . '/source/pdo_sqlsrv/LICENSE'); + FileSystem::moveFileOrDir($source_dir . '/source/shared', $source_dir . '/source/pdo_sqlsrv/shared'); + FileSystem::moveFileOrDir($source_dir . '/source/pdo_sqlsrv', SOURCE_PATH . '/pdo_sqlsrv'); + FileSystem::removeDir($source_dir); + FileSystem::moveFileOrDir(SOURCE_PATH . '/pdo_sqlsrv', $source_dir); + return true; + } + return false; + } + public static function patchYamlWin32(): bool { FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/yaml/config.w32', "lib.substr(lib.length - 6, 6) == '_a.lib'", "lib.substr(lib.length - 6, 6) == '_a.lib' || 'yes' == 'yes'"); From 47ab5d7584f68f1963d9fd8996e103040b65af85 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 5 Dec 2025 13:57:28 +0100 Subject: [PATCH 19/73] use c17 for extensions as well? --- src/SPC/builder/Extension.php | 2 +- src/SPC/builder/extension/mongodb.php | 5 ----- src/SPC/builder/extension/pgsql.php | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 08b403e61..57ed9dd38 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -576,7 +576,7 @@ protected function addExtensionDependency(string $name, bool $optional = false): protected function getExtraEnv(): array { - return []; + return ['CFLAGS' => '-std=c17']; } /** diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php index 1c22f2899..745417bb1 100644 --- a/src/SPC/builder/extension/mongodb.php +++ b/src/SPC/builder/extension/mongodb.php @@ -24,9 +24,4 @@ public function getUnixConfigureArg(bool $shared = false): string $arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled '; return clean_spaces($arg); } - - protected function getExtraEnv(): array - { - return ['CFLAGS' => '-std=c17']; - } } diff --git a/src/SPC/builder/extension/pgsql.php b/src/SPC/builder/extension/pgsql.php index f22f7ba68..06efa8b13 100644 --- a/src/SPC/builder/extension/pgsql.php +++ b/src/SPC/builder/extension/pgsql.php @@ -45,7 +45,7 @@ public function getWindowsConfigureArg(bool $shared = false): string protected function getExtraEnv(): array { return [ - 'CFLAGS' => '-Wno-int-conversion', + 'CFLAGS' => '-std=c17 -Wno-int-conversion', ]; } } From dce63d3c87ae88dce86731a61b68b525f4c2a535 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 6 Dec 2025 11:18:10 +0100 Subject: [PATCH 20/73] we need extensions to explicitly tell which c std they need --- src/SPC/builder/Extension.php | 2 +- src/SPC/builder/extension/mongodb.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 57ed9dd38..bc475d115 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -576,7 +576,7 @@ protected function addExtensionDependency(string $name, bool $optional = false): protected function getExtraEnv(): array { - return ['CFLAGS' => '-std=c17']; + return ['CFLAGS' => '']; } /** diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php index 745417bb1..08861e4ef 100644 --- a/src/SPC/builder/extension/mongodb.php +++ b/src/SPC/builder/extension/mongodb.php @@ -24,4 +24,9 @@ public function getUnixConfigureArg(bool $shared = false): string $arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled '; return clean_spaces($arg); } + + public function getExtraEnv(): array + { + return ['CFLAGS' => '-std=c17']; + } } From a54021bf1966bd9bd92014916c0cb88cc4dd5a1d Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 10 Dec 2025 08:42:28 +0100 Subject: [PATCH 21/73] Apply suggestion from @henderkes --- src/SPC/builder/Extension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index bc475d115..08b403e61 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -576,7 +576,7 @@ protected function addExtensionDependency(string $name, bool $optional = false): protected function getExtraEnv(): array { - return ['CFLAGS' => '']; + return []; } /** From f0b5e4f59eb595a8b9a7d6663932060cba91e64e Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Wed, 10 Dec 2025 15:43:24 +0800 Subject: [PATCH 22/73] Fix typo in ncurses.php enable-symlinks option (#994) --- src/SPC/builder/unix/library/ncurses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/ncurses.php b/src/SPC/builder/unix/library/ncurses.php index 27725c3d5..fa63eb3f8 100644 --- a/src/SPC/builder/unix/library/ncurses.php +++ b/src/SPC/builder/unix/library/ncurses.php @@ -29,7 +29,7 @@ protected function build(): void '--without-tests', '--without-dlsym', '--without-debug', - '-enable-symlinks', + '--enable-symlinks', "--bindir={$this->getBinDir()}", "--includedir={$this->getIncludeDir()}", "--libdir={$this->getLibDir()}", From 3c89ce6c7f834d66c65e47c24724d6619c41a0fd Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Wed, 10 Dec 2025 17:14:27 +0800 Subject: [PATCH 23/73] Update version to 2.7.10 (#997) --- src/SPC/ConsoleApplication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 1b1d3e199..7fc56ae3c 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -34,7 +34,7 @@ */ final class ConsoleApplication extends Application { - public const string VERSION = '2.7.9'; + public const string VERSION = '2.7.10'; public function __construct() { From acd0e2b23a2ad29bb7cb77e25fc0f1e4b6f99698 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 15 Dec 2025 17:00:20 +0800 Subject: [PATCH 24/73] Prepare for skeleton --- skeleton-test.php | 21 ++ src/Package/Artifact/zig.php | 1 + src/StaticPHP/Config/ArtifactConfig.php | 10 +- src/StaticPHP/Config/PackageConfig.php | 10 +- src/StaticPHP/ConsoleApplication.php | 8 +- src/StaticPHP/Registry/Registry.php | 57 +++- src/StaticPHP/Skeleton/ArtifactGenerator.php | 57 ++++ src/StaticPHP/Skeleton/ExecutorGenerator.php | 16 ++ src/StaticPHP/Skeleton/PackageGenerator.php | 283 +++++++++++++++++++ tests/bootstrap.php | 2 +- 10 files changed, 447 insertions(+), 18 deletions(-) create mode 100644 skeleton-test.php create mode 100644 src/StaticPHP/Skeleton/ArtifactGenerator.php create mode 100644 src/StaticPHP/Skeleton/ExecutorGenerator.php create mode 100644 src/StaticPHP/Skeleton/PackageGenerator.php diff --git a/skeleton-test.php b/skeleton-test.php new file mode 100644 index 000000000..689d33854 --- /dev/null +++ b/skeleton-test.php @@ -0,0 +1,21 @@ +addDependency('bar') + ->addStaticLib('libfoo.a', 'unix') + ->addStaticLib('libfoo.a', 'unix') + ->addArtifact($artifact_generator = new ArtifactGenerator('foo')->setSource(['type' => 'url', 'url' => 'https://example.com/foo.tar.gz'])); + +$pkg_config = $package_generator->generateConfig(); +$artifact_config = $artifact_generator->generateConfig(); + +echo "===== pkg.json =====" . PHP_EOL; +echo json_encode($pkg_config, 64|128|256) . PHP_EOL; +echo "===== artifact.json =====" . PHP_EOL; +echo json_encode($artifact_config, 64|128|256) . PHP_EOL; diff --git a/src/Package/Artifact/zig.php b/src/Package/Artifact/zig.php index 2ac7b454b..a73473954 100644 --- a/src/Package/Artifact/zig.php +++ b/src/Package/Artifact/zig.php @@ -8,6 +8,7 @@ use StaticPHP\Artifact\Downloader\DownloadResult; use StaticPHP\Attribute\Artifact\AfterBinaryExtract; use StaticPHP\Attribute\Artifact\CustomBinary; +use StaticPHP\Attribute\Artifact\CustomSource; use StaticPHP\Exception\DownloaderException; use StaticPHP\Runtime\SystemTarget; diff --git a/src/StaticPHP/Config/ArtifactConfig.php b/src/StaticPHP/Config/ArtifactConfig.php index d25c6dd1a..e840c0bf7 100644 --- a/src/StaticPHP/Config/ArtifactConfig.php +++ b/src/StaticPHP/Config/ArtifactConfig.php @@ -5,12 +5,13 @@ namespace StaticPHP\Config; use StaticPHP\Exception\WrongUsageException; +use StaticPHP\Registry\Registry; class ArtifactConfig { private static array $artifact_configs = []; - public static function loadFromDir(string $dir): void + public static function loadFromDir(string $dir, string $registry_name): void { if (!is_dir($dir)) { throw new WrongUsageException("Directory {$dir} does not exist, cannot load artifact config."); @@ -18,18 +19,18 @@ public static function loadFromDir(string $dir): void $files = glob("{$dir}/artifact.*.json"); if (is_array($files)) { foreach ($files as $file) { - self::loadFromFile($file); + self::loadFromFile($file, $registry_name); } } if (file_exists("{$dir}/artifact.json")) { - self::loadFromFile("{$dir}/artifact.json"); + self::loadFromFile("{$dir}/artifact.json", $registry_name); } } /** * Load artifact configurations from a specified JSON file. */ - public static function loadFromFile(string $file): void + public static function loadFromFile(string $file, string $registry_name): void { $content = file_get_contents($file); if ($content === false) { @@ -42,6 +43,7 @@ public static function loadFromFile(string $file): void ConfigValidator::validateAndLintArtifacts(basename($file), $data); foreach ($data as $artifact_name => $config) { self::$artifact_configs[$artifact_name] = $config; + Registry::_bindArtifactConfigFile($artifact_name, $registry_name, $file); } } diff --git a/src/StaticPHP/Config/PackageConfig.php b/src/StaticPHP/Config/PackageConfig.php index dc0b3d546..3342dfc78 100644 --- a/src/StaticPHP/Config/PackageConfig.php +++ b/src/StaticPHP/Config/PackageConfig.php @@ -5,6 +5,7 @@ namespace StaticPHP\Config; use StaticPHP\Exception\WrongUsageException; +use StaticPHP\Registry\Registry; use StaticPHP\Runtime\SystemTarget; class PackageConfig @@ -15,7 +16,7 @@ class PackageConfig * Load package configurations from a specified directory. * It will look for files matching the pattern 'pkg.*.json' and 'pkg.json'. */ - public static function loadFromDir(string $dir): void + public static function loadFromDir(string $dir, string $registry_name): void { if (!is_dir($dir)) { throw new WrongUsageException("Directory {$dir} does not exist, cannot load pkg.json config."); @@ -23,11 +24,11 @@ public static function loadFromDir(string $dir): void $files = glob("{$dir}/pkg.*.json"); if (is_array($files)) { foreach ($files as $file) { - self::loadFromFile($file); + self::loadFromFile($file, $registry_name); } } if (file_exists("{$dir}/pkg.json")) { - self::loadFromFile("{$dir}/pkg.json"); + self::loadFromFile("{$dir}/pkg.json", $registry_name); } } @@ -36,7 +37,7 @@ public static function loadFromDir(string $dir): void * * @param string $file the path to the json package configuration file */ - public static function loadFromFile(string $file): void + public static function loadFromFile(string $file, string $registry_name): void { $content = file_get_contents($file); if ($content === false) { @@ -49,6 +50,7 @@ public static function loadFromFile(string $file): void ConfigValidator::validateAndLintPackages(basename($file), $data); foreach ($data as $pkg_name => $config) { self::$package_configs[$pkg_name] = $config; + Registry::_bindPackageConfigFile($pkg_name, $registry_name, $file); } } diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php index 0e5371ac4..bd0cfd60a 100644 --- a/src/StaticPHP/ConsoleApplication.php +++ b/src/StaticPHP/ConsoleApplication.php @@ -9,6 +9,7 @@ use StaticPHP\Command\Dev\EnvCommand; use StaticPHP\Command\Dev\IsInstalledCommand; use StaticPHP\Command\Dev\ShellCommand; +use StaticPHP\Command\Dev\SkeletonCommand; use StaticPHP\Command\DoctorCommand; use StaticPHP\Command\DownloadCommand; use StaticPHP\Command\ExtractCommand; @@ -27,12 +28,12 @@ class ConsoleApplication extends Application public function __construct() { - parent::__construct('static-php-cli', self::VERSION); + parent::__construct('StaticPHP', self::VERSION); require_once ROOT_DIR . '/src/bootstrap.php'; - // check registry - Registry::checkLoadedRegistries(); + // resolve registry + Registry::resolve(); /** * @var string $name @@ -59,6 +60,7 @@ public function __construct() new ShellCommand(), new IsInstalledCommand(), new EnvCommand(), + new SkeletonCommand(), ]); // add additional commands from registries diff --git a/src/StaticPHP/Registry/Registry.php b/src/StaticPHP/Registry/Registry.php index 4ae5df4f4..909de021f 100644 --- a/src/StaticPHP/Registry/Registry.php +++ b/src/StaticPHP/Registry/Registry.php @@ -13,9 +13,13 @@ class Registry { - /** @var string[] List of loaded registry names */ + /** @var array List of loaded registries */ private static array $loaded_registries = []; + /** @var array Maps of package and artifact names to their registry config file paths (for reverse lookup) */ + private static array $package_reversed_registry_files = []; + private static array $artifact_reversed_registry_files = []; + /** * Load a registry from file path. * This method handles external registries that may not be in composer autoload. @@ -85,9 +89,9 @@ public static function loadRegistry(string $registry_file, bool $auto_require = foreach ($data['package']['config'] as $path) { $path = self::fullpath($path, dirname($registry_file)); if (is_file($path)) { - PackageConfig::loadFromFile($path); + PackageConfig::loadFromFile($path, $registry_name); } elseif (is_dir($path)) { - PackageConfig::loadFromDir($path); + PackageConfig::loadFromDir($path, $registry_name); } } } @@ -97,9 +101,9 @@ public static function loadRegistry(string $registry_file, bool $auto_require = foreach ($data['artifact']['config'] as $path) { $path = self::fullpath($path, dirname($registry_file)); if (is_file($path)) { - ArtifactConfig::loadFromFile($path); + ArtifactConfig::loadFromFile($path, $registry_name); } elseif (is_dir($path)) { - ArtifactConfig::loadFromDir($path); + ArtifactConfig::loadFromDir($path, $registry_name); } } } @@ -187,7 +191,12 @@ public static function loadFromEnvOrOption(?string $registries = null): void } } - public static function checkLoadedRegistries(): void + /** + * Resolve loaded registries. + * This method finalizes the loading process by registering default stages + * and validating stage events. + */ + public static function resolve(): void { // Register default stages for all PhpExtensionPackage instances // This must be done after all registries are loaded to ensure custom stages take precedence @@ -217,6 +226,42 @@ public static function reset(): void self::$loaded_registries = []; } + /** + * Bind a package name to its registry config file for reverse lookup. + * + * @internal + */ + public static function _bindPackageConfigFile(string $package_name, string $registry_name, string $config_file): void + { + self::$package_reversed_registry_files[$package_name] = [ + 'registry' => $registry_name, + 'config' => $config_file, + ]; + } + + /** + * Bind an artifact name to its registry config file for reverse lookup. + * + * @internal + */ + public static function _bindArtifactConfigFile(string $artifact_name, string $registry_name, string $config_file): void + { + self::$artifact_reversed_registry_files[$artifact_name] = [ + 'registry' => $registry_name, + 'config' => $config_file, + ]; + } + + public static function getPackageConfigInfo(string $package_name): ?array + { + return self::$package_reversed_registry_files[$package_name] ?? null; + } + + public static function getArtifactConfigInfo(string $artifact_name): ?array + { + return self::$artifact_reversed_registry_files[$artifact_name] ?? null; + } + /** * Parse a class entry from the classes array. * Supports two formats: diff --git a/src/StaticPHP/Skeleton/ArtifactGenerator.php b/src/StaticPHP/Skeleton/ArtifactGenerator.php new file mode 100644 index 000000000..031d095bb --- /dev/null +++ b/src/StaticPHP/Skeleton/ArtifactGenerator.php @@ -0,0 +1,57 @@ +name; + } + + public function setSource(array $source): static + { + $clone = clone $this; + $clone->source = $source; + return $clone; + } + + public function setCustomSource(): static + { + $clone = clone $this; + $clone->source = ['type' => 'custom']; + $clone->generate_class = true; + $clone->generate_custom_source_func = true; + return $clone; + } + + public function getSource(): ?array + { + return $this->source; + } + + public function generateConfig(): array + { + $config = []; + + if ($this->source) { + $config['source'] = $this->source; + } + return $config; + } +} diff --git a/src/StaticPHP/Skeleton/ExecutorGenerator.php b/src/StaticPHP/Skeleton/ExecutorGenerator.php new file mode 100644 index 000000000..02edf2ebd --- /dev/null +++ b/src/StaticPHP/Skeleton/ExecutorGenerator.php @@ -0,0 +1,16 @@ + $depends An array of dependencies required by the package, categorized by operating system. */ + protected array $depends = []; + + /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $suggests An array of suggested packages for the package, categorized by operating system. */ + protected array $suggests = []; + + /** @var array $frameworks An array of macOS frameworks for the package */ + protected array $frameworks = []; + + /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $static_libs An array of static libraries required by the package, categorized by operating system. */ + protected array $static_libs = []; + + /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $headers An array of header files required by the package, categorized by operating system. */ + protected array $headers = []; + + /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $static_bins An array of static binaries required by the package, categorized by operating system. */ + protected array $static_bins = []; + + /** @var ArtifactGenerator|null $artifact Artifact */ + protected ?ArtifactGenerator $artifact = null; + + /** @var array $licenses Licenses */ + protected array $licenses = []; + + /** @var array<'Darwin'|'Linux'|'Windows', null|string> $build_for_enables Enable build function generating */ + protected array $build_for_enables = [ + 'Darwin' => null, + 'Linux' => null, + 'Windows' => null, + ]; + + /** @var array */ + protected array $func_executor_binding = []; + + /** + * @param string $package_name Package name + * @param 'library'|'target'|'virtual-target'|'php-extension' $type Package type ('library', 'target', 'virtual-target', etc.) + */ + public function __construct(protected string $package_name, protected string $type) {} + + /** + * Add package dependency. + * + * @param string $package Package name + * @param string $os Operating system ('' for all OSes, '@unix', '@windows', '@macos') + */ + public function addDependency(string $package, string $os = ''): static + { + if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { + throw new ValidationException("Invalid OS suffix: {$os}"); + } + $clone = clone $this; + if (!isset($clone->depends[$os])) { + $clone->depends[$os] = []; + } + if (!in_array($package, $clone->depends[$os], true)) { + $clone->depends[$os][] = $package; + } + return $clone; + } + + /** + * Add package suggestion. + * + * @param string $package Package name + * @param string $os Operating system ('' for all OSes, '@unix', '@windows', '@macos') + */ + public function addSuggestion(string $package, string $os = ''): static + { + if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { + throw new ValidationException("Invalid OS suffix: {$os}"); + } + $clone = clone $this; + if (!isset($clone->suggests[$os])) { + $clone->suggests[$os] = []; + } + if (!in_array($package, $clone->suggests[$os], true)) { + $clone->suggests[$os][] = $package; + } + return $clone; + } + + public function addStaticLib(string $lib_a, string $os = ''): static + { + if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { + throw new ValidationException("Invalid OS suffix: {$os}"); + } + if (!str_ends_with($lib_a, '.lib') && !str_ends_with($lib_a, '.a')) { + throw new ValidationException("Static library must end with .lib or .a, got: {$lib_a}"); + } + if (str_ends_with($lib_a, '.lib') && in_array($os, ['unix', 'linux', 'macos'], true)) { + throw new ValidationException("Static library with .lib extension cannot be added for non-Windows OS: {$lib_a}"); + } + if (str_ends_with($lib_a, '.a') && $os === 'windows') { + throw new ValidationException("Static library with .a extension cannot be added for Windows OS: {$lib_a}"); + } + if (isset($this->static_libs[$os]) && in_array($lib_a, $this->static_libs[$os], true)) { + // already exists + return $this; + } + $clone = clone $this; + if (!isset($clone->static_libs[$os])) { + $clone->static_libs[$os] = []; + } + if (!in_array($lib_a, $clone->static_libs[$os], true)) { + $clone->static_libs[$os][] = $lib_a; + } + return $clone; + } + + public function addHeader(string $header_file, string $os = ''): static + { + if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { + throw new ValidationException("Invalid OS suffix: {$os}"); + } + $clone = clone $this; + if (!isset($clone->headers[$os])) { + $clone->headers[$os] = []; + } + if (!in_array($header_file, $clone->headers[$os], true)) { + $clone->headers[$os][] = $header_file; + } + return $clone; + } + + public function addStaticBin(string $bin_file, string $os = ''): static + { + if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { + throw new ValidationException("Invalid OS suffix: {$os}"); + } + $clone = clone $this; + if (!isset($clone->static_bins[$os])) { + $clone->static_bins[$os] = []; + } + if (!in_array($bin_file, $clone->static_bins[$os], true)) { + $clone->static_bins[$os][] = $bin_file; + } + return $clone; + } + + /** + * Add package artifact. + * + * @param ArtifactGenerator $artifactGenerator Artifact generator + */ + public function addArtifact(ArtifactGenerator $artifactGenerator): static + { + $clone = clone $this; + $clone->artifact = $artifactGenerator; + return $clone; + } + + /** + * Add license from string. + * + * @param string $text License content + */ + public function addLicenseFromString(string $text): static + { + $clone = clone $this; + $clone->licenses[] = [ + 'type' => 'text', + 'text' => $text, + ]; + return $clone; + } + + /** + * Add license from file. + * + * @param string $file_path License file path + */ + public function addLicenseFromFile(string $file_path): static + { + $clone = clone $this; + $clone->licenses[] = [ + 'type' => 'file', + 'path' => $file_path, + ]; + return $clone; + } + + /** + * Enable build for specific OS. + * + * @param 'Windows'|'Linux'|'Darwin'|array<'Windows'|'Linux'|'Darwin'> $build_for Build for OS + */ + public function enableBuild(string|array $build_for, ?string $build_function_name = null): static + { + $clone = clone $this; + if (is_array($build_for)) { + foreach ($build_for as $bf) { + $clone = $clone->enableBuild($bf, $build_function_name ?? 'build'); + } + return $clone; + } + $clone->build_for_enables[$build_for] = $build_function_name ?? "buildFor{$build_for}"; + return $clone; + } + + /** + * Bind function executor. + * + * @param string $func_name Function name + * @param ExecutorGenerator $executor Executor generator + */ + public function addFunctionExecutorBinding(string $func_name, ExecutorGenerator $executor): static + { + $clone = clone $this; + $clone->func_executor_binding[$func_name] = $executor; + return $clone; + } + + /** + * Generate package config + */ + public function generateConfig(): array + { + $config = ['type' => $this->type]; + + // Add dependencies + foreach ($this->depends as $suffix => $depends) { + $k = $suffix !== '' ? "depends@{$suffix}" : 'depends'; + $config[$k] = $depends; + } + + // add suggests + foreach ($this->suggests as $suffix => $suggests) { + $k = $suffix !== '' ? "suggests@{$suffix}" : 'suggests'; + $config[$k] = $suggests; + } + + // Add frameworks + if (!empty($this->frameworks)) { + $config['frameworks'] = $this->frameworks; + } + + // Add static libs + foreach ($this->static_libs as $suffix => $libs) { + $k = $suffix !== '' ? "static-libs@{$suffix}" : 'static-libs'; + $config[$k] = $libs; + } + + // Add headers + foreach ($this->headers as $suffix => $headers) { + $k = $suffix !== '' ? "headers@{$suffix}" : 'headers'; + $config[$k] = $headers; + } + + // Add static bins + foreach ($this->static_bins as $suffix => $bins) { + $k = $suffix !== '' ? "static-bins@{$suffix}" : 'static-bins'; + $config[$k] = $bins; + } + + // Add artifact + if ($this->artifact !== null) { + $config['artifact'] = $this->artifact->getName(); + } + + // Add licenses + if (!empty($this->licenses)) { + if (count($this->licenses) === 1) { + $config['license'] = $this->licenses[0]; + } else { + $config['license'] = $this->licenses; + } + } + + return $config; + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index ba9173323..14397d038 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -4,6 +4,6 @@ use Psr\Log\LogLevel; require_once __DIR__ . '/../src/bootstrap.php'; -\StaticPHP\Registry\Registry::checkLoadedRegistries(); +\StaticPHP\Registry\Registry::resolve(); logger()->setLevel(LogLevel::ERROR); From d064e1353cf7dd8e97a769267fc9a804e38169f1 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 15 Dec 2025 18:50:20 +0100 Subject: [PATCH 25/73] the libwebp 1.6.0 bug affects centos 7 too --- src/SPC/builder/extension/memcache.php | 5 +++++ src/SPC/builder/unix/library/libwebp.php | 8 ++++++-- src/globals/test-extensions.php | 14 +++++++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php index b63fa47a4..59c6065d4 100644 --- a/src/SPC/builder/extension/memcache.php +++ b/src/SPC/builder/extension/memcache.php @@ -43,4 +43,9 @@ public function patchBeforeBuildconf(): bool ); return true; } + + protected function getExtraEnv(): array + { + return ['CFLAGS' => '-std=c17']; + } } diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 54f9e7847..47fd0078c 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -5,12 +5,16 @@ namespace SPC\builder\unix\library; use SPC\util\executor\UnixCMakeExecutor; -use SPC\util\SPCTarget; trait libwebp { protected function build(): void { + $code = 'int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }'; + $cc = getenv('CC') ?: 'gcc'; + [$ret] = shell()->execWithResult("echo '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1"); + $disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64'; + UnixCMakeExecutor::create($this) ->addConfigureArgs( '-DWEBP_BUILD_EXTRAS=OFF', @@ -23,7 +27,7 @@ protected function build(): void '-DWEBP_BUILD_WEBPINFO=OFF', '-DWEBP_BUILD_WEBPMUX=OFF', '-DWEBP_BUILD_FUZZTEST=OFF', - SPCTarget::getLibcVersion() === '2.31' && GNU_ARCH === 'x86_64' ? '-DWEBP_ENABLE_SIMD=OFF' : '' // fix an edge bug for debian 11 with gcc 10 + $disableAvx2 ? '-DWEBP_ENABLE_SIMD=OFF' : '' ) ->build(); // patch pkgconfig diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 8a30b008e..72e751244 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -16,19 +16,19 @@ // '8.1', // '8.2', // '8.3', - '8.4', + // '8.4', '8.5', // 'git', ]; // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - 'macos-15-intel', // bin/spc for x86_64 - 'macos-15', // bin/spc for arm64 + // 'macos-15-intel', // bin/spc for x86_64 + // 'macos-15', // bin/spc for arm64 // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 - // 'ubuntu-24.04', // bin/spc for x86_64 - // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 + 'ubuntu-24.04', // bin/spc for x86_64 + 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 // 'windows-2025', @@ -50,7 +50,7 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'bcmath,xsl,xml', + 'Linux', 'Darwin' => 'imagick', 'Windows' => 'bcmath', }; @@ -66,7 +66,7 @@ // If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true. $with_libs = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => '', + 'Linux', 'Darwin' => 'libwebp', 'Windows' => '', }; From 1707c679e8b8cd3f5face5073b81d43bbff8db08 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 18 Dec 2025 15:32:50 +0800 Subject: [PATCH 26/73] Sort --- config/artifact.json | 276 +++++----- config/pkg.ext.json | 1154 ++++++++++++++++++++-------------------- config/pkg.lib.json | 644 +++++++++++----------- config/pkg.target.json | 124 ++--- 4 files changed, 1099 insertions(+), 1099 deletions(-) diff --git a/config/artifact.json b/config/artifact.json index c8fd66215..ad8507b90 100644 --- a/config/artifact.json +++ b/config/artifact.json @@ -1,135 +1,4 @@ { - "vswhere": { - "binary": { - "windows-x86_64": { - "type": "url", - "url": "https://github.com/microsoft/vswhere/releases/download/3.1.7/vswhere.exe", - "extract": "{pkg_root_path}/bin/vswhere.exe" - } - } - }, - "musl-wrapper": { - "source": "https://musl.libc.org/releases/musl-1.2.5.tar.gz" - }, - "php-src": { - "source": { - "type": "php-release" - } - }, - "php-sdk-binary-tools": { - "binary": { - "windows-x86_64": { - "type": "git", - "rev": "master", - "url": "https://github.com/php/php-sdk-binary-tools.git", - "extract": "{php_sdk_path}" - } - } - }, - "go-xcaddy": { - "binary": "custom" - }, - "musl-toolchain": { - "binary": { - "linux-x86_64": { - "type": "url", - "url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz", - "extract": "{pkg_root_path}/musl-toolchain" - }, - "linux-aarch64": { - "type": "url", - "url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz", - "extract": "{pkg_root_path}/musl-toolchain" - } - } - }, - "pkg-config": { - "source": "https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz", - "binary": { - "linux-x86_64": { - "type": "ghrel", - "repo": "static-php/static-php-cli-hosted", - "match": "pkg-config-aarch64-linux-musl-1.2.5.txz", - "extract": { - "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" - } - }, - "linux-aarch64": { - "type": "ghrel", - "repo": "static-php/static-php-cli-hosted", - "match": "pkg-config-x86_64-linux-musl-1.2.5.txz", - "extract": { - "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" - } - }, - "macos-x86_64": { - "type": "ghrel", - "repo": "static-php/static-php-cli-hosted", - "match": "pkg-config-x86_64-darwin.txz", - "extract": { - "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" - } - }, - "macos-aarch64": { - "type": "ghrel", - "repo": "static-php/static-php-cli-hosted", - "match": "pkg-config-aarch64-darwin.txz", - "extract": "{pkg_root_path}" - } - } - }, - "strawberry-perl": { - "binary": { - "windows-x86_64": { - "type": "url", - "url": "https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip", - "extract": "{pkg_root_path}/strawberry-perl" - } - } - }, - "upx": { - "binary": { - "linux-x86_64": { - "type": "ghrel", - "repo": "upx/upx", - "match": "upx.+-amd64_linux\\.tar\\.xz", - "extract": { - "upx": "{pkg_root_path}/bin/upx" - } - }, - "linux-aarch64": { - "type": "ghrel", - "repo": "upx/upx", - "match": "upx.+-arm64_linux\\.tar\\.xz", - "extract": { - "upx": "{pkg_root_path}/bin/upx" - } - }, - "windows-x86_64": { - "type": "ghrel", - "repo": "upx/upx", - "match": "upx.+-win64\\.zip", - "extract": { - "upx.exe": "{pkg_root_path}/bin/upx.exe" - } - } - } - }, - "zig": { - "binary": "custom" - }, - "nasm": { - "binary": { - "windows-x86_64": { - "type": "url", - "url": "https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip", - "extract": { - "nasm.exe": "{php_sdk_path}/bin/nasm.exe", - "ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe" - } - } - } - }, "amqp": { "source": { "type": "url", @@ -395,6 +264,9 @@ "repo": "guanzhi/GmSSL" } }, + "go-xcaddy": { + "binary": "custom" + }, "grpc": { "binary": "hosted", "source": { @@ -733,13 +605,6 @@ "extract": "php-src/ext/memcached" } }, - "mimalloc": { - "source": { - "type": "ghtagtar", - "repo": "microsoft/mimalloc", - "match": "v2\\.\\d\\.[^3].*" - } - }, "micro": { "source": { "type": "git", @@ -748,6 +613,13 @@ "url": "https://github.com/static-php/phpmicro" } }, + "mimalloc": { + "source": { + "type": "ghtagtar", + "repo": "microsoft/mimalloc", + "match": "v2\\.\\d\\.[^3].*" + } + }, "mongodb": { "source": { "type": "ghrel", @@ -765,6 +637,35 @@ "extract": "php-src/ext/msgpack" } }, + "musl-toolchain": { + "binary": { + "linux-x86_64": { + "type": "url", + "url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz", + "extract": "{pkg_root_path}/musl-toolchain" + }, + "linux-aarch64": { + "type": "url", + "url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz", + "extract": "{pkg_root_path}/musl-toolchain" + } + } + }, + "musl-wrapper": { + "source": "https://musl.libc.org/releases/musl-1.2.5.tar.gz" + }, + "nasm": { + "binary": { + "windows-x86_64": { + "type": "url", + "url": "https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip", + "extract": { + "nasm.exe": "{php_sdk_path}/bin/nasm.exe", + "ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe" + } + } + } + }, "ncurses": { "binary": "hosted", "source": { @@ -850,6 +751,56 @@ "extract": "php-src/ext/pdo_sqlsrv" } }, + "php-sdk-binary-tools": { + "binary": { + "windows-x86_64": { + "type": "git", + "rev": "master", + "url": "https://github.com/php/php-sdk-binary-tools.git", + "extract": "{php_sdk_path}" + } + } + }, + "php-src": { + "source": { + "type": "php-release" + } + }, + "pkg-config": { + "binary": { + "linux-x86_64": { + "type": "ghrel", + "repo": "static-php/static-php-cli-hosted", + "match": "pkg-config-aarch64-linux-musl-1.2.5.txz", + "extract": { + "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" + } + }, + "linux-aarch64": { + "type": "ghrel", + "repo": "static-php/static-php-cli-hosted", + "match": "pkg-config-x86_64-linux-musl-1.2.5.txz", + "extract": { + "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" + } + }, + "macos-x86_64": { + "type": "ghrel", + "repo": "static-php/static-php-cli-hosted", + "match": "pkg-config-x86_64-darwin.txz", + "extract": { + "bin/pkg-config": "{pkg_root_path}/bin/pkg-config" + } + }, + "macos-aarch64": { + "type": "ghrel", + "repo": "static-php/static-php-cli-hosted", + "match": "pkg-config-aarch64-darwin.txz", + "extract": "{pkg_root_path}" + } + }, + "source": "https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz" + }, "postgresql": { "source": { "type": "ghtagtar", @@ -950,6 +901,15 @@ "extract": "php-src/ext/sqlsrv" } }, + "strawberry-perl": { + "binary": { + "windows-x86_64": { + "type": "url", + "url": "https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip", + "extract": "{pkg_root_path}/strawberry-perl" + } + } + }, "swoole": { "source": { "type": "ghtar", @@ -982,6 +942,43 @@ "version": "2.3.12" } }, + "upx": { + "binary": { + "linux-x86_64": { + "type": "ghrel", + "repo": "upx/upx", + "match": "upx.+-amd64_linux\\.tar\\.xz", + "extract": { + "upx": "{pkg_root_path}/bin/upx" + } + }, + "linux-aarch64": { + "type": "ghrel", + "repo": "upx/upx", + "match": "upx.+-arm64_linux\\.tar\\.xz", + "extract": { + "upx": "{pkg_root_path}/bin/upx" + } + }, + "windows-x86_64": { + "type": "ghrel", + "repo": "upx/upx", + "match": "upx.+-win64\\.zip", + "extract": { + "upx.exe": "{pkg_root_path}/bin/upx.exe" + } + } + } + }, + "vswhere": { + "binary": { + "windows-x86_64": { + "type": "url", + "url": "https://github.com/microsoft/vswhere/releases/download/3.1.7/vswhere.exe", + "extract": "{pkg_root_path}/bin/vswhere.exe" + } + } + }, "watcher": { "source": { "type": "ghtar", @@ -1041,6 +1038,9 @@ "extract": "php-src/ext/yaml" } }, + "zig": { + "binary": "custom" + }, "zlib": { "binary": "hosted", "source": { diff --git a/config/pkg.ext.json b/config/pkg.ext.json index 70fe34e63..b1e819eb3 100644 --- a/config/pkg.ext.json +++ b/config/pkg.ext.json @@ -1,66 +1,66 @@ { "ext-amqp": { - "type": "php-extension", - "php-extension": { - "support": { - "BSD": "wip" - }, - "arg-type": "custom" - }, + "artifact": "amqp", "depends": [ "librabbitmq" ], "depends@windows": [ "ext-openssl" ], - "artifact": "amqp", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "support": { + "BSD": "wip" + }, + "arg-type": "custom" + }, + "type": "php-extension" }, "ext-apcu": { - "type": "php-extension", "artifact": "apcu", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "php-extension" }, "ext-ast": { - "type": "php-extension", "artifact": "ast", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "php-extension" }, "ext-bcmath": { "type": "php-extension" }, "ext-brotli": { - "type": "php-extension", - "php-extension": { - "arg-type": "enable" - }, + "artifact": "ext-brotli", "depends": [ "brotli" ], - "artifact": "ext-brotli", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "arg-type": "enable" + }, + "type": "php-extension" }, "ext-bz2": { - "type": "php-extension", + "depends": [ + "bzip2" + ], "php-extension": { "arg-type@windows": "with", "arg-type": "with-path" }, - "depends": [ - "bzip2" - ] + "type": "php-extension" }, "ext-calendar": { "type": "php-extension" @@ -69,68 +69,67 @@ "type": "php-extension" }, "ext-curl": { - "type": "php-extension", - "php-extension": { - "arg-type": "with", - "notes": true - }, "depends": [ "curl" ], "depends@windows": [ "ext-zlib", "ext-openssl" - ] + ], + "php-extension": { + "arg-type": "with", + "notes": true + }, + "type": "php-extension" }, "ext-dba": { - "type": "php-extension", "php-extension": { "arg-type": "custom" }, "suggests": [ "qdbm" - ] + ], + "type": "php-extension" }, "ext-dio": { - "type": "php-extension", - "php-extension": { - "support": { - "BSD": "wip" - } - }, "artifact": "dio", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-dom": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" - }, - "arg-type": "custom", - "arg-type@windows": "with" + } }, + "type": "php-extension" + }, + "ext-dom": { "depends": [ "libxml2", "zlib" ], "depends@windows": [ "ext-xml" - ] + ], + "php-extension": { + "support": { + "BSD": "wip" + }, + "arg-type": "custom", + "arg-type@windows": "with" + }, + "type": "php-extension" }, "ext-ds": { - "type": "php-extension", "artifact": "ext-ds", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "php-extension" }, "ext-enchant": { - "type": "php-extension", "php-extension": { "support": { "Windows": "wip", @@ -138,24 +137,33 @@ "Darwin": "wip", "Linux": "wip" } - } + }, + "type": "php-extension" }, "ext-ev": { - "type": "php-extension", - "php-extension": { - "arg-type@windows": "with" - }, + "artifact": "ev", "depends": [ "ext-sockets" ], - "artifact": "ev", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "arg-type@windows": "with" + }, + "type": "php-extension" }, "ext-event": { - "type": "php-extension", + "artifact": "ext-event", + "depends": [ + "libevent", + "ext-openssl" + ], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -164,24 +172,21 @@ "arg-type": "custom", "notes": true }, - "depends": [ - "libevent", - "ext-openssl" - ], "suggests": [ "ext-sockets" ], - "artifact": "ext-event", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-exif": { "type": "php-extension" }, "ext-ffi": { - "type": "php-extension", + "depends": [ + "libffi" + ], + "depends@windows": [ + "libffi-win" + ], "php-extension": { "support": { "Linux": "partial", @@ -190,12 +195,7 @@ "arg-type": "custom", "notes": true }, - "depends@windows": [ - "libffi-win" - ], - "depends": [ - "libffi" - ] + "type": "php-extension" }, "ext-fileinfo": { "type": "php-extension" @@ -204,13 +204,17 @@ "type": "php-extension" }, "ext-ftp": { - "type": "php-extension", "suggests": [ "openssl" - ] + ], + "type": "php-extension" }, "ext-gd": { - "type": "php-extension", + "depends": [ + "zlib", + "libpng", + "ext-zlib" + ], "php-extension": { "support": { "BSD": "wip" @@ -219,20 +223,18 @@ "arg-type@windows": "with", "notes": true }, - "depends": [ - "zlib", - "libpng", - "ext-zlib" - ], "suggests": [ "libavif", "libwebp", "libjpeg", "freetype" - ] + ], + "type": "php-extension" }, "ext-gettext": { - "type": "php-extension", + "depends": [ + "gettext" + ], "php-extension": { "support": { "Windows": "wip", @@ -240,12 +242,18 @@ }, "arg-type": "with-path" }, - "depends": [ - "gettext" - ] + "type": "php-extension" }, "ext-glfw": { - "type": "php-extension", + "artifact": "ext-glfw", + "depends": [ + "glfw" + ], + "depends@windows": [], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -255,18 +263,12 @@ "arg-type": "custom", "notes": true }, - "depends": [ - "glfw" - ], - "depends@windows": [], - "artifact": "ext-glfw", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-gmp": { - "type": "php-extension", + "depends": [ + "gmp" + ], "php-extension": { "support": { "Windows": "wip", @@ -274,47 +276,50 @@ }, "arg-type": "with-path" }, - "depends": [ - "gmp" - ] + "type": "php-extension" }, "ext-gmssl": { - "type": "php-extension", - "php-extension": { - "support": { - "BSD": "wip" - } - }, + "artifact": "ext-gmssl", "depends": [ "gmssl" ], - "artifact": "ext-gmssl", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-grpc": { - "type": "php-extension", + }, "php-extension": { "support": { - "Windows": "wip", "BSD": "wip" - }, - "arg-type": "enable-path" + } }, + "type": "php-extension" + }, + "ext-grpc": { + "artifact": "grpc", "depends": [ "grpc" ], "lang": "cpp", - "artifact": "grpc", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "support": { + "Windows": "wip", + "BSD": "wip" + }, + "arg-type": "enable-path" + }, + "type": "php-extension" }, "ext-iconv": { - "type": "php-extension", + "depends": [ + "libiconv" + ], + "depends@windows": [ + "libiconv-win" + ], "php-extension": { "support": { "BSD": "wip" @@ -322,15 +327,14 @@ "arg-type": "with-path", "arg-type@windows": "with" }, - "depends@windows": [ - "libiconv-win" - ], - "depends": [ - "libiconv" - ] + "type": "php-extension" }, "ext-igbinary": { - "type": "php-extension", + "artifact": "igbinary", + "license": { + "type": "file", + "path": "COPYING" + }, "php-extension": { "support": { "BSD": "wip" @@ -340,14 +344,17 @@ "ext-session", "ext-apcu" ], - "artifact": "igbinary", - "license": { - "type": "file", - "path": "COPYING" - } + "type": "php-extension" }, "ext-imagick": { - "type": "php-extension", + "artifact": "ext-imagick", + "depends": [ + "imagemagick" + ], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -356,17 +363,19 @@ "arg-type": "custom", "notes": true }, + "type": "php-extension" + }, + "ext-imap": { + "artifact": "ext-imap", "depends": [ - "imagemagick" + "imap" ], - "artifact": "ext-imagick", "license": { "type": "file", - "path": "LICENSE" - } - }, - "ext-imap": { - "type": "php-extension", + "path": [ + "LICENSE" + ] + }, "php-extension": { "support": { "Windows": "wip", @@ -375,22 +384,17 @@ "arg-type": "custom", "notes": true }, - "depends": [ - "imap" - ], "suggests": [ "ext-openssl" ], - "artifact": "ext-imap", - "license": { - "type": "file", - "path": [ - "LICENSE" - ] - } + "type": "php-extension" }, "ext-inotify": { - "type": "php-extension", + "artifact": "inotify", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "no", @@ -398,28 +402,26 @@ "Darwin": "no" } }, - "artifact": "inotify", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-intl": { - "type": "php-extension", - "php-extension": { - "support": { - "BSD": "wip" - } - }, + "depends": [ + "icu" + ], "depends@windows": [ "icu-static-win" ], - "depends": [ - "icu" - ] + "php-extension": { + "support": { + "BSD": "wip" + } + }, + "type": "php-extension" }, "ext-ldap": { - "type": "php-extension", + "depends": [ + "ldap" + ], "php-extension": { "support": { "Windows": "wip", @@ -427,17 +429,17 @@ }, "arg-type": "with-path" }, - "depends": [ - "ldap" - ], "suggests": [ "gmp", "libsodium", "ext-openssl" - ] + ], + "type": "php-extension" }, "ext-libxml": { - "type": "php-extension", + "depends": [ + "ext-xml" + ], "php-extension": { "support": { "BSD": "wip" @@ -447,50 +449,47 @@ "build-static": true, "build-with-php": true }, - "depends": [ - "ext-xml" - ] + "type": "php-extension" }, "ext-lz4": { - "type": "php-extension", - "php-extension": { - "support": { - "Windows": "wip", - "BSD": "wip" - }, - "arg-type": "custom" - }, + "artifact": "ext-lz4", "depends": [ "liblz4" ], - "artifact": "ext-lz4", "license": { "type": "file", "path": [ "LICENSE" ] - } + }, + "php-extension": { + "support": { + "Windows": "wip", + "BSD": "wip" + }, + "arg-type": "custom" + }, + "type": "php-extension" }, "ext-mbregex": { - "type": "php-extension", + "depends": [ + "onig", + "ext-mbstring" + ], "php-extension": { "arg-type": "custom", "build-shared": false, "build-static": true }, - "depends": [ - "onig", - "ext-mbstring" - ] + "type": "php-extension" }, "ext-mbstring": { - "type": "php-extension", "php-extension": { "arg-type": "custom" - } + }, + "type": "php-extension" }, "ext-mcrypt": { - "type": "php-extension", "php-extension": { "support": { "Windows": "no", @@ -499,10 +498,19 @@ "Linux": "no" }, "notes": true - } + }, + "type": "php-extension" }, "ext-memcache": { - "type": "php-extension", + "artifact": "ext-memcache", + "depends": [ + "ext-zlib", + "ext-session" + ], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -511,18 +519,21 @@ "arg-type": "custom", "build-with-php": true }, + "type": "php-extension" + }, + "ext-memcached": { + "artifact": "memcached", "depends": [ - "ext-zlib", - "ext-session" + "libmemcached", + "fastlz", + "ext-session", + "ext-zlib" ], - "artifact": "ext-memcache", + "lang": "cpp", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-memcached": { - "type": "php-extension", + }, "php-extension": { "support": { "Windows": "wip", @@ -530,27 +541,24 @@ }, "arg-type": "custom" }, - "depends": [ - "libmemcached", - "fastlz", - "ext-session", - "ext-zlib" - ], "suggests": [ "zstd", "ext-igbinary", "ext-msgpack", "ext-session" ], - "lang": "cpp", - "artifact": "memcached", + "type": "php-extension" + }, + "ext-mongodb": { + "artifact": "mongodb", + "frameworks": [ + "CoreFoundation", + "Security" + ], "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-mongodb": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip", @@ -564,18 +572,17 @@ "zstd", "zlib" ], - "frameworks": [ - "CoreFoundation", - "Security" + "type": "php-extension" + }, + "ext-msgpack": { + "artifact": "msgpack", + "depends": [ + "ext-session" ], - "artifact": "mongodb", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-msgpack": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" @@ -583,37 +590,29 @@ "arg-type@windows": "enable", "arg-type": "with" }, - "depends": [ - "ext-session" - ], - "artifact": "msgpack", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-mysqli": { - "type": "php-extension", + "depends": [ + "ext-mysqlnd" + ], "php-extension": { "arg-type": "with", "build-with-php": true }, - "depends": [ - "ext-mysqlnd" - ] + "type": "php-extension" }, "ext-mysqlnd": { - "type": "php-extension", + "depends": [ + "zlib" + ], "php-extension": { "arg-type@windows": "with", "build-with-php": true }, - "depends": [ - "zlib" - ] + "type": "php-extension" }, "ext-oci8": { - "type": "php-extension", "php-extension": { "support": { "Windows": "wip", @@ -622,10 +621,13 @@ "Linux": "no" }, "notes": true - } + }, + "type": "php-extension" }, "ext-odbc": { - "type": "php-extension", + "depends": [ + "unixodbc" + ], "php-extension": { "support": { "BSD": "wip", @@ -633,47 +635,52 @@ }, "arg-type": "custom" }, - "depends": [ - "unixodbc" - ] + "type": "php-extension" }, "ext-opcache": { - "type": "php-extension", "php-extension": { "arg-type@windows": "enable", "arg-type": "custom", "zend-extension": true - } + }, + "type": "php-extension" }, "ext-openssl": { - "type": "php-extension", + "depends": [ + "openssl", + "zlib", + "ext-zlib" + ], "php-extension": { "arg-type": "custom", "arg-type@windows": "with", "build-with-php": true, "notes": true }, - "depends": [ - "openssl", - "zlib", - "ext-zlib" - ] + "type": "php-extension" }, "ext-opentelemetry": { - "type": "php-extension", + "artifact": "opentelemetry", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "BSD": "wip" } }, - "artifact": "opentelemetry", + "type": "php-extension" + }, + "ext-parallel": { + "artifact": "parallel", + "depends@windows": [ + "pthreads4w" + ], "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-parallel": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" @@ -681,17 +688,13 @@ "arg-type@windows": "with", "notes": true }, - "depends@windows": [ - "pthreads4w" - ], - "artifact": "parallel", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-password-argon2": { - "type": "php-extension", + "depends": [ + "libargon2", + "openssl" + ], "php-extension": { "support": { "Windows": "wip", @@ -700,98 +703,100 @@ "arg-type": "custom", "notes": true }, - "depends": [ - "libargon2", - "openssl" - ] + "type": "php-extension" }, "ext-pcntl": { - "type": "php-extension", "php-extension": { "support": { "Windows": "no" } - } + }, + "type": "php-extension" }, "ext-pdo": { "type": "php-extension" }, "ext-pdo_mysql": { - "type": "php-extension", - "php-extension": { - "arg-type": "with" - }, "depends": [ "ext-pdo", "ext-mysqlnd" - ] - }, - "ext-pdo_odbc": { - "type": "php-extension", + ], "php-extension": { - "support": { - "BSD": "wip" - }, - "arg-type": "custom" + "arg-type": "with" }, + "type": "php-extension" + }, + "ext-pdo_odbc": { "depends": [ "unixodbc", "ext-pdo", "ext-odbc" - ] - }, - "ext-pdo_pgsql": { - "type": "php-extension", + ], "php-extension": { "support": { "BSD": "wip" }, - "arg-type": "with-path", - "arg-type@windows": "custom" + "arg-type": "custom" }, - "depends@windows": [ - "postgresql-win" - ], + "type": "php-extension" + }, + "ext-pdo_pgsql": { "depends": [ "postgresql", "ext-pdo", "ext-pgsql" - ] - }, - "ext-pdo_sqlite": { - "type": "php-extension", + ], + "depends@windows": [ + "postgresql-win" + ], "php-extension": { "support": { "BSD": "wip" }, - "arg-type": "with" + "arg-type": "with-path", + "arg-type@windows": "custom" }, + "type": "php-extension" + }, + "ext-pdo_sqlite": { "depends": [ "sqlite", "ext-pdo", "ext-sqlite3" - ] - }, - "ext-pdo_sqlsrv": { - "type": "php-extension", + ], "php-extension": { "support": { "BSD": "wip" }, "arg-type": "with" }, + "type": "php-extension" + }, + "ext-pdo_sqlsrv": { + "artifact": "pdo_sqlsrv", "depends": [ "ext-pdo", "ext-sqlsrv" ], - "artifact": "pdo_sqlsrv", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "support": { + "BSD": "wip" + }, + "arg-type": "with" + }, + "type": "php-extension" }, "ext-pgsql": { - "type": "php-extension", + "depends": [ + "postgresql" + ], + "depends@windows": [ + "postgresql-win" + ], "php-extension": { "support": { "BSD": "wip" @@ -799,43 +804,43 @@ "arg-type": "custom", "notes": true }, - "depends@windows": [ - "postgresql-win" - ], - "depends": [ - "postgresql" - ] + "type": "php-extension" }, "ext-phar": { - "type": "php-extension", "depends": [ "ext-zlib" - ] + ], + "type": "php-extension" }, "ext-posix": { - "type": "php-extension", "php-extension": { "support": { "Windows": "no" } - } + }, + "type": "php-extension" }, "ext-protobuf": { - "type": "php-extension", + "artifact": "protobuf", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", "BSD": "wip" } }, - "artifact": "protobuf", + "type": "php-extension" + }, + "ext-rar": { + "artifact": "rar", + "lang": "cpp", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-rar": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip", @@ -843,15 +848,18 @@ }, "notes": true }, + "type": "php-extension" + }, + "ext-rdkafka": { + "artifact": "ext-rdkafka", + "depends": [ + "librdkafka" + ], "lang": "cpp", - "artifact": "rar", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-rdkafka": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip", @@ -859,18 +867,12 @@ }, "arg-type": "custom" }, - "depends": [ - "librdkafka" - ], - "lang": "cpp", - "artifact": "ext-rdkafka", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-readline": { - "type": "php-extension", + "depends": [ + "libedit" + ], "php-extension": { "support": { "Windows": "wip", @@ -880,12 +882,17 @@ "build-shared": false, "build-static": true }, - "depends": [ - "libedit" - ] + "type": "php-extension" }, "ext-redis": { - "type": "php-extension", + "artifact": "redis", + "license": { + "type": "file", + "path": [ + "LICENSE", + "COPYING" + ] + }, "php-extension": { "support": { "BSD": "wip" @@ -899,38 +906,36 @@ "ext-igbinary", "ext-msgpack" ], - "artifact": "redis", - "license": { - "type": "file", - "path": [ - "LICENSE", - "COPYING" - ] - } + "type": "php-extension" }, "ext-session": { - "type": "php-extension", "php-extension": { "build-with-php": true - } + }, + "type": "php-extension" }, "ext-shmop": { - "type": "php-extension", "php-extension": { "build-with-php": true - } + }, + "type": "php-extension" }, "ext-simdjson": { - "type": "php-extension", - "lang": "cpp", "artifact": "ext-simdjson", + "lang": "cpp", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "php-extension" }, "ext-simplexml": { - "type": "php-extension", + "depends": [ + "libxml2" + ], + "depends@windows": [ + "ext-xml" + ], "php-extension": { "support": { "BSD": "wip" @@ -938,15 +943,18 @@ "arg-type": "custom", "build-with-php": true }, - "depends": [ - "libxml2" - ], - "depends@windows": [ - "ext-xml" - ] + "type": "php-extension" }, "ext-snappy": { - "type": "php-extension", + "artifact": "ext-snappy", + "depends": [ + "snappy" + ], + "lang": "cpp", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -954,21 +962,15 @@ }, "arg-type": "custom" }, - "depends": [ - "snappy" - ], "suggests": [ "ext-apcu" ], - "lang": "cpp", - "artifact": "ext-snappy", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-snmp": { - "type": "php-extension", + "depends": [ + "net-snmp" + ], "php-extension": { "support": { "Windows": "wip", @@ -977,40 +979,45 @@ "arg-type@windows": "with", "arg-type": "with" }, - "depends": [ - "net-snmp" - ] + "type": "php-extension" }, "ext-soap": { - "type": "php-extension", + "depends": [ + "ext-libxml", + "ext-session" + ], "php-extension": { "support": { "BSD": "wip" }, "arg-type": "custom" }, - "depends": [ - "ext-libxml", - "ext-session" - ] + "type": "php-extension" }, "ext-sockets": { "type": "php-extension" }, "ext-sodium": { - "type": "php-extension", + "depends": [ + "libsodium" + ], "php-extension": { "support": { "BSD": "wip" }, "arg-type": "with" }, - "depends": [ - "libsodium" - ] + "type": "php-extension" }, "ext-spx": { - "type": "php-extension", + "artifact": "spx", + "depends": [ + "zlib" + ], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "BSD": "wip", @@ -1019,17 +1026,12 @@ "arg-type": "custom", "notes": true }, - "depends": [ - "zlib" - ], - "artifact": "spx", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-sqlite3": { - "type": "php-extension", + "depends": [ + "sqlite" + ], "php-extension": { "support": { "BSD": "wip" @@ -1038,17 +1040,10 @@ "arg-type@windows": "with", "build-with-php": true }, - "depends": [ - "sqlite" - ] + "type": "php-extension" }, "ext-sqlsrv": { - "type": "php-extension", - "php-extension": { - "support": { - "BSD": "wip" - } - }, + "artifact": "sqlsrv", "depends": [ "unixodbc" ], @@ -1056,42 +1051,39 @@ "ext-pcntl" ], "lang": "cpp", - "artifact": "sqlsrv", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-ssh2": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" - }, - "arg-type": "with-path", - "arg-type@windows": "with" + } }, + "type": "php-extension" + }, + "ext-ssh2": { + "artifact": "ext-ssh2", "depends": [ "libssh2", "ext-openssl", "ext-zlib" ], - "artifact": "ext-ssh2", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-swoole": { - "type": "php-extension", + }, "php-extension": { "support": { - "Windows": "no", "BSD": "wip" }, - "arg-type": "custom", - "notes": true + "arg-type": "with-path", + "arg-type@windows": "with" }, + "type": "php-extension" + }, + "ext-swoole": { + "artifact": "swoole", "depends": [ "libcares", "brotli", @@ -1100,6 +1092,19 @@ "ext-openssl", "ext-curl" ], + "lang": "cpp", + "license": { + "type": "file", + "path": "LICENSE" + }, + "php-extension": { + "support": { + "Windows": "no", + "BSD": "wip" + }, + "arg-type": "custom", + "notes": true + }, "suggests": [ "zstd", "ext-sockets", @@ -1109,18 +1114,18 @@ "ext-swoole-hook-odbc" ], "suggests@linux": [ - "zstd", - "liburing" - ], - "lang": "cpp", - "artifact": "swoole", - "license": { - "type": "file", - "path": "LICENSE" - } + "zstd", + "liburing" + ], + "type": "php-extension" }, "ext-swoole-hook-mysql": { - "type": "php-extension", + "depends": [ + "ext-mysqlnd", + "ext-pdo", + "ext-pdo_mysql", + "ext-swoole" + ], "php-extension": { "support": { "Windows": "no", @@ -1129,18 +1134,17 @@ "arg-type": "none", "notes": true }, - "depends": [ - "ext-mysqlnd", - "ext-pdo", - "ext-pdo_mysql", - "ext-swoole" - ], "suggests": [ "ext-mysqli" - ] + ], + "type": "php-extension" }, "ext-swoole-hook-odbc": { - "type": "php-extension", + "depends": [ + "unixodbc", + "ext-pdo", + "ext-swoole" + ], "php-extension": { "support": { "Windows": "no", @@ -1149,14 +1153,14 @@ "arg-type": "none", "notes": true }, + "type": "php-extension" + }, + "ext-swoole-hook-pgsql": { "depends": [ - "unixodbc", + "ext-pgsql", "ext-pdo", "ext-swoole" - ] - }, - "ext-swoole-hook-pgsql": { - "type": "php-extension", + ], "php-extension": { "support": { "Windows": "no", @@ -1166,14 +1170,14 @@ "arg-type": "none", "notes": true }, + "type": "php-extension" + }, + "ext-swoole-hook-sqlite": { "depends": [ - "ext-pgsql", + "ext-sqlite3", "ext-pdo", "ext-swoole" - ] - }, - "ext-swoole-hook-sqlite": { - "type": "php-extension", + ], "php-extension": { "support": { "Windows": "no", @@ -1182,14 +1186,14 @@ "arg-type": "none", "notes": true }, - "depends": [ - "ext-sqlite3", - "ext-pdo", - "ext-swoole" - ] + "type": "php-extension" }, "ext-swow": { - "type": "php-extension", + "artifact": "swow", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "BSD": "wip" @@ -1203,40 +1207,38 @@ "ext-openssl", "ext-curl" ], - "artifact": "swow", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-sysvmsg": { - "type": "php-extension", "php-extension": { "support": { "Windows": "no", "BSD": "wip" } - } + }, + "type": "php-extension" }, "ext-sysvsem": { - "type": "php-extension", "php-extension": { "support": { "Windows": "no", "BSD": "wip" } - } + }, + "type": "php-extension" }, "ext-sysvshm": { - "type": "php-extension", "php-extension": { "support": { "BSD": "wip" } - } + }, + "type": "php-extension" }, "ext-tidy": { - "type": "php-extension", + "depends": [ + "tidy" + ], "php-extension": { "support": { "Windows": "wip", @@ -1244,32 +1246,37 @@ }, "arg-type": "with-path" }, - "depends": [ - "tidy" - ] + "type": "php-extension" }, "ext-tokenizer": { - "type": "php-extension", "php-extension": { "build-with-php": true - } + }, + "type": "php-extension" }, "ext-trader": { - "type": "php-extension", + "artifact": "ext-trader", + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "BSD": "wip", "Windows": "wip" } }, - "artifact": "ext-trader", + "type": "php-extension" + }, + "ext-uuid": { + "artifact": "ext-uuid", + "depends": [ + "libuuid" + ], "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-uuid": { - "type": "php-extension", + }, "php-extension": { "support": { "Windows": "wip", @@ -1277,17 +1284,18 @@ }, "arg-type": "with-path" }, + "type": "php-extension" + }, + "ext-uv": { + "artifact": "ext-uv", "depends": [ - "libuuid" + "libuv", + "ext-sockets" ], - "artifact": "ext-uuid", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-uv": { - "type": "php-extension", + }, "php-extension": { "support": { "Windows": "wip", @@ -1295,18 +1303,14 @@ }, "arg-type": "with-path" }, - "depends": [ - "libuv", - "ext-sockets" - ], - "artifact": "ext-uv", + "type": "php-extension" + }, + "ext-xdebug": { + "artifact": "xdebug", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-xdebug": { - "type": "php-extension", + }, "php-extension": { "support": { "Windows": "wip", @@ -1319,14 +1323,17 @@ "notes": true, "zend-extension": true }, - "artifact": "xdebug", + "type": "php-extension" + }, + "ext-xhprof": { + "artifact": "xhprof", + "depends": [ + "ext-ctype" + ], "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-xhprof": { - "type": "php-extension", + }, "php-extension": { "support": { "Windows": "wip", @@ -1335,17 +1342,18 @@ "build-with-php": true, "notes": true }, + "type": "php-extension" + }, + "ext-xlswriter": { + "artifact": "xlswriter", "depends": [ - "ext-ctype" + "ext-zlib", + "ext-zip" ], - "artifact": "xhprof", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-xlswriter": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" @@ -1355,18 +1363,15 @@ "suggests": [ "openssl" ], - "depends": [ - "ext-zlib", - "ext-zip" - ], - "artifact": "xlswriter", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" }, "ext-xml": { - "type": "php-extension", + "depends": [ + "libxml2" + ], + "depends@windows": [ + "ext-iconv" + ], "php-extension": { "support": { "BSD": "wip" @@ -1376,15 +1381,16 @@ "build-with-php": true, "notes": true }, + "type": "php-extension" + }, + "ext-xmlreader": { "depends": [ "libxml2" ], "depends@windows": [ - "ext-iconv" - ] - }, - "ext-xmlreader": { - "type": "php-extension", + "ext-xml", + "ext-dom" + ], "php-extension": { "support": { "BSD": "wip" @@ -1392,16 +1398,15 @@ "arg-type": "custom", "build-with-php": true }, + "type": "php-extension" + }, + "ext-xmlwriter": { "depends": [ "libxml2" ], "depends@windows": [ - "ext-xml", - "ext-dom" - ] - }, - "ext-xmlwriter": { - "type": "php-extension", + "ext-xml" + ], "php-extension": { "support": { "BSD": "wip" @@ -1409,15 +1414,14 @@ "arg-type": "custom", "build-with-php": true }, - "depends": [ - "libxml2" - ], - "depends@windows": [ - "ext-xml" - ] + "type": "php-extension" }, "ext-xsl": { - "type": "php-extension", + "depends": [ + "libxslt", + "ext-xml", + "ext-dom" + ], "php-extension": { "support": { "Windows": "wip", @@ -1425,71 +1429,63 @@ }, "arg-type": "with-path" }, - "depends": [ - "libxslt", - "ext-xml", - "ext-dom" - ] + "type": "php-extension" }, "ext-xz": { - "type": "php-extension", - "php-extension": { - "arg-type": "with" - }, + "artifact": "ext-xz", "depends": [ "xz" ], - "artifact": "ext-xz", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-yac": { - "type": "php-extension", + }, "php-extension": { - "support": { - "BSD": "wip" - }, - "arg-type": "custom" + "arg-type": "with" }, + "type": "php-extension" + }, + "ext-yac": { + "artifact": "yac", "depends": [ "fastlz", "ext-igbinary" ], - "artifact": "yac", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-yaml": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" }, - "arg-type@windows": "with", - "arg-type": "with-path" + "arg-type": "custom" }, + "type": "php-extension" + }, + "ext-yaml": { + "artifact": "yaml", "depends": [ "libyaml" ], - "artifact": "yaml", "license": { "type": "file", "path": "LICENSE" - } - }, - "ext-zip": { - "type": "php-extension", + }, "php-extension": { "support": { "BSD": "wip" }, - "arg-type": "custom", - "arg-type@windows": "enable" + "arg-type@windows": "with", + "arg-type": "with-path" }, + "type": "php-extension" + }, + "ext-zip": { + "artifact": "ext-zip", + "depends": [ + "libzip" + ], "depends@windows": [ "libzip", "zlib", @@ -1498,17 +1494,23 @@ "ext-zlib", "ext-bz2" ], - "depends": [ - "libzip" - ], - "artifact": "ext-zip", "license": { "type": "file", "path": "LICENSE" - } + }, + "php-extension": { + "support": { + "BSD": "wip" + }, + "arg-type": "custom", + "arg-type@windows": "enable" + }, + "type": "php-extension" }, "ext-zlib": { - "type": "php-extension", + "depends": [ + "zlib" + ], "php-extension": { "arg-type": "custom", "arg-type@windows": "enable", @@ -1516,12 +1518,17 @@ "build-static": true, "build-with-php": true }, - "depends": [ - "zlib" - ] + "type": "php-extension" }, "ext-zstd": { - "type": "php-extension", + "artifact": "ext-zstd", + "depends": [ + "zstd" + ], + "license": { + "type": "file", + "path": "LICENSE" + }, "php-extension": { "support": { "Windows": "wip", @@ -1529,13 +1536,6 @@ }, "arg-type": "custom" }, - "depends": [ - "zstd" - ], - "artifact": "ext-zstd", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "php-extension" } } diff --git a/config/pkg.lib.json b/config/pkg.lib.json index 79e1a8534..6cade9b7f 100644 --- a/config/pkg.lib.json +++ b/config/pkg.lib.json @@ -1,54 +1,62 @@ { "attr": { - "type": "library", "artifact": "attr", "license": { "type": "file", "path": "doc/COPYING.LGPL" - } + }, + "type": "library" }, "brotli": { - "type": "library", + "artifact": "brotli", "headers": [ "brotli" ], + "license": { + "type": "file", + "path": "LICENSE" + }, "pkg-configs": [ "libbrotlicommon", "libbrotlidec", "libbrotlienc" ], - "artifact": "brotli", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "bzip2": { - "type": "library", + "artifact": "bzip2", "headers": [ "bzlib.h" ], - "artifact": "bzip2", "license": { "type": "text", "text": "This program, \"bzip2\", the associated library \"libbzip2\", and all documentation, are copyright (C) 1996-2010 Julian R Seward. All rights reserved. \n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nJulian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.6 of 6 September 2010\n\nPATENTS: To the best of my knowledge, bzip2 and libbzip2 do not use any patented algorithms. However, I do not have the resources to carry out a patent search. Therefore I cannot give any guarantee of the above statement." - } + }, + "type": "library" }, "curl": { - "type": "library", + "artifact": "curl", + "depends": [ + "openssl", + "zlib" + ], "depends@windows": [ "zlib", "libssh2", "nghttp2" ], - "depends": [ - "openssl", - "zlib" + "frameworks": [ + "CoreFoundation", + "CoreServices", + "SystemConfiguration" ], - "suggests@windows": [ - "brotli", - "zstd" + "headers": [ + "curl" ], + "license": { + "type": "file", + "path": "COPYING" + }, "suggests": [ "libssh2", "brotli", @@ -59,150 +67,142 @@ "libcares", "ldap" ], - "headers": [ - "curl" - ], - "frameworks": [ - "CoreFoundation", - "CoreServices", - "SystemConfiguration" + "suggests@windows": [ + "brotli", + "zstd" ], - "artifact": "curl", - "license": { - "type": "file", - "path": "COPYING" - } + "type": "library" }, "fastlz": { - "type": "library", + "artifact": "fastlz", "headers": [ "fastlz/fastlz.h" ], - "artifact": "fastlz", "license": { "type": "file", "path": "LICENSE.MIT" - } + }, + "type": "library" }, "freetype": { - "type": "library", + "artifact": "freetype", "depends": [ "zlib" ], - "suggests": [ - "libpng", - "bzip2", - "brotli" - ], "headers": [ "freetype2/freetype/freetype.h", "freetype2/ft2build.h" ], - "artifact": "freetype", "license": { "type": "file", "path": "LICENSE.TXT" - } + }, + "suggests": [ + "libpng", + "bzip2", + "brotli" + ], + "type": "library" }, "gettext": { - "type": "library", + "artifact": "gettext", "depends": [ "libiconv" ], - "suggests": [ - "ncurses", - "libxml2" - ], "frameworks": [ "CoreFoundation" ], - "artifact": "gettext", "license": { "type": "file", "path": "gettext-runtime/intl/COPYING.LIB" - } + }, + "suggests": [ + "ncurses", + "libxml2" + ], + "type": "library" }, "glfw": { - "type": "library", + "artifact": "ext-glfw", "frameworks": [ "CoreVideo", "OpenGL", "Cocoa", "IOKit" ], - "artifact": "ext-glfw", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "gmp": { - "type": "library", + "artifact": "gmp", "headers": [ "gmp.h" ], - "artifact": "gmp", "license": { "type": "text", "text": "Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs." - } + }, + "type": "library" }, "gmssl": { - "type": "library", + "artifact": "gmssl", "frameworks": [ "Security" ], - "artifact": "gmssl", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "grpc": { - "type": "library", + "artifact": "grpc", "depends": [ "zlib", "openssl", "libcares" ], - "pkg-configs": [ - "grpc" - ], "frameworks": [ "CoreFoundation" ], - "artifact": "grpc", "license": { "type": "file", "path": "LICENSE" - } + }, + "pkg-configs": [ + "grpc" + ], + "type": "library" }, "icu": { - "type": "library", + "artifact": "icu", + "license": { + "type": "file", + "path": "LICENSE" + }, "pkg-configs": [ "icu-uc", "icu-i18n", "icu-io" ], - "artifact": "icu", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "icu-static-win": { - "type": "library", + "artifact": "icu-static-win", "headers@windows": [ "unicode" ], - "artifact": "icu-static-win", "license": { "type": "text", "text": "none" - } + }, + "type": "library" }, "imagemagick": { - "type": "library", + "artifact": "imagemagick", "depends": [ "zlib", "libjpeg", @@ -214,183 +214,183 @@ "libheif", "bzip2" ], + "license": { + "type": "file", + "path": "LICENSE" + }, + "pkg-configs": [ + "Magick++-7.Q16HDRI", + "MagickCore-7.Q16HDRI", + "MagickWand-7.Q16HDRI" + ], "suggests": [ "zstd", "xz", "libzip", "libxml2" ], - "pkg-configs": [ - "Magick++-7.Q16HDRI", - "MagickCore-7.Q16HDRI", - "MagickWand-7.Q16HDRI" - ], - "artifact": "imagemagick", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "imap": { - "type": "library", - "suggests": [ - "openssl" - ], "artifact": "imap", "license": { "type": "file", "path": "LICENSE" - } + }, + "suggests": [ + "openssl" + ], + "type": "library" }, "jbig": { - "type": "library", + "artifact": "jbig", "headers": [ "jbig.h", "jbig85.h", "jbig_ar.h" ], - "artifact": "jbig", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "ldap": { - "type": "library", + "artifact": "ldap", "depends": [ "openssl", "zlib", "gmp", "libsodium" ], + "license": { + "type": "file", + "path": "LICENSE" + }, "pkg-configs": [ "ldap", "lber" ], - "artifact": "ldap", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "lerc": { - "type": "library", "artifact": "lerc", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libacl": { - "type": "library", + "artifact": "libacl", "depends": [ "attr" ], - "artifact": "libacl", "license": { "type": "file", "path": "doc/COPYING.LGPL" - } + }, + "type": "library" }, "libaom": { - "type": "library", "artifact": "libaom", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libargon2": { - "type": "library", "artifact": "libargon2", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libavif": { - "type": "library", "artifact": "libavif", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libcares": { - "type": "library", + "artifact": "libcares", "headers": [ "ares.h", "ares_dns.h", "ares_nameser.h" ], - "artifact": "libcares", "license": { "type": "file", "path": "LICENSE.md" - } + }, + "type": "library" }, "libde265": { - "type": "library", "artifact": "libde265", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "libedit": { - "type": "library", + "artifact": "libedit", "depends": [ "ncurses" ], - "artifact": "libedit", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "libevent": { - "type": "library", + "artifact": "libevent", "depends": [ "openssl" ], - "artifact": "libevent", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libffi": { - "type": "library", - "headers@windows": [ + "artifact": "libffi", + "headers": [ "ffi.h", - "fficonfig.h", "ffitarget.h" ], - "headers": [ + "headers@windows": [ "ffi.h", + "fficonfig.h", "ffitarget.h" ], - "artifact": "libffi", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libffi-win": { - "type": "library", + "artifact": "libffi-win", "headers@windows": [ "ffi.h", "ffitarget.h", "fficonfig.h" ], - "artifact": "libffi-win", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libheif": { - "type": "library", + "artifact": "libheif", "depends": [ "libde265", "libwebp", @@ -398,113 +398,121 @@ "zlib", "brotli" ], - "artifact": "libheif", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "libiconv": { - "type": "library", + "artifact": "libiconv", "headers": [ "iconv.h", "libcharset.h", "localcharset.h" ], - "artifact": "libiconv", "license": { "type": "file", "path": "COPYING.LIB" - } + }, + "type": "library" }, "libiconv-win": { - "type": "library", "artifact": "libiconv-win", "license": { "type": "file", "path": "source/COPYING" - } + }, + "type": "library" }, "libjpeg": { - "type": "library", - "suggests@windows": [ - "zlib" - ], "artifact": "libjpeg", "license": { "type": "file", "path": "LICENSE.md" - } + }, + "suggests@windows": [ + "zlib" + ], + "type": "library" }, "libjxl": { - "type": "library", + "artifact": "libjxl", "depends": [ "brotli", "libjpeg", "libpng", "libwebp" ], + "license": { + "type": "file", + "path": "LICENSE" + }, "pkg-configs": [ "libjxl", "libjxl_cms", "libjxl_threads", "libhwy" ], - "artifact": "libjxl", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "liblz4": { - "type": "library", "artifact": "liblz4", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libmemcached": { - "type": "library", "artifact": "libmemcached", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libpng": { - "type": "library", + "artifact": "libpng", "depends": [ "zlib" ], - "headers@windows": [ - "png.h", - "pngconf.h" - ], "headers": [ "png.h", "pngconf.h", "pnglibconf.h" ], - "artifact": "libpng", + "headers@windows": [ + "png.h", + "pngconf.h" + ], "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "librabbitmq": { - "type": "library", + "artifact": "librabbitmq", "depends": [ "openssl" ], - "artifact": "librabbitmq", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "librdkafka": { - "type": "library", + "artifact": "librdkafka", + "license": { + "type": "file", + "path": "LICENSE" + }, + "pkg-configs": [ + "rdkafka++-static", + "rdkafka-static" + ], "suggests": [ "curl", "liblz4", @@ -512,26 +520,18 @@ "zlib", "zstd" ], - "pkg-configs": [ - "rdkafka++-static", - "rdkafka-static" - ], - "artifact": "librdkafka", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "libsodium": { - "type": "library", "artifact": "libsodium", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "libssh2": { - "type": "library", + "artifact": "libssh2", "depends": [ "openssl" ], @@ -540,18 +540,22 @@ "libssh2_publickey.h", "libssh2_sftp.h" ], - "artifact": "libssh2", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "libtiff": { - "type": "library", + "artifact": "libtiff", "depends": [ "zlib", "libjpeg" ], + "license": { + "type": "file", + "path": "LICENSE.md" + }, "suggests": [ "lerc", "libwebp", @@ -559,41 +563,36 @@ "xz", "zstd" ], - "artifact": "libtiff", - "license": { - "type": "file", - "path": "LICENSE.md" - } + "type": "library" }, "liburing": { - "type": "library", + "artifact": "liburing", "headers@linux": [ "liburing/", "liburing.h" ], + "license": { + "type": "file", + "path": "COPYING" + }, "pkg-configs": [ "liburing", "liburing-ffi" ], - "artifact": "liburing", - "license": { - "type": "file", - "path": "COPYING" - } + "type": "library" }, "libuuid": { - "type": "library", + "artifact": "libuuid", "headers": [ "uuid/uuid.h" ], - "artifact": "libuuid", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "libuv": { - "type": "library", "artifact": "libuv", "license": [ { @@ -604,10 +603,15 @@ "type": "file", "path": "LICENSE-extra" } - ] + ], + "type": "library" }, "libwebp": { - "type": "library", + "artifact": "libwebp", + "license": { + "type": "file", + "path": "COPYING" + }, "pkg-configs": [ "libwebp", "libwebpdecoder", @@ -615,206 +619,202 @@ "libwebpmux", "libsharpyuv" ], - "artifact": "libwebp", - "license": { - "type": "file", - "path": "COPYING" - } + "type": "library" }, "libxml2": { - "type": "library", - "depends@windows": [ - "libiconv-win" - ], + "artifact": "libxml2", "depends": [ "libiconv" ], - "suggests@windows": [ - "zlib" - ], - "suggests": [ - "xz", - "zlib" + "depends@windows": [ + "libiconv-win" ], "headers": [ "libxml2" ], - "pkg-configs": [ - "libxml-2.0" - ], - "artifact": "libxml2", "license": { "type": "file", "path": "Copyright" - } + }, + "pkg-configs": [ + "libxml-2.0" + ], + "suggests": [ + "xz", + "zlib" + ], + "suggests@windows": [ + "zlib" + ], + "type": "library" }, "libxslt": { - "type": "library", + "artifact": "libxslt", "depends": [ "libxml2" ], - "artifact": "libxslt", "license": { "type": "file", "path": "Copyright" - } + }, + "type": "library" }, "libyaml": { - "type": "library", + "artifact": "libyaml", "headers": [ "yaml.h" ], - "artifact": "libyaml", "license": { "type": "file", "path": "License" - } + }, + "type": "library" }, "libzip": { - "type": "library", + "artifact": "libzip", + "depends": [ + "zlib" + ], "depends@windows": [ "zlib", "bzip2", "xz" ], - "depends": [ - "zlib" - ], - "suggests@windows": [ - "zstd", - "openssl" + "headers": [ + "zip.h", + "zipconf.h" ], + "license": { + "type": "file", + "path": "LICENSE" + }, "suggests": [ "bzip2", "xz", "zstd", "openssl" ], - "headers": [ - "zip.h", - "zipconf.h" + "suggests@windows": [ + "zstd", + "openssl" ], - "artifact": "libzip", - "license": { - "type": "file", - "path": "LICENSE" - } + "type": "library" }, "mimalloc": { - "type": "library", "artifact": "mimalloc", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "ncurses": { - "type": "library", "artifact": "ncurses", - "static-libs@unix": [ - "libncurses.a" - ], "license": { "type": "file", "path": "COPYING" - } + }, + "static-libs@unix": [ + "libncurses.a" + ], + "type": "library" }, "net-snmp": { - "type": "library", + "artifact": "net-snmp", "depends": [ "openssl", "zlib" ], + "license": { + "type": "file", + "path": "COPYING" + }, "pkg-configs": [ "netsnmp", "netsnmp-agent" ], - "artifact": "net-snmp", - "license": { - "type": "file", - "path": "COPYING" - } + "type": "library" }, "nghttp2": { - "type": "library", + "artifact": "nghttp2", "depends": [ "zlib", "openssl" ], - "suggests": [ - "libxml2", - "nghttp3", - "ngtcp2" - ], "headers": [ "nghttp2" ], - "artifact": "nghttp2", "license": { "type": "file", "path": "COPYING" - } + }, + "suggests": [ + "libxml2", + "nghttp3", + "ngtcp2" + ], + "type": "library" }, "nghttp3": { - "type": "library", + "artifact": "nghttp3", "depends": [ "openssl" ], "headers": [ "nghttp3" ], - "artifact": "nghttp3", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "ngtcp2": { - "type": "library", + "artifact": "ngtcp2", "depends": [ "openssl" ], - "suggests": [ - "nghttp3", - "brotli" - ], "headers": [ "ngtcp2" ], - "artifact": "ngtcp2", "license": { "type": "file", "path": "COPYING" - } + }, + "suggests": [ + "nghttp3", + "brotli" + ], + "type": "library" }, "onig": { - "type": "library", + "artifact": "onig", "headers": [ "oniggnu.h", "oniguruma.h" ], - "artifact": "onig", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "openssl": { - "type": "library", + "artifact": "openssl", "depends": [ "zlib" ], "headers": [ "openssl" ], - "artifact": "openssl", "license": { "type": "file", "path": "LICENSE.txt" - } + }, + "type": "library" }, "postgresql": { - "type": "library", + "artifact": "postgresql", "depends": [ "libiconv", "libxml2", @@ -822,69 +822,69 @@ "zlib", "libedit" ], + "license": { + "type": "file", + "path": "COPYRIGHT" + }, + "pkg-configs": [ + "libpq" + ], "suggests": [ "icu", "libxslt", "ldap", "zstd" ], - "pkg-configs": [ - "libpq" - ], - "artifact": "postgresql", - "license": { - "type": "file", - "path": "COPYRIGHT" - } + "type": "library" }, "postgresql-win": { - "type": "library", "artifact": "postgresql-win", "license": { "type": "text", "text": "PostgreSQL Database Management System\n(also known as Postgres, formerly as Postgres95)\n\nPortions Copyright (c) 1996-2025, The PostgreSQL Global Development Group\n\nPortions Copyright (c) 1994, The Regents of the University of California\n\nPermission to use, copy, modify, and distribute this software and its\ndocumentation for any purpose, without fee, and without a written\nagreement is hereby granted, provided that the above copyright notice\nand this paragraph and the following two paragraphs appear in all\ncopies.\n\nIN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY\nFOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,\nINCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS\nDOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGE.\n\nTHE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS\nON AN \"AS IS\" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS\nTO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." - } + }, + "type": "library" }, "pthreads4w": { - "type": "library", "artifact": "pthreads4w", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "qdbm": { - "type": "library", + "artifact": "qdbm", "headers@windows": [ "depot.h" ], - "artifact": "qdbm", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "re2c": { - "type": "library", "artifact": "re2c", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" }, "readline": { - "type": "library", + "artifact": "readline", "depends": [ "ncurses" ], - "artifact": "readline", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "snappy": { - "type": "library", + "artifact": "snappy", "depends": [ "zlib" ], @@ -894,99 +894,99 @@ "snappy-sinksource.h", "snappy-stubs-public.h" ], - "artifact": "snappy", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "sqlite": { - "type": "library", + "artifact": "sqlite", "headers": [ "sqlite3.h", "sqlite3ext.h" ], - "artifact": "sqlite", "license": { "type": "text", "text": "The author disclaims copyright to this source code. In place of\na legal notice, here is a blessing:\n\n * May you do good and not evil.\n * May you find forgiveness for yourself and forgive others.\n * May you share freely, never taking more than you give." - } + }, + "type": "library" }, "tidy": { - "type": "library", "artifact": "tidy", "license": { "type": "file", "path": "README/LICENSE.md" - } + }, + "type": "library" }, "unixodbc": { - "type": "library", + "artifact": "unixodbc", "depends": [ "libiconv" ], - "artifact": "unixodbc", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "watcher": { - "type": "library", + "artifact": "watcher", "headers": [ "wtr/watcher-c.h" ], - "artifact": "watcher", "license": { "type": "file", "path": "license" - } + }, + "type": "library" }, "xz": { - "type": "library", + "artifact": "xz", "depends": [ "libiconv" ], + "headers": [ + "lzma" + ], "headers@windows": [ "lzma", "lzma.h" ], - "headers": [ - "lzma" - ], - "artifact": "xz", "license": { "type": "file", "path": "COPYING" - } + }, + "type": "library" }, "zlib": { - "type": "library", + "artifact": "zlib", "headers": [ "zlib.h", "zconf.h" ], - "artifact": "zlib", "license": { "type": "text", "text": "(C) 1995-2022 Jean-loup Gailly and Mark Adler\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nJean-loup Gailly Mark Adler\njloup@gzip.org madler@alumni.caltech.edu" - } + }, + "type": "library" }, "zstd": { - "type": "library", - "headers@windows": [ + "artifact": "zstd", + "headers": [ + "zdict.h", "zstd.h", "zstd_errors.h" ], - "headers": [ - "zdict.h", + "headers@windows": [ "zstd.h", "zstd_errors.h" ], - "artifact": "zstd", "license": { "type": "file", "path": "LICENSE" - } + }, + "type": "library" } } diff --git a/config/pkg.target.json b/config/pkg.target.json index 2ae49f400..8e04df905 100644 --- a/config/pkg.target.json +++ b/config/pkg.target.json @@ -1,98 +1,98 @@ { - "vswhere": { - "type": "target", - "artifact": "vswhere", - "static-bins@windows": [ - "vswhere.exe" - ] + "frankenphp": { + "artifact": "frankenphp", + "depends": [ + "php-embed", + "go-xcaddy" + ], + "depends@macos": [ + "php-embed", + "go-xcaddy", + "libxml2" + ], + "type": "virtual-target" }, - "pkg-config": { - "type": "target", + "go-xcaddy": { + "artifact": "go-xcaddy", "static-bins": [ - "pkg-config" + "xcaddy" ], - "artifact": "pkg-config" + "type": "target" + }, + "musl-toolchain": { + "artifact": "musl-toolchain", + "type": "target" + }, + "nasm": { + "artifact": "nasm", + "type": "target" }, "php": { - "type": "target", "artifact": "php-src", "depends@macos": [ "libxml2" - ] + ], + "type": "target" }, - "php-cli": { - "type": "virtual-target", + "php-cgi": { "depends": [ "php" - ] + ], + "type": "virtual-target" }, - "php-micro": { - "type": "virtual-target", - "artifact": "micro", + "php-cli": { "depends": [ "php" - ] + ], + "type": "virtual-target" }, - "php-cgi": { - "type": "virtual-target", + "php-embed": { "depends": [ "php" - ] + ], + "type": "virtual-target" }, "php-fpm": { - "type": "virtual-target", "depends": [ "php" - ] + ], + "type": "virtual-target" }, - "php-embed": { - "type": "virtual-target", + "php-micro": { + "artifact": "micro", "depends": [ "php" - ] - }, - "frankenphp": { - "type": "virtual-target", - "artifact": "frankenphp", - "depends": [ - "php-embed", - "go-xcaddy" ], - "depends@macos": [ - "php-embed", - "go-xcaddy", - "libxml2" - ] + "type": "virtual-target" }, - "go-xcaddy": { - "type": "target", - "artifact": "go-xcaddy", - "static-bins": [ - "xcaddy" - ] + "php-sdk-binary-tools": { + "artifact": "php-sdk-binary-tools", + "type": "target" }, - "musl-toolchain": { - "type": "target", - "artifact": "musl-toolchain" + "pkg-config": { + "artifact": "pkg-config", + "static-bins": [ + "pkg-config" + ], + "type": "target" }, "strawberry-perl": { - "type": "target", - "artifact": "strawberry-perl" + "artifact": "strawberry-perl", + "type": "target" }, "upx": { - "type": "target", - "artifact": "upx" - }, - "zig": { - "type": "target", - "artifact": "zig" + "artifact": "upx", + "type": "target" }, - "nasm": { - "type": "target", - "artifact": "nasm" + "vswhere": { + "artifact": "vswhere", + "static-bins@windows": [ + "vswhere.exe" + ], + "type": "target" }, - "php-sdk-binary-tools": { - "type": "target", - "artifact": "php-sdk-binary-tools" + "zig": { + "artifact": "zig", + "type": "target" } } From dd5762fbd399f644b2ecb2f4dc7fc9e34bbed18c Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 18 Dec 2025 15:43:58 +0800 Subject: [PATCH 27/73] Add lib skeleton command and sort config, spc_mode suuport, etc... --- phpstan.neon | 1 + skeleton-test.php | 23 +- src/Package/Artifact/zig.php | 1 - src/StaticPHP/Artifact/ArtifactDownloader.php | 3 +- src/StaticPHP/Command/BaseCommand.php | 3 +- src/StaticPHP/Command/Dev/SkeletonCommand.php | 402 ++++++++++++++++++ .../Command/Dev/SortConfigCommand.php | 49 +++ src/StaticPHP/Config/ArtifactConfig.php | 9 +- src/StaticPHP/Config/PackageConfig.php | 9 +- src/StaticPHP/ConsoleApplication.php | 2 + src/StaticPHP/Package/PackageInstaller.php | 3 +- src/StaticPHP/Registry/Registry.php | 81 ++-- src/StaticPHP/Skeleton/ArtifactGenerator.php | 60 ++- src/StaticPHP/Skeleton/ExecutorGenerator.php | 20 + src/StaticPHP/Skeleton/PackageGenerator.php | 239 ++++++++--- src/StaticPHP/Util/FileSystem.php | 17 + src/StaticPHP/Util/InteractiveTerm.php | 1 + src/globals/defines.php | 25 +- src/globals/functions.php | 25 ++ 19 files changed, 865 insertions(+), 108 deletions(-) create mode 100644 src/StaticPHP/Command/Dev/SkeletonCommand.php create mode 100644 src/StaticPHP/Command/Dev/SortConfigCommand.php diff --git a/phpstan.neon b/phpstan.neon index cf6e49742..45e512ba0 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,7 @@ parameters: reportUnmatchedIgnoredErrors: false level: 4 + phpVersion: 80400 paths: - ./src/ ignoreErrors: diff --git a/skeleton-test.php b/skeleton-test.php index 689d33854..59fbbb7e1 100644 --- a/skeleton-test.php +++ b/skeleton-test.php @@ -1,21 +1,28 @@ addDependency('bar') ->addStaticLib('libfoo.a', 'unix') ->addStaticLib('libfoo.a', 'unix') - ->addArtifact($artifact_generator = new ArtifactGenerator('foo')->setSource(['type' => 'url', 'url' => 'https://example.com/foo.tar.gz'])); + ->addArtifact($artifact_generator = new ArtifactGenerator('foo')->setSource(['type' => 'url', 'url' => 'https://example.com/foo.tar.gz'])) + ->enableBuild(['Darwin', 'Linux'], 'build') + ->addFunctionExecutorBinding('build', new ExecutorGenerator(UnixCMakeExecutor::class)); -$pkg_config = $package_generator->generateConfig(); -$artifact_config = $artifact_generator->generateConfig(); +$pkg_config = $package_generator->generateConfigArray(); +$artifact_config = $artifact_generator->generateConfigArray(); -echo "===== pkg.json =====" . PHP_EOL; -echo json_encode($pkg_config, 64|128|256) . PHP_EOL; -echo "===== artifact.json =====" . PHP_EOL; -echo json_encode($artifact_config, 64|128|256) . PHP_EOL; +echo '===== pkg.json =====' . PHP_EOL; +echo json_encode($pkg_config, 64 | 128 | 256) . PHP_EOL; +echo '===== artifact.json =====' . PHP_EOL; +echo json_encode($artifact_config, 64 | 128 | 256) . PHP_EOL; +echo '===== php code for package =====' . PHP_EOL; +echo $package_generator->generatePackageClassFile('Package\Library'); diff --git a/src/Package/Artifact/zig.php b/src/Package/Artifact/zig.php index a73473954..2ac7b454b 100644 --- a/src/Package/Artifact/zig.php +++ b/src/Package/Artifact/zig.php @@ -8,7 +8,6 @@ use StaticPHP\Artifact\Downloader\DownloadResult; use StaticPHP\Attribute\Artifact\AfterBinaryExtract; use StaticPHP\Attribute\Artifact\CustomBinary; -use StaticPHP\Attribute\Artifact\CustomSource; use StaticPHP\Exception\DownloaderException; use StaticPHP\Runtime\SystemTarget; diff --git a/src/StaticPHP/Artifact/ArtifactDownloader.php b/src/StaticPHP/Artifact/ArtifactDownloader.php index 315cfb11d..b53ddd8a2 100644 --- a/src/StaticPHP/Artifact/ArtifactDownloader.php +++ b/src/StaticPHP/Artifact/ArtifactDownloader.php @@ -329,8 +329,7 @@ public function download(bool $interactive = true): void } if ($interactive) { $skip_msg = !empty($skipped) ? ' (Skipped ' . count($skipped) . ' artifacts for being already downloaded)' : ''; - InteractiveTerm::success("Downloaded all {$count} artifacts.{$skip_msg}", true); - echo PHP_EOL; + InteractiveTerm::success("Downloaded all {$count} artifacts.{$skip_msg}\n", true); } } } catch (SPCException $e) { diff --git a/src/StaticPHP/Command/BaseCommand.php b/src/StaticPHP/Command/BaseCommand.php index e416be26d..02f84ffb5 100644 --- a/src/StaticPHP/Command/BaseCommand.php +++ b/src/StaticPHP/Command/BaseCommand.php @@ -23,7 +23,6 @@ abstract class BaseCommand extends Command \___ \| __/ _` | __| |/ __| |_) | |_| | |_) | ___) | || (_| | |_| | (__| __/| _ | __/ |____/ \__\__,_|\__|_|\___|_| |_| |_|_| {version} - '; protected bool $no_motd = false; @@ -71,7 +70,7 @@ public function initialize(InputInterface $input, OutputInterface $output): void $version = $this->getVersionWithCommit(); if (!$this->no_motd) { $str = str_replace('{version}', '' . ConsoleColor::none("v{$version}"), '' . ConsoleColor::magenta(self::$motd)); - echo $this->input->getOption('no-ansi') ? strip_ansi_colors($str) : $str; + $this->output->writeln($this->input->getOption('no-ansi') ? strip_ansi_colors($str) : $str); } } diff --git a/src/StaticPHP/Command/Dev/SkeletonCommand.php b/src/StaticPHP/Command/Dev/SkeletonCommand.php new file mode 100644 index 000000000..b19eb4a11 --- /dev/null +++ b/src/StaticPHP/Command/Dev/SkeletonCommand.php @@ -0,0 +1,402 @@ +output->writeln('The dev:skel command is not available in phar mode.'); + return 1; + } + if (SystemTarget::getTargetOS() === 'Windows') { + $this->output->writeln('The dev:skel command is not available on Windows systems.'); + return 1; + } + + $this->runMainMenu(); + + return 0; + } + + public function validatePackageName(string $name): ?string + { + if (!preg_match('/^[a-zA-Z0-9_-]+$/', $name)) { + return 'Library name can only contain letters, numbers, underscores, and hyphens.'; + } + // must start with a letter + if (!preg_match('/^[a-zA-Z]/', $name)) { + return 'Library name must start with a letter.'; + } + return null; + } + + private function runMainMenu(): void + { + $main = select('Please select the skeleton option', [ + 'library' => 'Create a new library package', + 'target' => 'Create a new target package', + 'php-extension' => 'Create a new PHP extension', + 'q' => 'Exit', + ]); + $generator = match ($main) { + 'library' => $this->runCreateLib(), + 'target' => $this->runCreateTarget(), + 'php-extension' => $this->runCreateExt(), + 'q' => exit(0), + default => null, + }; + $write = $generator->writeAll(); + $this->output->writeln("Package config in: {$write['package_config']}"); + $this->output->writeln("Artifact config in: {$write['artifact_config']}"); + $this->output->writeln('Package class:'); + $this->output->writeln($write['package_class_content']); + } + + private function runCreateLib(): PackageGenerator + { + // init empty + $static_libs = ''; + $headers = ''; + $static_bins = ''; + $pkg_configs = ''; + + // ask name + $package_name = text('Please enter your library name', placeholder: 'e.g. pcre2', validate: [$this, 'validatePackageName']); + + // ask OS + $os = select("[{$package_name}] On which OS family do you want to build this library?", [ + 'unix' => 'Both Linux and Darwin (unix-like OS)', + 'linux' => 'Linux only', + 'macos' => 'Darwin(macOS) only', + 'windows' => 'Windows only', + 'all' => 'All supported OS (' . implode(', ', SUPPORTED_OS_FAMILY) . ')', + ]); + + $produce = select("[{$package_name}] What does this library produce?", [ + 'static_libs' => 'Static Libraries (.a/.lib)', + 'headers' => 'Header Files (.h)', + 'static_bins' => 'Static Binaries (executables)', + 'pkg_configs' => 'Pkg-Config files (.pc)', + 'all' => 'All of the above', + ]); + + if ($produce === 'all' || $produce === 'static_libs') { + $static_libs = text( + 'Please enter the names of the static libraries produced', + placeholder: 'e.g. libpcre2.a, libbar.a', + default: str_starts_with($package_name, 'lib') ? "{$package_name}.a" : "lib{$package_name}.a", + validate: function ($value) { + $names = array_map('trim', explode(',', $value)); + if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { + return 'Library names can only contain letters, numbers, underscores, hyphens, and dots.'; + } + return null; + }, + hint: 'Separate multiple names with commas' + ); + } + if ($produce === 'all' || $produce === 'headers') { + $headers = text( + 'Please enter the names of the header files produced', + placeholder: 'e.g. foo.h, bar.h', + default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.h' : $package_name . '.h', + validate: function ($value) { + $names = array_map('trim', explode(',', $value)); + if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { + return 'Header file names can only contain letters, numbers, underscores, hyphens, and dots.'; + } + return null; + }, + hint: 'Separate multiple names with commas, directories are allowed (e.g. openssl directory)' + ); + } + if ($produce === 'all' || $produce === 'static_bins') { + $static_bins = text( + 'Please enter the names of the static binaries produced', + placeholder: 'e.g. foo, bar', + default: $package_name, + validate: function ($value) { + $names = array_map('trim', explode(',', $value)); + if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { + return 'Binary names can only contain letters, numbers, underscores, hyphens, and dots.'; + } + return null; + }, + hint: 'Separate multiple names with commas' + ); + } + if ($produce === 'all' || $produce === 'pkg_configs') { + $pkg_configs = text( + 'Please enter the names of the pkg-config files produced', + placeholder: 'e.g. foo.pc, bar.pc', + default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.pc' : $package_name . '.pc', + validate: function ($value) { + if (!str_ends_with($value, '.pc')) { + return 'Pkg-config file names must end with .pc extension.'; + } + return null; + }, + hint: 'Separate multiple names with commas' + ); + } + + if ($headers === '' && $static_bins === '' && $static_libs === '' && $pkg_configs === '') { + $this->output->writeln('You must specify at least one of static libraries, header files, or static binaries produced.'); + exit(1); + } + + // ask source + $artifact_generator = $this->runCreateArtifact($package_name, true, false, null); + $package_generator = new PackageGenerator($package_name, 'library'); + // set artifact + $package_generator = $package_generator->addArtifact($artifact_generator); + // set os + $package_generator = match ($os) { + 'unix' => $package_generator->enableBuild(['Darwin', 'Linux'], 'build'), + 'linux' => $package_generator->enableBuild(['Linux'], 'build'), + 'macos' => $package_generator->enableBuild(['Darwin'], 'build'), + 'windows' => $package_generator->enableBuild(['Windows'], 'build'), + 'all' => $package_generator->enableBuild(SUPPORTED_OS_FAMILY, 'build'), + default => $package_generator, + }; + // set produce + if ($static_libs !== '') { + $lib_names = array_map('trim', explode(',', $static_libs)); + foreach ($lib_names as $lib_name) { + $package_generator = $package_generator->addStaticLib($lib_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); + } + } + if ($headers !== '') { + $header_names = array_map('trim', explode(',', $headers)); + foreach ($header_names as $header_name) { + $package_generator = $package_generator->addHeaderFile($header_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); + } + } + if ($static_bins !== '') { + $bin_names = array_map('trim', explode(',', $static_bins)); + foreach ($bin_names as $bin_name) { + $package_generator = $package_generator->addStaticBin($bin_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); + } + } + if ($pkg_configs !== '') { + $pc_names = array_map('trim', explode(',', $pkg_configs)); + foreach ($pc_names as $pc_name) { + $package_generator = $package_generator->addPkgConfigFile($pc_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); + } + } + // ask for package config writing selection, same as artifact + $package_configs = Registry::getLoadedPackageConfigs(); + $package_config_file = select("[{$package_name}] Please select the package config file to write the package config to", $package_configs); + return $package_generator->setConfigFile($package_config_file); + } + + private function runCreateArtifact( + string $package_name, + ?bool $create_source, + ?bool $create_binary, + string|true|null $default_extract_dir = true + ): ArtifactGenerator { + $artifact = new ArtifactGenerator($package_name); + + if ($create_source === null) { + $create_source = confirm("[{$package_name}] Do you want to create a source artifact?"); + } + + if (!$create_source) { + goto binary; + } + + $source_type = select("[{$package_name}] Where is the source code located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME); + + $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'source'); + $artifact = $artifact->setSource($source_config); + + binary: + if ($create_binary === null) { + $create_binary = confirm("[{$package_name}] Do you want to create a binary artifact?"); + } + + if (!$create_binary) { + goto end; + } + + $binary_fix = [ + 'macos-x86_64' => null, + 'macos-aarch64' => null, + 'linux-x86_64' => null, + 'linux-aarch64' => null, + 'windows-x86_64' => null, + ]; + while (($os = select("[{$package_name}] Please configure the binary downloading options for OS", [ + 'macos-x86_64' => 'macos-x86_64' . ($binary_fix['macos-x86_64'] ? ' (done)' : ''), + 'macos-aarch64' => 'macos-aarch64' . ($binary_fix['macos-aarch64'] ? ' (done)' : ''), + 'linux-x86_64' => 'linux-x86_64' . ($binary_fix['linux-x86_64'] ? ' (done)' : ''), + 'linux-aarch64' => 'linux-aarch64' . ($binary_fix['linux-aarch64'] ? ' (done)' : ''), + 'windows-x86_64' => 'windows-x86_64' . ($binary_fix['windows-x86_64'] ? ' (done)' : ''), + 'copy' => 'Duplicate from another OS', + 'finish' => 'Submit', + ])) !== 'finish') { + $source_type = select("[{$package_name}] Where is the binary for {$os} located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME); + $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'binary'); + // set to artifact + $artifact = $artifact->setBinary($os, $source_config); + $binary_fix[$os] = true; + } + + end: + + // generate config files, select existing package config file to write + $artifact_configs = Registry::getLoadedArtifactConfigs(); + $artifact_config_file = select("[{$package_name}] Please select the artifact config file to write the artifact config to", $artifact_configs); + return $artifact->setConfigFile($artifact_config_file); + } + + private function runCreateTarget(): PackageGenerator + { + throw new WrongUsageException('Not implemented'); + } + + private function runCreateExt(): PackageGenerator + { + throw new WrongUsageException('Not implemented'); + } + + private function askDownloadTypeConfig(string $package_name, int|string $source_type, bool|string|null $default_extract_dir, string $config_type): array + { + $source_config = ['type' => $source_type]; + switch ($source_type) { + case 'bitbuckettag': + $source_config['repo'] = text("[{$package_name}] Please enter the BitBucket repository (e.g. user/repo)"); + break; + case 'filelist': + $source_config['url'] = text( + "[{$package_name}] Please enter the file index website URL", + placeholder: 'e.g. https://ftp.gnu.org/pub/gnu/gettext/', + hint: 'Make sure the target url is a directory listing page like ftp.gnu.org.' + ); + $source_config['regex'] = text( + "[{$package_name}] Please enter the regex pattern to match the archive file", + placeholder: 'e.g. /gettext-(\d+\.\d+(\.\d+)?)\.tar\.gz/', + default: "/href=\"(?{$package_name}-(?[^\"]+)\\.tar\\.gz)\"/", + hint: 'Make sure the regex contains a capturing group for the version number.' + ); + break; + case 'git': + $source_config['url'] = text( + "[{$package_name}] Please enter the Git repository URL", + validate: function ($value) { + if (!filter_var($value, FILTER_VALIDATE_URL) && !preg_match('/^(git|ssh|http|https|git@[-\w.]+):(\/\/)?(.*?)(\.git)(\/?|#[-\d\w._]+?)$/', $value)) { + return 'Please enter a valid Git repository URL.'; + } + return null; + }, + hint: 'e.g. https://github.com/user/repo.git' + ); + $source_config['rev'] = text( + "[{$package_name}] Please enter the Git revision (branch, tag, or commit hash)", + default: 'main', + hint: 'e.g. main, master, v1.0.0, or a commit hash' + ); + break; + case 'ghrel': + $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)"); + $source_config['match'] = text( + "[{$package_name}] Please enter the regex pattern to match the source archive file", + placeholder: 'e.g. /foo-(\d+\.\d+(\.\d+)?)\.tar\.gz/', + default: "{$package_name}-.+\\.tar\\.gz", + ); + break; + case 'ghtar': + case 'ghtagtar': + $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)"); + $source_config['prefer-stable'] = confirm("[{$package_name}] Do you want to prefer stable releases?"); + if ($source_type === 'ghtagtar' && confirm('Do you want to match tags with a specific pattern?', default: false)) { + $source_config['match'] = text( + "[{$package_name}] Please enter the regex pattern to match tags", + placeholder: 'e.g. v(\d+\.\d+(\.\d+)?)', + ); + } + break; + case 'local': + $source_config['dirname'] = text( + "[{$package_name}] Please enter the local directory path", + validate: function ($value) { + if (trim($value) === '') { + return 'Local source directory cannot be empty.'; + } + if (!is_dir($value)) { + return 'The specified local source directory does not exist.'; + } + return null; + }, + ); + break; + case 'pie': + $source_config['repo'] = text( + "[{$package_name}] Please enter the PIE repository name", + placeholder: 'e.g. user/repo', + ); + break; + case 'url': + $source_config['url'] = text( + "[{$package_name}] Please enter the file download URL", + validate: function ($value) { + if (!filter_var($value, FILTER_VALIDATE_URL)) { + return 'Please enter a valid URL.'; + } + return null; + }, + ); + break; + case 'custom': + break; + } + // ask extract dir if is true + if ($default_extract_dir === true) { + if (confirm('Do you want to specify a custom extract directory?')) { + $extract_hint = match ($config_type) { + 'source' => 'the source will be from the `source/` dir by default', + 'binary' => 'the binary will be from the `pkgroot/{arch}-{os}/` dir by default', + default => '', + }; + $default_extract_dir = text( + "[{$package_name}] Please enter the source extract directory", + validate: function ($value) { + if (trim($value) === '') { + return 'Extract directory cannot be empty.'; + } + return null; + }, + hint: 'You can use relative path, ' . $extract_hint . '.' + ); + } else { + $default_extract_dir = null; + } + } + if ($default_extract_dir !== null) { + $source_config['extract'] = $default_extract_dir; + } + + // return config + return $source_config; + } +} diff --git a/src/StaticPHP/Command/Dev/SortConfigCommand.php b/src/StaticPHP/Command/Dev/SortConfigCommand.php new file mode 100644 index 000000000..aa3a9ecdb --- /dev/null +++ b/src/StaticPHP/Command/Dev/SortConfigCommand.php @@ -0,0 +1,49 @@ +sortConfigFile($file); + } + $loaded_pkg_configs = Registry::getLoadedPackageConfigs(); + foreach ($loaded_pkg_configs as $file) { + $this->sortConfigFile($file); + } + return static::SUCCESS; + } + + private function sortConfigFile(mixed $file): void + { + $content = file_get_contents($file); + if ($content === false) { + $this->output->writeln("Failed to read artifact config file: {$file}"); + return; + } + $data = json_decode($content, true); + if (!is_array($data)) { + $this->output->writeln("Invalid JSON format in artifact config file: {$file}"); + return; + } + ksort($data); + foreach ($data as $artifact_name => &$config) { + ksort($config); + } + unset($config); + $new_content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; + file_put_contents($file, $new_content); + $this->output->writeln("Sorted artifact config file: {$file}"); + } +} diff --git a/src/StaticPHP/Config/ArtifactConfig.php b/src/StaticPHP/Config/ArtifactConfig.php index e840c0bf7..49abae926 100644 --- a/src/StaticPHP/Config/ArtifactConfig.php +++ b/src/StaticPHP/Config/ArtifactConfig.php @@ -11,26 +11,30 @@ class ArtifactConfig { private static array $artifact_configs = []; - public static function loadFromDir(string $dir, string $registry_name): void + public static function loadFromDir(string $dir, string $registry_name): array { if (!is_dir($dir)) { throw new WrongUsageException("Directory {$dir} does not exist, cannot load artifact config."); } + $loaded = []; $files = glob("{$dir}/artifact.*.json"); if (is_array($files)) { foreach ($files as $file) { self::loadFromFile($file, $registry_name); + $loaded[] = $file; } } if (file_exists("{$dir}/artifact.json")) { self::loadFromFile("{$dir}/artifact.json", $registry_name); + $loaded[] = "{$dir}/artifact.json"; } + return $loaded; } /** * Load artifact configurations from a specified JSON file. */ - public static function loadFromFile(string $file, string $registry_name): void + public static function loadFromFile(string $file, string $registry_name): string { $content = file_get_contents($file); if ($content === false) { @@ -45,6 +49,7 @@ public static function loadFromFile(string $file, string $registry_name): void self::$artifact_configs[$artifact_name] = $config; Registry::_bindArtifactConfigFile($artifact_name, $registry_name, $file); } + return $file; } /** diff --git a/src/StaticPHP/Config/PackageConfig.php b/src/StaticPHP/Config/PackageConfig.php index 3342dfc78..56ef7ab1c 100644 --- a/src/StaticPHP/Config/PackageConfig.php +++ b/src/StaticPHP/Config/PackageConfig.php @@ -16,20 +16,24 @@ class PackageConfig * Load package configurations from a specified directory. * It will look for files matching the pattern 'pkg.*.json' and 'pkg.json'. */ - public static function loadFromDir(string $dir, string $registry_name): void + public static function loadFromDir(string $dir, string $registry_name): array { if (!is_dir($dir)) { throw new WrongUsageException("Directory {$dir} does not exist, cannot load pkg.json config."); } + $loaded = []; $files = glob("{$dir}/pkg.*.json"); if (is_array($files)) { foreach ($files as $file) { self::loadFromFile($file, $registry_name); + $loaded[] = $file; } } if (file_exists("{$dir}/pkg.json")) { self::loadFromFile("{$dir}/pkg.json", $registry_name); + $loaded[] = "{$dir}/pkg.json"; } + return $loaded; } /** @@ -37,7 +41,7 @@ public static function loadFromDir(string $dir, string $registry_name): void * * @param string $file the path to the json package configuration file */ - public static function loadFromFile(string $file, string $registry_name): void + public static function loadFromFile(string $file, string $registry_name): string { $content = file_get_contents($file); if ($content === false) { @@ -52,6 +56,7 @@ public static function loadFromFile(string $file, string $registry_name): void self::$package_configs[$pkg_name] = $config; Registry::_bindPackageConfigFile($pkg_name, $registry_name, $file); } + return $file; } /** diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php index bd0cfd60a..fd7650aa8 100644 --- a/src/StaticPHP/ConsoleApplication.php +++ b/src/StaticPHP/ConsoleApplication.php @@ -10,6 +10,7 @@ use StaticPHP\Command\Dev\IsInstalledCommand; use StaticPHP\Command\Dev\ShellCommand; use StaticPHP\Command\Dev\SkeletonCommand; +use StaticPHP\Command\Dev\SortConfigCommand; use StaticPHP\Command\DoctorCommand; use StaticPHP\Command\DownloadCommand; use StaticPHP\Command\ExtractCommand; @@ -61,6 +62,7 @@ public function __construct() new IsInstalledCommand(), new EnvCommand(), new SkeletonCommand(), + new SortConfigCommand(), ]); // add additional commands from registries diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php index 4c44ce920..ae3b7346a 100644 --- a/src/StaticPHP/Package/PackageInstaller.php +++ b/src/StaticPHP/Package/PackageInstaller.php @@ -133,9 +133,8 @@ public function run(bool $interactive = true, bool $disable_delay_msg = false): // show install or build options in terminal with beautiful output $this->printInstallerInfo(); - InteractiveTerm::notice('Build process will start after 2s ...'); + InteractiveTerm::notice('Build process will start after 2s ...' . PHP_EOL); sleep(2); - echo PHP_EOL; } // Early validation: check if packages can be built or installed before downloading diff --git a/src/StaticPHP/Registry/Registry.php b/src/StaticPHP/Registry/Registry.php index 909de021f..e464ed471 100644 --- a/src/StaticPHP/Registry/Registry.php +++ b/src/StaticPHP/Registry/Registry.php @@ -13,13 +13,39 @@ class Registry { - /** @var array List of loaded registries */ + /** @var string[] List of loaded registries */ private static array $loaded_registries = []; + /** @var array Loaded registry configs */ + private static array $registry_configs = []; + + private static array $loaded_package_configs = []; + + private static array $loaded_artifact_configs = []; + /** @var array Maps of package and artifact names to their registry config file paths (for reverse lookup) */ private static array $package_reversed_registry_files = []; + private static array $artifact_reversed_registry_files = []; + /** + * Get the current registry configuration. + * "Current" depends on SPC load mode + */ + public static function getRegistryConfig(?string $registry_name = null): array + { + if ($registry_name === null && spc_mode(SPC_MODE_SOURCE)) { + return self::$registry_configs['internal']; + } + if ($registry_name !== null && isset(self::$registry_configs[$registry_name])) { + return self::$registry_configs[$registry_name]; + } + if ($registry_name === null) { + throw new RegistryException('No registry name specified.'); + } + throw new RegistryException("Registry '{$registry_name}' is not loaded."); + } + /** * Load a registry from file path. * This method handles external registries that may not be in composer autoload. @@ -52,12 +78,14 @@ public static function loadRegistry(string $registry_file, bool $auto_require = return; } self::$loaded_registries[] = $registry_name; + self::$registry_configs[$registry_name] = $data; + self::$registry_configs[$registry_name]['_file'] = $registry_file; logger()->debug("Loading registry '{$registry_name}' from file: {$registry_file}"); // Load composer autoload if specified (for external registries with their own dependencies) if (isset($data['autoload']) && is_string($data['autoload'])) { - $autoload_path = self::fullpath($data['autoload'], dirname($registry_file)); + $autoload_path = FileSystem::fullpath($data['autoload'], dirname($registry_file)); if (file_exists($autoload_path)) { logger()->debug("Loading external autoload from: {$autoload_path}"); require_once $autoload_path; @@ -69,7 +97,7 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load doctor items from PSR-4 directories if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) { foreach ($data['doctor']['psr-4'] as $namespace => $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require); } } @@ -87,11 +115,11 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load package configs if (isset($data['package']['config']) && is_array($data['package']['config'])) { foreach ($data['package']['config'] as $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); if (is_file($path)) { - PackageConfig::loadFromFile($path, $registry_name); + self::$loaded_package_configs[] = PackageConfig::loadFromFile($path, $registry_name); } elseif (is_dir($path)) { - PackageConfig::loadFromDir($path, $registry_name); + self::$loaded_package_configs = array_merge(self::$loaded_package_configs, PackageConfig::loadFromDir($path, $registry_name)); } } } @@ -99,11 +127,11 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load artifact configs if (isset($data['artifact']['config']) && is_array($data['artifact']['config'])) { foreach ($data['artifact']['config'] as $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); if (is_file($path)) { - ArtifactConfig::loadFromFile($path, $registry_name); + self::$loaded_artifact_configs[] = ArtifactConfig::loadFromFile($path, $registry_name); } elseif (is_dir($path)) { - ArtifactConfig::loadFromDir($path, $registry_name); + self::$loaded_package_configs = array_merge(self::$loaded_package_configs, ArtifactConfig::loadFromDir($path, $registry_name)); } } } @@ -111,7 +139,7 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load packages from PSR-4 directories if (isset($data['package']['psr-4']) && is_assoc_array($data['package']['psr-4'])) { foreach ($data['package']['psr-4'] as $namespace => $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); PackageLoader::loadFromPsr4Dir($path, $namespace, $auto_require); } } @@ -129,7 +157,7 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load artifacts from PSR-4 directories if (isset($data['artifact']['psr-4']) && is_assoc_array($data['artifact']['psr-4'])) { foreach ($data['artifact']['psr-4'] as $namespace => $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); ArtifactLoader::loadFromPsr4Dir($path, $namespace, $auto_require); } } @@ -147,7 +175,7 @@ public static function loadRegistry(string $registry_file, bool $auto_require = // load additional commands from PSR-4 directories if (isset($data['command']['psr-4']) && is_assoc_array($data['command']['psr-4'])) { foreach ($data['command']['psr-4'] as $namespace => $path) { - $path = self::fullpath($path, dirname($registry_file)); + $path = FileSystem::fullpath($path, dirname($registry_file)); $classes = FileSystem::getClassesPsr4($path, $namespace, auto_require: $auto_require); $instances = array_map(fn ($x) => new $x(), $classes); ConsoleApplication::_addAdditionalCommands($instances); @@ -262,6 +290,16 @@ public static function getArtifactConfigInfo(string $artifact_name): ?array return self::$artifact_reversed_registry_files[$artifact_name] ?? null; } + public static function getLoadedPackageConfigs(): array + { + return self::$loaded_package_configs; + } + + public static function getLoadedArtifactConfigs(): array + { + return self::$loaded_artifact_configs; + } + /** * Parse a class entry from the classes array. * Supports two formats: @@ -298,7 +336,7 @@ private static function requireClassFile(string $class, ?string $file_path, stri // If file path is provided, require it if ($file_path !== null) { - $full_path = self::fullpath($file_path, $base_path); + $full_path = FileSystem::fullpath($file_path, $base_path); require_once $full_path; return; } @@ -311,21 +349,4 @@ private static function requireClassFile(string $class, ?string $file_path, stri " 3. Provide file path in classes map: \"{$class}\": \"path/to/file.php\"" ); } - - /** - * Return full path, resolving relative paths against a base path. - * - * @param string $path Input path (relative or absolute) - * @param string $relative_path_base Base path for relative paths - */ - private static function fullpath(string $path, string $relative_path_base): string - { - if (FileSystem::isRelativePath($path)) { - $path = $relative_path_base . DIRECTORY_SEPARATOR . $path; - } - if (!file_exists($path)) { - throw new RegistryException("Path does not exist: {$path}"); - } - return FileSystem::convertPath($path); - } } diff --git a/src/StaticPHP/Skeleton/ArtifactGenerator.php b/src/StaticPHP/Skeleton/ArtifactGenerator.php index 031d095bb..e05f94d14 100644 --- a/src/StaticPHP/Skeleton/ArtifactGenerator.php +++ b/src/StaticPHP/Skeleton/ArtifactGenerator.php @@ -1,11 +1,21 @@ source; } - public function generateConfig(): array + public function setBinary(string $os, array $config): static + { + $clone = clone $this; + if ($clone->binary === null) { + $clone->binary = [$os => $config]; + } else { + $clone->binary[$os] = $config; + } + return $clone; + } + + public function generateConfigArray(): array { $config = []; if ($this->source) { $config['source'] = $this->source; } + if ($this->binary) { + $config['binary'] = $this->binary; + } return $config; } + + public function setConfigFile(string $file): static + { + $clone = clone $this; + $clone->config_file = $file; + return $clone; + } + + /** + * Write the artifact configuration to the config file. + */ + public function writeConfigFile(): string + { + if ($this->config_file === null) { + throw new ValidationException('Config file path is not set.'); + } + $config_array = $this->generateConfigArray(); + $config_file_json = json_decode(FileSystem::readFile($this->config_file), true); + if (!is_array($config_file_json)) { + throw new ValidationException('Existing config file is not a valid JSON array.'); + } + + $config_file_json[$this->name] = $config_array; + // sort keys + ksort($config_file_json); + $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + if ($json_content === false) { + throw new ValidationException('Failed to encode config array to JSON.'); + } + if (file_put_contents($this->config_file, $json_content) === false) { + throw new FileSystemException("Failed to write config file: {$this->config_file}"); + } + return $this->config_file; + } } diff --git a/src/StaticPHP/Skeleton/ExecutorGenerator.php b/src/StaticPHP/Skeleton/ExecutorGenerator.php index 02edf2ebd..69d7a9f89 100644 --- a/src/StaticPHP/Skeleton/ExecutorGenerator.php +++ b/src/StaticPHP/Skeleton/ExecutorGenerator.php @@ -1,9 +1,14 @@ class) { + UnixCMakeExecutor::class => [UnixCMakeExecutor::class, 'UnixCMakeExecutor::create($package)->build();'], + UnixAutoconfExecutor::class => [UnixAutoconfExecutor::class, 'UnixAutoconfExecutor::create($package)->build();'], + WindowsCMakeExecutor::class => [WindowsCMakeExecutor::class, 'WindowsCMakeExecutor::create($package)->build();'], + default => throw new ValidationException("Unsupported executor class: {$this->class}"), + }; + } } diff --git a/src/StaticPHP/Skeleton/PackageGenerator.php b/src/StaticPHP/Skeleton/PackageGenerator.php index 95d3c87f1..89802899a 100644 --- a/src/StaticPHP/Skeleton/PackageGenerator.php +++ b/src/StaticPHP/Skeleton/PackageGenerator.php @@ -1,33 +1,49 @@ $depends An array of dependencies required by the package, categorized by operating system. */ + /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $depends An array of dependencies required by the package, categorized by operating system. */ protected array $depends = []; - /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $suggests An array of suggested packages for the package, categorized by operating system. */ + /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $suggests An array of suggested packages for the package, categorized by operating system. */ protected array $suggests = []; /** @var array $frameworks An array of macOS frameworks for the package */ protected array $frameworks = []; - /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $static_libs An array of static libraries required by the package, categorized by operating system. */ + /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_libs An array of static libraries required by the package, categorized by operating system. */ protected array $static_libs = []; - /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $headers An array of header files required by the package, categorized by operating system. */ + /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $headers An array of header files required by the package, categorized by operating system. */ protected array $headers = []; - /** @var array<''|'unix'|'windows'|'macos'|'linux', string[]> $static_bins An array of static binaries required by the package, categorized by operating system. */ + /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_bins An array of static binaries required by the package, categorized by operating system. */ protected array $static_bins = []; - /** @var ArtifactGenerator|null $artifact Artifact */ + protected ?string $config_file = null; + + /** @var null|ArtifactGenerator $artifact Artifact */ protected ?ArtifactGenerator $artifact = null; /** @var array $licenses Licenses */ @@ -44,28 +60,28 @@ class PackageGenerator protected array $func_executor_binding = []; /** - * @param string $package_name Package name - * @param 'library'|'target'|'virtual-target'|'php-extension' $type Package type ('library', 'target', 'virtual-target', etc.) + * @param string $package_name Package name + * @param 'library'|'php-extension'|'target'|'virtual-target' $type Package type ('library', 'target', 'virtual-target', etc.) */ public function __construct(protected string $package_name, protected string $type) {} /** * Add package dependency. * - * @param string $package Package name - * @param string $os Operating system ('' for all OSes, '@unix', '@windows', '@macos') + * @param string $package Package name + * @param string $os_category Operating system ('' for all OSes, 'unix', 'windows', 'macos') */ - public function addDependency(string $package, string $os = ''): static + public function addDependency(string $package, string $os_category = ''): static { - if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { - throw new ValidationException("Invalid OS suffix: {$os}"); + if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { + throw new ValidationException("Invalid OS suffix: {$os_category}"); } $clone = clone $this; - if (!isset($clone->depends[$os])) { - $clone->depends[$os] = []; + if (!isset($clone->depends[$os_category])) { + $clone->depends[$os_category] = []; } - if (!in_array($package, $clone->depends[$os], true)) { - $clone->depends[$os][] = $package; + if (!in_array($package, $clone->depends[$os_category], true)) { + $clone->depends[$os_category][] = $package; } return $clone; } @@ -73,78 +89,78 @@ public function addDependency(string $package, string $os = ''): static /** * Add package suggestion. * - * @param string $package Package name - * @param string $os Operating system ('' for all OSes, '@unix', '@windows', '@macos') + * @param string $package Package name + * @param string $os_category Operating system ('' for all OSes) */ - public function addSuggestion(string $package, string $os = ''): static + public function addSuggestion(string $package, string $os_category = ''): static { - if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { - throw new ValidationException("Invalid OS suffix: {$os}"); + if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { + throw new ValidationException("Invalid OS suffix: {$os_category}"); } $clone = clone $this; - if (!isset($clone->suggests[$os])) { - $clone->suggests[$os] = []; + if (!isset($clone->suggests[$os_category])) { + $clone->suggests[$os_category] = []; } - if (!in_array($package, $clone->suggests[$os], true)) { - $clone->suggests[$os][] = $package; + if (!in_array($package, $clone->suggests[$os_category], true)) { + $clone->suggests[$os_category][] = $package; } return $clone; } - public function addStaticLib(string $lib_a, string $os = ''): static + public function addStaticLib(string $lib_a, string $os_category = ''): static { - if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { - throw new ValidationException("Invalid OS suffix: {$os}"); + if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { + throw new ValidationException("Invalid OS suffix: {$os_category}"); } if (!str_ends_with($lib_a, '.lib') && !str_ends_with($lib_a, '.a')) { throw new ValidationException("Static library must end with .lib or .a, got: {$lib_a}"); } - if (str_ends_with($lib_a, '.lib') && in_array($os, ['unix', 'linux', 'macos'], true)) { + if (str_ends_with($lib_a, '.lib') && in_array($os_category, ['unix', 'linux', 'macos'], true)) { throw new ValidationException("Static library with .lib extension cannot be added for non-Windows OS: {$lib_a}"); } - if (str_ends_with($lib_a, '.a') && $os === 'windows') { + if (str_ends_with($lib_a, '.a') && $os_category === 'windows') { throw new ValidationException("Static library with .a extension cannot be added for Windows OS: {$lib_a}"); } - if (isset($this->static_libs[$os]) && in_array($lib_a, $this->static_libs[$os], true)) { + if (isset($this->static_libs[$os_category]) && in_array($lib_a, $this->static_libs[$os_category], true)) { // already exists return $this; } $clone = clone $this; - if (!isset($clone->static_libs[$os])) { - $clone->static_libs[$os] = []; + if (!isset($clone->static_libs[$os_category])) { + $clone->static_libs[$os_category] = []; } - if (!in_array($lib_a, $clone->static_libs[$os], true)) { - $clone->static_libs[$os][] = $lib_a; + if (!in_array($lib_a, $clone->static_libs[$os_category], true)) { + $clone->static_libs[$os_category][] = $lib_a; } return $clone; } - public function addHeader(string $header_file, string $os = ''): static + public function addHeader(string $header_file, string $os_category = ''): static { - if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { - throw new ValidationException("Invalid OS suffix: {$os}"); + if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { + throw new ValidationException("Invalid OS suffix: {$os_category}"); } $clone = clone $this; - if (!isset($clone->headers[$os])) { - $clone->headers[$os] = []; + if (!isset($clone->headers[$os_category])) { + $clone->headers[$os_category] = []; } - if (!in_array($header_file, $clone->headers[$os], true)) { - $clone->headers[$os][] = $header_file; + if (!in_array($header_file, $clone->headers[$os_category], true)) { + $clone->headers[$os_category][] = $header_file; } return $clone; } - public function addStaticBin(string $bin_file, string $os = ''): static + public function addStaticBin(string $bin_file, string $os_category = ''): static { - if (!in_array($os, ['', 'unix', 'windows', 'macos', 'linux'], true)) { - throw new ValidationException("Invalid OS suffix: {$os}"); + if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { + throw new ValidationException("Invalid OS suffix: {$os_category}"); } $clone = clone $this; - if (!isset($clone->static_bins[$os])) { - $clone->static_bins[$os] = []; + if (!isset($clone->static_bins[$os_category])) { + $clone->static_bins[$os_category] = []; } - if (!in_array($bin_file, $clone->static_bins[$os], true)) { - $clone->static_bins[$os][] = $bin_file; + if (!in_array($bin_file, $clone->static_bins[$os_category], true)) { + $clone->static_bins[$os_category][] = $bin_file; } return $clone; } @@ -194,9 +210,9 @@ public function addLicenseFromFile(string $file_path): static /** * Enable build for specific OS. * - * @param 'Windows'|'Linux'|'Darwin'|array<'Windows'|'Linux'|'Darwin'> $build_for Build for OS + * @param 'Darwin'|'Linux'|'Windows'|array<'Darwin'|'Linux'|'Windows'> $build_for Build for OS */ - public function enableBuild(string|array $build_for, ?string $build_function_name = null): static + public function enableBuild(array|string $build_for, ?string $build_function_name = null): static { $clone = clone $this; if (is_array($build_for)) { @@ -205,6 +221,9 @@ public function enableBuild(string|array $build_for, ?string $build_function_nam } return $clone; } + if (!in_array($build_for, SUPPORTED_OS_FAMILY, true)) { + throw new ValidationException("Unsupported build_for value: {$build_for}"); + } $clone->build_for_enables[$build_for] = $build_function_name ?? "buildFor{$build_for}"; return $clone; } @@ -212,8 +231,8 @@ public function enableBuild(string|array $build_for, ?string $build_function_nam /** * Bind function executor. * - * @param string $func_name Function name - * @param ExecutorGenerator $executor Executor generator + * @param string $func_name Function name + * @param ExecutorGenerator $executor Executor generator */ public function addFunctionExecutorBinding(string $func_name, ExecutorGenerator $executor): static { @@ -222,10 +241,73 @@ public function addFunctionExecutorBinding(string $func_name, ExecutorGenerator return $clone; } + public function generatePackageClassFile(string $namespace, bool $uppercase = false): string + { + $printer = new class extends Printer { + public string $indentation = ' '; + }; + $file = new PhpFile(); + $namespace = $file->setStrictTypes()->addNamespace($namespace); + + $uses = []; + + // class name and package attribute + $class_name = str_replace('-', '_', $uppercase ? ucwords($this->package_name, '-') : $this->package_name); + $class_attribute = match ($this->type) { + 'library' => Library::class, + 'php-extension' => Extension::class, + 'target', 'virtual-target' => Target::class, + }; + $package_class = match ($this->type) { + 'library' => LibraryPackage::class, + 'php-extension' => PhpExtensionPackage::class, + 'target', 'virtual-target' => TargetPackage::class, + }; + $uses[] = $class_attribute; + $uses[] = $package_class; + $uses[] = BuildFor::class; + $uses[] = PackageInstaller::class; + + foreach ($uses as $use) { + $namespace->addUse($use); + } + + // add class attribute + $class = $namespace->addClass($class_name); + $class->addAttribute($class_attribute, [$this->package_name]); + + // add build functions if enabled + $funcs = []; + foreach ($this->build_for_enables as $os_family => $func_name) { + if ($func_name !== null) { + $funcs[$func_name][] = $os_family; + } + } + foreach ($funcs as $name => $oss) { + $method = $class->addMethod(name: $name ?: 'build') + ->setPublic() + ->setReturnType('void'); + // check if function executor is bound + if (isset($this->func_executor_binding[$name])) { + $executor = $this->func_executor_binding[$name]; + [$executor_use, $code] = $executor->generateCode(); + $namespace->addUse($executor_use); + $method->setBody($code); + } + $method->addParameter('package')->setType($package_class); + $method->addParameter('installer')->setType(PackageInstaller::class); + foreach ($oss as $os) { + $method->addAttribute(BuildFor::class, [$os]); + } + } + + return $printer->printFile($file); + } + /** * Generate package config */ - public function generateConfig(): array + public function generateConfigArray(): array { $config = ['type' => $this->type]; @@ -280,4 +362,51 @@ public function generateConfig(): array return $config; } + + public function setConfigFile(string $config_file): static + { + $clone = clone $this; + $clone->config_file = $config_file; + return $clone; + } + + public function writeConfigFile(): string + { + if ($this->config_file === null) { + throw new ValidationException('Config file path is not set.'); + } + $config_array = $this->generateConfigArray(); + $config_file_json = json_decode(FileSystem::readFile($this->config_file), true); + if (!is_array($config_file_json)) { + throw new ValidationException('Existing config file is not a valid JSON array.'); + } + $config_file_json[$this->package_name] = $config_array; + ksort($config_file_json); + $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + if ($json_content === false) { + throw new ValidationException('Failed to encode package config to JSON.'); + } + if (file_put_contents($this->config_file, $json_content) === false) { + throw new FileSystemException("Failed to write config file: {$this->config_file}"); + } + return $this->config_file; + } + + public function writeAll(): array + { + // write config + $package_config_file = $this->writeConfigFile(); + $artifact_config_file = $this->artifact->writeConfigFile(); + + // write class file + $package_class_file_content = $this->generatePackageClassFile('StaticPHP\Packages'); + $package_class_file_path = str_replace('-', '_', $this->package_name) . '.php'; + // file_put_contents($package_class_file_path, $package_class_file_content); // Uncomment this line to actually write the file + return [ + 'package_config' => $package_config_file, + 'artifact_config' => $artifact_config_file, + 'package_class_file' => $package_class_file_path, + 'package_class_content' => $package_class_file_content, + ]; + } } diff --git a/src/StaticPHP/Util/FileSystem.php b/src/StaticPHP/Util/FileSystem.php index 2f540d70d..1c21a92b5 100644 --- a/src/StaticPHP/Util/FileSystem.php +++ b/src/StaticPHP/Util/FileSystem.php @@ -472,6 +472,23 @@ public static function replaceFileLineContainsString(string $file, string $find, return file_put_contents($file, implode('', $lines)); } + /** + * Return full path, resolving relative paths against a base path. + * + * @param string $path Input path (relative or absolute) + * @param string $relative_path_base Base path for relative paths + */ + public static function fullpath(string $path, string $relative_path_base): string + { + if (FileSystem::isRelativePath($path)) { + $path = $relative_path_base . DIRECTORY_SEPARATOR . $path; + } + if (!file_exists($path)) { + throw new FileSystemException("Path does not exist: {$path}"); + } + return FileSystem::convertPath($path); + } + private static function replaceFile(string $filename, int $replace_type = REPLACE_FILE_STR, mixed $callback_or_search = null, mixed $to_replace = null): false|int { logger()->debug('Replacing file with type[' . $replace_type . ']: ' . $filename); diff --git a/src/StaticPHP/Util/InteractiveTerm.php b/src/StaticPHP/Util/InteractiveTerm.php index 1682ed1f6..0570f31c6 100644 --- a/src/StaticPHP/Util/InteractiveTerm.php +++ b/src/StaticPHP/Util/InteractiveTerm.php @@ -52,6 +52,7 @@ public static function plain(string $message, string $level = 'info'): void default => logger()->info(strip_ansi_colors($message)), }; } else { + $output = $level === 'error' && $output instanceof ConsoleOutput ? $output->getErrorOutput() : $output; $output->writeln(($no_ansi ? 'strip_ansi_colors' : 'strval')($message)); } } diff --git a/src/globals/defines.php b/src/globals/defines.php index 3e6d23605..dbcb63f22 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -96,13 +96,32 @@ const SPC_DOWNLOAD_TYPE_DISPLAY_NAME = [ 'bitbuckettag' => 'BitBucket', - 'filelist' => 'website', + 'filelist' => 'File index website', 'git' => 'git', 'ghrel' => 'GitHub release', - 'ghtar', 'ghtagtar' => 'GitHub tarball', + 'ghtar' => 'GitHub release tarball', + 'ghtagtar' => 'GitHub tag tarball', 'local' => 'local dir', - 'pie' => 'PHP Installer for Extensions', + 'pie' => 'PHP Installer for Extensions (PIE)', 'url' => 'url', 'php-release' => 'php.net', 'custom' => 'custom downloader', ]; + +const SUPPORTED_OS_CATEGORY = [ + 'unix', + 'windows', + 'linux', + 'macos', +]; + +const SUPPORTED_OS_FAMILY = [ + 'Linux', + 'Darwin', + 'Windows', +]; + +const SPC_MODE_SOURCE = 1; +const SPC_MODE_VENDOR = 2; +const SPC_MODE_PHAR = 4; +const SPC_MODE_VENDOR_PHAR = SPC_MODE_VENDOR | SPC_MODE_PHAR; diff --git a/src/globals/functions.php b/src/globals/functions.php index 93cd1ae09..bb22f3a71 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -10,6 +10,31 @@ use StaticPHP\Runtime\Shell\WindowsCmd; use ZM\Logger\ConsoleLogger; +/** + * Get the current SPC loading mode. If passed a mode to check, will return whether current mode matches the given mode. + */ +function spc_mode(?int $check_mode = null): bool|int +{ + $mode = SPC_MODE_SOURCE; + // if current file is in phar, then it's phar mode + if (str_starts_with(__FILE__, 'phar://') && Phar::running()) { + // judge whether it's vendor mode (inside vendor/) or source mode (inside src/) + if (basename(dirname(__FILE__, 3)) === 'static-php-cli' && basename(dirname(__FILE__, 5)) === 'vendor') { + $mode = SPC_MODE_VENDOR_PHAR; + } else { + $mode = SPC_MODE_PHAR; + } + } elseif (basename(dirname(__FILE__, 3)) === 'static-php-cli' && basename(dirname(__FILE__, 5)) === 'vendor') { + $mode = SPC_MODE_VENDOR; + } + + if ($check_mode === null) { + return $mode; + } + // use bitwise AND to check mode + return ($mode & $check_mode) !== 0; +} + /** * Judge if an array is an associative array */ From 9fdfef50574d6eed60d707e0f0d2a304c7c7825d Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Thu, 18 Dec 2025 21:21:47 +0800 Subject: [PATCH 28/73] macOS don't need to disable avx2 explicitly (#1007) --- src/SPC/ConsoleApplication.php | 2 +- src/SPC/builder/unix/library/libwebp.php | 2 +- src/globals/test-extensions.php | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 7fc56ae3c..9500a231a 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -34,7 +34,7 @@ */ final class ConsoleApplication extends Application { - public const string VERSION = '2.7.10'; + public const string VERSION = '2.7.11'; public function __construct() { diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 47fd0078c..068185829 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -13,7 +13,7 @@ protected function build(): void $code = 'int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }'; $cc = getenv('CC') ?: 'gcc'; [$ret] = shell()->execWithResult("echo '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1"); - $disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64'; + $disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64' && PHP_OS_FAMILY === 'Linux'; UnixCMakeExecutor::create($this) ->addConfigureArgs( diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 72e751244..cdd27e235 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -23,13 +23,13 @@ // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - // 'macos-15-intel', // bin/spc for x86_64 + 'macos-15-intel', // bin/spc for x86_64 // 'macos-15', // bin/spc for arm64 // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 - 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 - 'ubuntu-24.04', // bin/spc for x86_64 - 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 - 'ubuntu-24.04-arm', // bin/spc for arm64 + // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 + // 'ubuntu-24.04', // bin/spc for x86_64 + // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 + // 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 // 'windows-2025', ]; From 656a58c3fad9e5c4075ba9fd79c7ec4830e0048f Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 09:58:45 +0100 Subject: [PATCH 29/73] remove source dir after successful build in CI environment --- src/SPC/builder/LibraryBase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index c88e8d96c..0018868fa 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -195,6 +195,9 @@ public function tryBuild(bool $force_build = false): int $this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build'); $this->build(); $this->installLicense(); + if (getenv('CI')) { + FileSystem::removeDir($this->source_dir); + } $this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build'); return LIB_STATUS_OK; } From 024745885321448a70cdfc7e0a9b514a1bae21cf Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 11:06:21 +0100 Subject: [PATCH 30/73] we were installing to wrong dir if source name != lib name --- src/SPC/builder/LibraryBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index 0018868fa..9d676b245 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -357,11 +357,11 @@ protected function installLicense(): void } foreach ($license_files as $index => $license) { if ($license['type'] === 'text') { - FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']); + FileSystem::writeFile(BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt", $license['text']); continue; } if ($license['type'] === 'file') { - copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt"); + copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt"); } } } From ce44e00bd40afeb03d7a27671510f1b6846d3a85 Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 12:35:06 +0100 Subject: [PATCH 31/73] @crazywhalecc how to use patch points to delete source dirs? --- src/SPC/builder/Extension.php | 3 +++ src/SPC/builder/LibraryBase.php | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 08b403e61..0df87e912 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -385,6 +385,9 @@ public function buildShared(array $visited = []): void logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)'); return; } + if (Config::getExt($this->getName(), 'type') === 'addon') { + return; + } logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)'); foreach ($this->dependencies as $dependency) { if (!$dependency instanceof Extension) { diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index 9d676b245..81abceee0 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -184,21 +184,21 @@ public function tryBuild(bool $force_build = false): int // extract first if not exists if (!is_dir($this->source_dir)) { - $this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract'); + $this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-extract'); SourceManager::initSource(libs: [static::NAME], source_only: true); - $this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract'); + $this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-extract'); } if (!$this->patched && $this->patchBeforeBuild()) { file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!'); } - $this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build'); + $this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-build'); $this->build(); $this->installLicense(); if (getenv('CI')) { FileSystem::removeDir($this->source_dir); } - $this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build'); + $this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-build'); return LIB_STATUS_OK; } @@ -349,8 +349,8 @@ protected function getSnakeCaseName(): string */ protected function installLicense(): void { - FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName()); $source = Config::getLib($this->getName(), 'source'); + FileSystem::createDir(BUILD_ROOT_PATH . "/source-licenses/{$source}"); $license_files = Config::getSource($source)['license'] ?? []; if (is_assoc_array($license_files)) { $license_files = [$license_files]; From 037d224fd7d6bfbb6b82b314d1d68d5668421d5e Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 12:38:17 +0100 Subject: [PATCH 32/73] why does phpstan think this is necessary? --- src/SPC/builder/Extension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 0df87e912..e79b886bf 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -385,7 +385,7 @@ public function buildShared(array $visited = []): void logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)'); return; } - if (Config::getExt($this->getName(), 'type') === 'addon') { + if ((string) Config::getExt($this->getName(), 'type') === 'addon') { return; } logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)'); From e677be74d7e1f85d5503a285f4fd8998e4c8428f Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 13:07:21 +0100 Subject: [PATCH 33/73] remove --- src/SPC/builder/LibraryBase.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index 81abceee0..d34663021 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -195,9 +195,6 @@ public function tryBuild(bool $force_build = false): int $this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-build'); $this->build(); $this->installLicense(); - if (getenv('CI')) { - FileSystem::removeDir($this->source_dir); - } $this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-build'); return LIB_STATUS_OK; } From 9e051c8c8068bb97a2c0533a78fa82cceab70dab Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 14:52:02 +0100 Subject: [PATCH 34/73] fix: check for link first before checking for is_dir --- src/SPC/store/FileSystem.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index f6c538bdf..1d0815ce2 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -408,13 +408,13 @@ public static function removeDir(string $dir): bool continue; } $sub_file = self::convertPath($dir . '/' . $v); - if (is_dir($sub_file)) { - # 如果是 目录 且 递推 , 则递推添加下级文件 - if (!self::removeDir($sub_file)) { + if (is_link($sub_file) || is_file($sub_file)) { + if (!unlink($sub_file)) { return false; } - } elseif (is_link($sub_file) || is_file($sub_file)) { - if (!unlink($sub_file)) { + } elseif (is_dir($sub_file)) { + # 如果是 目录 且 递推 , 则递推添加下级文件 + if (!self::removeDir($sub_file)) { return false; } } From e1a14bbb9fa9522ccfde72f8e69d689b6c158ca6 Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 17:39:05 +0100 Subject: [PATCH 35/73] fix implicit include --- src/SPC/builder/unix/library/libwebp.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index 068185829..015fa73ba 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -10,9 +10,10 @@ trait libwebp { protected function build(): void { - $code = 'int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }'; + $code = '#include +int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }'; $cc = getenv('CC') ?: 'gcc'; - [$ret] = shell()->execWithResult("echo '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1"); + [$ret] = shell()->execWithResult("printf '%s' '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1"); $disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64' && PHP_OS_FAMILY === 'Linux'; UnixCMakeExecutor::create($this) From 53f7cdefe0e791d621d86cc2ce6938d228ec3b19 Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 18 Dec 2025 20:12:01 +0100 Subject: [PATCH 36/73] fix swoole compilation with php 8.5.1 --- src/SPC/builder/extension/swoole.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index f6ff5931d..4e292a362 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -17,6 +17,7 @@ class swoole extends Extension public function patchBeforeMake(): bool { $patched = parent::patchBeforeMake(); + FileSystem::replaceFileStr($this->source_dir . '/ext-src/php_swoole_private.h', 'PHP_VERSION_ID > 80500', 'PHP_VERSION_ID >= 80600'); if ($this->builder instanceof MacOSBuilder) { // Fix swoole with event extension conflict bug $util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h'; From 6b5200002e6d744a450038e982c3c88d386ef3e6 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 20 Dec 2025 23:29:25 +0100 Subject: [PATCH 37/73] fix downloader selecting drafts --- composer.lock | 428 ++++++++++++++++++----------------- src/SPC/store/Downloader.php | 3 + 2 files changed, 224 insertions(+), 207 deletions(-) diff --git a/composer.lock b/composer.lock index e8f320c7c..a69833c7c 100644 --- a/composer.lock +++ b/composer.lock @@ -8,7 +8,7 @@ "packages": [ { "name": "illuminate/collections", - "version": "v11.46.1", + "version": "v11.47.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -64,7 +64,7 @@ }, { "name": "illuminate/conditionable", - "version": "v11.46.1", + "version": "v11.47.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -110,16 +110,16 @@ }, { "name": "illuminate/contracts", - "version": "v11.46.1", + "version": "v11.47.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "4b2a67d1663f50085bc91e6371492697a5d2d4e8" + "reference": "4787042340aae19a7ea0fa82f4073c4826204a48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/4b2a67d1663f50085bc91e6371492697a5d2d4e8", - "reference": "4b2a67d1663f50085bc91e6371492697a5d2d4e8", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/4787042340aae19a7ea0fa82f4073c4826204a48", + "reference": "4787042340aae19a7ea0fa82f4073c4826204a48", "shasum": "" }, "require": { @@ -154,11 +154,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-03-24T11:54:20+00:00" + "time": "2025-11-27T16:16:07+00:00" }, { "name": "illuminate/macroable", - "version": "v11.46.1", + "version": "v11.47.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -416,16 +416,16 @@ }, { "name": "symfony/console", - "version": "v7.3.6", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", "shasum": "" }, "require": { @@ -433,7 +433,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -447,16 +447,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -490,7 +490,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.6" + "source": "https://github.com/symfony/console/tree/v7.4.1" }, "funding": [ { @@ -510,7 +510,7 @@ "type": "tidelift" } ], - "time": "2025-11-04T01:21:42+00:00" + "time": "2025-12-05T15:23:39+00:00" }, { "name": "symfony/deprecation-contracts", @@ -916,16 +916,16 @@ }, { "name": "symfony/process", - "version": "v7.3.4", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", + "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", "shasum": "" }, "require": { @@ -957,7 +957,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.4" + "source": "https://github.com/symfony/process/tree/v7.4.0" }, "funding": [ { @@ -977,7 +977,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-10-16T11:21:06+00:00" }, { "name": "symfony/service-contracts", @@ -1068,34 +1068,34 @@ }, { "name": "symfony/string", - "version": "v7.3.4", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc", + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -1134,7 +1134,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/string/tree/v8.0.1" }, "funding": [ { @@ -1154,32 +1154,32 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.5", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc", - "reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -1210,7 +1210,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.5" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -1230,7 +1230,7 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2025-12-04T18:11:45+00:00" }, { "name": "zhamao/logger", @@ -1615,16 +1615,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.2", + "version": "v2.3.3", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", + "url": "https://api.github.com/repos/amphp/parallel/zipball/296b521137a54d3a02425b464e5aee4c93db2c60", + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60", "shasum": "" }, "require": { @@ -1687,7 +1687,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.2" + "source": "https://github.com/amphp/parallel/tree/v2.3.3" }, "funding": [ { @@ -1695,7 +1695,7 @@ "type": "github" } ], - "time": "2025-08-27T21:55:40+00:00" + "time": "2025-11-15T06:23:42+00:00" }, { "name": "amphp/parser", @@ -2113,7 +2113,7 @@ }, { "name": "captainhook/captainhook-phar", - "version": "5.25.11", + "version": "5.27.3", "source": { "type": "git", "url": "https://github.com/captainhook-git/captainhook-phar.git", @@ -2167,7 +2167,7 @@ ], "support": { "issues": "https://github.com/captainhook-git/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.11" + "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.27.3" }, "funding": [ { @@ -2864,16 +2864,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.89.2", + "version": "v3.92.3", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7569658f91e475ec93b99bd5964b059ad1336dcf" + "reference": "2ba8f5a60f6f42fb65758cfb3768434fa2d1c7e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7569658f91e475ec93b99bd5964b059ad1336dcf", - "reference": "7569658f91e475ec93b99bd5964b059ad1336dcf", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2ba8f5a60f6f42fb65758cfb3768434fa2d1c7e8", + "reference": "2ba8f5a60f6f42fb65758cfb3768434fa2d1c7e8", "shasum": "" }, "require": { @@ -2891,17 +2891,17 @@ "react/socket": "^1.16", "react/stream": "^1.4", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.33", "symfony/polyfill-php80": "^1.33", "symfony/polyfill-php81": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0" + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.7", @@ -2913,8 +2913,9 @@ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34", - "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2", - "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2" + "symfony/polyfill-php85": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2 || ^8.0", + "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2 || ^8.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -2929,7 +2930,7 @@ "PhpCsFixer\\": "src/" }, "exclude-from-classmap": [ - "src/Fixer/Internal/*" + "src/**/Internal/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2955,7 +2956,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.2" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.92.3" }, "funding": [ { @@ -2963,7 +2964,7 @@ "type": "github" } ], - "time": "2025-11-06T21:12:50+00:00" + "time": "2025-12-18T10:45:02+00:00" }, { "name": "humbug/box", @@ -3212,21 +3213,21 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.1", + "version": "6.6.3", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396" + "reference": "134e98916fa2f663afa623970af345cd788e8967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", - "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/134e98916fa2f663afa623970af345cd788e8967", + "reference": "134e98916fa2f663afa623970af345cd788e8967", "shasum": "" }, "require": { "ext-json": "*", - "marc-mabe/php-enum": "^4.0", + "marc-mabe/php-enum": "^4.4", "php": "^7.2 || ^8.0" }, "require-dev": { @@ -3281,9 +3282,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.1" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.3" }, - "time": "2025-11-07T18:30:29+00:00" + "time": "2025-12-02T10:21:33+00:00" }, { "name": "kelunik/certificate", @@ -3345,33 +3346,38 @@ }, { "name": "league/uri", - "version": "7.5.1", + "version": "7.7.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/8d587cddee53490f9b82bf203d3a9aa7ea4f9807", + "reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "league/uri-interfaces": "^7.7", + "php": "^8.1", + "psr/http-factory": "^1" }, "conflict": { "league/uri-schemes": "^1.0" }, "suggest": { "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", + "ext-uri": "to use the PHP native URI class", "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", "league/uri-components": "Needed to easily manipulate URI objects components", + "league/uri-polyfill": "Needed to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle WHATWG URL", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3399,6 +3405,7 @@ "description": "URI manipulation library", "homepage": "https://uri.thephpleague.com", "keywords": [ + "URN", "data-uri", "file-uri", "ftp", @@ -3411,9 +3418,11 @@ "psr-7", "query-string", "querystring", + "rfc2141", "rfc3986", "rfc3987", "rfc6570", + "rfc8141", "uri", "uri-template", "url", @@ -3423,7 +3432,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "source": "https://github.com/thephpleague/uri/tree/7.7.0" }, "funding": [ { @@ -3431,26 +3440,25 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2025-12-07T16:02:06+00:00" }, { "name": "league/uri-interfaces", - "version": "7.5.0", + "version": "7.7.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/62ccc1a0435e1c54e10ee6022df28d6c04c2946c", + "reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c", "shasum": "" }, "require": { "ext-filter": "*", "php": "^8.1", - "psr/http-factory": "^1", "psr/http-message": "^1.1 || ^2.0" }, "suggest": { @@ -3458,6 +3466,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle WHATWG URL", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3482,7 +3491,7 @@ "homepage": "https://nyamsprod.com" } ], - "description": "Common interfaces and classes for URI representation and interaction", + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", "homepage": "https://uri.thephpleague.com", "keywords": [ "data-uri", @@ -3507,7 +3516,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.7.0" }, "funding": [ { @@ -3515,7 +3524,7 @@ "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2025-12-07T16:03:21+00:00" }, { "name": "marc-mabe/php-enum", @@ -3704,16 +3713,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -3756,9 +3765,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "phar-io/composer-distributor", @@ -4147,16 +4156,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.3", + "version": "5.6.5", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" + "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90614c73d3800e187615e2dd236ad0e2a01bf761", + "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761", "shasum": "" }, "require": { @@ -4205,22 +4214,22 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.5" }, - "time": "2025-08-01T19:43:32+00:00" + "time": "2025-11-27T19:50:05+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.10.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195", + "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195", "shasum": "" }, "require": { @@ -4263,9 +4272,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0" }, - "time": "2024-11-09T15:12:26+00:00" + "time": "2025-11-21T15:09:14+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -4690,16 +4699,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.58", + "version": "10.5.60", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca" + "reference": "f2e26f52f80ef77832e359205f216eeac00e320c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f2e26f52f80ef77832e359205f216eeac00e320c", + "reference": "f2e26f52f80ef77832e359205f216eeac00e320c", "shasum": "" }, "require": { @@ -4771,7 +4780,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.60" }, "funding": [ { @@ -4795,7 +4804,7 @@ "type": "tidelift" } ], - "time": "2025-09-28T12:04:46+00:00" + "time": "2025-12-06T07:50:42+00:00" }, { "name": "psr/event-dispatcher", @@ -5104,16 +5113,16 @@ }, { "name": "react/dns", - "version": "v1.13.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/reactphp/dns.git", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", "shasum": "" }, "require": { @@ -5168,7 +5177,7 @@ ], "support": { "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.13.0" + "source": "https://github.com/reactphp/dns/tree/v1.14.0" }, "funding": [ { @@ -5176,20 +5185,20 @@ "type": "open_collective" } ], - "time": "2024-06-13T14:18:03+00:00" + "time": "2025-11-18T19:34:28+00:00" }, { "name": "react/event-loop", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", "shasum": "" }, "require": { @@ -5240,7 +5249,7 @@ ], "support": { "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" }, "funding": [ { @@ -5248,7 +5257,7 @@ "type": "open_collective" } ], - "time": "2023-11-13T13:48:05+00:00" + "time": "2025-11-17T20:46:25+00:00" }, { "name": "react/promise", @@ -5325,16 +5334,16 @@ }, { "name": "react/socket", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", "shasum": "" }, "require": { @@ -5393,7 +5402,7 @@ ], "support": { "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.16.0" + "source": "https://github.com/reactphp/socket/tree/v1.17.0" }, "funding": [ { @@ -5401,7 +5410,7 @@ "type": "open_collective" } ], - "time": "2024-07-26T10:38:09+00:00" + "time": "2025-11-19T20:47:34+00:00" }, { "name": "react/stream", @@ -5483,16 +5492,16 @@ }, { "name": "revolt/event-loop", - "version": "v1.0.7", + "version": "v1.0.8", "source": { "type": "git", "url": "https://github.com/revoltphp/event-loop.git", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c", + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c", "shasum": "" }, "require": { @@ -5549,9 +5558,9 @@ ], "support": { "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8" }, - "time": "2025-01-25T19:27:39+00:00" + "time": "2025-08-27T21:33:23+00:00" }, { "name": "sebastian/cli-parser", @@ -6620,24 +6629,24 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "573f95783a2ec6e38752979db139f09fec033f03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03", + "reference": "573f95783a2ec6e38752979db139f09fec033f03", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<6.4", + "symfony/security-http": "<7.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -6646,13 +6655,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -6680,7 +6690,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0" }, "funding": [ { @@ -6700,7 +6710,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2025-10-30T14:17:19+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6780,16 +6790,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.3.6", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" + "reference": "d551b38811096d0be9c4691d406991b47c0c630a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", - "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", + "reference": "d551b38811096d0be9c4691d406991b47c0c630a", "shasum": "" }, "require": { @@ -6798,7 +6808,7 @@ "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6826,7 +6836,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.6" + "source": "https://github.com/symfony/filesystem/tree/v7.4.0" }, "funding": [ { @@ -6846,27 +6856,27 @@ "type": "tidelift" } ], - "time": "2025-11-05T09:52:27+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/finder", - "version": "v7.3.5", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f" + "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f", + "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", + "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6894,7 +6904,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.5" + "source": "https://github.com/symfony/finder/tree/v7.4.0" }, "funding": [ { @@ -6914,24 +6924,24 @@ "type": "tidelift" } ], - "time": "2025-10-15T18:45:57+00:00" + "time": "2025-11-05T05:42:40+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.3.3", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7", + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -6965,7 +6975,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" + "source": "https://github.com/symfony/options-resolver/tree/v8.0.0" }, "funding": [ { @@ -6985,7 +6995,7 @@ "type": "tidelift" } ], - "time": "2025-08-05T10:16:07+00:00" + "time": "2025-11-12T15:55:31+00:00" }, { "name": "symfony/polyfill-iconv", @@ -7153,20 +7163,20 @@ }, { "name": "symfony/stopwatch", - "version": "v7.3.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/67df1914c6ccd2d7b52f70d40cf2aea02159d942", + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942", "shasum": "" }, "require": { - "php": ">=8.2", + "php": ">=8.4", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -7195,7 +7205,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v8.0.0" }, "funding": [ { @@ -7206,25 +7216,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-24T10:49:57+00:00" + "time": "2025-08-04T07:36:47+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.5", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d" + "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece", + "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece", "shasum": "" }, "require": { @@ -7236,10 +7250,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -7278,7 +7292,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.5" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.0" }, "funding": [ { @@ -7298,7 +7312,7 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2025-10-27T20:36:44+00:00" }, { "name": "thecodingmachine/safe", @@ -7441,16 +7455,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -7479,7 +7493,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.3.0" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -7487,7 +7501,7 @@ "type": "github" } ], - "time": "2025-11-13T13:44:09+00:00" + "time": "2025-11-17T20:03:58+00:00" }, { "name": "webmozart/assert", diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index 63bec8075..a2911e46b 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -108,6 +108,9 @@ public static function getLatestGithubTarball(string $name, array $source, strin if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) { continue; } + if (($rel['draft'] ?? false) === true && (($source['prefer-stable'] ?? false) || !$rel['tarball_url'])) { + continue; + } if (!($source['match'] ?? null)) { $url = $rel['tarball_url'] ?? null; break; From f7ca621efec86cd5f24ec69410ac86d7644e0cf8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 26 Dec 2025 15:03:54 +0800 Subject: [PATCH 38/73] Test --- src/globals/test-extensions.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index cdd27e235..0402eaf37 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,10 +13,10 @@ // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - // '8.1', + '8.1', // '8.2', // '8.3', - // '8.4', + '8.4', '8.5', // 'git', ]; @@ -24,10 +24,10 @@ // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ 'macos-15-intel', // bin/spc for x86_64 - // 'macos-15', // bin/spc for arm64 - // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 - // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 - // 'ubuntu-24.04', // bin/spc for x86_64 + 'macos-15', // bin/spc for arm64 + 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 + 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 + 'ubuntu-24.04', // bin/spc for x86_64 // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 // 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 @@ -50,7 +50,7 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imagick', + 'Linux', 'Darwin' => 'swoole,imagick', 'Windows' => 'bcmath', }; From 8650ce4f8ff7c61ce47eb80a648b1ea386f0d1c2 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Fri, 26 Dec 2025 17:15:45 +0800 Subject: [PATCH 39/73] Add MACOSX_DEPLOYMENT_TARGET to env.ini (#1009) --- config/env.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/env.ini b/config/env.ini index 7448cc373..4b0795f8e 100644 --- a/config/env.ini +++ b/config/env.ini @@ -142,6 +142,8 @@ SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable- SPC_CMD_VAR_PHP_EMBED_TYPE="static" ; EXTRA_CFLAGS for `configure` and `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Werror=unknown-warning-option ${SPC_DEFAULT_C_FLAGS}" +; minimum compatible macOS version (LLVM vars, availability not guaranteed) +MACOSX_DEPLOYMENT_TARGET=12.0 [freebsd] ; compiler environments From 9a681a9fa6249130bddcb7d342761f389c8d49ef Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 27 Dec 2025 21:19:31 +0100 Subject: [PATCH 40/73] add mariadb mysqlnd plugins --- config/ext.json | 30 +++++++++++++++++++ config/source.json | 18 +++++++++++ src/SPC/builder/extension/mysqlnd_ed25519.php | 22 ++++++++++++++ src/SPC/builder/extension/mysqlnd_parsec.php | 22 ++++++++++++++ src/globals/test-extensions.php | 10 +++---- 5 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/SPC/builder/extension/mysqlnd_ed25519.php create mode 100644 src/SPC/builder/extension/mysqlnd_parsec.php diff --git a/config/ext.json b/config/ext.json index d3fd2aa27..78a0ea38a 100644 --- a/config/ext.json +++ b/config/ext.json @@ -487,6 +487,36 @@ "zlib" ] }, + "mysqlnd_ed25519": { + "type": "external", + "source": "mysqlnd_ed25519", + "arg-type": "enable", + "target": [ + "shared" + ], + "ext-depends": [ + "mysqlnd" + ], + "lib-depends": [ + "libsodium", + "openssl" + ] + }, + "mysqlnd_parsec": { + "type": "external", + "source": "mysqlnd_parsec", + "arg-type": "enable", + "target": [ + "shared" + ], + "ext-depends": [ + "mysqlnd" + ], + "lib-depends": [ + "libsodium", + "openssl" + ] + }, "oci8": { "type": "wip", "support": { diff --git a/config/source.json b/config/source.json index c96822d6b..255d95848 100644 --- a/config/source.json +++ b/config/source.json @@ -871,6 +871,24 @@ "path": "LICENSE" } }, + "mysqlnd_ed25519": { + "type": "pie", + "repo": "mariadb/mysqlnd_ed25519", + "path": "php-src/ext/mysqlnd_ed25519", + "license": { + "type": "file", + "path": "LICENSE" + } + }, + "mysqlnd_parsec": { + "type": "pie", + "repo": "mariadb/mysqlnd_parsec", + "path": "php-src/ext/mysqlnd_parsec", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "ncurses": { "type": "filelist", "url": "https://ftp.gnu.org/pub/gnu/ncurses/", diff --git a/src/SPC/builder/extension/mysqlnd_ed25519.php b/src/SPC/builder/extension/mysqlnd_ed25519.php new file mode 100644 index 000000000..7b2b4abcd --- /dev/null +++ b/src/SPC/builder/extension/mysqlnd_ed25519.php @@ -0,0 +1,22 @@ +getConfigureArg(); + } +} diff --git a/src/SPC/builder/extension/mysqlnd_parsec.php b/src/SPC/builder/extension/mysqlnd_parsec.php new file mode 100644 index 000000000..d044b1c52 --- /dev/null +++ b/src/SPC/builder/extension/mysqlnd_parsec.php @@ -0,0 +1,22 @@ +getConfigureArg(); + } +} diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 0402eaf37..d76153e49 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,9 +13,9 @@ // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - '8.1', - // '8.2', - // '8.3', + // '8.1', + '8.2', + '8.3', '8.4', '8.5', // 'git', @@ -50,13 +50,13 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'swoole,imagick', + 'Linux', 'Darwin' => 'mysqli', 'Windows' => 'bcmath', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => '', + 'Linux' => 'mysqlnd_parsec,mysqlnd_ed25519', 'Darwin' => '', 'Windows' => '', }; From 09b89a30f925510c4cd039a83bb0908390496d81 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 27 Dec 2025 22:20:02 +0100 Subject: [PATCH 41/73] WIP: use system libraries for grpc without building our own grpc lib --- src/SPC/builder/LibraryBase.php | 11 ++++++++- src/SPC/builder/traits/UnixLibraryTrait.php | 2 +- src/SPC/util/SPCConfigUtil.php | 26 +++++++++++++++++---- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index d34663021..383faa41a 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -375,8 +375,17 @@ protected function isLibraryInstalled(): bool return false; } } + $pkg_config_path = getenv('PKG_CONFIG_PATH') ?: ''; + $search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path)); foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) { - if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) { + $found = false; + foreach ($search_paths as $path) { + if (file_exists($path . "/{$name}.pc")) { + $found = true; + break; + } + } + if (!$found) { return false; } } diff --git a/src/SPC/builder/traits/UnixLibraryTrait.php b/src/SPC/builder/traits/UnixLibraryTrait.php index 868cf6f7b..ec1e7c2be 100644 --- a/src/SPC/builder/traits/UnixLibraryTrait.php +++ b/src/SPC/builder/traits/UnixLibraryTrait.php @@ -34,7 +34,7 @@ public function patchPkgconfPrefix(array $files = [], int $patch_option = PKGCON $files = array_map(fn ($x) => "{$x}.pc", $conf_pc); } foreach ($files as $name) { - $realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name); + $realpath = realpath(BUILD_LIB_PATH . '/pkgconfig/' . $name); if ($realpath === false) { throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !'); } diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index a74d6a24c..7d2001f52 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -226,9 +226,17 @@ private function getIncludesString(array $libraries): string // parse pkg-configs foreach ($libraries as $library) { $pc = Config::getLib($library, 'pkg-configs', []); + $pkg_config_path = getenv('PKG_CONFIG_PATH') ?: ''; + $search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path)); foreach ($pc as $file) { - if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$file}.pc")) { - throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); + $found = false; + foreach ($search_paths as $path) { + if (file_exists($path . "/{$file}.pc")) { + $found = true; + } + } + if (!$found) { + throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist. Please build it first."); } } $pc_cflags = implode(' ', $pc); @@ -257,9 +265,17 @@ private function getLibsString(array $libraries, bool $use_short_libs = true): s foreach ($libraries as $library) { // add pkg-configs libs $pkg_configs = Config::getLib($library, 'pkg-configs', []); - foreach ($pkg_configs as $pkg_config) { - if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$pkg_config}.pc")) { - throw new WrongUsageException("pkg-config file '{$pkg_config}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); + $pkg_config_path = getenv('PKG_CONFIG_PATH') ?: ''; + $search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path)); + foreach ($pkg_configs as $file) { + $found = false; + foreach ($search_paths as $path) { + if (file_exists($path . "/{$file}.pc")) { + $found = true; + } + } + if (!$found) { + throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist. Please build it first."); } } $pkg_configs = implode(' ', $pkg_configs); From e952f1c76abf73703f0b160306e90c109e75d0eb Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 27 Dec 2025 22:36:24 +0100 Subject: [PATCH 42/73] we don't even need to build grpc library for grpc extension... --- config/ext.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/ext.json b/config/ext.json index 78a0ea38a..e5f4d7706 100644 --- a/config/ext.json +++ b/config/ext.json @@ -236,7 +236,9 @@ "arg-type-unix": "enable-path", "cpp-extension": true, "lib-depends": [ - "grpc" + "zlib", + "openssl", + "libcares" ] }, "iconv": { From 5ef46230513bf6b44634c01752bad1412dfd1238 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 27 Dec 2025 23:05:35 +0100 Subject: [PATCH 43/73] grpc will fail for php 8.5, it's not updated yet --- src/globals/test-extensions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index d76153e49..d9202e08d 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -56,7 +56,7 @@ // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => 'mysqlnd_parsec,mysqlnd_ed25519', + 'Linux' => 'grpc,mysqlnd_parsec,mysqlnd_ed25519', 'Darwin' => '', 'Windows' => '', }; From 93a35908de867c9784cfafe59a257ba0e7b704bb Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 28 Dec 2025 12:11:56 +0100 Subject: [PATCH 44/73] factor grpc extension out to ext-grpc, keep library for now, even though unused --- config/ext.json | 2 +- config/source.json | 12 ++++++++++++ src/SPC/builder/extension/grpc.php | 9 --------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/config/ext.json b/config/ext.json index e5f4d7706..62ec48772 100644 --- a/config/ext.json +++ b/config/ext.json @@ -232,7 +232,7 @@ "BSD": "wip" }, "type": "external", - "source": "grpc", + "source": "ext-grpc", "arg-type-unix": "enable-path", "cpp-extension": true, "lib-depends": [ diff --git a/config/source.json b/config/source.json index 255d95848..530e4703d 100644 --- a/config/source.json +++ b/config/source.json @@ -151,6 +151,18 @@ "path": "LICENSE" } }, + "ext-grpc": { + "type": "url", + "url": "https://pecl.php.net/get/grpc", + "path": "php-src/ext/grpc", + "filename": "grpc.tgz", + "license": { + "type": "file", + "path": [ + "LICENSE" + ] + } + }, "ext-imagick": { "type": "url", "url": "https://pecl.php.net/get/imagick", diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php index fb31c85fe..ce8243d00 100644 --- a/src/SPC/builder/extension/grpc.php +++ b/src/SPC/builder/extension/grpc.php @@ -21,15 +21,6 @@ public function patchBeforeBuildconf(): bool if ($this->builder instanceof WindowsBuilder) { throw new ValidationException('grpc extension does not support windows yet'); } - if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) { - return false; - } - // soft link to the grpc source code - if (is_dir($this->source_dir . '/src/php/ext/grpc')) { - shell()->exec('ln -s ' . $this->source_dir . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc'); - } else { - throw new ValidationException('Cannot find grpc source code in ' . $this->source_dir . '/src/php/ext/grpc'); - } if (SPCTarget::getTargetOS() === 'Darwin') { FileSystem::replaceFileRegex( SOURCE_PATH . '/php-src/ext/grpc/config.m4', From 2f3122627e054d51ed131c5f80a4972c434e8662 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 28 Dec 2025 12:44:24 +0100 Subject: [PATCH 45/73] make grpc php 8.5 compatible --- src/SPC/builder/extension/grpc.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php index ce8243d00..42dcdd5b8 100644 --- a/src/SPC/builder/extension/grpc.php +++ b/src/SPC/builder/extension/grpc.php @@ -21,9 +21,14 @@ public function patchBeforeBuildconf(): bool if ($this->builder instanceof WindowsBuilder) { throw new ValidationException('grpc extension does not support windows yet'); } + FileSystem::replaceFileStr( + $this->source_dir . '/src/php/ext/grpc/call.c', + 'zend_exception_get_default(TSRMLS_C),', + 'zend_ce_exception,', + ); if (SPCTarget::getTargetOS() === 'Darwin') { FileSystem::replaceFileRegex( - SOURCE_PATH . '/php-src/ext/grpc/config.m4', + $this->source_dir . '/config.m4', '/GRPC_LIBDIR=.*$/m', 'GRPC_LIBDIR=' . BUILD_LIB_PATH . "\n" . 'LDFLAGS="$LDFLAGS -framework CoreFoundation"' ); From e7a88f1df76956297d19db09dcd3e22812162aa7 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 29 Dec 2025 21:15:53 +0100 Subject: [PATCH 46/73] enable fat for gmp when next version releases --- src/SPC/builder/unix/library/gmp.php | 4 +++- src/globals/test-extensions.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index f625274f6..97a88ba1c 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -14,7 +14,9 @@ protected function build(): void ->appendEnv([ 'CFLAGS' => '-std=c17', ]) - ->configure() + ->configure( + '--enable-fat' + ) ->make(); $this->patchPkgconfPrefix(['gmp.pc']); } diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index d9202e08d..e2186c8e4 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -50,7 +50,7 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'mysqli', + 'Linux', 'Darwin' => 'mysqli,gmp', 'Windows' => 'bcmath', }; From 08388c0b153bd9e96b77c543a468ec46cdf99ad8 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 29 Dec 2025 22:12:25 +0100 Subject: [PATCH 47/73] force enable tailcall vm with zig --- src/SPC/toolchain/ZigToolchain.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/toolchain/ZigToolchain.php b/src/SPC/toolchain/ZigToolchain.php index bb423db20..212a158f7 100644 --- a/src/SPC/toolchain/ZigToolchain.php +++ b/src/SPC/toolchain/ZigToolchain.php @@ -65,9 +65,11 @@ public function afterInit(): void GlobalEnvManager::putenv("SPC_EXTRA_LIBS={$extra_libs}"); } $cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: ''; + GlobalEnvManager::putenv('SPC_EXTRA_PHP_VARS=php_cv_preserve_none=yes'); $has_avx512 = str_contains($cflags, '-mavx512') || str_contains($cflags, '-march=x86-64-v4'); if (!$has_avx512) { - GlobalEnvManager::putenv('SPC_EXTRA_PHP_VARS=php_cv_have_avx512=no php_cv_have_avx512vbmi=no'); + $extra_vars = getenv('SPC_EXTRA_PHP_VARS') ?: ''; + GlobalEnvManager::putenv("SPC_EXTRA_PHP_VARS=php_cv_have_avx512=no php_cv_have_avx512vbmi=no {$extra_vars}"); } } From 7688a556562ed4200255e820d64695cdd601d39a Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 29 Dec 2025 22:16:53 +0100 Subject: [PATCH 48/73] don't get zig master branch --- src/SPC/store/pkg/Zig.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/SPC/store/pkg/Zig.php b/src/SPC/store/pkg/Zig.php index e9865dbe3..c2a81c0da 100644 --- a/src/SPC/store/pkg/Zig.php +++ b/src/SPC/store/pkg/Zig.php @@ -72,8 +72,11 @@ public function fetch(string $name, bool $force = false, ?array $config = null): $latest_version = null; foreach ($index_json as $version => $data) { - $latest_version = $version; - break; + // Skip the master branch, get the latest stable release + if ($version !== 'master') { + $latest_version = $version; + break; + } } if (!$latest_version) { From 022fdb2fc5b8ed2d78c0cac972fe4d9cd5f2d7d4 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 29 Dec 2025 23:58:54 +0100 Subject: [PATCH 49/73] fix no-strip --- src/SPC/builder/unix/UnixBuilderBase.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index d98059cb0..e2507f1f4 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -145,11 +145,10 @@ public function deployBinary(string $src, string $dst, bool $executable = true): throw new SPCInternalException("Deploy failed. Cannot find file after copy: {$dst}"); } - // extract debug info - $this->extractDebugInfo($dst); - - // strip if (!$this->getOption('no-strip')) { + // extract debug info + $this->extractDebugInfo($dst); + // extra strip $this->stripBinary($dst); } From a06cc3249169c3c1e7c76c6c9a8d53c075924882 Mon Sep 17 00:00:00 2001 From: henderkes Date: Tue, 30 Dec 2025 11:58:57 +0100 Subject: [PATCH 50/73] pin libpng to released tags, not git --- config/source.json | 13 +++++++------ src/SPC/store/Downloader.php | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/config/source.json b/config/source.json index 530e4703d..1bae46ce7 100644 --- a/config/source.json +++ b/config/source.json @@ -682,9 +682,10 @@ } }, "libpng": { - "type": "git", - "url": "https://github.com/glennrp/libpng.git", - "rev": "libpng16", + "type": "ghtagtar", + "repo": "pnggroup/libpng", + "match": "v1\\.6\\.\\d+", + "query": "?per_page=150", "provide-pre-built": true, "license": { "type": "file", @@ -692,9 +693,9 @@ } }, "librabbitmq": { - "type": "git", - "url": "https://github.com/alanxz/rabbitmq-c.git", - "rev": "master", + "type": "ghtar", + "repo": "alanxz/rabbitmq-c", + "prefer-stable": true, "license": { "type": "file", "path": "LICENSE" diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index a2911e46b..ccf61dd8d 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -97,8 +97,9 @@ public static function getLatestBitbucketTag(string $name, array $source): array public static function getLatestGithubTarball(string $name, array $source, string $type = 'releases'): array { logger()->debug("finding {$name} source from github {$type} tarball"); + $source['query'] ??= ''; $data = json_decode(self::curlExec( - url: "https://api.github.com/repos/{$source['repo']}/{$type}", + url: "https://api.github.com/repos/{$source['repo']}/{$type}{$source['query']}", hooks: [[CurlHook::class, 'setupGithubToken']], retries: self::getRetryAttempts() ), true, 512, JSON_THROW_ON_ERROR); From 64f7a3553e3fd961045f36842f05bfe2b3f9664b Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 1 Jan 2026 12:33:55 +0100 Subject: [PATCH 51/73] don't need it anymore --- src/SPC/toolchain/ZigToolchain.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SPC/toolchain/ZigToolchain.php b/src/SPC/toolchain/ZigToolchain.php index 212a158f7..1b7cc70dc 100644 --- a/src/SPC/toolchain/ZigToolchain.php +++ b/src/SPC/toolchain/ZigToolchain.php @@ -65,7 +65,6 @@ public function afterInit(): void GlobalEnvManager::putenv("SPC_EXTRA_LIBS={$extra_libs}"); } $cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: ''; - GlobalEnvManager::putenv('SPC_EXTRA_PHP_VARS=php_cv_preserve_none=yes'); $has_avx512 = str_contains($cflags, '-mavx512') || str_contains($cflags, '-march=x86-64-v4'); if (!$has_avx512) { $extra_vars = getenv('SPC_EXTRA_PHP_VARS') ?: ''; From d1b194999d22f8d6f55b715150fe9e10524fcd3c Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 2 Jan 2026 21:13:22 +0100 Subject: [PATCH 52/73] use OPENSSL_CONF directory for openssl default configuration --- src/SPC/builder/linux/library/openssl.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index a78b6a642..8d071f2d9 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -51,6 +51,8 @@ public function build(): void $zlib_extra = ''; } + $openssl_conf = getenv('OPENSSL_CONF'); + $openssl_dir = $openssl_conf ? dirname($openssl_conf) : '/etc/ssl'; $ex_lib = trim($ex_lib); shell()->cd($this->source_dir)->initializeEnv($this) @@ -58,7 +60,7 @@ public function build(): void "{$env} ./Configure no-shared {$extra} " . '--prefix=' . BUILD_ROOT_PATH . ' ' . '--libdir=' . BUILD_LIB_PATH . ' ' . - '--openssldir=/etc/ssl ' . + "--openssldir={$openssl_dir} " . "{$zlib_extra}" . 'enable-pie ' . 'no-legacy ' . From fff24845298730398bd70cbaaba90be997f7595d Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 2 Jan 2026 22:52:03 +0100 Subject: [PATCH 53/73] postgresql doesn't build under c23 --- src/SPC/builder/unix/library/postgresql.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index 6e0cb606e..a72f3a1a6 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -50,7 +50,7 @@ protected function build(): void $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false)); $env_vars = [ - 'CFLAGS' => $config['cflags'], + 'CFLAGS' => $config['cflags'] . ' -std=c17', 'CPPFLAGS' => '-DPIC', 'LDFLAGS' => $config['ldflags'], 'LIBS' => $config['libs'], From 559a2909a911a5557bee0d97430649e7f9d5daa0 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 2 Jan 2026 23:21:29 +0100 Subject: [PATCH 54/73] use little trick to order libargon2 before libsodium --- config/lib.json | 3 +++ src/SPC/builder/extension/password_argon2.php | 19 ------------------- src/SPC/util/SPCConfigUtil.php | 1 - 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/config/lib.json b/config/lib.json index 47f3c7b89..3be972484 100644 --- a/config/lib.json +++ b/config/lib.json @@ -361,6 +361,9 @@ "source": "libargon2", "static-libs-unix": [ "libargon2.a" + ], + "lib-suggests": [ + "libsodium" ] }, "libavif": { diff --git a/src/SPC/builder/extension/password_argon2.php b/src/SPC/builder/extension/password_argon2.php index 30e6fd2c5..d42fe4e37 100644 --- a/src/SPC/builder/extension/password_argon2.php +++ b/src/SPC/builder/extension/password_argon2.php @@ -24,25 +24,6 @@ public function runCliCheckUnix(): void } } - public function patchBeforeMake(): bool - { - $patched = parent::patchBeforeMake(); - if ($this->builder->getLib('libsodium') !== null) { - $extraLibs = getenv('SPC_EXTRA_LIBS'); - if ($extraLibs !== false) { - $extraLibs = str_replace( - [BUILD_LIB_PATH . '/libargon2.a', BUILD_LIB_PATH . '/libsodium.a'], - ['', BUILD_LIB_PATH . '/libargon2.a ' . BUILD_LIB_PATH . '/libsodium.a'], - $extraLibs, - ); - $extraLibs = trim(preg_replace('/\s+/', ' ', $extraLibs)); // normalize spacing - f_putenv('SPC_EXTRA_LIBS=' . $extraLibs); - return true; - } - } - return $patched; - } - public function getConfigureArg(bool $shared = false): string { if ($this->builder->getLib('openssl') !== null) { diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 7d2001f52..8c4fa9267 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -80,7 +80,6 @@ public function config(array $extensions = [], array $libraries = [], bool $incl $libs = $this->getLibsString($libraries, !$this->absolute_libs); // additional OS-specific libraries (e.g. macOS -lresolv) - // embed if ($extra_libs = SPCTarget::getRuntimeLibs()) { $libs .= " {$extra_libs}"; } From 890ff475f131c809de2b2e3309b85d33f28f5274 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 14:09:16 +0100 Subject: [PATCH 55/73] our memcache patch prevents shared building --- config/ext.json | 3 +-- src/SPC/builder/extension/memcache.php | 35 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/config/ext.json b/config/ext.json index 62ec48772..419be5a9b 100644 --- a/config/ext.json +++ b/config/ext.json @@ -410,8 +410,7 @@ "ext-depends": [ "zlib", "session" - ], - "build-with-php": true + ] }, "memcached": { "support": { diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php index 59c6065d4..feba0151b 100644 --- a/src/SPC/builder/extension/memcache.php +++ b/src/SPC/builder/extension/memcache.php @@ -18,6 +18,9 @@ public function getUnixConfigureArg(bool $shared = false): string public function patchBeforeBuildconf(): bool { + if (!$this->isBuildStatic()) { + return false; + } FileSystem::replaceFileStr( SOURCE_PATH . '/php-src/ext/memcache/config9.m4', 'if test -d $abs_srcdir/src ; then', @@ -44,6 +47,38 @@ public function patchBeforeBuildconf(): bool return true; } + public function patchBeforeSharedConfigure(): bool + { + if (!$this->isBuildShared()) { + return false; + } + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/memcache/config9.m4', + 'if test -d $abs_srcdir/main ; then', + 'if test -d $abs_srcdir/src ; then', + ); + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/memcache/config9.m4', + 'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"', + 'export CPPFLAGS="$CPPFLAGS $INCLUDES"', + ); + // add for in-tree building + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/memcache/php_memcache.h', + <<<'EOF' +#ifndef PHP_MEMCACHE_H +#define PHP_MEMCACHE_H + +extern zend_module_entry memcache_module_entry; +#define phpext_memcache_ptr &memcache_module_entry + +#endif +EOF, + '' + ); + return true; + } + protected function getExtraEnv(): array { return ['CFLAGS' => '-std=c17']; From 54001ab868b17b4b99b74443a88d5f1244895534 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 16:33:40 +0100 Subject: [PATCH 56/73] simplify logic a bit --- src/SPC/builder/linux/LinuxBuilder.php | 49 +++----------------------- 1 file changed, 5 insertions(+), 44 deletions(-) diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 0d6f77fba..63abf018b 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -319,7 +319,7 @@ private function getMakeExtraVars(): array return array_filter([ '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' => preg_replace('/-release\s+(\S+)/', '', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS')), 'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie", ]); } @@ -328,14 +328,12 @@ private function processLibphpSoFile(string $libphpSo): 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}"; + $releaseName = "libphp-{$release}.so"; + $libphpRelease = "{$libDir}/{$releaseName}"; if (!file_exists($libphpRelease) && file_exists($libphpSo)) { rename($libphpSo, $libphpRelease); } @@ -344,52 +342,15 @@ private function processLibphpSoFile(string $libphpSo): void if (file_exists($libphpSo)) { unlink($libphpSo); } - symlink($realLibName, 'libphp.so'); + symlink($releaseName, 'libphp.so'); shell()->exec(sprintf( 'patchelf --set-soname %s %s', - escapeshellarg($realLibName), + escapeshellarg($releaseName), escapeshellarg($libphpRelease) )); } - if (is_dir($modulesDir)) { - chdir($modulesDir); - foreach ($this->getExts() 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) - )); - } - } - } } /** From 1be353fd13051949e301cbaef71f32bd13a57250 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 16:45:39 +0100 Subject: [PATCH 57/73] more concise message --- src/SPC/builder/unix/UnixBuilderBase.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index e2507f1f4..050394f06 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -235,8 +235,10 @@ protected function sanityCheck(int $build_target): void $lens .= ' -static'; } $dynamic_exports = ''; + $embedType = 'static'; // if someone changed to EMBED_TYPE=shared, we need to add LD_LIBRARY_PATH if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { + $embedType = 'shared'; if (PHP_OS_FAMILY === 'Darwin') { $ext_path = 'DYLD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$DYLD_LIBRARY_PATH '; } else { @@ -255,18 +257,19 @@ protected function sanityCheck(int $build_target): void } } $cc = getenv('CC'); + [$ret, $out] = shell()->cd($sample_file_path)->execWithResult("{$cc} -o embed embed.c {$lens} {$dynamic_exports}"); if ($ret !== 0) { throw new ValidationException( - 'embed failed sanity check: build failed. Error message: ' . implode("\n", $out), - validation_module: 'static libphp.a sanity check' + 'embed failed to build. Error message: ' . implode("\n", $out), + validation_module: $embedType . 'libphp embed build sanity check' ); } [$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed'); if ($ret !== 0 || trim(implode('', $output)) !== 'hello') { throw new ValidationException( - 'embed failed sanity check: run failed. Error message: ' . implode("\n", $output), - validation_module: 'static libphp.a sanity check' + 'embed failed to run. Error message: ' . implode("\n", $output), + validation_module: $embedType . ' libphp embed run sanity check' ); } } From 76025b95c1683b29bcdcbeda30ee4f31513d7365 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 16:46:14 +0100 Subject: [PATCH 58/73] missing space --- src/SPC/builder/unix/UnixBuilderBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 050394f06..464c9b2fc 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -262,7 +262,7 @@ protected function sanityCheck(int $build_target): void if ($ret !== 0) { throw new ValidationException( 'embed failed to build. Error message: ' . implode("\n", $out), - validation_module: $embedType . 'libphp embed build sanity check' + validation_module: $embedType . ' libphp embed build sanity check' ); } [$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed'); From 6bbb3c969ce914c146b96849c7210c9592fe8323 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 17:03:43 +0100 Subject: [PATCH 59/73] remove -release handling functionality --- bin/spc-alpine-docker | 3 +- bin/spc-gnu-docker | 5 ---- src/SPC/builder/linux/LinuxBuilder.php | 33 +--------------------- src/SPC/doctor/item/LinuxToolCheckList.php | 5 +--- 4 files changed, 3 insertions(+), 43 deletions(-) diff --git a/bin/spc-alpine-docker b/bin/spc-alpine-docker index 2790a5c34..1abf10480 100755 --- a/bin/spc-alpine-docker +++ b/bin/spc-alpine-docker @@ -108,8 +108,7 @@ RUN apk update; \ wget \ xz \ gettext-dev \ - binutils-gold \ - patchelf + binutils-gold RUN curl -#fSL https://dl.static-php.dev/static-php-cli/bulk/php-8.4.4-cli-linux-\$(uname -m).tar.gz | tar -xz -C /usr/local/bin && \ chmod +x /usr/local/bin/php diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index 68f85109f..286ef9859 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -92,11 +92,6 @@ RUN echo "source scl_source enable devtoolset-10" >> /etc/bashrc RUN source /etc/bashrc RUN yum install -y which -RUN curl -fsSL -o patchelf.tgz https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0-$SPC_USE_ARCH.tar.gz && \ - mkdir -p /patchelf && \ - tar -xzf patchelf.tgz -C /patchelf --strip-components=1 && \ - cp /patchelf/bin/patchelf /usr/bin/ - RUN curl -o cmake.tgz -#fSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$SPC_USE_ARCH.tar.gz && \ mkdir /cmake && \ tar -xzf cmake.tgz -C /cmake --strip-components 1 diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 63abf018b..22c2d47a1 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -284,8 +284,6 @@ protected function buildEmbed(): void // process libphp.so for shared embed $libphpSo = BUILD_LIB_PATH . '/libphp.so'; if (file_exists($libphpSo)) { - // post actions: rename libphp.so to libphp-.so if -release is set in LDFLAGS - $this->processLibphpSoFile($libphpSo); // deploy libphp.so $this->deployBinary($libphpSo, $libphpSo, false); } @@ -319,40 +317,11 @@ private function getMakeExtraVars(): array return array_filter([ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), 'EXTRA_LIBS' => $config['libs'], - 'EXTRA_LDFLAGS' => preg_replace('/-release\s+(\S+)/', '', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS')), + 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), 'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie", ]); } - private function processLibphpSoFile(string $libphpSo): void - { - $ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: ''; - $libDir = BUILD_LIB_PATH; - $cwd = getcwd(); - - if (preg_match('/-release\s+(\S+)/', $ldflags, $matches)) { - $release = $matches[1]; - $releaseName = "libphp-{$release}.so"; - $libphpRelease = "{$libDir}/{$releaseName}"; - if (!file_exists($libphpRelease) && file_exists($libphpSo)) { - rename($libphpSo, $libphpRelease); - } - if (file_exists($libphpRelease)) { - chdir($libDir); - if (file_exists($libphpSo)) { - unlink($libphpSo); - } - symlink($releaseName, 'libphp.so'); - shell()->exec(sprintf( - 'patchelf --set-soname %s %s', - escapeshellarg($releaseName), - escapeshellarg($libphpRelease) - )); - } - chdir($cwd); - } - } - /** * Patch micro.sfx after UPX compression. * micro needs special section handling in LinuxBuilder. diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index ab8144a21..53b356ff3 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -22,7 +22,6 @@ class LinuxToolCheckList 'bzip2', 'cmake', 'gcc', 'g++', 'patch', 'binutils-gold', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_DEBIAN = [ @@ -31,7 +30,6 @@ class LinuxToolCheckList 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'xz', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_RHEL = [ @@ -39,8 +37,7 @@ class LinuxToolCheckList 'git', 'autoconf', 'automake', 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'which', - 'xz', 'libtool', 'gettext-devel', - 'patchelf', 'file', + 'xz', 'libtool', 'gettext-devel', 'file', ]; public const TOOLS_ARCH = [ From f8b0c2c98078d0963ceb6846991825b0760838f3 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 19:08:14 +0100 Subject: [PATCH 60/73] add release thing to extension build too --- src/SPC/builder/Extension.php | 1 + src/SPC/builder/linux/LinuxBuilder.php | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index e79b886bf..040eae026 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -546,6 +546,7 @@ protected function getSharedExtensionEnv(): array 'CFLAGS' => $config['cflags'], 'CXXFLAGS' => $config['cflags'], 'LDFLAGS' => $config['ldflags'], + 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), 'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"), 'LD_LIBRARY_PATH' => BUILD_LIB_PATH, ]; diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 22c2d47a1..004c37def 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -283,9 +283,14 @@ protected function buildEmbed(): void // process libphp.so for shared embed $libphpSo = BUILD_LIB_PATH . '/libphp.so'; + $libphpSoDest = BUILD_LIB_PATH . '/libphp.so'; if (file_exists($libphpSo)) { // deploy libphp.so - $this->deployBinary($libphpSo, $libphpSo, false); + preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches); + if (!empty($matches[1])) { + $libphpSoDest = str_replace('.so', '-' . $matches[1] . '.so', $libphpSo); + } + $this->deployBinary($libphpSo, $libphpSoDest, false); } // process shared extensions build-with-php From 94644d374ff8d10e678ae0cac9fdd236bd187593 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 19:12:16 +0100 Subject: [PATCH 61/73] fix --- src/SPC/builder/extension/memcache.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php index feba0151b..32cb301c6 100644 --- a/src/SPC/builder/extension/memcache.php +++ b/src/SPC/builder/extension/memcache.php @@ -62,20 +62,6 @@ public function patchBeforeSharedConfigure(): bool 'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"', 'export CPPFLAGS="$CPPFLAGS $INCLUDES"', ); - // add for in-tree building - FileSystem::replaceFileStr( - SOURCE_PATH . '/php-src/ext/memcache/php_memcache.h', - <<<'EOF' -#ifndef PHP_MEMCACHE_H -#define PHP_MEMCACHE_H - -extern zend_module_entry memcache_module_entry; -#define phpext_memcache_ptr &memcache_module_entry - -#endif -EOF, - '' - ); return true; } From 3a17cec52193f01cf9e6354c476546747ae27fac Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 3 Jan 2026 19:15:57 +0100 Subject: [PATCH 62/73] deploy extensions with -release flag too --- src/SPC/builder/Extension.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 040eae026..c0cb152d9 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -455,12 +455,17 @@ public function buildUnixShared(): void // process *.so file $soFile = BUILD_MODULES_PATH . '/' . $this->getName() . '.so'; + $soDest = $soFile; + preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches); + if (!empty($matches[1])) { + $soDest = str_replace('.so', '-' . $matches[1] . '.so', $soFile); + } if (!file_exists($soFile)) { throw new ValidationException("extension {$this->getName()} build failed: {$soFile} not found", validation_module: "Extension {$this->getName()} build"); } /** @var UnixBuilderBase $builder */ $builder = $this->builder; - $builder->deployBinary($soFile, $soFile, false); + $builder->deployBinary($soFile, $soDest, false); } /** From 34910d18e959931ea2216c756ee3b42075495627 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 4 Jan 2026 02:31:41 +0100 Subject: [PATCH 63/73] add patch point for shared ext build --- src/SPC/builder/Extension.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index c0cb152d9..816ea8116 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -401,10 +401,12 @@ public function buildShared(array $visited = []): void if (Config::getExt($this->getName(), 'type') === 'addon') { return; } + $this->builder->emitPatchPoint('before-shared-ext[' . $this->getName() . ']-build'); match (PHP_OS_FAMILY) { 'Darwin', 'Linux' => $this->buildUnixShared(), default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'), }; + $this->builder->emitPatchPoint('after-shared-ext[' . $this->getName() . ']-build'); } catch (SPCException $e) { $e->bindExtensionInfo(['extension_name' => $this->getName()]); throw $e; From cd2dc5bce40462c11b8a20bb49cf453ee480c6cc Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Tue, 13 Jan 2026 16:51:57 +0800 Subject: [PATCH 64/73] Fix nghttp2 and curl build configurations for static linking (#1014) --- src/SPC/builder/windows/library/curl.php | 5 +++-- src/SPC/builder/windows/library/nghttp2.php | 7 ++++++- src/globals/test-extensions.php | 12 ++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/SPC/builder/windows/library/curl.php b/src/SPC/builder/windows/library/curl.php index 1229dbd69..bba130e1a 100644 --- a/src/SPC/builder/windows/library/curl.php +++ b/src/SPC/builder/windows/library/curl.php @@ -30,7 +30,6 @@ protected function build(): void '-DCMAKE_BUILD_TYPE=Release ' . '-DBUILD_SHARED_LIBS=OFF ' . '-DBUILD_STATIC_LIBS=ON ' . - '-DCURL_STATICLIB=ON ' . '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . '-DBUILD_CURL_EXE=OFF ' . // disable curl.exe '-DBUILD_TESTING=OFF ' . // disable tests @@ -42,9 +41,9 @@ protected function build(): void '-DCURL_USE_OPENSSL=OFF ' . // disable openssl due to certificate issue '-DCURL_ENABLE_SSL=ON ' . '-DUSE_NGHTTP2=ON ' . // enable nghttp2 + '-DSHARE_LIB_OBJECT=OFF ' . // disable shared lib object '-DCURL_USE_LIBSSH2=ON ' . // enable libssh2 '-DENABLE_IPV6=ON ' . // enable ipv6 - '-DNGHTTP2_CFLAGS="/DNGHTTP2_STATICLIB" ' . $alt ) ->execWithWrapper( @@ -53,5 +52,7 @@ protected function build(): void ); // move libcurl.lib to libcurl_a.lib rename(BUILD_LIB_PATH . '\libcurl.lib', BUILD_LIB_PATH . '\libcurl_a.lib'); + + FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\curl\curl.h', '#ifdef CURL_STATICLIB', '#if 1'); } } diff --git a/src/SPC/builder/windows/library/nghttp2.php b/src/SPC/builder/windows/library/nghttp2.php index 7e6e999dc..5a1c6bf15 100644 --- a/src/SPC/builder/windows/library/nghttp2.php +++ b/src/SPC/builder/windows/library/nghttp2.php @@ -29,11 +29,16 @@ protected function build(): void '-DBUILD_SHARED_LIBS=OFF ' . '-DENABLE_STATIC_CRT=ON ' . '-DENABLE_LIB_ONLY=ON ' . - '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . + '-DENABLE_STATIC_CRT=ON ' . + '-DENABLE_DOC=OFF ' . + '-DBUILD_TESTING=OFF ' ) ->execWithWrapper( $this->builder->makeSimpleWrapper('cmake'), "--build build --config Release --target install -j{$this->builder->concurrency}" ); + + FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\nghttp2\nghttp2.h', '#ifdef NGHTTP2_STATICLIB', '#if 1'); } } diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index cdd27e235..93f86348b 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,17 +13,17 @@ // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - // '8.1', + '8.1', // '8.2', // '8.3', - // '8.4', + '8.4', '8.5', // 'git', ]; // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - 'macos-15-intel', // bin/spc for x86_64 + // 'macos-15-intel', // bin/spc for x86_64 // 'macos-15', // bin/spc for arm64 // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 @@ -31,7 +31,7 @@ // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 // 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 - // 'windows-2025', + 'windows-2025', ]; // whether enable thread safe @@ -50,7 +50,7 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imagick', + 'Linux', 'Darwin' => 'curl', 'Windows' => 'bcmath', }; @@ -67,7 +67,7 @@ // If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true. $with_libs = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => 'libwebp', - 'Windows' => '', + 'Windows' => 'nghttp2', }; // Please change your test base combination. We recommend testing with `common`. From d902e70b4d72867944b553982ed5152dbf58c810 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 16 Jan 2026 12:28:41 +0100 Subject: [PATCH 65/73] fix arm64 builds --- config/source.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/source.json b/config/source.json index 1bae46ce7..33295e87d 100644 --- a/config/source.json +++ b/config/source.json @@ -712,7 +712,7 @@ "libsodium": { "type": "ghrel", "repo": "jedisct1/libsodium", - "match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz", + "match": "libsodium-(?!1\\.0\\.21)\\d+(\\.\\d+)*\\.tar\\.gz", "prefer-stable": true, "provide-pre-built": true, "license": { From b09337de09ad23dea235a127d4eb23c9563a0773 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 17 Jan 2026 10:51:21 +0100 Subject: [PATCH 66/73] add excimer extension --- config/ext.json | 8 ++++++++ config/source.json | 12 +++++++++++- src/SPC/builder/extension/excimer.php | 19 +++++++++++++++++++ src/SPC/builder/unix/UnixBuilderBase.php | 4 +--- 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/SPC/builder/extension/excimer.php diff --git a/config/ext.json b/config/ext.json index d3fd2aa27..e88ad20cf 100644 --- a/config/ext.json +++ b/config/ext.json @@ -127,6 +127,14 @@ "sockets" ] }, + "excimer": { + "support": { + "Windows": "wip", + "BSD": "wip" + }, + "type": "external", + "source": "ext-excimer" + }, "exif": { "type": "builtin" }, diff --git a/config/source.json b/config/source.json index c96822d6b..0f32bcc9a 100644 --- a/config/source.json +++ b/config/source.json @@ -126,13 +126,23 @@ }, "ext-event": { "type": "url", - "url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz", + "url": "https://bitbucket.org/osmanov/pecl-event/get/3.1.4.tar.gz", "path": "php-src/ext/event", "license": { "type": "file", "path": "LICENSE" } }, + "ext-excimer": { + "type": "url", + "url": "https://pecl.php.net/get/excimer", + "path": "php-src/ext/excimer", + "filename": "excimer.tgz", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "ext-glfw": { "type": "git", "url": "https://github.com/mario-deluna/php-glfw", diff --git a/src/SPC/builder/extension/excimer.php b/src/SPC/builder/extension/excimer.php new file mode 100644 index 000000000..03dd8f228 --- /dev/null +++ b/src/SPC/builder/extension/excimer.php @@ -0,0 +1,19 @@ +extractDebugInfo($dst); - // strip if (!$this->getOption('no-strip')) { + $this->extractDebugInfo($dst); $this->stripBinary($dst); } From 19f941797ed0a8aac3d924469f5378fdbe46052d Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 17 Jan 2026 11:26:28 +0100 Subject: [PATCH 67/73] zig now supports -Wl,-exported_symbols_list --- src/SPC/builder/traits/UnixSystemUtilTrait.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index b1ef9db45..ff75bf7c2 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -72,12 +72,8 @@ public static function getDynamicExportedSymbols(string $lib_file): ?string if (!is_file($symbol_file)) { throw new SPCInternalException("The symbol file {$symbol_file} does not exist, please check if nm command is available."); } - // https://github.com/ziglang/zig/issues/24662 - if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { - return '-Wl,--export-dynamic'; - } - // macOS - if (SPCTarget::getTargetOS() !== 'Linux') { + // macOS/zig + if (SPCTarget::getTargetOS() !== 'Linux' || ToolchainManager::getToolchainClass() === ZigToolchain::class) { return "-Wl,-exported_symbols_list,{$symbol_file}"; } return "-Wl,--dynamic-list={$symbol_file}"; From 1e2b4017ac773cae62ba79c4b31adc90c0823435 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 17 Jan 2026 11:27:29 +0100 Subject: [PATCH 68/73] test excimer --- src/globals/test-extensions.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 93f86348b..ec3c71287 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,7 +13,7 @@ // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - '8.1', + // '8.1', // '8.2', // '8.3', '8.4', @@ -23,15 +23,15 @@ // test os (macos-15-intel, macos-15, ubuntu-latest, windows-latest are available) $test_os = [ - // 'macos-15-intel', // bin/spc for x86_64 - // 'macos-15', // bin/spc for arm64 + 'macos-15-intel', // bin/spc for x86_64 + 'macos-15', // bin/spc for arm64 // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 - // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 + 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 // 'ubuntu-24.04', // bin/spc for x86_64 - // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 + 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 // 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 - 'windows-2025', + // 'windows-2025', ]; // whether enable thread safe @@ -50,13 +50,13 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'curl', + 'Linux', 'Darwin' => 'opcache', 'Windows' => 'bcmath', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => '', + 'Linux' => 'excimer', 'Darwin' => '', 'Windows' => '', }; @@ -67,7 +67,7 @@ // If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true. $with_libs = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => 'libwebp', - 'Windows' => 'nghttp2', + 'Windows' => '', }; // Please change your test base combination. We recommend testing with `common`. From af75ffaf24837f6d684048777d7e0b9f3486467a Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 19 Jan 2026 10:22:33 +0100 Subject: [PATCH 69/73] suggestions, change openssldir --- config/env.ini | 4 ++++ config/ext.json | 8 ++++++-- src/SPC/builder/Extension.php | 3 --- src/SPC/builder/linux/library/openssl.php | 6 ++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/config/env.ini b/config/env.ini index 7448cc373..b989f5c35 100644 --- a/config/env.ini +++ b/config/env.ini @@ -115,6 +115,10 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE ; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS="" +; optional, path to openssl conf. This affects where openssl will look for the default CA. +; default on Debian/Alpine: /etc/ssl, default on RHEL: /etc/pki/tls +OPENSSLDIR="" + [macos] ; build target: macho or macho (possibly we could support macho-universal in the future) ; Currently we do not support universal and cross-compilation for macOS. diff --git a/config/ext.json b/config/ext.json index 419be5a9b..c5bbb45de 100644 --- a/config/ext.json +++ b/config/ext.json @@ -499,7 +499,9 @@ "mysqlnd" ], "lib-depends": [ - "libsodium", + "libsodium" + ], + "lib-suggests": [ "openssl" ] }, @@ -514,7 +516,9 @@ "mysqlnd" ], "lib-depends": [ - "libsodium", + "libsodium" + ], + "lib-suggests": [ "openssl" ] }, diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 816ea8116..925a4c8ef 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -398,9 +398,6 @@ public function buildShared(array $visited = []): void $dependency->buildShared([...$visited, $this->getName()]); } } - if (Config::getExt($this->getName(), 'type') === 'addon') { - return; - } $this->builder->emitPatchPoint('before-shared-ext[' . $this->getName() . ']-build'); match (PHP_OS_FAMILY) { 'Darwin', 'Linux' => $this->buildUnixShared(), diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index 8d071f2d9..bfc3936ba 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -21,6 +21,7 @@ namespace SPC\builder\linux\library; +use SPC\builder\linux\SystemUtil; use SPC\store\FileSystem; class openssl extends LinuxLibraryBase @@ -51,8 +52,9 @@ public function build(): void $zlib_extra = ''; } - $openssl_conf = getenv('OPENSSL_CONF'); - $openssl_dir = $openssl_conf ? dirname($openssl_conf) : '/etc/ssl'; + $openssl_dir = getenv('OPENSSLDIR') ?: null; + // TODO: in v3 use the following: $openssl_dir ??= SystemUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl'; + $openssl_dir ??= '/etc/ssl'; $ex_lib = trim($ex_lib); shell()->cd($this->source_dir)->initializeEnv($this) From 372760e469d57a1852c93d7a62c989cf8ce4011e Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 19 Jan 2026 18:56:28 +0800 Subject: [PATCH 70/73] Update patch point docs --- docs/en/guide/manual-build.md | 34 ++++++++++++++++++---------------- docs/zh/guide/manual-build.md | 2 ++ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/en/guide/manual-build.md b/docs/en/guide/manual-build.md index 28f0ec87e..319022ca3 100644 --- a/docs/en/guide/manual-build.md +++ b/docs/en/guide/manual-build.md @@ -549,22 +549,24 @@ otherwise it will be executed repeatedly in other events. The following are the supported `patch_point` event names and corresponding locations: -| Event name | Event description | -|------------------------------|----------------------------------------------------------------------------------------------------| -| before-libs-extract | Triggered before the dependent libraries extracted | -| after-libs-extract | Triggered after the compiled dependent libraries extracted | -| before-php-extract | Triggered before PHP source code extracted | -| after-php-extract | Triggered after PHP source code extracted | -| before-micro-extract | Triggered before phpmicro extract | -| after-micro-extract | Triggered after phpmicro extracted | -| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory | -| after-exts-extract | Triggered after the extension extracted to the PHP source directory | -| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) | -| after-library[*name*]-build | Triggered after the library named `name` is compiled | -| before-php-buildconf | Triggered before compiling PHP command `./buildconf` | -| before-php-configure | Triggered before compiling PHP command `./configure` | -| before-php-make | Triggered before compiling PHP command `make` | -| before-sanity-check | Triggered after compiling PHP but before running extended checks | +| Event name | Event description | +|---------------------------------|----------------------------------------------------------------------------------------------------| +| before-libs-extract | Triggered before the dependent libraries extracted | +| after-libs-extract | Triggered after the compiled dependent libraries extracted | +| before-php-extract | Triggered before PHP source code extracted | +| after-php-extract | Triggered after PHP source code extracted | +| before-micro-extract | Triggered before phpmicro extract | +| after-micro-extract | Triggered after phpmicro extracted | +| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory | +| after-exts-extract | Triggered after the extension extracted to the PHP source directory | +| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) | +| after-library[*name*]-build | Triggered after the library named `name` is compiled | +| after-shared-ext[*name*]-build | Triggered after the shared extension named `name` is compiled | +| before-shared-ext[*name*]-build | Triggered before the shared extension named `name` is compiled | +| before-php-buildconf | Triggered before compiling PHP command `./buildconf` | +| before-php-configure | Triggered before compiling PHP command `./configure` | +| before-php-make | Triggered before compiling PHP command `make` | +| before-sanity-check | Triggered after compiling PHP but before running extended checks | The following is a simple example of temporarily modifying the PHP source code. Enable the CLI function to search for the `php.ini` configuration in the current working directory: diff --git a/docs/zh/guide/manual-build.md b/docs/zh/guide/manual-build.md index 4c24cab8f..d7745a02b 100644 --- a/docs/zh/guide/manual-build.md +++ b/docs/zh/guide/manual-build.md @@ -500,6 +500,8 @@ bin/spc dev:sort-config ext | after-exts-extract | 在要编译的扩展解压到 PHP 源码目录后触发 | | before-library[*name*]-build | 在名称为 `name` 的库编译前触发(如 `before-library[postgresql]-build`) | | after-library[*name*]-build | 在名称为 `name` 的库编译后触发 | +| after-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译后触发(如 `after-shared-ext[redis]-build`) | +| before-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译前触发 | | before-php-buildconf | 在编译 PHP 命令 `./buildconf` 前触发 | | before-php-configure | 在编译 PHP 命令 `./configure` 前触发 | | before-php-make | 在编译 PHP 命令 `make` 前触发 | From b3c450291a4fe5c7437af446283a11025cf6648a Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 19 Jan 2026 12:00:06 +0100 Subject: [PATCH 71/73] up version --- src/SPC/ConsoleApplication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 9500a231a..19fdd41dc 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -34,7 +34,7 @@ */ final class ConsoleApplication extends Application { - public const string VERSION = '2.7.11'; + public const string VERSION = '2.8.0'; public function __construct() { From 2c22bf25ea4d63b445fbaa9356931a3e5c3ef939 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 20 Jan 2026 16:56:46 +0800 Subject: [PATCH 72/73] Refactor getOSRelease method for improved readability and efficiency --- src/StaticPHP/Util/System/LinuxUtil.php | 64 ++++++++++++------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/StaticPHP/Util/System/LinuxUtil.php b/src/StaticPHP/Util/System/LinuxUtil.php index 79ad89ed7..2b1adf3d9 100644 --- a/src/StaticPHP/Util/System/LinuxUtil.php +++ b/src/StaticPHP/Util/System/LinuxUtil.php @@ -12,7 +12,6 @@ class LinuxUtil extends UnixUtil /** * Get current linux distro name and version. * - * @noinspection PhpMissingBreakStatementInspection * @return array{dist: string, ver: string, family: string} Linux distro info (unknown if not found) */ public static function getOSRelease(): array @@ -22,42 +21,39 @@ public static function getOSRelease(): array 'ver' => 'unknown', 'family' => 'unknown', ]; - switch (true) { - case file_exists('/etc/centos-release'): - $lines = file('/etc/centos-release'); - $centos = true; - goto rh; - case file_exists('/etc/redhat-release'): - $lines = file('/etc/redhat-release'); - $centos = false; - rh: - foreach ($lines as $line) { - if (preg_match('/release\s+(\d*(\.\d+)*)/', $line, $matches)) { - /* @phpstan-ignore-next-line */ - $ret['dist'] = $centos ? 'centos' : 'redhat'; - $ret['ver'] = $matches[1]; - } + + if (file_exists('/etc/centos-release') || file_exists('/etc/redhat-release')) { + $is_centos = file_exists('/etc/centos-release'); + $file = $is_centos ? '/etc/centos-release' : '/etc/redhat-release'; + $lines = file($file); + + foreach ($lines as $line) { + if (preg_match('/release\s+(\d*(\.\d+)*)/', $line, $matches)) { + $ret['dist'] = $is_centos ? 'centos' : 'redhat'; + $ret['ver'] = $matches[1]; + } + } + } elseif (file_exists('/etc/os-release')) { + $lines = file('/etc/os-release'); + + foreach ($lines as $line) { + if (preg_match('/^ID=(.*)$/', $line, $matches)) { + $ret['dist'] = $matches[1]; } - break; - case file_exists('/etc/os-release'): - $lines = file('/etc/os-release'); - foreach ($lines as $line) { - if (preg_match('/^ID=(.*)$/', $line, $matches)) { - $ret['dist'] = $matches[1]; - } - if (preg_match('/^ID_LIKE=(.*)$/', $line, $matches)) { - $ret['family'] = $matches[1]; - } - if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) { - $ret['ver'] = $matches[1]; - } + if (preg_match('/^ID_LIKE=(.*)$/', $line, $matches)) { + $ret['family'] = $matches[1]; } - $ret['dist'] = trim($ret['dist'], '"\''); - $ret['ver'] = trim($ret['ver'], '"\''); - if (strcasecmp($ret['dist'], 'centos') === 0) { - $ret['dist'] = 'redhat'; + if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) { + $ret['ver'] = $matches[1]; } - break; + } + + $ret['dist'] = trim($ret['dist'], '"\''); + $ret['ver'] = trim($ret['ver'], '"\''); + + if (strcasecmp($ret['dist'], 'centos') === 0) { + $ret['dist'] = 'redhat'; + } } return $ret; } From a0cab24e568f5f80de547127af3157f9ebc9daf0 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Thu, 22 Jan 2026 09:32:22 +0800 Subject: [PATCH 73/73] Remove skeleton command --- skeleton-test.php | 28 -- src/StaticPHP/Command/Dev/SkeletonCommand.php | 402 ----------------- src/StaticPHP/ConsoleApplication.php | 2 - src/StaticPHP/Skeleton/ArtifactGenerator.php | 115 ----- src/StaticPHP/Skeleton/PackageGenerator.php | 412 ------------------ 5 files changed, 959 deletions(-) delete mode 100644 skeleton-test.php delete mode 100644 src/StaticPHP/Command/Dev/SkeletonCommand.php delete mode 100644 src/StaticPHP/Skeleton/ArtifactGenerator.php delete mode 100644 src/StaticPHP/Skeleton/PackageGenerator.php diff --git a/skeleton-test.php b/skeleton-test.php deleted file mode 100644 index 59fbbb7e1..000000000 --- a/skeleton-test.php +++ /dev/null @@ -1,28 +0,0 @@ -addDependency('bar') - ->addStaticLib('libfoo.a', 'unix') - ->addStaticLib('libfoo.a', 'unix') - ->addArtifact($artifact_generator = new ArtifactGenerator('foo')->setSource(['type' => 'url', 'url' => 'https://example.com/foo.tar.gz'])) - ->enableBuild(['Darwin', 'Linux'], 'build') - ->addFunctionExecutorBinding('build', new ExecutorGenerator(UnixCMakeExecutor::class)); - -$pkg_config = $package_generator->generateConfigArray(); -$artifact_config = $artifact_generator->generateConfigArray(); - -echo '===== pkg.json =====' . PHP_EOL; -echo json_encode($pkg_config, 64 | 128 | 256) . PHP_EOL; -echo '===== artifact.json =====' . PHP_EOL; -echo json_encode($artifact_config, 64 | 128 | 256) . PHP_EOL; -echo '===== php code for package =====' . PHP_EOL; -echo $package_generator->generatePackageClassFile('Package\Library'); diff --git a/src/StaticPHP/Command/Dev/SkeletonCommand.php b/src/StaticPHP/Command/Dev/SkeletonCommand.php deleted file mode 100644 index b19eb4a11..000000000 --- a/src/StaticPHP/Command/Dev/SkeletonCommand.php +++ /dev/null @@ -1,402 +0,0 @@ -output->writeln('The dev:skel command is not available in phar mode.'); - return 1; - } - if (SystemTarget::getTargetOS() === 'Windows') { - $this->output->writeln('The dev:skel command is not available on Windows systems.'); - return 1; - } - - $this->runMainMenu(); - - return 0; - } - - public function validatePackageName(string $name): ?string - { - if (!preg_match('/^[a-zA-Z0-9_-]+$/', $name)) { - return 'Library name can only contain letters, numbers, underscores, and hyphens.'; - } - // must start with a letter - if (!preg_match('/^[a-zA-Z]/', $name)) { - return 'Library name must start with a letter.'; - } - return null; - } - - private function runMainMenu(): void - { - $main = select('Please select the skeleton option', [ - 'library' => 'Create a new library package', - 'target' => 'Create a new target package', - 'php-extension' => 'Create a new PHP extension', - 'q' => 'Exit', - ]); - $generator = match ($main) { - 'library' => $this->runCreateLib(), - 'target' => $this->runCreateTarget(), - 'php-extension' => $this->runCreateExt(), - 'q' => exit(0), - default => null, - }; - $write = $generator->writeAll(); - $this->output->writeln("Package config in: {$write['package_config']}"); - $this->output->writeln("Artifact config in: {$write['artifact_config']}"); - $this->output->writeln('Package class:'); - $this->output->writeln($write['package_class_content']); - } - - private function runCreateLib(): PackageGenerator - { - // init empty - $static_libs = ''; - $headers = ''; - $static_bins = ''; - $pkg_configs = ''; - - // ask name - $package_name = text('Please enter your library name', placeholder: 'e.g. pcre2', validate: [$this, 'validatePackageName']); - - // ask OS - $os = select("[{$package_name}] On which OS family do you want to build this library?", [ - 'unix' => 'Both Linux and Darwin (unix-like OS)', - 'linux' => 'Linux only', - 'macos' => 'Darwin(macOS) only', - 'windows' => 'Windows only', - 'all' => 'All supported OS (' . implode(', ', SUPPORTED_OS_FAMILY) . ')', - ]); - - $produce = select("[{$package_name}] What does this library produce?", [ - 'static_libs' => 'Static Libraries (.a/.lib)', - 'headers' => 'Header Files (.h)', - 'static_bins' => 'Static Binaries (executables)', - 'pkg_configs' => 'Pkg-Config files (.pc)', - 'all' => 'All of the above', - ]); - - if ($produce === 'all' || $produce === 'static_libs') { - $static_libs = text( - 'Please enter the names of the static libraries produced', - placeholder: 'e.g. libpcre2.a, libbar.a', - default: str_starts_with($package_name, 'lib') ? "{$package_name}.a" : "lib{$package_name}.a", - validate: function ($value) { - $names = array_map('trim', explode(',', $value)); - if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { - return 'Library names can only contain letters, numbers, underscores, hyphens, and dots.'; - } - return null; - }, - hint: 'Separate multiple names with commas' - ); - } - if ($produce === 'all' || $produce === 'headers') { - $headers = text( - 'Please enter the names of the header files produced', - placeholder: 'e.g. foo.h, bar.h', - default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.h' : $package_name . '.h', - validate: function ($value) { - $names = array_map('trim', explode(',', $value)); - if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { - return 'Header file names can only contain letters, numbers, underscores, hyphens, and dots.'; - } - return null; - }, - hint: 'Separate multiple names with commas, directories are allowed (e.g. openssl directory)' - ); - } - if ($produce === 'all' || $produce === 'static_bins') { - $static_bins = text( - 'Please enter the names of the static binaries produced', - placeholder: 'e.g. foo, bar', - default: $package_name, - validate: function ($value) { - $names = array_map('trim', explode(',', $value)); - if (array_any($names, fn ($name) => !preg_match('/^[a-zA-Z0-9_.-]+$/', $name))) { - return 'Binary names can only contain letters, numbers, underscores, hyphens, and dots.'; - } - return null; - }, - hint: 'Separate multiple names with commas' - ); - } - if ($produce === 'all' || $produce === 'pkg_configs') { - $pkg_configs = text( - 'Please enter the names of the pkg-config files produced', - placeholder: 'e.g. foo.pc, bar.pc', - default: str_starts_with($package_name, 'lib') ? str_replace('lib', '', $package_name) . '.pc' : $package_name . '.pc', - validate: function ($value) { - if (!str_ends_with($value, '.pc')) { - return 'Pkg-config file names must end with .pc extension.'; - } - return null; - }, - hint: 'Separate multiple names with commas' - ); - } - - if ($headers === '' && $static_bins === '' && $static_libs === '' && $pkg_configs === '') { - $this->output->writeln('You must specify at least one of static libraries, header files, or static binaries produced.'); - exit(1); - } - - // ask source - $artifact_generator = $this->runCreateArtifact($package_name, true, false, null); - $package_generator = new PackageGenerator($package_name, 'library'); - // set artifact - $package_generator = $package_generator->addArtifact($artifact_generator); - // set os - $package_generator = match ($os) { - 'unix' => $package_generator->enableBuild(['Darwin', 'Linux'], 'build'), - 'linux' => $package_generator->enableBuild(['Linux'], 'build'), - 'macos' => $package_generator->enableBuild(['Darwin'], 'build'), - 'windows' => $package_generator->enableBuild(['Windows'], 'build'), - 'all' => $package_generator->enableBuild(SUPPORTED_OS_FAMILY, 'build'), - default => $package_generator, - }; - // set produce - if ($static_libs !== '') { - $lib_names = array_map('trim', explode(',', $static_libs)); - foreach ($lib_names as $lib_name) { - $package_generator = $package_generator->addStaticLib($lib_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); - } - } - if ($headers !== '') { - $header_names = array_map('trim', explode(',', $headers)); - foreach ($header_names as $header_name) { - $package_generator = $package_generator->addHeaderFile($header_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); - } - } - if ($static_bins !== '') { - $bin_names = array_map('trim', explode(',', $static_bins)); - foreach ($bin_names as $bin_name) { - $package_generator = $package_generator->addStaticBin($bin_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); - } - } - if ($pkg_configs !== '') { - $pc_names = array_map('trim', explode(',', $pkg_configs)); - foreach ($pc_names as $pc_name) { - $package_generator = $package_generator->addPkgConfigFile($pc_name, $os === 'all' ? 'all' : ($os === 'unix' ? 'unix' : $os)); - } - } - // ask for package config writing selection, same as artifact - $package_configs = Registry::getLoadedPackageConfigs(); - $package_config_file = select("[{$package_name}] Please select the package config file to write the package config to", $package_configs); - return $package_generator->setConfigFile($package_config_file); - } - - private function runCreateArtifact( - string $package_name, - ?bool $create_source, - ?bool $create_binary, - string|true|null $default_extract_dir = true - ): ArtifactGenerator { - $artifact = new ArtifactGenerator($package_name); - - if ($create_source === null) { - $create_source = confirm("[{$package_name}] Do you want to create a source artifact?"); - } - - if (!$create_source) { - goto binary; - } - - $source_type = select("[{$package_name}] Where is the source code located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME); - - $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'source'); - $artifact = $artifact->setSource($source_config); - - binary: - if ($create_binary === null) { - $create_binary = confirm("[{$package_name}] Do you want to create a binary artifact?"); - } - - if (!$create_binary) { - goto end; - } - - $binary_fix = [ - 'macos-x86_64' => null, - 'macos-aarch64' => null, - 'linux-x86_64' => null, - 'linux-aarch64' => null, - 'windows-x86_64' => null, - ]; - while (($os = select("[{$package_name}] Please configure the binary downloading options for OS", [ - 'macos-x86_64' => 'macos-x86_64' . ($binary_fix['macos-x86_64'] ? ' (done)' : ''), - 'macos-aarch64' => 'macos-aarch64' . ($binary_fix['macos-aarch64'] ? ' (done)' : ''), - 'linux-x86_64' => 'linux-x86_64' . ($binary_fix['linux-x86_64'] ? ' (done)' : ''), - 'linux-aarch64' => 'linux-aarch64' . ($binary_fix['linux-aarch64'] ? ' (done)' : ''), - 'windows-x86_64' => 'windows-x86_64' . ($binary_fix['windows-x86_64'] ? ' (done)' : ''), - 'copy' => 'Duplicate from another OS', - 'finish' => 'Submit', - ])) !== 'finish') { - $source_type = select("[{$package_name}] Where is the binary for {$os} located?", SPC_DOWNLOAD_TYPE_DISPLAY_NAME); - $source_config = $this->askDownloadTypeConfig($package_name, $source_type, $default_extract_dir, 'binary'); - // set to artifact - $artifact = $artifact->setBinary($os, $source_config); - $binary_fix[$os] = true; - } - - end: - - // generate config files, select existing package config file to write - $artifact_configs = Registry::getLoadedArtifactConfigs(); - $artifact_config_file = select("[{$package_name}] Please select the artifact config file to write the artifact config to", $artifact_configs); - return $artifact->setConfigFile($artifact_config_file); - } - - private function runCreateTarget(): PackageGenerator - { - throw new WrongUsageException('Not implemented'); - } - - private function runCreateExt(): PackageGenerator - { - throw new WrongUsageException('Not implemented'); - } - - private function askDownloadTypeConfig(string $package_name, int|string $source_type, bool|string|null $default_extract_dir, string $config_type): array - { - $source_config = ['type' => $source_type]; - switch ($source_type) { - case 'bitbuckettag': - $source_config['repo'] = text("[{$package_name}] Please enter the BitBucket repository (e.g. user/repo)"); - break; - case 'filelist': - $source_config['url'] = text( - "[{$package_name}] Please enter the file index website URL", - placeholder: 'e.g. https://ftp.gnu.org/pub/gnu/gettext/', - hint: 'Make sure the target url is a directory listing page like ftp.gnu.org.' - ); - $source_config['regex'] = text( - "[{$package_name}] Please enter the regex pattern to match the archive file", - placeholder: 'e.g. /gettext-(\d+\.\d+(\.\d+)?)\.tar\.gz/', - default: "/href=\"(?{$package_name}-(?[^\"]+)\\.tar\\.gz)\"/", - hint: 'Make sure the regex contains a capturing group for the version number.' - ); - break; - case 'git': - $source_config['url'] = text( - "[{$package_name}] Please enter the Git repository URL", - validate: function ($value) { - if (!filter_var($value, FILTER_VALIDATE_URL) && !preg_match('/^(git|ssh|http|https|git@[-\w.]+):(\/\/)?(.*?)(\.git)(\/?|#[-\d\w._]+?)$/', $value)) { - return 'Please enter a valid Git repository URL.'; - } - return null; - }, - hint: 'e.g. https://github.com/user/repo.git' - ); - $source_config['rev'] = text( - "[{$package_name}] Please enter the Git revision (branch, tag, or commit hash)", - default: 'main', - hint: 'e.g. main, master, v1.0.0, or a commit hash' - ); - break; - case 'ghrel': - $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)"); - $source_config['match'] = text( - "[{$package_name}] Please enter the regex pattern to match the source archive file", - placeholder: 'e.g. /foo-(\d+\.\d+(\.\d+)?)\.tar\.gz/', - default: "{$package_name}-.+\\.tar\\.gz", - ); - break; - case 'ghtar': - case 'ghtagtar': - $source_config['repo'] = text("[{$package_name}] Please enter the GitHub repository (e.g. user/repo)"); - $source_config['prefer-stable'] = confirm("[{$package_name}] Do you want to prefer stable releases?"); - if ($source_type === 'ghtagtar' && confirm('Do you want to match tags with a specific pattern?', default: false)) { - $source_config['match'] = text( - "[{$package_name}] Please enter the regex pattern to match tags", - placeholder: 'e.g. v(\d+\.\d+(\.\d+)?)', - ); - } - break; - case 'local': - $source_config['dirname'] = text( - "[{$package_name}] Please enter the local directory path", - validate: function ($value) { - if (trim($value) === '') { - return 'Local source directory cannot be empty.'; - } - if (!is_dir($value)) { - return 'The specified local source directory does not exist.'; - } - return null; - }, - ); - break; - case 'pie': - $source_config['repo'] = text( - "[{$package_name}] Please enter the PIE repository name", - placeholder: 'e.g. user/repo', - ); - break; - case 'url': - $source_config['url'] = text( - "[{$package_name}] Please enter the file download URL", - validate: function ($value) { - if (!filter_var($value, FILTER_VALIDATE_URL)) { - return 'Please enter a valid URL.'; - } - return null; - }, - ); - break; - case 'custom': - break; - } - // ask extract dir if is true - if ($default_extract_dir === true) { - if (confirm('Do you want to specify a custom extract directory?')) { - $extract_hint = match ($config_type) { - 'source' => 'the source will be from the `source/` dir by default', - 'binary' => 'the binary will be from the `pkgroot/{arch}-{os}/` dir by default', - default => '', - }; - $default_extract_dir = text( - "[{$package_name}] Please enter the source extract directory", - validate: function ($value) { - if (trim($value) === '') { - return 'Extract directory cannot be empty.'; - } - return null; - }, - hint: 'You can use relative path, ' . $extract_hint . '.' - ); - } else { - $default_extract_dir = null; - } - } - if ($default_extract_dir !== null) { - $source_config['extract'] = $default_extract_dir; - } - - // return config - return $source_config; - } -} diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php index fd7650aa8..9e37698c6 100644 --- a/src/StaticPHP/ConsoleApplication.php +++ b/src/StaticPHP/ConsoleApplication.php @@ -9,7 +9,6 @@ use StaticPHP\Command\Dev\EnvCommand; use StaticPHP\Command\Dev\IsInstalledCommand; use StaticPHP\Command\Dev\ShellCommand; -use StaticPHP\Command\Dev\SkeletonCommand; use StaticPHP\Command\Dev\SortConfigCommand; use StaticPHP\Command\DoctorCommand; use StaticPHP\Command\DownloadCommand; @@ -61,7 +60,6 @@ public function __construct() new ShellCommand(), new IsInstalledCommand(), new EnvCommand(), - new SkeletonCommand(), new SortConfigCommand(), ]); diff --git a/src/StaticPHP/Skeleton/ArtifactGenerator.php b/src/StaticPHP/Skeleton/ArtifactGenerator.php deleted file mode 100644 index e05f94d14..000000000 --- a/src/StaticPHP/Skeleton/ArtifactGenerator.php +++ /dev/null @@ -1,115 +0,0 @@ -name; - } - - public function setSource(array $source): static - { - $clone = clone $this; - $clone->source = $source; - return $clone; - } - - public function setCustomSource(): static - { - $clone = clone $this; - $clone->source = ['type' => 'custom']; - $clone->generate_class = true; - $clone->generate_custom_source_func = true; - return $clone; - } - - public function getSource(): ?array - { - return $this->source; - } - - public function setBinary(string $os, array $config): static - { - $clone = clone $this; - if ($clone->binary === null) { - $clone->binary = [$os => $config]; - } else { - $clone->binary[$os] = $config; - } - return $clone; - } - - public function generateConfigArray(): array - { - $config = []; - - if ($this->source) { - $config['source'] = $this->source; - } - if ($this->binary) { - $config['binary'] = $this->binary; - } - return $config; - } - - public function setConfigFile(string $file): static - { - $clone = clone $this; - $clone->config_file = $file; - return $clone; - } - - /** - * Write the artifact configuration to the config file. - */ - public function writeConfigFile(): string - { - if ($this->config_file === null) { - throw new ValidationException('Config file path is not set.'); - } - $config_array = $this->generateConfigArray(); - $config_file_json = json_decode(FileSystem::readFile($this->config_file), true); - if (!is_array($config_file_json)) { - throw new ValidationException('Existing config file is not a valid JSON array.'); - } - - $config_file_json[$this->name] = $config_array; - // sort keys - ksort($config_file_json); - $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - if ($json_content === false) { - throw new ValidationException('Failed to encode config array to JSON.'); - } - if (file_put_contents($this->config_file, $json_content) === false) { - throw new FileSystemException("Failed to write config file: {$this->config_file}"); - } - return $this->config_file; - } -} diff --git a/src/StaticPHP/Skeleton/PackageGenerator.php b/src/StaticPHP/Skeleton/PackageGenerator.php deleted file mode 100644 index 89802899a..000000000 --- a/src/StaticPHP/Skeleton/PackageGenerator.php +++ /dev/null @@ -1,412 +0,0 @@ - $depends An array of dependencies required by the package, categorized by operating system. */ - protected array $depends = []; - - /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $suggests An array of suggested packages for the package, categorized by operating system. */ - protected array $suggests = []; - - /** @var array $frameworks An array of macOS frameworks for the package */ - protected array $frameworks = []; - - /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_libs An array of static libraries required by the package, categorized by operating system. */ - protected array $static_libs = []; - - /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $headers An array of header files required by the package, categorized by operating system. */ - protected array $headers = []; - - /** @var array<''|'linux'|'macos'|'unix'|'windows', string[]> $static_bins An array of static binaries required by the package, categorized by operating system. */ - protected array $static_bins = []; - - protected ?string $config_file = null; - - /** @var null|ArtifactGenerator $artifact Artifact */ - protected ?ArtifactGenerator $artifact = null; - - /** @var array $licenses Licenses */ - protected array $licenses = []; - - /** @var array<'Darwin'|'Linux'|'Windows', null|string> $build_for_enables Enable build function generating */ - protected array $build_for_enables = [ - 'Darwin' => null, - 'Linux' => null, - 'Windows' => null, - ]; - - /** @var array */ - protected array $func_executor_binding = []; - - /** - * @param string $package_name Package name - * @param 'library'|'php-extension'|'target'|'virtual-target' $type Package type ('library', 'target', 'virtual-target', etc.) - */ - public function __construct(protected string $package_name, protected string $type) {} - - /** - * Add package dependency. - * - * @param string $package Package name - * @param string $os_category Operating system ('' for all OSes, 'unix', 'windows', 'macos') - */ - public function addDependency(string $package, string $os_category = ''): static - { - if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { - throw new ValidationException("Invalid OS suffix: {$os_category}"); - } - $clone = clone $this; - if (!isset($clone->depends[$os_category])) { - $clone->depends[$os_category] = []; - } - if (!in_array($package, $clone->depends[$os_category], true)) { - $clone->depends[$os_category][] = $package; - } - return $clone; - } - - /** - * Add package suggestion. - * - * @param string $package Package name - * @param string $os_category Operating system ('' for all OSes) - */ - public function addSuggestion(string $package, string $os_category = ''): static - { - if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { - throw new ValidationException("Invalid OS suffix: {$os_category}"); - } - $clone = clone $this; - if (!isset($clone->suggests[$os_category])) { - $clone->suggests[$os_category] = []; - } - if (!in_array($package, $clone->suggests[$os_category], true)) { - $clone->suggests[$os_category][] = $package; - } - return $clone; - } - - public function addStaticLib(string $lib_a, string $os_category = ''): static - { - if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { - throw new ValidationException("Invalid OS suffix: {$os_category}"); - } - if (!str_ends_with($lib_a, '.lib') && !str_ends_with($lib_a, '.a')) { - throw new ValidationException("Static library must end with .lib or .a, got: {$lib_a}"); - } - if (str_ends_with($lib_a, '.lib') && in_array($os_category, ['unix', 'linux', 'macos'], true)) { - throw new ValidationException("Static library with .lib extension cannot be added for non-Windows OS: {$lib_a}"); - } - if (str_ends_with($lib_a, '.a') && $os_category === 'windows') { - throw new ValidationException("Static library with .a extension cannot be added for Windows OS: {$lib_a}"); - } - if (isset($this->static_libs[$os_category]) && in_array($lib_a, $this->static_libs[$os_category], true)) { - // already exists - return $this; - } - $clone = clone $this; - if (!isset($clone->static_libs[$os_category])) { - $clone->static_libs[$os_category] = []; - } - if (!in_array($lib_a, $clone->static_libs[$os_category], true)) { - $clone->static_libs[$os_category][] = $lib_a; - } - return $clone; - } - - public function addHeader(string $header_file, string $os_category = ''): static - { - if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { - throw new ValidationException("Invalid OS suffix: {$os_category}"); - } - $clone = clone $this; - if (!isset($clone->headers[$os_category])) { - $clone->headers[$os_category] = []; - } - if (!in_array($header_file, $clone->headers[$os_category], true)) { - $clone->headers[$os_category][] = $header_file; - } - return $clone; - } - - public function addStaticBin(string $bin_file, string $os_category = ''): static - { - if (!in_array($os_category, ['', ...SUPPORTED_OS_CATEGORY], true)) { - throw new ValidationException("Invalid OS suffix: {$os_category}"); - } - $clone = clone $this; - if (!isset($clone->static_bins[$os_category])) { - $clone->static_bins[$os_category] = []; - } - if (!in_array($bin_file, $clone->static_bins[$os_category], true)) { - $clone->static_bins[$os_category][] = $bin_file; - } - return $clone; - } - - /** - * Add package artifact. - * - * @param ArtifactGenerator $artifactGenerator Artifact generator - */ - public function addArtifact(ArtifactGenerator $artifactGenerator): static - { - $clone = clone $this; - $clone->artifact = $artifactGenerator; - return $clone; - } - - /** - * Add license from string. - * - * @param string $text License content - */ - public function addLicenseFromString(string $text): static - { - $clone = clone $this; - $clone->licenses[] = [ - 'type' => 'text', - 'text' => $text, - ]; - return $clone; - } - - /** - * Add license from file. - * - * @param string $file_path License file path - */ - public function addLicenseFromFile(string $file_path): static - { - $clone = clone $this; - $clone->licenses[] = [ - 'type' => 'file', - 'path' => $file_path, - ]; - return $clone; - } - - /** - * Enable build for specific OS. - * - * @param 'Darwin'|'Linux'|'Windows'|array<'Darwin'|'Linux'|'Windows'> $build_for Build for OS - */ - public function enableBuild(array|string $build_for, ?string $build_function_name = null): static - { - $clone = clone $this; - if (is_array($build_for)) { - foreach ($build_for as $bf) { - $clone = $clone->enableBuild($bf, $build_function_name ?? 'build'); - } - return $clone; - } - if (!in_array($build_for, SUPPORTED_OS_FAMILY, true)) { - throw new ValidationException("Unsupported build_for value: {$build_for}"); - } - $clone->build_for_enables[$build_for] = $build_function_name ?? "buildFor{$build_for}"; - return $clone; - } - - /** - * Bind function executor. - * - * @param string $func_name Function name - * @param ExecutorGenerator $executor Executor generator - */ - public function addFunctionExecutorBinding(string $func_name, ExecutorGenerator $executor): static - { - $clone = clone $this; - $clone->func_executor_binding[$func_name] = $executor; - return $clone; - } - - public function generatePackageClassFile(string $namespace, bool $uppercase = false): string - { - $printer = new class extends Printer { - public string $indentation = ' '; - }; - $file = new PhpFile(); - $namespace = $file->setStrictTypes()->addNamespace($namespace); - - $uses = []; - - // class name and package attribute - $class_name = str_replace('-', '_', $uppercase ? ucwords($this->package_name, '-') : $this->package_name); - $class_attribute = match ($this->type) { - 'library' => Library::class, - 'php-extension' => Extension::class, - 'target', 'virtual-target' => Target::class, - }; - $package_class = match ($this->type) { - 'library' => LibraryPackage::class, - 'php-extension' => PhpExtensionPackage::class, - 'target', 'virtual-target' => TargetPackage::class, - }; - $uses[] = $class_attribute; - $uses[] = $package_class; - $uses[] = BuildFor::class; - $uses[] = PackageInstaller::class; - - foreach ($uses as $use) { - $namespace->addUse($use); - } - - // add class attribute - $class = $namespace->addClass($class_name); - $class->addAttribute($class_attribute, [$this->package_name]); - - // add build functions if enabled - $funcs = []; - foreach ($this->build_for_enables as $os_family => $func_name) { - if ($func_name !== null) { - $funcs[$func_name][] = $os_family; - } - } - foreach ($funcs as $name => $oss) { - $method = $class->addMethod(name: $name ?: 'build') - ->setPublic() - ->setReturnType('void'); - // check if function executor is bound - if (isset($this->func_executor_binding[$name])) { - $executor = $this->func_executor_binding[$name]; - [$executor_use, $code] = $executor->generateCode(); - $namespace->addUse($executor_use); - $method->setBody($code); - } - $method->addParameter('package')->setType($package_class); - $method->addParameter('installer')->setType(PackageInstaller::class); - foreach ($oss as $os) { - $method->addAttribute(BuildFor::class, [$os]); - } - } - - return $printer->printFile($file); - } - - /** - * Generate package config - */ - public function generateConfigArray(): array - { - $config = ['type' => $this->type]; - - // Add dependencies - foreach ($this->depends as $suffix => $depends) { - $k = $suffix !== '' ? "depends@{$suffix}" : 'depends'; - $config[$k] = $depends; - } - - // add suggests - foreach ($this->suggests as $suffix => $suggests) { - $k = $suffix !== '' ? "suggests@{$suffix}" : 'suggests'; - $config[$k] = $suggests; - } - - // Add frameworks - if (!empty($this->frameworks)) { - $config['frameworks'] = $this->frameworks; - } - - // Add static libs - foreach ($this->static_libs as $suffix => $libs) { - $k = $suffix !== '' ? "static-libs@{$suffix}" : 'static-libs'; - $config[$k] = $libs; - } - - // Add headers - foreach ($this->headers as $suffix => $headers) { - $k = $suffix !== '' ? "headers@{$suffix}" : 'headers'; - $config[$k] = $headers; - } - - // Add static bins - foreach ($this->static_bins as $suffix => $bins) { - $k = $suffix !== '' ? "static-bins@{$suffix}" : 'static-bins'; - $config[$k] = $bins; - } - - // Add artifact - if ($this->artifact !== null) { - $config['artifact'] = $this->artifact->getName(); - } - - // Add licenses - if (!empty($this->licenses)) { - if (count($this->licenses) === 1) { - $config['license'] = $this->licenses[0]; - } else { - $config['license'] = $this->licenses; - } - } - - return $config; - } - - public function setConfigFile(string $config_file): static - { - $clone = clone $this; - $clone->config_file = $config_file; - return $clone; - } - - public function writeConfigFile(): string - { - if ($this->config_file === null) { - throw new ValidationException('Config file path is not set.'); - } - $config_array = $this->generateConfigArray(); - $config_file_json = json_decode(FileSystem::readFile($this->config_file), true); - if (!is_array($config_file_json)) { - throw new ValidationException('Existing config file is not a valid JSON array.'); - } - $config_file_json[$this->package_name] = $config_array; - ksort($config_file_json); - $json_content = json_encode($config_file_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - if ($json_content === false) { - throw new ValidationException('Failed to encode package config to JSON.'); - } - if (file_put_contents($this->config_file, $json_content) === false) { - throw new FileSystemException("Failed to write config file: {$this->config_file}"); - } - return $this->config_file; - } - - public function writeAll(): array - { - // write config - $package_config_file = $this->writeConfigFile(); - $artifact_config_file = $this->artifact->writeConfigFile(); - - // write class file - $package_class_file_content = $this->generatePackageClassFile('StaticPHP\Packages'); - $package_class_file_path = str_replace('-', '_', $this->package_name) . '.php'; - // file_put_contents($package_class_file_path, $package_class_file_content); // Uncomment this line to actually write the file - return [ - 'package_config' => $package_config_file, - 'artifact_config' => $artifact_config_file, - 'package_class_file' => $package_class_file_path, - 'package_class_content' => $package_class_file_content, - ]; - } -}