mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-09 09:55:37 +08:00
Compare commits
17 Commits
f2e483540b
...
2.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97eff64b5b | ||
|
|
e522258693 | ||
|
|
b84c68fe11 | ||
|
|
8505feaa66 | ||
|
|
41f49c20ff | ||
|
|
1912ae36e6 | ||
|
|
08efc81cf0 | ||
|
|
a3b09c69cc | ||
|
|
5cf105c3a5 | ||
|
|
7408781d13 | ||
|
|
0afc8ea2c3 | ||
|
|
67b073776c | ||
|
|
8b48cf7f70 | ||
|
|
63287dd9c4 | ||
|
|
fc7ac921e2 | ||
|
|
57e3193a2a | ||
|
|
388f547878 |
12
README-en.md
12
README-en.md
@@ -37,7 +37,11 @@ Here is the architecture support status, where `CI` represents support for GitHu
|
|||||||
|
|
||||||
Currently supported PHP versions for compilation are: `7.4`, `8.0`, `8.1`, `8.2`.
|
Currently supported PHP versions for compilation are: `7.4`, `8.0`, `8.1`, `8.2`.
|
||||||
|
|
||||||
## Usage
|
## Docs
|
||||||
|
|
||||||
|
docs here: <https://static-php-cli.zhamao.me>.
|
||||||
|
|
||||||
|
## Simple Usage
|
||||||
|
|
||||||
Please first select the extension you want to compile based on the extension list below.
|
Please first select the extension you want to compile based on the extension list below.
|
||||||
|
|
||||||
@@ -49,7 +53,7 @@ If you don't compile yourself, you can download pre-compiled artifact from Actio
|
|||||||
|
|
||||||
### Supported Extensions
|
### Supported Extensions
|
||||||
|
|
||||||
[Supported Extension List](/ext-support.md)
|
[Supported Extension List](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
||||||
|
|
||||||
> If there is no extension you need here, you can submit an issue.
|
> If there is no extension you need here, you can submit an issue.
|
||||||
|
|
||||||
@@ -100,7 +104,7 @@ Basic usage for building php and micro with some extensions:
|
|||||||
cd static-php-cli
|
cd static-php-cli
|
||||||
composer update
|
composer update
|
||||||
chmod +x bin/spc
|
chmod +x bin/spc
|
||||||
# Check system tool dependencies, fix them automatically (only support macOS) (TODO: Linux distro support)
|
# Check system tool dependencies, fix them automatically
|
||||||
./bin/spc doctor
|
./bin/spc doctor
|
||||||
# fetch all libraries
|
# fetch all libraries
|
||||||
./bin/spc fetch --all
|
./bin/spc fetch --all
|
||||||
@@ -217,6 +221,8 @@ The basic principles for contributing are as follows:
|
|||||||
camelCase and underscore formats should be followed, and mixing within the same module is prohibited.
|
camelCase and underscore formats should be followed, and mixing within the same module is prohibited.
|
||||||
- When compiling external libraries and creating patches, compatibility with different operating systems should be considered.
|
- When compiling external libraries and creating patches, compatibility with different operating systems should be considered.
|
||||||
|
|
||||||
|
If you want to contribute document content, please go to [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs).
|
||||||
|
|
||||||
## Sponsor this project
|
## Sponsor this project
|
||||||
|
|
||||||
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md).
|
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md).
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -36,6 +36,10 @@ If you are using English, see [English README](README-en.md).
|
|||||||
|
|
||||||
目前支持编译的 PHP 版本为:`7.4`,`8.0`,`8.1`,`8.2`。
|
目前支持编译的 PHP 版本为:`7.4`,`8.0`,`8.1`,`8.2`。
|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
点击这里查看文档:<https://static-php-cli.zhamao.me>。
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
请先根据下方扩展列表选择你要编译的扩展。
|
请先根据下方扩展列表选择你要编译的扩展。
|
||||||
@@ -48,7 +52,7 @@ If you are using English, see [English README](README-en.md).
|
|||||||
|
|
||||||
### 支持的扩展情况
|
### 支持的扩展情况
|
||||||
|
|
||||||
[扩展支持列表](/ext-support.md)
|
[扩展支持列表](https://static-php-cli.zhamao.me/zh/guide/extensions.html)
|
||||||
|
|
||||||
> 如果这里没有你需要的扩展,可以提交 Issue。
|
> 如果这里没有你需要的扩展,可以提交 Issue。
|
||||||
|
|
||||||
@@ -94,7 +98,7 @@ chmod +x bin/setup-runtime
|
|||||||
cd static-php-cli
|
cd static-php-cli
|
||||||
composer update
|
composer update
|
||||||
chmod +x bin/spc
|
chmod +x bin/spc
|
||||||
# 检查环境依赖,并根据提示的命令安装缺失的编译工具(目前仅支持 macOS,Linux 后续会支持)
|
# 检查环境依赖,并根据提示的命令安装缺失的编译工具
|
||||||
./bin/spc doctor
|
./bin/spc doctor
|
||||||
# 拉取所有依赖库
|
# 拉取所有依赖库
|
||||||
./bin/spc fetch --all
|
./bin/spc fetch --all
|
||||||
@@ -200,6 +204,8 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
|||||||
|
|
||||||
另外,添加新扩展的贡献方式,可以参考下方 `进阶`。
|
另外,添加新扩展的贡献方式,可以参考下方 `进阶`。
|
||||||
|
|
||||||
|
如果你想贡献文档内容,请到项目仓库 [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs) 贡献。
|
||||||
|
|
||||||
## 赞助本项目
|
## 赞助本项目
|
||||||
|
|
||||||
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。
|
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。
|
||||||
|
|||||||
111
ext-support.md
111
ext-support.md
@@ -1,112 +1,3 @@
|
|||||||
# Extension List
|
# Extension List
|
||||||
|
|
||||||
> - yes: supported and tested
|
See: [Docs - Extensions](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
||||||
> - untested: supported, but not tested
|
|
||||||
> - empty: not supported yet
|
|
||||||
> - no with issue link: not supported yet due to issue
|
|
||||||
> - partial with issue link: supported but not perfect due to issue
|
|
||||||
|
|
||||||
| | Linux | macOS | Windows |
|
|
||||||
|-----------------|---------------------------------------------------------------------|----------------------------------------------------------------|---------|
|
|
||||||
| apcu | yes, untested | yes, untested | |
|
|
||||||
| bcmath | yes | yes | |
|
|
||||||
| bz2 | yes | yes | |
|
|
||||||
| calendar | yes | yes | |
|
|
||||||
| ctype | yes | yes | |
|
|
||||||
| curl | yes | yes | |
|
|
||||||
| dba | yes | yes | |
|
|
||||||
| dom | yes | yes | |
|
|
||||||
| enchant | | | |
|
|
||||||
| event | yes | yes | |
|
|
||||||
| exif | yes | yes | |
|
|
||||||
| ffi | | yes, [docs]() | |
|
|
||||||
| filter | yes | yes | |
|
|
||||||
| fileinfo | yes | yes | |
|
|
||||||
| ftp | yes | yes | |
|
|
||||||
| gd | yes | yes | |
|
|
||||||
| gettext | | | |
|
|
||||||
| gmp | yes | yes | |
|
|
||||||
| iconv | yes | yes | |
|
|
||||||
| imagick | yes | yes | |
|
|
||||||
| inotify | yes | yes | |
|
|
||||||
| intl | [partial](https://github.com/crazywhalecc/static-php-cli/issues/66) | yes | |
|
|
||||||
| mbstring | yes | yes | |
|
|
||||||
| mbregex | yes | yes | |
|
|
||||||
| mcrypt | | [no](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
|
||||||
| mongodb | yes | yes | |
|
|
||||||
| mysqli | yes | yes | |
|
|
||||||
| mysqlnd | yes | yes | |
|
|
||||||
| opcache | yes | yes | |
|
|
||||||
| openssl | yes | yes | |
|
|
||||||
| password-argon2 | | | |
|
|
||||||
| pcntl | yes | yes | |
|
|
||||||
| pdo | yes | yes | |
|
|
||||||
| pdo_mysql | yes | yes | |
|
|
||||||
| pdo_sqlite | yes | yes | |
|
|
||||||
| pdo_pgsql | | | |
|
|
||||||
| phar | yes | yes | |
|
|
||||||
| posix | yes | yes | |
|
|
||||||
| protobuf | yes | yes | |
|
|
||||||
| readline | yes, untested | yes, untested | |
|
|
||||||
| redis | yes | yes | |
|
|
||||||
| session | yes | yes | |
|
|
||||||
| shmop | yes | yes | |
|
|
||||||
| simplexml | yes | yes | |
|
|
||||||
| soap | yes | yes | |
|
|
||||||
| sockets | yes | yes | |
|
|
||||||
| sodium | yes | yes | |
|
|
||||||
| sqlite3 | yes | yes | |
|
|
||||||
| ssh2 | yes, untested | yes, untested | |
|
|
||||||
| swow | yes | yes | |
|
|
||||||
| swoole | [partial](https://github.com/crazywhalecc/static-php-cli/issues/51) | yes | |
|
|
||||||
| tokenizer | yes | yes | |
|
|
||||||
| xlswriter | yes | yes | |
|
|
||||||
| xml | yes | yes | |
|
|
||||||
| xmlreader | yes, untested | yes, untested | |
|
|
||||||
| xmlwriter | yes, untested | yes, untested | |
|
|
||||||
| zip | yes, untested | yes, untested | |
|
|
||||||
| zlib | yes | yes | |
|
|
||||||
| zstd | yes | yes | |
|
|
||||||
|
|
||||||
## Additional Requirements
|
|
||||||
|
|
||||||
- phpmicro requires PHP >= 8.0
|
|
||||||
- swoole >= 5.0 requires PHP >= 8.0
|
|
||||||
- swow requires PHP >= 8.0
|
|
||||||
|
|
||||||
## Typical Extension List Example
|
|
||||||
|
|
||||||
Here are some extension list example for different use.
|
|
||||||
|
|
||||||
- For general use: `"bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,ftp,filter,gd,iconv,xml,mbstring,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip"`
|
|
||||||
- For static-php-cli self: `"posix,pcntl,phar,tokenizer,iconv,zlib"`
|
|
||||||
- For static-php-cli self (with dev dependencies): `"posix,pcntl,phar,tokenizer,iconv,zlib,xml,dom,xmlwriter,xmlreader,fileinfo"`
|
|
||||||
- Minimum, with no extension: `""`
|
|
||||||
|
|
||||||
Compile with all supported extensions (exclude `swow`, `swoole`, because these will change the default behavior of php):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bin/spc build --build-all bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,mbregex,mbstring,mongodb,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,protobuf,redis,session,shmop,simplexml,soap,sockets,sqlite3,tokenizer,xml,xmlreader,xmlwriter,yaml,zip,zlib,zstd --with-libs=libjpeg,freetype,libwebp,libavif --debug
|
|
||||||
```
|
|
||||||
|
|
||||||
## Additional Libraries
|
|
||||||
|
|
||||||
Some extensions have soft dependencies, you can enable extra features by adding these libs using `--with-libs`.
|
|
||||||
|
|
||||||
For example, to compile with gd extension, with `libwebp, libgif, libavif, libjpeg, freetype` extra features:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bin/spc build gd --with-libs=libjpeg,freetype,libwebp,libavif --build-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
> If you don't add them, your compilation will not enable these features.
|
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
- swow and swoole cannot be compiled at the same time.
|
|
||||||
- openssl needs manual configuration for ssl certificate. (TODO: I will write a wiki about it)
|
|
||||||
- some extensions need system configuration, e.g. `curl` and `openssl` will search ssl certificate on your system.
|
|
||||||
|
|
||||||
## Bugs and TODOs
|
|
||||||
|
|
||||||
See [#32](https://github.com/crazywhalecc/static-php-cli/issues/32).
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
use UnixBuilderTrait;
|
use UnixBuilderTrait;
|
||||||
|
|
||||||
/** @var string[] Linux 环境下编译依赖的命令 */
|
/** @var string[] Linux 环境下编译依赖的命令 */
|
||||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
||||||
|
|
||||||
/** @var string 使用的 libc */
|
/** @var string 使用的 libc */
|
||||||
public string $libc;
|
public string $libc;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class libpng extends MacOSLibraryBase
|
|||||||
};
|
};
|
||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
->exec('chmod +x ./configure')
|
->exec('chmod +x ./configure')
|
||||||
|
->exec('chmod +x ./install-sh')
|
||||||
->exec(
|
->exec(
|
||||||
"{$this->builder->configure_env} ./configure " .
|
"{$this->builder->configure_env} ./configure " .
|
||||||
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
|||||||
#[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')]
|
#[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')]
|
||||||
class DoctorCommand extends BaseCommand
|
class DoctorCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
|
public function configure()
|
||||||
|
{
|
||||||
|
$this->addOption('auto-fix', null, null, 'Automatically fix failed items (if possible)');
|
||||||
|
}
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$checker = new CheckListHandler($this->input, $this->output);
|
$checker = new CheckListHandler($this->input, $this->output);
|
||||||
$checker->runCheck(FIX_POLICY_PROMPT);
|
$checker->runCheck($this->input->getOption('auto-fix') ? FIX_POLICY_AUTOFIX : FIX_POLICY_PROMPT);
|
||||||
$this->output->writeln('<info>Doctor check complete !</info>');
|
$this->output->writeln('<info>Doctor check complete !</info>');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
@@ -18,6 +19,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
#[AsCommand('download', 'Download required sources', ['fetch'])]
|
#[AsCommand('download', 'Download required sources', ['fetch'])]
|
||||||
class DownloadCommand extends BaseCommand
|
class DownloadCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
|
use UnixSystemUtilTrait;
|
||||||
|
|
||||||
protected string $php_major_ver;
|
protected string $php_major_ver;
|
||||||
|
|
||||||
public function configure()
|
public function configure()
|
||||||
@@ -28,12 +31,13 @@ class DownloadCommand extends BaseCommand
|
|||||||
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format like 8.1', '8.1');
|
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format like 8.1', '8.1');
|
||||||
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
||||||
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
|
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
|
||||||
|
$this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output)
|
public function initialize(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
// --all 等于 "" "",也就是所有东西都要下载
|
// --all 等于 "" "",也就是所有东西都要下载
|
||||||
if ($input->getOption('all') || $input->getOption('clean')) {
|
if ($input->getOption('all') || $input->getOption('clean') || $input->getOption('from-zip')) {
|
||||||
$input->setArgument('sources', '');
|
$input->setArgument('sources', '');
|
||||||
}
|
}
|
||||||
parent::initialize($input, $output);
|
parent::initialize($input, $output);
|
||||||
@@ -66,6 +70,44 @@ class DownloadCommand extends BaseCommand
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --from-zip
|
||||||
|
if ($path = $this->getOption('from-zip')) {
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
logger()->critical('File ' . $path . ' not exist or not a zip archive.');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// remove old download files first
|
||||||
|
if (is_dir(DOWNLOAD_PATH)) {
|
||||||
|
logger()->warning('You are doing some operations that not recoverable: removing directories below');
|
||||||
|
logger()->warning(DOWNLOAD_PATH);
|
||||||
|
logger()->alert('I will remove these dir after 5 seconds !');
|
||||||
|
sleep(5);
|
||||||
|
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
|
||||||
|
}
|
||||||
|
// unzip command check
|
||||||
|
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
|
||||||
|
logger()->critical('Missing unzip command, you need to install it first !');
|
||||||
|
logger()->critical('You can use "bin/spc doctor" command to check and install required tools');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// create downloads
|
||||||
|
try {
|
||||||
|
if (PHP_OS_FAMILY !== 'Windows') {
|
||||||
|
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path));
|
||||||
|
}
|
||||||
|
// Windows TODO
|
||||||
|
|
||||||
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
|
throw new RuntimeException('.lock.json not exist in "downloads/"');
|
||||||
|
}
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
logger()->critical('Extract failed: ' . $e->getMessage());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
logger()->info('Extract success');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Define PHP major version
|
// Define PHP major version
|
||||||
$ver = $this->php_major_ver = $this->getOption('with-php') ?? '8.1';
|
$ver = $this->php_major_ver = $this->getOption('with-php') ?? '8.1';
|
||||||
define('SPC_BUILD_PHP_VERSION', $ver);
|
define('SPC_BUILD_PHP_VERSION', $ver);
|
||||||
|
|||||||
116
src/SPC/command/MicroCombineCommand.php
Normal file
116
src/SPC/command/MicroCombineCommand.php
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<?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('micro:combine', 'Combine micro.sfx and php code together')]
|
||||||
|
class MicroCombineCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
public function configure()
|
||||||
|
{
|
||||||
|
$this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined');
|
||||||
|
$this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file');
|
||||||
|
$this->addOption('with-ini-set', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'ini to inject into micro.sfx when combining');
|
||||||
|
$this->addOption('with-ini-file', 'N', InputOption::VALUE_REQUIRED, 'ini file to inject into micro.sfx when combining');
|
||||||
|
$this->addOption('output', 'O', InputOption::VALUE_REQUIRED, 'Customize your output binary file name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
// 0. Initialize path variables
|
||||||
|
$internal = FileSystem::convertPath(BUILD_ROOT_PATH . '/bin/micro.sfx');
|
||||||
|
$micro_file = $this->input->getOption('with-micro');
|
||||||
|
$file = $this->getArgument('file');
|
||||||
|
$ini_set = $this->input->getOption('with-ini-set');
|
||||||
|
$ini_file = $this->input->getOption('with-ini-file');
|
||||||
|
$target_ini = [];
|
||||||
|
$output = $this->input->getOption('output') ?? 'my-app';
|
||||||
|
$ini_part = '';
|
||||||
|
// 1. Make sure specified micro.sfx file exists
|
||||||
|
if ($micro_file !== null && !file_exists($micro_file)) {
|
||||||
|
$this->output->writeln('<error>The micro.sfx file you specified is incorrect or does not exist!</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 2. Make sure buildroot/bin/micro.sfx exists
|
||||||
|
if ($micro_file === null && !file_exists($internal)) {
|
||||||
|
$this->output->writeln('<error>You haven\'t compiled micro.sfx yet, please use "build" command and "--build-micro" to compile phpmicro first!</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 3. Use buildroot/bin/micro.sfx
|
||||||
|
if ($micro_file === null) {
|
||||||
|
$micro_file = $internal;
|
||||||
|
}
|
||||||
|
// 4. Make sure php or phar file exists
|
||||||
|
if (!is_file(FileSystem::convertPath($file))) {
|
||||||
|
$this->output->writeln('<error>The file to combine does not exist!</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 5. Confirm ini files (ini-set has higher priority)
|
||||||
|
if ($ini_file !== null) {
|
||||||
|
// Check file exist first
|
||||||
|
if (!file_exists($ini_file)) {
|
||||||
|
$this->output->writeln('<error>The ini file to combine does not exist! (' . $ini_file . ')</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
$arr = parse_ini_file($ini_file);
|
||||||
|
if ($arr === false) {
|
||||||
|
$this->output->writeln('<error>Cannot parse ini file</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
$target_ini = array_merge($target_ini, $arr);
|
||||||
|
}
|
||||||
|
// 6. Confirm ini sets
|
||||||
|
if ($ini_set !== []) {
|
||||||
|
foreach ($ini_set as $item) {
|
||||||
|
$arr = parse_ini_string($item);
|
||||||
|
if ($arr === false) {
|
||||||
|
$this->output->writeln('<error>--with-ini-set parse failed</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
$target_ini = array_merge($target_ini, $arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 7. Generate ini injection parts
|
||||||
|
if (!empty($target_ini)) {
|
||||||
|
$ini_str = $this->encodeINI($target_ini);
|
||||||
|
logger()->debug('Injecting ini parts: ' . PHP_EOL . $ini_str);
|
||||||
|
$ini_part = "\xfd\xf6\x69\xe6";
|
||||||
|
$ini_part .= pack('N', strlen($ini_str));
|
||||||
|
$ini_part .= $ini_str;
|
||||||
|
}
|
||||||
|
// 8. Combine !
|
||||||
|
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
|
||||||
|
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
|
||||||
|
$result = file_put_contents($output, $file_target);
|
||||||
|
if ($result === false) {
|
||||||
|
$this->output->writeln('<error>Combine failed.</error>');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 9. chmod +x
|
||||||
|
chmod($output, 0755);
|
||||||
|
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function encodeINI(array $array): string
|
||||||
|
{
|
||||||
|
$res = [];
|
||||||
|
foreach ($array as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$res[] = "[{$key}]";
|
||||||
|
foreach ($val as $skey => $sval) {
|
||||||
|
$res[] = "{$skey}=" . (is_numeric($sval) ? $sval : '"' . $sval . '"');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$res[] = "{$key}=" . (is_numeric($val) ? $val : '"' . $val . '"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode("\n", $res);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/SPC/doctor/item/LinuxToolCheckList.php
Normal file
90
src/SPC/doctor/item/LinuxToolCheckList.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\doctor\item;
|
||||||
|
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
|
use SPC\doctor\AsCheckItem;
|
||||||
|
use SPC\doctor\AsFixItem;
|
||||||
|
use SPC\doctor\CheckResult;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
|
class LinuxToolCheckList
|
||||||
|
{
|
||||||
|
use UnixSystemUtilTrait;
|
||||||
|
|
||||||
|
public const TOOLS_ALPINE = [
|
||||||
|
'make', 'bison', 'flex',
|
||||||
|
'git', 'autoconf', 'automake',
|
||||||
|
'tar', 'unzip', 'gzip',
|
||||||
|
'bzip2', 'cmake', 'gcc',
|
||||||
|
'g++', 'patch',
|
||||||
|
];
|
||||||
|
|
||||||
|
public const TOOLS_DEBIAN = [
|
||||||
|
'make', 'bison', 'flex',
|
||||||
|
'git', 'autoconf', 'automake',
|
||||||
|
'tar', 'unzip', 'gzip',
|
||||||
|
'bzip2', 'cmake', 'patch',
|
||||||
|
];
|
||||||
|
|
||||||
|
#[AsCheckItem('if necessary tools are installed', limit_os: 'Linux')]
|
||||||
|
public function checkCliTools(): ?CheckResult
|
||||||
|
{
|
||||||
|
$distro = SystemUtil::getOSRelease();
|
||||||
|
|
||||||
|
$required = match ($distro['dist']) {
|
||||||
|
'alpine' => self::TOOLS_ALPINE,
|
||||||
|
default => self::TOOLS_DEBIAN,
|
||||||
|
};
|
||||||
|
$missing = [];
|
||||||
|
foreach ($required as $cmd) {
|
||||||
|
if ($this->findCommand($cmd) === null) {
|
||||||
|
$missing[] = $cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($missing)) {
|
||||||
|
return match ($distro['dist']) {
|
||||||
|
'ubuntu', 'alpine', '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'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')]
|
||||||
|
public function checkSystemOSPackages(): ?CheckResult
|
||||||
|
{
|
||||||
|
$distro = SystemUtil::getOSRelease();
|
||||||
|
if ($distro['dist'] === 'alpine') {
|
||||||
|
// check linux-headers installation
|
||||||
|
if (!file_exists('/usr/include/linux/mman.h')) {
|
||||||
|
return CheckResult::fail('linux-headers not installed on your system', 'install-linux-tools', [$distro, ['linux-headers']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsFixItem('install-linux-tools')]
|
||||||
|
public function fixBuildTools(array $distro, array $missing): bool
|
||||||
|
{
|
||||||
|
$install_cmd = match ($distro['dist']) {
|
||||||
|
'ubuntu', 'debian' => 'apt install -y',
|
||||||
|
'alpine' => 'apk add',
|
||||||
|
default => throw new RuntimeException('Current linux distro is not supported for auto-install musl packages'),
|
||||||
|
};
|
||||||
|
$prefix = '';
|
||||||
|
if (get_current_user() !== 'root') {
|
||||||
|
$prefix = 'sudo ';
|
||||||
|
logger()->warning('Current user is not root, using sudo for running command');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $missing));
|
||||||
|
} catch (RuntimeException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -439,6 +439,20 @@ class FileSystem
|
|||||||
self::$_extract_hook[$name][] = $callback;
|
self::$_extract_hook[$name][] = $callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the path is a relative path (judging according to whether the first character is "/")
|
||||||
|
*
|
||||||
|
* @param string $path Path
|
||||||
|
*/
|
||||||
|
public static function isRelativePath(string $path): bool
|
||||||
|
{
|
||||||
|
// 适配 Windows 的多盘符目录形式
|
||||||
|
if (DIRECTORY_SEPARATOR === '\\') {
|
||||||
|
return !(strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':');
|
||||||
|
}
|
||||||
|
return strlen($path) > 0 && $path[0] !== '/';
|
||||||
|
}
|
||||||
|
|
||||||
private static function emitSourceExtractHook(string $name)
|
private static function emitSourceExtractHook(string $name)
|
||||||
{
|
{
|
||||||
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {
|
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {
|
||||||
|
|||||||
Reference in New Issue
Block a user