mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-18 04:44:53 +08:00
Add php and lib-base as special libraries to add dependencies to the root node (#618)
* Remove E_STRICT * Add lib-base and php as special libs * Remove debug code * Fix phpunit with new config structure * Fix phpunit test and fix license dumper bug for new type of lib * Add missing lib type filter for windows builder
This commit is contained in:
parent
15c7e41501
commit
d30d1fc447
@ -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": [
|
||||
@ -599,9 +624,6 @@
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"pkg-config": {
|
||||
"source": "pkg-config"
|
||||
},
|
||||
"postgresql": {
|
||||
"source": "postgresql",
|
||||
"static-libs-unix": [
|
||||
|
||||
@ -146,6 +146,17 @@ abstract class LibraryBase
|
||||
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
|
||||
@ -203,7 +214,8 @@ abstract class LibraryBase
|
||||
}
|
||||
// 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)) {
|
||||
@ -236,10 +248,14 @@ abstract class LibraryBase
|
||||
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;
|
||||
|
||||
@ -110,13 +110,11 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
$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!');
|
||||
|
||||
@ -236,6 +236,9 @@ class WindowsBuilder extends BuilderBase
|
||||
|
||||
// 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!');
|
||||
|
||||
@ -46,7 +46,6 @@ abstract class BaseCommand extends Command
|
||||
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'],
|
||||
@ -56,7 +55,7 @@ abstract class BaseCommand extends Command
|
||||
logger()->{$level_tip[1]}($error);
|
||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||
return true;
|
||||
}, E_ALL | E_STRICT);
|
||||
});
|
||||
$version = ConsoleApplication::VERSION;
|
||||
if (!$this->no_motd) {
|
||||
echo " _ _ _ _
|
||||
|
||||
@ -7,6 +7,7 @@ namespace SPC\command;
|
||||
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;
|
||||
@ -107,13 +108,14 @@ class BuildCliCommand extends BuildCommand
|
||||
$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',
|
||||
];
|
||||
|
||||
@ -7,6 +7,7 @@ namespace SPC\command;
|
||||
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;
|
||||
@ -61,7 +62,9 @@ class BuildLibsCommand extends BuildCommand
|
||||
$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();
|
||||
|
||||
@ -72,10 +72,6 @@ class DownloadCommand extends BaseCommand
|
||||
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
|
||||
@ -323,7 +319,10 @@ class DownloadCommand extends BaseCommand
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
@ -33,7 +33,17 @@ class SortConfigCommand extends BaseCommand
|
||||
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;
|
||||
|
||||
@ -73,7 +73,7 @@ class Config
|
||||
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', ''],
|
||||
|
||||
@ -53,13 +53,45 @@ class ConfigValidator
|
||||
*/
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ class DependencyUtil
|
||||
$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);
|
||||
@ -44,7 +44,7 @@ class DependencyUtil
|
||||
}
|
||||
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', []),
|
||||
];
|
||||
}
|
||||
@ -210,6 +210,9 @@ class DependencyUtil
|
||||
}
|
||||
$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);
|
||||
}
|
||||
|
||||
@ -70,6 +70,9 @@ class LicenseDumper
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -71,7 +71,7 @@ class ExtensionTest extends TestCase
|
||||
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);
|
||||
|
||||
@ -26,7 +26,7 @@ class UnixSystemUtilTest extends TestCase
|
||||
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();
|
||||
}
|
||||
|
||||
@ -29,6 +29,8 @@ final class DependencyUtilTest extends TestCase
|
||||
],
|
||||
];
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'libaaa' => [
|
||||
'source' => 'test1',
|
||||
'static-libs' => ['libaaa.a'],
|
||||
|
||||
@ -34,6 +34,8 @@ final class LicenseDumperTest extends TestCase
|
||||
public function testDumpWithSingleLicense(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
@ -57,6 +59,8 @@ final class LicenseDumperTest extends TestCase
|
||||
public function testDumpWithMultipleLicenses(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user