From b88a68dab840e74cadd5b64957a71c07733258ff Mon Sep 17 00:00:00 2001 From: henderkes Date: Wed, 29 Oct 2025 18:55:26 +0100 Subject: [PATCH 01/14] fix postgresql libraries when --with-suggested-libs is false --- config/lib.json | 4 ++-- src/SPC/builder/unix/library/postgresql.php | 2 +- src/SPC/util/DependencyUtil.php | 19 ++++++++++++++++++- src/SPC/util/SPCConfigUtil.php | 3 ++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/config/lib.json b/config/lib.json index c3d864f4..4f1dd601 100644 --- a/config/lib.json +++ b/config/lib.json @@ -607,8 +607,8 @@ }, "libxml2": { "source": "libxml2", - "static-libs-unix": [ - "libxml2.a" + "pkg-configs": [ + "libxml-2.0" ], "static-libs-windows": [ "libxml2s.lib", diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index 67935d14..a81f93de 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -46,7 +46,7 @@ trait postgresql protected function build(): void { $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies()); - $spc = new SPCConfigUtil($this->getBuilder(), ['no_php' => true, 'libs_only_deps' => true]); + $spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]); $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs')); $env_vars = [ diff --git a/src/SPC/util/DependencyUtil.php b/src/SPC/util/DependencyUtil.php index 83123f65..c300832d 100644 --- a/src/SPC/util/DependencyUtil.php +++ b/src/SPC/util/DependencyUtil.php @@ -105,7 +105,7 @@ class DependencyUtil * @param array $additional_libs Array of additional libraries * @return array Ordered array of extension names */ - public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array + public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false, array $extra_libraries_from_builder = []): array { $dep_list = self::platExtToLibs(); @@ -144,6 +144,23 @@ class DependencyUtil $dep_list[$name]['suggests'] = array_values($dep_list[$name]['suggests']); } } + // include suggested libraries + if ($extra_libraries_from_builder) { + // check every deps suggests + foreach ($dep_list as $name => $obj) { + $del_list = []; + foreach ($obj['suggests'] as $id => $suggest) { + if (!str_starts_with($suggest, 'ext@') && in_array($suggest, $extra_libraries_from_builder)) { + $dep_list[$name]['depends'][] = $suggest; + $del_list[] = $id; + } + } + foreach ($del_list as $id) { + unset($dep_list[$name]['suggests'][$id]); + } + $dep_list[$name]['suggests'] = array_values($dep_list[$name]['suggests']); + } + } // convert ext_name to ext@ext_name $origin_exts = $exts; diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index f321ca10..d7f35efb 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -62,7 +62,8 @@ class SPCConfigUtil $extensions[] = $ext; } } - [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); + $extra_builder_libs = $this->builder?->getLibs() ?? []; + [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib, array_map(fn ($l) => $l->getName(), $extra_builder_libs)); ob_start(); if ($this->builder === null) { From ff15973a255736d59ec893c5043fc462be5010cd Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 31 Oct 2025 09:08:15 +0100 Subject: [PATCH 02/14] suggestions --- src/SPC/builder/unix/library/postgresql.php | 2 +- src/SPC/util/DependencyUtil.php | 19 +------------------ src/SPC/util/SPCConfigUtil.php | 3 +-- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index a81f93de..e55b6e93 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -45,7 +45,7 @@ trait postgresql protected function build(): void { - $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies()); + $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true)); $spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]); $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs')); diff --git a/src/SPC/util/DependencyUtil.php b/src/SPC/util/DependencyUtil.php index c300832d..83123f65 100644 --- a/src/SPC/util/DependencyUtil.php +++ b/src/SPC/util/DependencyUtil.php @@ -105,7 +105,7 @@ class DependencyUtil * @param array $additional_libs Array of additional libraries * @return array Ordered array of extension names */ - public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false, array $extra_libraries_from_builder = []): array + public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array { $dep_list = self::platExtToLibs(); @@ -144,23 +144,6 @@ class DependencyUtil $dep_list[$name]['suggests'] = array_values($dep_list[$name]['suggests']); } } - // include suggested libraries - if ($extra_libraries_from_builder) { - // check every deps suggests - foreach ($dep_list as $name => $obj) { - $del_list = []; - foreach ($obj['suggests'] as $id => $suggest) { - if (!str_starts_with($suggest, 'ext@') && in_array($suggest, $extra_libraries_from_builder)) { - $dep_list[$name]['depends'][] = $suggest; - $del_list[] = $id; - } - } - foreach ($del_list as $id) { - unset($dep_list[$name]['suggests'][$id]); - } - $dep_list[$name]['suggests'] = array_values($dep_list[$name]['suggests']); - } - } // convert ext_name to ext@ext_name $origin_exts = $exts; diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index d7f35efb..f321ca10 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -62,8 +62,7 @@ class SPCConfigUtil $extensions[] = $ext; } } - $extra_builder_libs = $this->builder?->getLibs() ?? []; - [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib, array_map(fn ($l) => $l->getName(), $extra_builder_libs)); + [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); ob_start(); if ($this->builder === null) { From 5cb6a75e7d651f7dfeef821c6cf321a05a3af521 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 3 Nov 2025 20:29:15 +0100 Subject: [PATCH 03/14] add extra features to librdkafka (curl, ssl, sasl --- config/lib.json | 4 ++++ src/SPC/builder/extension/rdkafka.php | 4 ++++ src/SPC/builder/unix/library/librdkafka.php | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config/lib.json b/config/lib.json index c3d864f4..4a01ad49 100644 --- a/config/lib.json +++ b/config/lib.json @@ -513,6 +513,10 @@ ], "cpp-library": true, "lib-suggests": [ + "curl", + "liblz4", + "openssl", + "zlib", "zstd" ] }, diff --git a/src/SPC/builder/extension/rdkafka.php b/src/SPC/builder/extension/rdkafka.php index 575ab309..283bad46 100644 --- a/src/SPC/builder/extension/rdkafka.php +++ b/src/SPC/builder/extension/rdkafka.php @@ -15,6 +15,7 @@ class rdkafka extends Extension { FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\n", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm \$RDKAFKA_LIBS\n"); FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\"\n", '-L$RDKAFKA_DIR/$PHP_LIBDIR -lm $RDKAFKA_LIBS"'); + FileSystem::replaceFileStr("{$this->source_dir}/config.m4", 'PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,', 'AC_CHECK_LIB([$LIBNAME], [$LIBSYMBOL],'); return true; } @@ -39,6 +40,9 @@ class rdkafka extends Extension { $pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1]; $pkgconf_libs = trim(implode('', $pkgconf_libs)); + $pkgconf_libs = str_replace(BUILD_LIB_PATH . '/lib', '-l', $pkgconf_libs); + $pkgconf_libs = str_replace('.a', '', $pkgconf_libs); + $pkgconf_libs = deduplicate_flags($pkgconf_libs); return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"'; } } diff --git a/src/SPC/builder/unix/library/librdkafka.php b/src/SPC/builder/unix/library/librdkafka.php index f2bea09f..b654eaaa 100644 --- a/src/SPC/builder/unix/library/librdkafka.php +++ b/src/SPC/builder/unix/library/librdkafka.php @@ -32,20 +32,28 @@ trait librdkafka 'zstd', function ($lib) { putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a"); - return ''; + return '--enable-zstd'; }, '--disable-zstd' ) + ->optionalLib( + 'curl', + function () { + $pkg_libs = shell()->execWithResult('pkg-config --libs --static libcurl')[1]; + putenv("STATIC_LIB_libcurl={$pkg_libs}"); + return '--enable-curl'; + }, + '--disable-curl' + ) + ->optionalLib('openssl', '--enable-ssl', '--disable-ssl') + ->optionalLib('zlib', '--enable-zlib', '--disable-zlib') ->removeConfigureArgs( '--with-pic', '--enable-pic', ) ->configure( - '--disable-curl', '--disable-sasl', '--disable-valgrind', - '--disable-zlib', - '--disable-ssl', ) ->make(); From 7a4f28e939674571698d7d88c18886d4d7b7ddc7 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 3 Nov 2025 20:39:26 +0100 Subject: [PATCH 04/14] add frankenphp version --- 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 0d123d1f..f3f073d9 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -301,7 +301,7 @@ abstract class UnixBuilderBase extends BuilderBase } $config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list); - $cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'); + $cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -DFRANKENPHP_VERSION=' . $frankenPhpVersion; $libs = $config['libs']; // Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix. if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') || From 0b17ce9e612773dab334324ef3245186ec3f253a Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 3 Nov 2025 20:47:42 +0100 Subject: [PATCH 05/14] test rdkafka with all suggested libs --- 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 5aef4bd8..7797367d 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -49,7 +49,7 @@ $prefer_pre_built = false; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'gettext', + 'Linux', 'Darwin' => 'rdkafka', 'Windows' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pdo,pdo_mysql,pdo_sqlite,phar,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip', }; From 589a4a9803c2b31be9da632160ffdaeae920b4d0 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 3 Nov 2025 21:13:47 +0100 Subject: [PATCH 06/14] test rdkafka with all suggested libs --- src/globals/test-extensions.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 391c401b..43ce5d15 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,11 +13,11 @@ declare(strict_types=1); // 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', + // '8.5', // 'git', ]; @@ -62,7 +62,7 @@ $shared_extensions = match (PHP_OS_FAMILY) { }; // If you want to test lib-suggests for all extensions and libraries, set it to true. -$with_suggested_libs = false; +$with_suggested_libs = true; // 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) { From fc118d709e3219c42e2c459c9b82930a7709e69b Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 3 Nov 2025 21:58:46 +0100 Subject: [PATCH 07/14] Remove deduplication of pkg-config libraries Removed deduplication of pkg-config libraries. --- src/SPC/builder/extension/rdkafka.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SPC/builder/extension/rdkafka.php b/src/SPC/builder/extension/rdkafka.php index 283bad46..644b475a 100644 --- a/src/SPC/builder/extension/rdkafka.php +++ b/src/SPC/builder/extension/rdkafka.php @@ -42,7 +42,6 @@ class rdkafka extends Extension $pkgconf_libs = trim(implode('', $pkgconf_libs)); $pkgconf_libs = str_replace(BUILD_LIB_PATH . '/lib', '-l', $pkgconf_libs); $pkgconf_libs = str_replace('.a', '', $pkgconf_libs); - $pkgconf_libs = deduplicate_flags($pkgconf_libs); return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"'; } } From aa5c829fae13f0ab0c1ae92b83a9e8f68c4ea619 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:35:15 +0800 Subject: [PATCH 08/14] Add missing file and line for Unhandled exception --- src/SPC/exception/ExceptionHandler.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index d784be71..df5e4bf0 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -159,7 +159,9 @@ class ExceptionHandler public static function handleDefaultException(\Throwable $e): void { $class = get_class($e); - self::logError("✗ Unhandled exception {$class}:\n\t{$e->getMessage()}\n"); + $file = $e->getFile(); + $line = $e->getLine(); + self::logError("✗ Unhandled exception {$class} on {$file} line {$line}:\n\t{$e->getMessage()}\n"); self::logError('Stack trace:'); self::logError(ConsoleColor::gray($e->getTraceAsString()) . PHP_EOL, 4); self::logError('⚠ Please report this exception to: https://github.com/crazywhalecc/static-php-cli/issues'); From f34ecf9468bca0c976102b2f933b72ca583014da Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:35:31 +0800 Subject: [PATCH 09/14] Use pkg-configs for librdkafka --- config/lib.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config/lib.json b/config/lib.json index 8d1da464..528777e1 100644 --- a/config/lib.json +++ b/config/lib.json @@ -506,10 +506,9 @@ }, "librdkafka": { "source": "librdkafka", - "static-libs-unix": [ - "librdkafka.a", - "librdkafka++.a", - "librdkafka-static.a" + "pkg-configs": [ + "rdkafka++-static", + "rdkafka-static" ], "cpp-library": true, "lib-suggests": [ From 4d5641f6ec11265ebe396b6ca1f672fe09226950 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:35:43 +0800 Subject: [PATCH 10/14] Change librdkafka to cmake --- src/SPC/builder/unix/library/librdkafka.php | 50 ++++++--------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/src/SPC/builder/unix/library/librdkafka.php b/src/SPC/builder/unix/library/librdkafka.php index b654eaaa..49b0962b 100644 --- a/src/SPC/builder/unix/library/librdkafka.php +++ b/src/SPC/builder/unix/library/librdkafka.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace SPC\builder\unix\library; use SPC\store\FileSystem; -use SPC\util\executor\UnixAutoconfExecutor; +use SPC\util\executor\UnixCMakeExecutor; trait librdkafka { @@ -26,42 +26,18 @@ trait librdkafka protected function build(): void { - UnixAutoconfExecutor::create($this) - ->appendEnv(['CFLAGS' => '-Wno-int-conversion -Wno-unused-but-set-variable -Wno-unused-variable']) - ->optionalLib( - 'zstd', - function ($lib) { - putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a"); - return '--enable-zstd'; - }, - '--disable-zstd' + UnixCMakeExecutor::create($this) + ->optionalLib('zstd', ...cmake_boolean_args('WITH_ZSTD')) + ->optionalLib('curl', ...cmake_boolean_args('WITH_CURL')) + ->optionalLib('openssl', ...cmake_boolean_args('WITH_SSL')) + ->optionalLib('zlib', ...cmake_boolean_args('WITH_ZLIB')) + ->addConfigureArgs( + '-DWITH_SASL=OFF', + '-DRDKAFKA_BUILD_STATIC=ON', + '-DRDKAFKA_BUILD_EXAMPLES=OFF', + '-DRDKAFKA_BUILD_TESTS=OFF', + '-DENABLE_LZ4_EXT=OFF', ) - ->optionalLib( - 'curl', - function () { - $pkg_libs = shell()->execWithResult('pkg-config --libs --static libcurl')[1]; - putenv("STATIC_LIB_libcurl={$pkg_libs}"); - return '--enable-curl'; - }, - '--disable-curl' - ) - ->optionalLib('openssl', '--enable-ssl', '--disable-ssl') - ->optionalLib('zlib', '--enable-zlib', '--disable-zlib') - ->removeConfigureArgs( - '--with-pic', - '--enable-pic', - ) - ->configure( - '--disable-sasl', - '--disable-valgrind', - ) - ->make(); - - $this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']); - // remove dynamic libs - shell() - ->exec("rm -rf {$this->getLibDir()}/*.so.*") - ->exec("rm -rf {$this->getLibDir()}/*.so") - ->exec("rm -rf {$this->getLibDir()}/*.dylib"); + ->build(); } } From 08362fb6e5976e9f5b21af41956b962b6673ff61 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:36:29 +0800 Subject: [PATCH 11/14] Add helper function for SPCConfigUtil --- src/SPC/builder/Extension.php | 75 ++++++++++----------- src/SPC/builder/extension/grpc.php | 2 +- src/SPC/builder/extension/rdkafka.php | 8 +-- src/SPC/builder/extension/swoole.php | 2 +- src/SPC/builder/unix/library/postgresql.php | 2 +- src/SPC/util/SPCConfigUtil.php | 59 ++++++++++++++++ 6 files changed, 100 insertions(+), 48 deletions(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 5b6a3329..0bdb36d2 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -220,7 +220,7 @@ class Extension */ public function patchBeforeSharedMake(): bool { - $config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs())); + $config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null; $lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : ''; @@ -486,18 +486,46 @@ class Extension return $this->build_static; } + public function getLibraryDependencies(bool $recursive = false): array + { + $ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase); + if (!$recursive) { + return $ret; + } + + $deps = []; + + $added = 1; + while ($added !== 0) { + $added = 0; + foreach ($ret as $depName => $dep) { + foreach ($dep->getDependencies(true) as $depdepName => $depdep) { + if (!array_key_exists($depdepName, $deps)) { + $deps[$depdepName] = $depdep; + ++$added; + } + } + if (!array_key_exists($depName, $deps)) { + $deps[$depName] = $dep; + } + } + } + + if (array_key_exists(0, $deps)) { + $zero = [0 => $deps[0]]; + unset($deps[0]); + return $zero + $deps; + } + return $deps; + } + /** * Returns the environment variables a shared extension needs to be built. * CFLAGS, CXXFLAGS, LDFLAGS and so on. */ protected function getSharedExtensionEnv(): array { - $config = (new SPCConfigUtil($this->builder))->config( - [$this->getName()], - array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)), - $this->builder->getOption('with-suggested-exts'), - $this->builder->getOption('with-suggested-libs'), - ); + $config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group '; $postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group '; @@ -567,37 +595,4 @@ class Extension } return [trim($staticLibString), trim($sharedLibString)]; } - - private function getLibraryDependencies(bool $recursive = false): array - { - $ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase); - if (!$recursive) { - return $ret; - } - - $deps = []; - - $added = 1; - while ($added !== 0) { - $added = 0; - foreach ($ret as $depName => $dep) { - foreach ($dep->getDependencies(true) as $depdepName => $depdep) { - if (!array_key_exists($depdepName, $deps)) { - $deps[$depdepName] = $depdep; - ++$added; - } - } - if (!array_key_exists($depName, $deps)) { - $deps[$depName] = $dep; - } - } - } - - if (array_key_exists(0, $deps)) { - $zero = [0 => $deps[0]]; - unset($deps[0]); - return $zero + $deps; - } - return $deps; - } } diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php index 7388eaff..fb31c85f 100644 --- a/src/SPC/builder/extension/grpc.php +++ b/src/SPC/builder/extension/grpc.php @@ -43,7 +43,7 @@ class grpc extends Extension public function patchBeforeConfigure(): bool { $util = new SPCConfigUtil($this->builder, ['libs_only_deps' => true]); - $config = $util->config(['grpc']); + $config = $util->getExtensionConfig($this); $libs = $config['libs']; FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lgrpc', $libs); return true; diff --git a/src/SPC/builder/extension/rdkafka.php b/src/SPC/builder/extension/rdkafka.php index 644b475a..58af50ff 100644 --- a/src/SPC/builder/extension/rdkafka.php +++ b/src/SPC/builder/extension/rdkafka.php @@ -7,6 +7,7 @@ namespace SPC\builder\extension; use SPC\builder\Extension; use SPC\store\FileSystem; use SPC\util\CustomExt; +use SPC\util\SPCConfigUtil; #[CustomExt('rdkafka')] class rdkafka extends Extension @@ -38,10 +39,7 @@ class rdkafka extends Extension public function getUnixConfigureArg(bool $shared = false): string { - $pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1]; - $pkgconf_libs = trim(implode('', $pkgconf_libs)); - $pkgconf_libs = str_replace(BUILD_LIB_PATH . '/lib', '-l', $pkgconf_libs); - $pkgconf_libs = str_replace('.a', '', $pkgconf_libs); - return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"'; + $pkgconf_libs = (new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]))->getExtensionConfig($this); + return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . " RDKAFKA_LIBS=\"{$pkgconf_libs['libs']}\""; } } diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index 7ff4b331..f6ff5931 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -70,7 +70,7 @@ class swoole extends Extension $arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd'; $arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite'; if ($this->builder->getExt('swoole-hook-odbc')) { - $config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']); + $config = (new SPCConfigUtil($this->builder))->getLibraryConfig($this->builder->getLib('unixodbc')); $arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"'; } diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index e55b6e93..6e0cb606 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -47,7 +47,7 @@ trait postgresql { $libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true)); $spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]); - $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs')); + $config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false)); $env_vars = [ 'CFLAGS' => $config['cflags'], diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index f321ca10..51b0b2d7 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -7,6 +7,7 @@ namespace SPC\util; use SPC\builder\BuilderBase; use SPC\builder\BuilderProvider; use SPC\builder\Extension; +use SPC\builder\LibraryBase; use SPC\exception\WrongUsageException; use SPC\store\Config; use Symfony\Component\Console\Input\ArgvInput; @@ -53,6 +54,9 @@ class SPCConfigUtil */ public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array { + logger()->debug('config extensions: ' . implode(',', $extensions)); + logger()->debug('config libs: ' . implode(',', $libraries)); + logger()->debug('config suggest for [ext, lib]: ' . ($include_suggest_ext ? 'true' : 'false') . ',' . ($include_suggest_lib ? 'true' : 'false')); $extra_exts = []; foreach ($extensions as $ext) { $extra_exts = array_merge($extra_exts, Config::getExt($ext, 'ext-suggests', [])); @@ -124,6 +128,61 @@ class SPCConfigUtil ]; } + /** + * [Helper function] + * Get configuration for a specific extension(s) dependencies. + * + * @param Extension|Extension[] $extension Extension instance or list + * @param bool $include_suggest_ext Whether to include suggested extensions + * @param bool $include_suggest_lib Whether to include suggested libraries + * @return array{ + * cflags: string, + * ldflags: string, + * libs: string + * } + */ + public function getExtensionConfig(array|Extension $extension, bool $include_suggest_ext = false, bool $include_suggest_lib = false): array + { + if (!is_array($extension)) { + $extension = [$extension]; + } + return $this->config( + extensions: array_map(fn ($x) => $x->getName(), $extension), + include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false, + include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false, + ); + } + + /** + * [Helper function] + * Get configuration for a specific library(s) dependencies. + * + * @param LibraryBase|LibraryBase[] $lib Library instance or list + * @param bool $include_suggest_lib Whether to include suggested libraries + * @return array{ + * cflags: string, + * ldflags: string, + * libs: string + * } + */ + public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_lib = false): array + { + if (!is_array($lib)) { + $lib = [$lib]; + } + $save_no_php = $this->no_php; + $this->no_php = true; + $save_libs_only_deps = $this->libs_only_deps; + $this->libs_only_deps = true; + $ret = $this->config( + libraries: array_map(fn ($x) => $x->getName(), $lib), + include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false, + ); + $this->no_php = $save_no_php; + $this->libs_only_deps = $save_libs_only_deps; + return $ret; + } + private function hasCpp(array $extensions, array $libraries): bool { // judge cpp-extension From 6d1c6d7f615aa770e359ca1ddf596dc8fae93f2d Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:38:11 +0800 Subject: [PATCH 12/14] Add PHPDocs --- src/SPC/builder/Extension.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 0bdb36d2..a6c6ab94 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -486,6 +486,11 @@ class Extension return $this->build_static; } + /** + * Get the library dependencies that current extension depends on. + * + * @param bool $recursive Whether it includes dependencies recursively + */ public function getLibraryDependencies(bool $recursive = false): array { $ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase); From 463a98b1bf8cf681eb658b43f6213d3ff5853db4 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 13:51:11 +0800 Subject: [PATCH 13/14] Support suggested libs not specified by with-suggested-libs --- src/SPC/builder/unix/library/librdkafka.php | 2 +- src/SPC/util/SPCConfigUtil.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/librdkafka.php b/src/SPC/builder/unix/library/librdkafka.php index 49b0962b..222760d0 100644 --- a/src/SPC/builder/unix/library/librdkafka.php +++ b/src/SPC/builder/unix/library/librdkafka.php @@ -31,12 +31,12 @@ trait librdkafka ->optionalLib('curl', ...cmake_boolean_args('WITH_CURL')) ->optionalLib('openssl', ...cmake_boolean_args('WITH_SSL')) ->optionalLib('zlib', ...cmake_boolean_args('WITH_ZLIB')) + ->optionalLib('liblz4', ...cmake_boolean_args('ENABLE_LZ4_EXT')) ->addConfigureArgs( '-DWITH_SASL=OFF', '-DRDKAFKA_BUILD_STATIC=ON', '-DRDKAFKA_BUILD_EXAMPLES=OFF', '-DRDKAFKA_BUILD_TESTS=OFF', - '-DENABLE_LZ4_EXT=OFF', ) ->build(); } diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 51b0b2d7..a74d6a24 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -146,8 +146,10 @@ class SPCConfigUtil if (!is_array($extension)) { $extension = [$extension]; } + $libs = array_map(fn ($y) => $y->getName(), array_merge(...array_map(fn ($x) => $x->getLibraryDependencies(true), $extension))); return $this->config( extensions: array_map(fn ($x) => $x->getName(), $extension), + libraries: $libs, include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false, include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false, ); From 2c590e58959832d20ca82a93924e9c32d627149f Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 4 Nov 2025 15:52:52 +0800 Subject: [PATCH 14/14] Define dependencies with kv array --- src/SPC/builder/Extension.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index a6c6ab94..c9cd0657 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -516,11 +516,6 @@ class Extension } } - if (array_key_exists(0, $deps)) { - $zero = [0 => $deps[0]]; - unset($deps[0]); - return $zero + $deps; - } return $deps; } @@ -552,7 +547,7 @@ class Extension } logger()->info("enabling {$this->name} without library {$name}"); } else { - $this->dependencies[] = $depLib; + $this->dependencies[$name] = $depLib; } } @@ -565,7 +560,7 @@ class Extension } logger()->info("enabling {$this->name} without extension {$name}"); } else { - $this->dependencies[] = $depExt; + $this->dependencies[$name] = $depExt; } }