use resolved dependency tree instead of asking for with_suggests everywhere

This commit is contained in:
henderkes
2026-05-11 11:35:15 +07:00
parent efdd2a74a5
commit 743934d1fe
6 changed files with 46 additions and 28 deletions

View File

@@ -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' : '') .

View File

@@ -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'],

View File

@@ -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',

View File

@@ -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'

View File

@@ -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;
}
}

View File

@@ -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) {