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