diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index c48c3ef3..583ad812 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -107,7 +107,7 @@ abstract class UnixBuilderBase extends BuilderBase // if no libs specified, compile all supported libs if ($sorted_libraries === [] && $this->isLibsOnly()) { $libraries = array_keys($support_lib_list); - $sorted_libraries = DependencyUtil::getLibsByDeps($libraries); + $sorted_libraries = DependencyUtil::getLibs($libraries); } // pkg-config must be compiled first, whether it is specified or not diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php index 265751ba..b007e7ff 100644 --- a/src/SPC/builder/windows/WindowsBuilder.php +++ b/src/SPC/builder/windows/WindowsBuilder.php @@ -192,7 +192,7 @@ class WindowsBuilder extends BuilderBase // if no libs specified, compile all supported libs if ($sorted_libraries === [] && $this->isLibsOnly()) { $libraries = array_keys($support_lib_list); - $sorted_libraries = DependencyUtil::getLibsByDeps($libraries); + $sorted_libraries = DependencyUtil::getLibs($libraries); } // add lib object for builder diff --git a/src/SPC/command/BuildLibsCommand.php b/src/SPC/command/BuildLibsCommand.php index f3fb8897..f4d3b26c 100644 --- a/src/SPC/command/BuildLibsCommand.php +++ b/src/SPC/command/BuildLibsCommand.php @@ -60,7 +60,7 @@ class BuildLibsCommand extends BuildCommand // 只编译 library 的情况下,标记 $builder->setLibsOnly(); // 编译和检查库完整 - $libraries = DependencyUtil::getLibsByDeps($libraries); + $libraries = DependencyUtil::getLibs($libraries); $builder->buildLibs($libraries); $time = round(microtime(true) - START_TIME, 3); diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index 542dae34..fa7f7543 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -214,7 +214,7 @@ class DownloadCommand extends BaseCommand */ private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array { - [$extensions, $libraries] = $include_suggests ? DependencyUtil::getAllExtLibsByDeps($extensions) : DependencyUtil::getExtLibsByDeps($extensions); + [$extensions, $libraries] = $include_suggests ? DependencyUtil::getExtsAndLibs($extensions, [], true, true) : DependencyUtil::getExtsAndLibs($extensions); $sources = []; foreach ($extensions as $extension) { if (Config::getExt($extension, 'type') === 'external') { diff --git a/src/SPC/command/DumpLicenseCommand.php b/src/SPC/command/DumpLicenseCommand.php index 5535f820..2d01a692 100644 --- a/src/SPC/command/DumpLicenseCommand.php +++ b/src/SPC/command/DumpLicenseCommand.php @@ -22,8 +22,8 @@ class DumpLicenseCommand extends BaseCommand { $this->addOption('for-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null); $this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src'); - $this->addOption('by-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null); - $this->addOption('by-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null); + $this->addOption('for-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null); + $this->addOption('for-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null); $this->addOption('dump-dir', null, InputOption::VALUE_REQUIRED, 'Change dump directory', BUILD_ROOT_PATH . '/license'); } @@ -39,7 +39,7 @@ class DumpLicenseCommand extends BaseCommand // 从参数中获取要编译的 extensions,并转换为数组 $extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions')))); // 根据提供的扩展列表获取依赖库列表并编译 - [$extensions, $libraries] = DependencyUtil::getExtLibsByDeps($extensions); + [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions); $dumper->addExts($extensions); $dumper->addLibs($libraries); if (!$this->getOption('without-php')) { @@ -52,22 +52,22 @@ class DumpLicenseCommand extends BaseCommand $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); return static::SUCCESS; } - if ($this->getOption('by-libs') !== null) { - $libraries = array_map('trim', array_filter(explode(',', $this->getOption('by-libs')))); - $libraries = DependencyUtil::getLibsByDeps($libraries); + if ($this->getOption('for-libs') !== null) { + $libraries = array_map('trim', array_filter(explode(',', $this->getOption('for-libs')))); + $libraries = DependencyUtil::getLibs($libraries); $dumper->addLibs($libraries); $dumper->dump($this->getOption('dump-dir')); $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); return static::SUCCESS; } - if ($this->getOption('by-sources') !== null) { - $sources = array_map('trim', array_filter(explode(',', $this->getOption('by-sources')))); + if ($this->getOption('for-sources') !== null) { + $sources = array_map('trim', array_filter(explode(',', $this->getOption('for-sources')))); $dumper->addSources($sources); $dumper->dump($this->getOption('dump-dir')); $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); return static::SUCCESS; } - $this->output->writeln('You must use one of "--for-extensions=", "--by-libs=", "--by-sources=" to dump'); + $this->output->writeln('You must use one of "--for-extensions=", "--for-libs=", "--for-sources=" to dump'); return static::FAILURE; } } diff --git a/src/SPC/command/dev/AllExtCommand.php b/src/SPC/command/dev/AllExtCommand.php index 0a161465..90675eb5 100644 --- a/src/SPC/command/dev/AllExtCommand.php +++ b/src/SPC/command/dev/AllExtCommand.php @@ -59,7 +59,7 @@ class AllExtCommand extends BaseCommand } try { - [, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]); + [, $libraries, $not_included] = DependencyUtil::getExtsAndLibs([$extension]); } catch (WrongUsageException) { $libraries = $not_included = []; } diff --git a/src/SPC/util/DependencyUtil.php b/src/SPC/util/DependencyUtil.php index fe958b82..e82a93dc 100644 --- a/src/SPC/util/DependencyUtil.php +++ b/src/SPC/util/DependencyUtil.php @@ -5,104 +5,164 @@ declare(strict_types=1); namespace SPC\util; use SPC\exception\FileSystemException; -use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\Config; /** - * 依赖处理工具类,包含处理扩展、库的依赖列表顺序等 + * Dependency processing tool class, including processing extensions, library dependency list order, etc. */ class DependencyUtil { - public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array + /** + * Convert platform extensions to library dependencies and suggestions. + * + * @throws WrongUsageException + * @throws FileSystemException + */ + public static function platExtToLibs(): array { - if (!$include_suggested_exts && !$include_suggested_libs) { - return self::getExtLibsByDeps($exts, $additional_libs); + $exts = Config::getExts(); + $libs = Config::getLibs(); + $dep_list = []; + foreach ($exts as $ext_name => $ext) { + // convert ext-depends value to ext@xxx + $ext_depends = Config::getExt($ext_name, 'ext-depends', []); + $ext_depends = array_map(fn ($x) => "ext@{$x}", $ext_depends); + // convert ext-suggests value to ext@xxx + $ext_suggests = Config::getExt($ext_name, 'ext-suggests', []); + $ext_suggests = array_map(fn ($x) => "ext@{$x}", $ext_suggests); + // merge ext-depends with lib-depends + $lib_depends = Config::getExt($ext_name, 'lib-depends', []); + $depends = array_merge($ext_depends, $lib_depends); + // merge ext-suggests with lib-suggests + $lib_suggests = Config::getExt($ext_name, 'lib-suggests', []); + $suggests = array_merge($ext_suggests, $lib_suggests); + $dep_list["ext@{$ext_name}"] = [ + 'depends' => $depends, + 'suggests' => $suggests, + ]; } - if ($include_suggested_exts && $include_suggested_libs) { - return self::getAllExtLibsByDeps($exts, $additional_libs); + foreach ($libs as $lib_name => $lib) { + $dep_list[$lib_name] = [ + 'depends' => Config::getLib($lib_name, 'lib-depends', []), + 'suggests' => Config::getLib($lib_name, 'lib-suggests', []), + ]; } - if (!$include_suggested_exts) { - return self::getExtLibsByDeps($exts, $additional_libs); - } - return self::getAllExtLibsByDeps($exts, $additional_libs, false); + // here is an array that only contains dependency map + return $dep_list; } /** - * Obtain the dependent lib list according to the required ext list, and sort according to the dependency - * - * @param array $exts extensions list - * @param array $additional_libs List of additional libraries to add to activate the extra library features triggered by lib-suggests - * @return array Returns an array containing three arrays, [extensions, libraries, not included extensions] * @throws WrongUsageException - * @throws RuntimeException * @throws FileSystemException */ - public static function getExtLibsByDeps(array $exts, array $additional_libs = [], bool $include_suggested_exts = false): array + public static function getLibs(array $libs, bool $include_suggested_libs = false): array { - $sorted = []; - $visited = []; - $not_included_exts = []; - foreach ($exts as $ext) { - if (!isset($visited[$ext])) { - self::visitExtDeps($ext, $visited, $sorted); - } - } - $sorted_suggests = []; - $visited_suggests = []; - $final = []; - foreach ($exts as $ext) { - if (!isset($visited_suggests[$ext])) { - self::visitExtAllDeps($ext, $visited_suggests, $sorted_suggests); - } - } - foreach ($sorted_suggests as $suggest) { - if (in_array($suggest, $sorted)) { - $final[] = $suggest; - } - } - $libs = $additional_libs; + $dep_list = self::platExtToLibs(); - foreach ($final as $ext) { - if (!in_array($ext, $exts)) { - $not_included_exts[] = $ext; - } - foreach (Config::getExt($ext, 'lib-depends', []) as $lib) { - if (!in_array($lib, $libs)) { - $libs[] = $lib; + if ($include_suggested_libs) { + foreach ($dep_list as $name => $obj) { + foreach ($obj['suggests'] as $id => $suggest) { + if (!str_starts_with($suggest, 'ext@')) { + $dep_list[$name]['depends'][] = $suggest; + array_splice($dep_list[$name]['suggests'], $id, 1); + } } } } - return [$final, self::getLibsByDeps($libs), $not_included_exts]; + + $final = self::doVisitPlat($libs, $dep_list); + + $libs_final = []; + foreach ($final as $item) { + if (!str_starts_with($item, 'ext@')) { + $libs_final[] = $item; + } + } + return $libs_final; } /** - * 根据 lib 库的依赖关系进行一个排序,同时返回多出来的依赖列表 - * - * @param array $libs 要排序的 libs 列表 - * @return array 排序后的列表 - * @throws FileSystemException - * @throws RuntimeException - * @throws WrongUsageException + * @throws FileSystemException|WrongUsageException */ - public static function getLibsByDeps(array $libs): array + public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array { - $sorted = []; - $visited = []; + $dep_list = self::platExtToLibs(); - // 遍历所有 - foreach ($libs as $lib) { - if (!isset($visited[$lib])) { - self::visitLibDeps($lib, $visited, $sorted); + // include suggested extensions + if ($include_suggested_exts) { + // check every deps suggests contains ext@ + foreach ($dep_list as $name => $obj) { + foreach ($obj['suggests'] as $id => $suggest) { + if (str_starts_with($suggest, 'ext@')) { + $dep_list[$name]['depends'][] = $suggest; + array_splice($dep_list[$name]['suggests'], $id, 1); + } + } } } + // include suggested libraries + if ($include_suggested_libs) { + // check every deps suggests + foreach ($dep_list as $name => $obj) { + foreach ($obj['suggests'] as $id => $suggest) { + if (!str_starts_with($suggest, 'ext@')) { + $dep_list[$name]['depends'][] = $suggest; + array_splice($dep_list[$name]['suggests'], $id, 1); + } + } + } + } + + // convert ext_name to ext@ext_name + $origin_exts = $exts; + $exts = array_map(fn ($x) => "ext@{$x}", $exts); + $exts = array_merge($exts, $additional_libs); + + $final = self::doVisitPlat($exts, $dep_list); + + // revert array + $exts_final = []; + $libs_final = []; + $not_included_final = []; + foreach ($final as $item) { + if (str_starts_with($item, 'ext@')) { + $tmp = substr($item, 4); + if (!in_array($tmp, $origin_exts)) { + $not_included_final[] = $tmp; + } + $exts_final[] = $tmp; + } else { + $libs_final[] = $item; + } + } + return [$exts_final, $libs_final, $not_included_final]; + } + + /** + * @throws WrongUsageException + */ + private static function doVisitPlat(array $deps, array $dep_list): array + { + // default: get extension exts and libs sorted by dep_list + $sorted = []; + $visited = []; + foreach ($deps as $ext_name) { + if (!isset($dep_list[$ext_name])) { + $ext_name = str_starts_with($ext_name, 'ext@') ? ('Extension [' . substr($ext_name, 4) . ']') : ('Library [' . $ext_name . ']'); + throw new WrongUsageException("{$ext_name} not exist !"); + } + if (!isset($visited[$ext_name])) { + self::visitPlatDeps($ext_name, $dep_list, $visited, $sorted); + } + } $sorted_suggests = []; $visited_suggests = []; $final = []; - foreach ($libs as $lib) { - if (!isset($visited_suggests[$lib])) { - self::visitLibAllDeps($lib, $visited_suggests, $sorted_suggests); + foreach ($deps as $ext_name) { + if (!isset($visited_suggests[$ext_name])) { + self::visitPlatAllDeps($ext_name, $dep_list, $visited_suggests, $sorted_suggests); } } foreach ($sorted_suggests as $suggest) { @@ -113,50 +173,7 @@ class DependencyUtil return $final; } - public static function getAllExtLibsByDeps(array $exts, array $additional_libs = [], bool $include_suggested_libs = true): array - { - $sorted = []; - $visited = []; - $not_included_exts = []; - foreach ($exts as $ext) { - if (!isset($visited[$ext])) { - self::visitExtAllDeps($ext, $visited, $sorted); - } - } - $libs = $additional_libs; - foreach ($sorted as $ext) { - if (!in_array($ext, $exts)) { - $not_included_exts[] = $ext; - } - $total = $include_suggested_libs ? array_merge(Config::getExt($ext, 'lib-depends', []), Config::getExt($ext, 'lib-suggests', [])) : Config::getExt($ext, 'lib-depends', []); - foreach ($total as $dep) { - if (!in_array($dep, $libs)) { - $libs[] = $dep; - } - } - } - return [$sorted, self::getAllLibsByDeps($libs), $not_included_exts]; - } - - public static function getAllLibsByDeps(array $libs): array - { - $sorted = []; - $visited = []; - - foreach ($libs as $lib) { - if (!isset($visited[$lib])) { - self::visitLibAllDeps($lib, $visited, $sorted); - } - } - return $sorted; - } - - /** - * @throws FileSystemException - * @throws RuntimeException - * @throws WrongUsageException - */ - private static function visitLibAllDeps(string $lib_name, array &$visited, array &$sorted): void + private static function visitPlatAllDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void { // 如果已经识别到了,那就不管 if (isset($visited[$lib_name])) { @@ -164,37 +181,13 @@ class DependencyUtil } $visited[$lib_name] = true; // 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常) - foreach (array_merge(Config::getLib($lib_name, 'lib-depends', []), Config::getLib($lib_name, 'lib-suggests', [])) as $dep) { - self::visitLibDeps($dep, $visited, $sorted); + foreach (array_merge($dep_list[$lib_name]['depends'], $dep_list[$lib_name]['suggests']) as $dep) { + self::visitPlatAllDeps($dep, $dep_list, $visited, $sorted); } $sorted[] = $lib_name; } - /** - * @throws RuntimeException - * @throws FileSystemException - * @throws WrongUsageException - */ - private static function visitExtAllDeps(string $ext_name, array &$visited, array &$sorted): void - { - // 如果已经识别到了,那就不管 - if (isset($visited[$ext_name])) { - return; - } - $visited[$ext_name] = true; - // 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常) - foreach (array_merge(Config::getExt($ext_name, 'ext-depends', []), Config::getExt($ext_name, 'ext-suggests', [])) as $dep) { - self::visitExtDeps($dep, $visited, $sorted); - } - $sorted[] = $ext_name; - } - - /** - * @throws RuntimeException - * @throws FileSystemException - * @throws WrongUsageException - */ - private static function visitLibDeps(string $lib_name, array &$visited, array &$sorted): void + private static function visitPlatDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void { // 如果已经识别到了,那就不管 if (isset($visited[$lib_name])) { @@ -202,26 +195,9 @@ class DependencyUtil } $visited[$lib_name] = true; // 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常) - foreach (Config::getLib($lib_name, 'lib-depends', []) as $dep) { - self::visitLibDeps($dep, $visited, $sorted); + foreach ($dep_list[$lib_name]['depends'] as $dep) { + self::visitPlatDeps($dep, $dep_list, $visited, $sorted); } $sorted[] = $lib_name; } - - /** - * @throws RuntimeException - * @throws FileSystemException - * @throws WrongUsageException - */ - private static function visitExtDeps(string $ext_name, array &$visited, array &$sorted): void - { - if (isset($visited[$ext_name])) { - return; - } - $visited[$ext_name] = true; - foreach (Config::getExt($ext_name, 'ext-depends', []) as $dep) { - self::visitExtDeps($dep, $visited, $sorted); - } - $sorted[] = $ext_name; - } }