From 743934d1fefdb3d083ddc2951afde962a61f9684 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 11 May 2026 11:35:15 +0700 Subject: [PATCH] use resolved dependency tree instead of asking for with_suggests everywhere --- src/Package/Extension/pgsql.php | 2 +- src/Package/Library/krb5.php | 2 +- src/Package/Library/postgresql.php | 2 +- src/StaticPHP/Package/PhpExtensionPackage.php | 6 +- src/StaticPHP/Registry/PackageLoader.php | 4 +- src/StaticPHP/Util/SPCConfigUtil.php | 58 +++++++++++++------ 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/Package/Extension/pgsql.php b/src/Package/Extension/pgsql.php index 6e2b8f0b..b5b22a00 100644 --- a/src/Package/Extension/pgsql.php +++ b/src/Package/Extension/pgsql.php @@ -20,7 +20,7 @@ class pgsql extends PhpExtensionPackage public function getUnixConfigureArg(bool $shared, PackageBuilder $builder, PackageInstaller $installer): string { if (php::getPHPVersionID() >= 80400) { - $libfiles = new SPCConfigUtil(['libs_only_deps' => true, 'absolute_libs' => true])->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages()), $builder->getOption('with-suggests'))['libs']; + $libfiles = new SPCConfigUtil(['libs_only_deps' => true, 'absolute_libs' => true])->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages()))['libs']; $libfiles = str_replace("{$builder->getLibDir()}/lib", '-l', $libfiles); $libfiles = str_replace('.a', '', $libfiles); return '--with-pgsql' . ($shared ? '=shared' : '') . diff --git a/src/Package/Library/krb5.php b/src/Package/Library/krb5.php index 1370afcc..428c6d9b 100644 --- a/src/Package/Library/krb5.php +++ b/src/Package/Library/krb5.php @@ -27,7 +27,7 @@ class krb5 $resolved = array_keys($installer->getResolvedPackages()); $spc = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true]); - $config = $spc->getPackageDepsConfig($lib->getName(), $resolved, include_suggests: true); + $config = $spc->getPackageDepsConfig($lib->getName(), $resolved); $extraEnv = [ 'CFLAGS' => '-fcommon', 'LIBS' => $config['libs'], diff --git a/src/Package/Library/postgresql.php b/src/Package/Library/postgresql.php index 45c48577..b449e859 100644 --- a/src/Package/Library/postgresql.php +++ b/src/Package/Library/postgresql.php @@ -58,7 +58,7 @@ class postgresql extends LibraryPackage public function buildUnix(PackageInstaller $installer, PackageBuilder $builder): void { $spc_config = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true]); - $config = $spc_config->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages()), include_suggests: $builder->getOption('with-suggests', false)); + $config = $spc_config->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages())); $env_vars = [ 'CFLAGS' => $config['cflags'] . ' -std=c17', diff --git a/src/StaticPHP/Package/PhpExtensionPackage.php b/src/StaticPHP/Package/PhpExtensionPackage.php index 6fc5757e..2919e227 100644 --- a/src/StaticPHP/Package/PhpExtensionPackage.php +++ b/src/StaticPHP/Package/PhpExtensionPackage.php @@ -274,8 +274,7 @@ class PhpExtensionPackage extends Package $compiler_extra = trim($compiler_extra . ' -lcompiler_rt'); GlobalEnvManager::putenv("SPC_COMPILER_EXTRA={$compiler_extra}"); } - // include_suggests so transitive optional libs (e.g. librdkafka → lz4/zstd/ssl) are in the link line - $config = (new SPCConfigUtil())->getExtensionConfig($this, include_suggests: true); + $config = (new SPCConfigUtil())->getExtensionConfig($this); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group '; $postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group '; @@ -336,8 +335,7 @@ class PhpExtensionPackage extends Package public function patchSharedLibAdd(): void { - // include_suggests so transitive optional libs (e.g. librdkafka → lz4/zstd/ssl) are in the link line - $config = (new SPCConfigUtil())->getExtensionConfig($this, include_suggests: true); + $config = (new SPCConfigUtil())->getExtensionConfig($this); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' diff --git a/src/StaticPHP/Registry/PackageLoader.php b/src/StaticPHP/Registry/PackageLoader.php index 212bcb10..b9e3364c 100644 --- a/src/StaticPHP/Registry/PackageLoader.php +++ b/src/StaticPHP/Registry/PackageLoader.php @@ -375,7 +375,7 @@ class PackageLoader continue; } foreach ($conditionals as $class) { - if (!ApplicationContext::has($class)) { + if (ApplicationContext::tryGet($class) === null) { continue 2; } } @@ -394,7 +394,7 @@ class PackageLoader continue; } foreach ($conditionals as $class) { - if (!ApplicationContext::has($class)) { + if (ApplicationContext::tryGet($class) === null) { continue 2; } } diff --git a/src/StaticPHP/Util/SPCConfigUtil.php b/src/StaticPHP/Util/SPCConfigUtil.php index 63b0e90e..fd2460ee 100644 --- a/src/StaticPHP/Util/SPCConfigUtil.php +++ b/src/StaticPHP/Util/SPCConfigUtil.php @@ -5,8 +5,10 @@ declare(strict_types=1); namespace StaticPHP\Util; use StaticPHP\Config\PackageConfig; +use StaticPHP\DI\ApplicationContext; use StaticPHP\Exception\WrongUsageException; use StaticPHP\Package\LibraryPackage; +use StaticPHP\Package\PackageInstaller; use StaticPHP\Package\PhpExtensionPackage; use StaticPHP\Runtime\SystemTarget; @@ -118,6 +120,10 @@ class SPCConfigUtil * [Helper function] * Get configuration for a specific extension(s) dependencies. * + * Uses the installer's resolved package set as the source of truth — only libraries that + * are actually enabled in this build appear in the result. The resolved set already + * reflects the user's `--with-suggests` choice. + * * @param array|PhpExtensionPackage $extension_packages Extension instance or list * @return array{ * cflags: string, @@ -125,30 +131,30 @@ class SPCConfigUtil * libs: string * } */ - public function getExtensionConfig(array|PhpExtensionPackage $extension_packages, bool $include_suggests = false): array + public function getExtensionConfig(array|PhpExtensionPackage $extension_packages): array { if (!is_array($extension_packages)) { $extension_packages = [$extension_packages]; } - return $this->config( - packages: array_map(fn ($y) => $y->getName(), $extension_packages), - include_suggests: $include_suggests, - ); + $names = array_map(fn ($y) => $y->getName(), $extension_packages); + return $this->configWithResolvedPackages($this->collectEnabledLinkPackages($names)); } /** * [Helper function] * Get configuration for a specific library(s) dependencies. * - * @param array|LibraryPackage $lib Library instance or list - * @param bool $include_suggests Whether to include suggested libraries + * Like {@see getExtensionConfig()}, draws from the resolved package set so we never + * link against a library that wasn't built. + * + * @param array|LibraryPackage $lib Library instance or list * @return array{ * cflags: string, * ldflags: string, * libs: string * } */ - public function getLibraryConfig(array|LibraryPackage $lib, bool $include_suggests = false): array + public function getLibraryConfig(array|LibraryPackage $lib): array { if (!is_array($lib)) { $lib = [$lib]; @@ -157,35 +163,31 @@ class SPCConfigUtil $this->no_php = true; $save_libs_only_deps = $this->libs_only_deps; $this->libs_only_deps = true; - $ret = $this->config( - packages: array_map(fn ($y) => $y->getName(), $lib), - include_suggests: $include_suggests, - ); + $names = array_map(fn ($y) => $y->getName(), $lib); + $ret = $this->configWithResolvedPackages($this->collectEnabledLinkPackages($names)); $this->no_php = $save_no_php; $this->libs_only_deps = $save_libs_only_deps; return $ret; } /** - * Get build configuration for a package and its sub-dependencies within a resolved set. + * Get build configuration for a package's sub-dependencies within a resolved set. * - * This is useful when you need to statically link something against a specific - * library and all its transitive dependencies. It properly handles optional - * dependencies by only including those that were actually resolved. + * Walks both depends and suggests edges — the resolved set is the filter, so anything + * reachable but unbuilt is naturally excluded. No `include_suggests` knob is needed. * * @param string $package_name The package to get config for * @param string[] $resolved_packages The full resolved package list - * @param bool $include_suggests Whether to include resolved suggests * @return array{ * cflags: string, * ldflags: string, * libs: string * } */ - public function getPackageDepsConfig(string $package_name, array $resolved_packages, bool $include_suggests = false): array + public function getPackageDepsConfig(string $package_name, array $resolved_packages): array { // Get sub-dependencies within the resolved set - $sub_deps = DependencyResolver::getSubDependencies($package_name, $resolved_packages, $include_suggests); + $sub_deps = DependencyResolver::getSubDependencies($package_name, $resolved_packages, include_suggests: true); if (empty($sub_deps)) { return [ @@ -299,6 +301,24 @@ class SPCConfigUtil return implode(' ', $list); } + /** + * For each input package name, gather its transitive deps within the installer's resolved + * set (walking depends + suggests edges), plus the package itself, deduped and in build order. + * + * @param string[] $package_names Input package names + * @return string[] Resolved packages to link against + */ + private function collectEnabledLinkPackages(array $package_names): array + { + $resolved = array_keys(ApplicationContext::get(PackageInstaller::class)->getResolvedPackages()); + $out = []; + foreach ($package_names as $name) { + $sub = DependencyResolver::getSubDependencies($name, $resolved, include_suggests: true); + $out = [...$out, ...$sub, $name]; + } + return array_values(array_unique($out)); + } + private function hasCpp(array $packages): bool { foreach ($packages as $package) {