mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-05 15:55:39 +08:00
Merge branch 'main' into feat/gnu-static
# Conflicts: # src/SPC/builder/linux/LinuxBuilder.php
This commit is contained in:
@@ -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 " _ _ _ _
|
||||
@@ -154,24 +153,24 @@ abstract class BaseCommand extends Command
|
||||
/**
|
||||
* Parse extension list from string, replace alias and filter internal extensions.
|
||||
*
|
||||
* @param string $ext_list Extension string list, e.g. "mbstring,posix,sockets"
|
||||
* @param array|string $ext_list Extension string list, e.g. "mbstring,posix,sockets" or array
|
||||
*/
|
||||
protected function parseExtensionList(string $ext_list): array
|
||||
protected function parseExtensionList(array|string $ext_list): array
|
||||
{
|
||||
// replace alias
|
||||
$ls = array_map(function ($x) {
|
||||
$lower = strtolower(trim($x));
|
||||
if (isset(SPC_EXTENSION_ALIAS[$lower])) {
|
||||
logger()->notice("Extension [{$lower}] is an alias of [" . SPC_EXTENSION_ALIAS[$lower] . '], it will be replaced.');
|
||||
logger()->debug("Extension [{$lower}] is an alias of [" . SPC_EXTENSION_ALIAS[$lower] . '], it will be replaced.');
|
||||
return SPC_EXTENSION_ALIAS[$lower];
|
||||
}
|
||||
return $lower;
|
||||
}, explode(',', $ext_list));
|
||||
}, is_array($ext_list) ? $ext_list : explode(',', $ext_list));
|
||||
|
||||
// filter internals
|
||||
return array_values(array_filter($ls, function ($x) {
|
||||
if (in_array($x, SPC_INTERNAL_EXTENSIONS)) {
|
||||
logger()->warning("Extension [{$x}] is an builtin extension, it will be ignored.");
|
||||
logger()->debug("Extension [{$x}] is an builtin extension, it will be ignored.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -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;
|
||||
@@ -32,7 +33,6 @@ class BuildCliCommand extends BuildCommand
|
||||
$this->addOption('build-embed', null, null, 'Build embed SAPI');
|
||||
$this->addOption('build-all', null, null, 'Build all SAPI');
|
||||
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
|
||||
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
||||
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
|
||||
$this->addOption('with-config-file-path', null, InputOption::VALUE_REQUIRED, 'Set the path in which to look for php.ini', $isWindows ? null : '/usr/local/etc/php');
|
||||
$this->addOption('with-config-file-scan-dir', null, InputOption::VALUE_REQUIRED, 'Set the directory to scan for .ini files after reading php.ini', $isWindows ? null : '/usr/local/etc/php/conf.d');
|
||||
@@ -108,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',
|
||||
];
|
||||
|
||||
@@ -33,5 +33,6 @@ abstract class BuildCommand extends BaseCommand
|
||||
$this->addOption('with-clean', null, null, 'fresh build, remove `source` dir before `make`');
|
||||
$this->addOption('bloat', null, null, 'add all libraries into binary');
|
||||
$this->addOption('rebuild', 'r', null, 'Delete old build and rebuild');
|
||||
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
160
src/SPC/command/DumpExtensionsCommand.php
Normal file
160
src/SPC/command/DumpExtensionsCommand.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand(name: 'dump-extensions', description: 'Determines the required php extensions')]
|
||||
class DumpExtensionsCommand extends BaseCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
public function configure(): void
|
||||
{
|
||||
// path to project files or specific composer file
|
||||
$this->addArgument('path', InputArgument::OPTIONAL, 'Path to project root', '.');
|
||||
$this->addOption('format', 'F', InputOption::VALUE_REQUIRED, 'Parsed output format', 'default');
|
||||
// output zero extension replacement rather than exit as failure
|
||||
$this->addOption('no-ext-output', 'N', InputOption::VALUE_REQUIRED, 'When no extensions found, output default combination (comma separated)');
|
||||
// no dev
|
||||
$this->addOption('no-dev', null, null, 'Do not include dev dependencies');
|
||||
// no spc filter
|
||||
$this->addOption('no-spc-filter', 'S', null, 'Do not use SPC filter to determine the required extensions');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$path = FileSystem::convertPath($this->getArgument('path'));
|
||||
|
||||
$path_installed = FileSystem::convertPath(rtrim($path, '/\\') . '/vendor/composer/installed.json');
|
||||
$path_lock = FileSystem::convertPath(rtrim($path, '/\\') . '/composer.lock');
|
||||
|
||||
$ext_installed = $this->extractFromInstalledJson($path_installed, !$this->getOption('no-dev'));
|
||||
if ($ext_installed === null) {
|
||||
if ($this->getOption('format') === 'default') {
|
||||
$this->output->writeln('<comment>vendor/composer/installed.json load failed, skipped</comment>');
|
||||
}
|
||||
$ext_installed = [];
|
||||
}
|
||||
|
||||
$ext_lock = $this->extractFromComposerLock($path_lock, !$this->getOption('no-dev'));
|
||||
if ($ext_lock === null) {
|
||||
$this->output->writeln('<error>composer.lock load failed</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
$extensions = array_unique(array_merge($ext_installed, $ext_lock));
|
||||
sort($extensions);
|
||||
|
||||
if (empty($extensions)) {
|
||||
if ($this->getOption('no-ext-output')) {
|
||||
$this->outputExtensions(explode(',', $this->getOption('no-ext-output')));
|
||||
return static::SUCCESS;
|
||||
}
|
||||
$this->output->writeln('<error>No extensions found</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
$this->outputExtensions($extensions);
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function filterExtensions(array $requirements): array
|
||||
{
|
||||
return array_map(
|
||||
fn ($key) => substr($key, 4),
|
||||
array_keys(
|
||||
array_filter($requirements, function ($key) {
|
||||
return str_starts_with($key, 'ext-');
|
||||
}, ARRAY_FILTER_USE_KEY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function loadJson(string $file): array|bool
|
||||
{
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents($file), true);
|
||||
if (!$data) {
|
||||
return false;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function extractFromInstalledJson(string $file, bool $include_dev = true): ?array
|
||||
{
|
||||
if (!($data = $this->loadJson($file))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$packages = $data['packages'] ?? [];
|
||||
|
||||
if (!$include_dev) {
|
||||
$packages = array_filter($packages, fn ($package) => !in_array($package['name'], $data['dev-package-names'] ?? []));
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
...array_map(fn ($x) => isset($x['require']) ? $this->filterExtensions($x['require']) : [], $packages)
|
||||
);
|
||||
}
|
||||
|
||||
private function extractFromComposerLock(string $file, bool $include_dev = true): ?array
|
||||
{
|
||||
if (!($data = $this->loadJson($file))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get packages ext
|
||||
$packages = $data['packages'] ?? [];
|
||||
$exts = array_merge(
|
||||
...array_map(fn ($package) => $this->filterExtensions($package['require'] ?? []), $packages)
|
||||
);
|
||||
|
||||
// get dev packages ext
|
||||
if ($include_dev) {
|
||||
$packages = $data['packages-dev'] ?? [];
|
||||
$exts = array_merge(
|
||||
$exts,
|
||||
...array_map(fn ($package) => $this->filterExtensions($package['require'] ?? []), $packages)
|
||||
);
|
||||
}
|
||||
|
||||
// get require ext
|
||||
$platform = $data['platform'] ?? [];
|
||||
$exts = array_merge($exts, $this->filterExtensions($platform));
|
||||
|
||||
// get require-dev ext
|
||||
if ($include_dev) {
|
||||
$platform = $data['platform-dev'] ?? [];
|
||||
$exts = array_merge($exts, $this->filterExtensions($platform));
|
||||
}
|
||||
|
||||
return $exts;
|
||||
}
|
||||
|
||||
private function outputExtensions(array $extensions): void
|
||||
{
|
||||
if (!$this->getOption('no-spc-filter')) {
|
||||
$extensions = $this->parseExtensionList($extensions);
|
||||
}
|
||||
switch ($this->getOption('format')) {
|
||||
case 'json':
|
||||
$this->output->writeln(json_encode($extensions, JSON_PRETTY_PRINT));
|
||||
break;
|
||||
case 'text':
|
||||
$this->output->writeln(implode(',', $extensions));
|
||||
break;
|
||||
default:
|
||||
$this->output->writeln('<info>Required PHP extensions' . ($this->getOption('no-dev') ? ' (without dev)' : '') . ':</info>');
|
||||
$this->output->writeln(implode(',', $extensions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user