mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-11 10:55:35 +08:00
Compare commits
8 Commits
2.0.0
...
a7d5a48b48
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7d5a48b48 | ||
|
|
fdc00301c0 | ||
|
|
7620d5900e | ||
|
|
e973fe743e | ||
|
|
149e844d59 | ||
|
|
12ea3218e8 | ||
|
|
f9e7af1c9a | ||
|
|
8d2f6baaa2 |
@@ -4,7 +4,7 @@ Build single static PHP binary, with PHP project together, with popular extensio
|
||||
|
||||
🌐 **[中文](README-zh.md)** | **[English](README.md)**
|
||||
|
||||
> 2.0 Release is coming soon, windows support will be added in v2.1.
|
||||
> Windows support will be added in v2.1.
|
||||
|
||||
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed SAPI 😎
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use Symfony\Component\Console\Command\ListCommand;
|
||||
*/
|
||||
final class ConsoleApplication extends Application
|
||||
{
|
||||
public const VERSION = '2.0.0';
|
||||
public const VERSION = '2.0.1';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder;
|
||||
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
@@ -30,6 +31,9 @@ abstract class BuilderBase
|
||||
/** @var array<string, mixed> compile options */
|
||||
protected array $options = [];
|
||||
|
||||
/** @var string patch point name */
|
||||
protected string $patch_point = '';
|
||||
|
||||
/**
|
||||
* Build libraries
|
||||
*
|
||||
@@ -78,9 +82,14 @@ abstract class BuilderBase
|
||||
$lib->calcDependency();
|
||||
}
|
||||
|
||||
// patch point
|
||||
$this->emitPatchPoint('before-libs-extract');
|
||||
|
||||
// extract sources
|
||||
SourceExtractor::initSource(libs: $sorted_libraries);
|
||||
|
||||
$this->emitPatchPoint('after-libs-extract');
|
||||
|
||||
// build all libs
|
||||
foreach ($this->libs as $lib) {
|
||||
match ($lib->tryBuild($this->getOption('rebuild', false))) {
|
||||
@@ -189,11 +198,17 @@ abstract class BuilderBase
|
||||
public function proveExts(array $extensions): void
|
||||
{
|
||||
CustomExt::loadCustomExt();
|
||||
$this->emitPatchPoint('before-php-extract');
|
||||
SourceExtractor::initSource(sources: ['php-src']);
|
||||
$this->emitPatchPoint('after-php-extract');
|
||||
if ($this->getPHPVersionID() >= 80000) {
|
||||
$this->emitPatchPoint('before-micro-extract');
|
||||
SourceExtractor::initSource(sources: ['micro']);
|
||||
$this->emitPatchPoint('after-micro-extract');
|
||||
}
|
||||
$this->emitPatchPoint('before-exts-extract');
|
||||
SourceExtractor::initSource(exts: $extensions);
|
||||
$this->emitPatchPoint('after-exts-extract');
|
||||
foreach ($extensions as $extension) {
|
||||
$class = CustomExt::getExtClass($extension);
|
||||
$ext = new $class($extension, $this);
|
||||
@@ -342,6 +357,39 @@ abstract class BuilderBase
|
||||
return implode(' ', $env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get builder patch point name.
|
||||
*/
|
||||
public function getPatchPoint(): string
|
||||
{
|
||||
return $this->patch_point;
|
||||
}
|
||||
|
||||
public function emitPatchPoint(string $point_name): void
|
||||
{
|
||||
$this->patch_point = $point_name;
|
||||
if (($patches = $this->getOption('with-added-patch', [])) === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($patches as $patch) {
|
||||
try {
|
||||
if (!file_exists($patch)) {
|
||||
throw new RuntimeException("Additional patch script file {$patch} not found!");
|
||||
}
|
||||
logger()->debug('Running additional patch script: ' . $patch);
|
||||
require $patch;
|
||||
} catch (\Throwable $e) {
|
||||
logger()->critical('Patch script ' . $patch . ' failed to run.');
|
||||
if ($this->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
} else {
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all libs are downloaded.
|
||||
* If not, throw exception.
|
||||
|
||||
@@ -17,6 +17,8 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
*/
|
||||
class BuilderProvider
|
||||
{
|
||||
private static ?BuilderBase $builder = null;
|
||||
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
@@ -24,7 +26,7 @@ class BuilderProvider
|
||||
*/
|
||||
public static function makeBuilderByInput(InputInterface $input): BuilderBase
|
||||
{
|
||||
return match (PHP_OS_FAMILY) {
|
||||
self::$builder = match (PHP_OS_FAMILY) {
|
||||
// 'Windows' => new WindowsBuilder(
|
||||
// binary_sdk_dir: $input->getOption('with-sdk-binary-dir'),
|
||||
// vs_ver: $input->getOption('vs-ver'),
|
||||
@@ -35,5 +37,17 @@ class BuilderProvider
|
||||
'BSD' => new BSDBuilder($input->getOptions()),
|
||||
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
|
||||
};
|
||||
return self::$builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
public static function getBuilder(): BuilderBase
|
||||
{
|
||||
if (self::$builder === null) {
|
||||
throw new WrongUsageException('Builder has not been initialized');
|
||||
}
|
||||
return self::$builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,9 @@ abstract class LibraryBase
|
||||
if (!$this->patched && $this->patchBeforeBuild()) {
|
||||
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
|
||||
}
|
||||
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
|
||||
$this->build();
|
||||
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
|
||||
return BUILD_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,10 +81,12 @@ class BSDBuilder extends BuilderBase
|
||||
}
|
||||
$this->setOption('extra-libs', $extra_libs);
|
||||
|
||||
$this->emitPatchPoint('before-php-buildconf');
|
||||
SourcePatcher::patchBeforeBuildconf($this);
|
||||
|
||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||
|
||||
$this->emitPatchPoint('before-php-configure');
|
||||
SourcePatcher::patchBeforeConfigure($this);
|
||||
|
||||
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
||||
@@ -115,6 +117,7 @@ class BSDBuilder extends BuilderBase
|
||||
$this->makeExtensionArgs()
|
||||
);
|
||||
|
||||
$this->emitPatchPoint('before-php-make');
|
||||
SourcePatcher::patchBeforeMake($this);
|
||||
|
||||
$this->cleanMake();
|
||||
@@ -140,6 +143,7 @@ class BSDBuilder extends BuilderBase
|
||||
}
|
||||
|
||||
if (php_uname('m') === $this->getOption('arch')) {
|
||||
$this->emitPatchPoint('before-sanity-check');
|
||||
$this->sanityCheck($build_target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,10 +147,13 @@ class LinuxBuilder extends BuilderBase
|
||||
'LDFLAGS' => '-L' . BUILD_LIB_PATH,
|
||||
'LIBS' => '-ldl -lpthread',
|
||||
]);
|
||||
|
||||
$this->emitPatchPoint('before-php-buildconf');
|
||||
SourcePatcher::patchBeforeBuildconf($this);
|
||||
|
||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||
|
||||
$this->emitPatchPoint('before-php-configure');
|
||||
SourcePatcher::patchBeforeConfigure($this);
|
||||
|
||||
$phpVersionID = $this->getPHPVersionID();
|
||||
@@ -193,6 +196,7 @@ class LinuxBuilder extends BuilderBase
|
||||
' ' . $envs_build_php . ' '
|
||||
);
|
||||
|
||||
$this->emitPatchPoint('before-php-make');
|
||||
SourcePatcher::patchBeforeMake($this);
|
||||
|
||||
$this->cleanMake();
|
||||
@@ -218,6 +222,7 @@ class LinuxBuilder extends BuilderBase
|
||||
}
|
||||
|
||||
if (php_uname('m') === $this->getOption('arch')) {
|
||||
$this->emitPatchPoint('before-sanity-check');
|
||||
$this->sanityCheck($build_target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,4 +209,21 @@ class SystemUtil
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fully-supported linux distros.
|
||||
*
|
||||
* @return string[] List of supported Linux distro name for doctor
|
||||
*/
|
||||
public static function getSupportedDistros(): array
|
||||
{
|
||||
return [
|
||||
// debian-like
|
||||
'debian', 'ubuntu', 'Deepin',
|
||||
// rhel-like
|
||||
'redhat',
|
||||
// alpine
|
||||
'alpine',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +141,12 @@ class MacOSBuilder extends BuilderBase
|
||||
}
|
||||
$this->setOption('extra-libs', $extra_libs);
|
||||
|
||||
$this->emitPatchPoint('before-php-buildconf');
|
||||
SourcePatcher::patchBeforeBuildconf($this);
|
||||
|
||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||
|
||||
$this->emitPatchPoint('before-php-configure');
|
||||
SourcePatcher::patchBeforeConfigure($this);
|
||||
|
||||
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
||||
@@ -190,6 +192,7 @@ class MacOSBuilder extends BuilderBase
|
||||
$envs_build_php
|
||||
);
|
||||
|
||||
$this->emitPatchPoint('before-php-make');
|
||||
SourcePatcher::patchBeforeMake($this);
|
||||
|
||||
$this->cleanMake();
|
||||
@@ -215,6 +218,7 @@ class MacOSBuilder extends BuilderBase
|
||||
}
|
||||
|
||||
if (php_uname('m') === $this->getOption('arch')) {
|
||||
$this->emitPatchPoint('before-sanity-check');
|
||||
$this->sanityCheck($build_target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ class BuildCliCommand extends BuildCommand
|
||||
$this->addOption('with-micro-fake-cli', null, null, 'Enable phpmicro fake cli');
|
||||
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
||||
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
||||
$this->addOption('with-added-patch', 'P', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Inject patch script outside');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
|
||||
@@ -188,7 +188,8 @@ class DownloadCommand extends BaseCommand
|
||||
// create downloads
|
||||
try {
|
||||
if (PHP_OS_FAMILY !== 'Windows') {
|
||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path));
|
||||
$abs_path = realpath($path);
|
||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
||||
}
|
||||
// Windows TODO
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ class LinuxToolCheckList
|
||||
'ubuntu',
|
||||
'alpine',
|
||||
'redhat',
|
||||
'Deepin',
|
||||
'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
|
||||
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
|
||||
};
|
||||
@@ -70,7 +71,7 @@ class LinuxToolCheckList
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
#[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')]
|
||||
#[AsCheckItem('if necessary linux headers are installed', limit_os: 'Linux')]
|
||||
public function checkSystemOSPackages(): ?CheckResult
|
||||
{
|
||||
if (SystemUtil::isMuslDist()) {
|
||||
@@ -90,7 +91,7 @@ class LinuxToolCheckList
|
||||
public function fixBuildTools(array $distro, array $missing): bool
|
||||
{
|
||||
$install_cmd = match ($distro['dist']) {
|
||||
'ubuntu', 'debian' => 'apt-get install -y',
|
||||
'ubuntu', 'debian', 'Deepin' => 'apt-get install -y',
|
||||
'alpine' => 'apk add',
|
||||
'redhat' => 'dnf install -y',
|
||||
default => throw new RuntimeException('Current linux distro does not have an auto-install script for musl packages yet.'),
|
||||
@@ -101,7 +102,7 @@ class LinuxToolCheckList
|
||||
logger()->warning('Current user is not root, using sudo for running command');
|
||||
}
|
||||
try {
|
||||
$is_debian = in_array($distro['dist'], ['debian', 'ubuntu']);
|
||||
$is_debian = in_array($distro['dist'], ['debian', 'ubuntu', 'Deepin']);
|
||||
$to_install = $is_debian ? str_replace('xz', 'xz-utils', $missing) : $missing;
|
||||
// debian, alpine libtool -> libtoolize
|
||||
$to_install = str_replace('libtoolize', 'libtool', $to_install);
|
||||
|
||||
@@ -13,13 +13,14 @@ class OSCheckList
|
||||
{
|
||||
use UnixSystemUtilTrait;
|
||||
|
||||
#[AsCheckItem('if current OS are supported', level: 999)]
|
||||
#[AsCheckItem('if current OS are supported', level: 1000)]
|
||||
public function checkOS(): ?CheckResult
|
||||
{
|
||||
if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD', 'Windows'])) {
|
||||
return CheckResult::fail('Current OS is not supported: ' . PHP_OS_FAMILY);
|
||||
}
|
||||
$distro = PHP_OS_FAMILY === 'Linux' ? (' ' . SystemUtil::getOSRelease()['dist']) : '';
|
||||
return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . $distro . ', supported');
|
||||
$known_distro = PHP_OS_FAMILY === 'Linux' && in_array(SystemUtil::getOSRelease()['dist'], SystemUtil::getSupportedDistros());
|
||||
return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . $distro . ', supported' . ($known_distro ? '' : ' (but not tested on this distro)'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use SPC\builder\BuilderBase;
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\UnixShell;
|
||||
@@ -127,3 +129,23 @@ function cmd(?bool $debug = null): WindowsCmd
|
||||
{
|
||||
return new WindowsCmd($debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current builder.
|
||||
*
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
function builder(): BuilderBase
|
||||
{
|
||||
return BuilderProvider::getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current patch point.
|
||||
*
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
function patch_point(): string
|
||||
{
|
||||
return BuilderProvider::getBuilder()->getPatchPoint();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user