Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions config/lib.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
{
"lib-base": {
"type": "root",
"lib-depends-unix": [
"pkg-config"
]
},
"php": {
"type": "root",
"source": "php-src",
"lib-depends": [
"micro",
"lib-base"
]
},
"micro": {
"type": "target",
"source": "micro"
},
"pkg-config": {
"type": "package",
"source": "pkg-config",
"bin-unix": [
"pkg-config"
]
},
"brotli": {
"source": "brotli",
"static-libs-unix": [
Expand Down Expand Up @@ -599,9 +624,6 @@
"zlib"
]
},
"pkg-config": {
"source": "pkg-config"
},
"postgresql": {
"source": "postgresql",
"static-libs-unix": [
Expand Down
26 changes: 21 additions & 5 deletions src/SPC/builder/LibraryBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ public function getHeaders(): array
return Config::getLib(static::NAME, 'headers', []);
}

/**
* Get binary files.
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getBinaryFiles(): array
{
return Config::getLib(static::NAME, 'bin', []);
}

/**
* @throws WrongUsageException
* @throws FileSystemException
Expand Down Expand Up @@ -203,7 +214,8 @@ public function tryBuild(bool $force_build = false): int
}
// force means just build
if ($force_build) {
logger()->info('Building required library [' . static::NAME . ']');
$type = Config::getLib(static::NAME, 'type', 'lib');
logger()->info('Building required ' . $type . ' [' . static::NAME . ']');

// extract first if not exists
if (!is_dir($this->source_dir)) {
Expand Down Expand Up @@ -236,10 +248,14 @@ public function tryBuild(bool $force_build = false): int
return LIB_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return LIB_STATUS_OK;
// current library is package and binary file is not exists
if (Config::getLib(static::NAME, 'type', 'lib') === 'package') {
foreach ($this->getBinaryFiles() as $name) {
if (!file_exists(BUILD_BIN_PATH . "/{$name}")) {
$this->tryBuild(true);
return LIB_STATUS_OK;
}
}
}
// if all the files exist at this point, skip the compilation process
return LIB_STATUS_ALREADY;
Expand Down
8 changes: 3 additions & 5 deletions src/SPC/builder/unix/UnixBuilderBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,11 @@ public function proveLibs(array $sorted_libraries): void
$sorted_libraries = DependencyUtil::getLibs($libraries);
}

// pkg-config must be compiled first, whether it is specified or not
if (!in_array('pkg-config', $sorted_libraries)) {
array_unshift($sorted_libraries, 'pkg-config');
}

// add lib object for builder
foreach ($sorted_libraries as $library) {
if (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
continue;
}
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
Expand Down
3 changes: 3 additions & 0 deletions src/SPC/builder/windows/WindowsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ public function proveLibs(array $sorted_libraries): void

// add lib object for builder
foreach ($sorted_libraries as $library) {
if (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
continue;
}
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
Expand Down
3 changes: 1 addition & 2 deletions src/SPC/command/BaseCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public function initialize(InputInterface $input, OutputInterface $output): void
E_USER_ERROR => ['PHP Error: ', 'error'],
E_USER_WARNING => ['PHP Warning: ', 'warning'],
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
E_STRICT => ['PHP Strict: ', 'notice'],
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
Expand All @@ -56,7 +55,7 @@ public function initialize(InputInterface $input, OutputInterface $output): void
logger()->{$level_tip[1]}($error);
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
return true;
}, E_ALL | E_STRICT);
});
$version = ConsoleApplication::VERSION;
if (!$this->no_motd) {
echo " _ _ _ _
Expand Down
4 changes: 3 additions & 1 deletion src/SPC/command/BuildCliCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use SPC\builder\BuilderProvider;
use SPC\exception\ExceptionHandler;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\DependencyUtil;
Expand Down Expand Up @@ -107,13 +108,14 @@ public function handle(): int
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));

// print info
$indent_texts = [
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
'Build SAPI' => $builder->getBuildTypeName($rule),
'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
'Libraries (' . count($libraries) . ')' => implode(',', $libraries),
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
];
Expand Down
5 changes: 4 additions & 1 deletion src/SPC/command/BuildLibsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use SPC\builder\BuilderProvider;
use SPC\exception\ExceptionHandler;
use SPC\exception\RuntimeException;
use SPC\store\Config;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -61,7 +62,9 @@ public function handle(): int
$builder->setLibsOnly();
// 编译和检查库完整
$libraries = DependencyUtil::getLibs($libraries);
logger()->info('Building libraries: ' . implode(',', $libraries));
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));

logger()->info('Building libraries: ' . implode(',', $display_libs));
sleep(2);
$builder->proveLibs($libraries);
$builder->validateLibsAndExts();
Expand Down
9 changes: 4 additions & 5 deletions src/SPC/command/DownloadCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ public function initialize(InputInterface $input, OutputInterface $output): void
if ($for_ext = $input->getOption('for-extensions')) {
$ext = $this->parseExtensionList($for_ext);
$sources = $this->calculateSourcesByExt($ext, !$input->getOption('without-suggestions'));
if (PHP_OS_FAMILY !== 'Windows') {
array_unshift($sources, 'pkg-config');
}
array_unshift($sources, 'php-src', 'micro');
$final_sources = array_merge($final_sources, array_diff($sources, $final_sources));
}
// mode: --for-libs
Expand Down Expand Up @@ -323,7 +319,10 @@ private function calculateSourcesByExt(array $extensions, bool $include_suggests
}
}
foreach ($libraries as $library) {
$sources[] = Config::getLib($library, 'source');
$source = Config::getLib($library, 'source');
if ($source !== null) {
$sources[] = $source;
}
}
return array_values(array_unique($sources));
}
Expand Down
12 changes: 11 additions & 1 deletion src/SPC/command/dev/SortConfigCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ public function handle(): int
case 'lib':
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
ConfigValidator::validateLibs($file);
ksort($file);
uksort($file, function ($a, $b) use ($file) {
$type_a = $file[$a]['type'] ?? 'lib';
$type_b = $file[$b]['type'] ?? 'lib';
$type_order = ['root', 'target', 'package', 'lib'];
// compare type first
if ($type_a !== $type_b) {
return array_search($type_a, $type_order) <=> array_search($type_b, $type_order);
}
// compare name
return $a <=> $b;
});
if (!file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n")) {
$this->output->writeln('<error>Write file lib.json failed!</error>');
return static::FAILURE;
Expand Down
2 changes: 1 addition & 1 deletion src/SPC/store/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public static function getLib(string $name, ?string $key = null, mixed $default
if (!isset(self::$lib[$name])) {
throw new WrongUsageException('lib [' . $name . '] is not supported yet');
}
$supported_sys_based = ['static-libs', 'headers', 'lib-depends', 'lib-suggests', 'frameworks'];
$supported_sys_based = ['static-libs', 'headers', 'lib-depends', 'lib-suggests', 'frameworks', 'bin'];
if ($key !== null && in_array($key, $supported_sys_based)) {
$m_key = match (PHP_OS_FAMILY) {
'Windows' => ['-windows', '-win', ''],
Expand Down
44 changes: 38 additions & 6 deletions src/SPC/util/ConfigValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,45 @@ public static function validateSource(array $data): void
*/
public static function validateLibs(mixed $data, array $source_data = []): void
{
is_array($data) || throw new ValidationException('lib.json is broken');
// check if it is an array
if (!is_array($data)) {
throw new ValidationException('lib.json is broken');
}
// check each lib
foreach ($data as $name => $lib) {
isset($lib['source']) || throw new ValidationException("lib {$name} does not assign any source");
is_string($lib['source']) || throw new ValidationException("lib {$name} source must be string");
empty($source_data) || isset($source_data[$lib['source']]) || throw new ValidationException("lib {$name} assigns an invalid source: {$lib['source']}");
!isset($lib['lib-depends']) || !is_assoc_array($lib['lib-depends']) || throw new ValidationException("lib {$name} dependencies must be a list");
!isset($lib['lib-suggests']) || !is_assoc_array($lib['lib-suggests']) || throw new ValidationException("lib {$name} suggested dependencies must be a list");
// check if lib is an assoc array
if (!is_assoc_array($lib)) {
throw new ValidationException("lib {$name} is not an object");
}
// check if lib has valid type
if (!in_array($lib['type'] ?? 'lib', ['lib', 'package', 'target', 'root'])) {
throw new ValidationException("lib {$name} type is invalid");
}
// check if lib and package has source
if (in_array($lib['type'] ?? 'lib', ['lib', 'package']) && !isset($lib['source'])) {
throw new ValidationException("lib {$name} does not assign any source");
}
// check if source is valid
if (isset($lib['source']) && !empty($source_data) && !isset($source_data[$lib['source']])) {
throw new ValidationException("lib {$name} assigns an invalid source: {$lib['source']}");
}
// check if [lib-depends|lib-suggests|static-libs][-windows|-unix|-macos|-linux] are valid list array
$suffixes = ['', '-windows', '-unix', '-macos', '-linux'];
foreach ($suffixes as $suffix) {
if (isset($lib['lib-depends' . $suffix]) && !is_list_array($lib['lib-depends' . $suffix])) {
throw new ValidationException("lib {$name} lib-depends must be a list");
}
if (isset($lib['lib-suggests' . $suffix]) && !is_list_array($lib['lib-suggests' . $suffix])) {
throw new ValidationException("lib {$name} lib-suggests must be a list");
}
if (isset($lib['static-libs' . $suffix]) && !is_list_array($lib['static-libs' . $suffix])) {
throw new ValidationException("lib {$name} static-libs must be a list");
}
}
// check if frameworks is a list array
if (isset($lib['frameworks']) && !is_list_array($lib['frameworks'])) {
throw new ValidationException("lib {$name} frameworks must be a list");
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/SPC/util/DependencyUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static function platExtToLibs(): array
$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);
$depends = array_merge($ext_depends, $lib_depends, ['php']);
// merge ext-suggests with lib-suggests
$lib_suggests = Config::getExt($ext_name, 'lib-suggests', []);
$suggests = array_merge($ext_suggests, $lib_suggests);
Expand All @@ -44,7 +44,7 @@ public static function platExtToLibs(): array
}
foreach ($libs as $lib_name => $lib) {
$dep_list[$lib_name] = [
'depends' => Config::getLib($lib_name, 'lib-depends', []),
'depends' => array_merge(Config::getLib($lib_name, 'lib-depends', []), ['lib-base']),
'suggests' => Config::getLib($lib_name, 'lib-suggests', []),
];
}
Expand Down Expand Up @@ -210,6 +210,9 @@ private static function visitPlatDeps(string $lib_name, array $dep_list, array &
}
$visited[$lib_name] = true;
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
if (!isset($dep_list[$lib_name])) {
throw new WrongUsageException("{$lib_name} not exist !");
}
foreach ($dep_list[$lib_name]['depends'] as $dep) {
self::visitPlatDeps($dep, $dep_list, $visited, $sorted);
}
Expand Down
3 changes: 3 additions & 0 deletions src/SPC/util/LicenseDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public function dump(string $target_dir): bool
}

foreach ($this->libs as $lib) {
if (Config::getLib($lib, 'type', 'lib') !== 'lib') {
continue;
}
$source_name = Config::getLib($lib, 'source');
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
$result = file_put_contents("{$target_dir}/lib_{$lib}_{$index}.txt", $license);
Expand Down
8 changes: 8 additions & 0 deletions src/globals/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ function is_assoc_array(mixed $array): bool
return is_array($array) && (!empty($array) && array_keys($array) !== range(0, count($array) - 1));
}

/**
* Judge if an array is a list
*/
function is_list_array(mixed $array): bool
{
return is_array($array) && (empty($array) || array_keys($array) === range(0, count($array) - 1));
}

/**
* Return a logger instance
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/SPC/builder/ExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function testGetDistName()
public function testRunCliCheckWindows()
{
if (is_unix()) {
$this->markTestIncomplete('This test is for Windows only');
$this->markTestSkipped('This test is for Windows only');
} else {
$this->extension->runCliCheckWindows();
$this->assertTrue(true);
Expand Down
2 changes: 1 addition & 1 deletion tests/SPC/builder/unix/UnixSystemUtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function setUp(): void
default => null,
};
if ($util_class === null) {
self::markTestIncomplete('This test is only for Unix');
self::markTestSkipped('This test is only for Unix');
}
$this->util = new $util_class();
}
Expand Down
2 changes: 2 additions & 0 deletions tests/SPC/util/DependencyUtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public function testGetExtLibsByDeps(): void
],
];
Config::$lib = [
'lib-base' => ['type' => 'root'],
'php' => ['type' => 'root'],
'libaaa' => [
'source' => 'test1',
'static-libs' => ['libaaa.a'],
Expand Down
4 changes: 4 additions & 0 deletions tests/SPC/util/LicenseDumperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ protected function tearDown(): void
public function testDumpWithSingleLicense(): void
{
Config::$lib = [
'lib-base' => ['type' => 'root'],
'php' => ['type' => 'root'],
'fake_lib' => [
'source' => 'fake_lib',
],
Expand All @@ -57,6 +59,8 @@ public function testDumpWithSingleLicense(): void
public function testDumpWithMultipleLicenses(): void
{
Config::$lib = [
'lib-base' => ['type' => 'root'],
'php' => ['type' => 'root'],
'fake_lib' => [
'source' => 'fake_lib',
],
Expand Down