mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-12 19:35:35 +08:00
Compare commits
99 Commits
3e7ef49bde
...
2.0-rc7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29be3a2e39 | ||
|
|
fbe149bcac | ||
|
|
92cafb36f6 | ||
|
|
8636f2e7c9 | ||
|
|
8f43a09533 | ||
|
|
654c5cba0c | ||
|
|
f9685b82a1 | ||
|
|
f2371d3702 | ||
|
|
fe39aecd72 | ||
|
|
68d176ad26 | ||
|
|
d7627dd81a | ||
|
|
a4e173f16d | ||
|
|
1437be3a9d | ||
|
|
059c32e59c | ||
|
|
e3a4cd6e1d | ||
|
|
dd9a5d8316 | ||
|
|
3b83c1fa7b | ||
|
|
ff128df76b | ||
|
|
cd04a9ea4f | ||
|
|
3b793005fe | ||
|
|
87e073a0b9 | ||
|
|
db8aa15677 | ||
|
|
6ed9749732 | ||
|
|
4e99211bc3 | ||
|
|
824748c2a7 | ||
|
|
fe6a98b30d | ||
|
|
49149cebf1 | ||
|
|
7b6a1b4212 | ||
|
|
965e7a25e2 | ||
|
|
0c3885c33d | ||
|
|
be32190829 | ||
|
|
f1d5916090 | ||
|
|
b2ea479fac | ||
|
|
16cc5df66d | ||
|
|
a63e3f4575 | ||
|
|
6b061e6332 | ||
|
|
4a17491aaa | ||
|
|
06f29712e2 | ||
|
|
4b1d59c5a9 | ||
|
|
1a81fe6a0d | ||
|
|
c63136d484 | ||
|
|
4b500f2dd8 | ||
|
|
9da20497cc | ||
|
|
5efc15b404 | ||
|
|
fa0740f216 | ||
|
|
52430cbdde | ||
|
|
01c4538ce0 | ||
|
|
3183ecceaf | ||
|
|
dd2e7cc129 | ||
|
|
adfa620ef4 | ||
|
|
1a32ddc70a | ||
|
|
4bfca6fe93 | ||
|
|
dbec043894 | ||
|
|
727d78a689 | ||
|
|
9b1e784604 | ||
|
|
50d44d8310 | ||
|
|
3b300698f3 | ||
|
|
899eb94b8b | ||
|
|
451a0c0e34 | ||
|
|
085c1a159c | ||
|
|
ca3f8a350d | ||
|
|
5025850f71 | ||
|
|
fe2f658e08 | ||
|
|
00a49c662b | ||
|
|
be8eb90b86 | ||
|
|
54e98666e7 | ||
|
|
e8b277ad0d | ||
|
|
3bd037f48f | ||
|
|
4d0e825b43 | ||
|
|
b14179a8de | ||
|
|
01111c51ee | ||
|
|
e7230d9f50 | ||
|
|
c22c5617ad | ||
|
|
cae7bb1dda | ||
|
|
c0830a9e1f | ||
|
|
33798ff108 | ||
|
|
8d348b9e14 | ||
|
|
3d2f6e4c3a | ||
|
|
88e9639482 | ||
|
|
0381a1c412 | ||
|
|
fdc3a7a04b | ||
|
|
6de5c1dab0 | ||
|
|
dc28ce0899 | ||
|
|
9286153742 | ||
|
|
f90892c92f | ||
|
|
5359f3a79a | ||
|
|
42fbf18bba | ||
|
|
ed227ce00e | ||
|
|
6c49d35aec | ||
|
|
238fd7fc74 | ||
|
|
1ebc58664e | ||
|
|
bcf64cbeef | ||
|
|
dc12d4d982 | ||
|
|
42e5877a7f | ||
|
|
a8924ac4fe | ||
|
|
7fb27c0c29 | ||
|
|
3d9a3194b2 | ||
|
|
e7e0ac006f | ||
|
|
cf35a270bb |
7
.github/workflows/build-linux-x86_64.yml
vendored
7
.github/workflows/build-linux-x86_64.yml
vendored
@@ -40,11 +40,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
# Install Ubuntu missing packages and mark os suffix
|
|
||||||
- run: |
|
|
||||||
sudo apt install musl-tools -y
|
|
||||||
echo "SPC_BUILD_OS=linux" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# Cache composer dependencies
|
# Cache composer dependencies
|
||||||
- id: cache-composer-deps
|
- id: cache-composer-deps
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -54,7 +49,7 @@ jobs:
|
|||||||
|
|
||||||
# If there's no Composer cache, install dependencies
|
# If there's no Composer cache, install dependencies
|
||||||
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
||||||
run: composer update --no-dev
|
run: composer update --no-dev --classmap-authoritative
|
||||||
|
|
||||||
# Cache downloaded source
|
# Cache downloaded source
|
||||||
- id: cache-download
|
- id: cache-download
|
||||||
|
|||||||
2
.github/workflows/build-macos-x86_64.yml
vendored
2
.github/workflows/build-macos-x86_64.yml
vendored
@@ -54,7 +54,7 @@ jobs:
|
|||||||
|
|
||||||
# If there's no Composer cache, install dependencies
|
# If there's no Composer cache, install dependencies
|
||||||
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
||||||
run: composer update --no-dev
|
run: composer update --no-dev --classmap-authoritative
|
||||||
|
|
||||||
# Cache downloaded source
|
# Cache downloaded source
|
||||||
- id: cache-download
|
- id: cache-download
|
||||||
|
|||||||
47
.github/workflows/release-build.yml
vendored
Normal file
47
.github/workflows/release-build.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Upload SPC Binary (Release)
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- published
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-release-artifacts:
|
||||||
|
name: "Upload SPC Binary (Release)"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
operating-system:
|
||||||
|
- "linux-x86_64"
|
||||||
|
- "macos-x86_64"
|
||||||
|
- "linux-aarch64"
|
||||||
|
- "macos-aarch64"
|
||||||
|
steps:
|
||||||
|
- name: "Checkout"
|
||||||
|
uses: "actions/checkout@v4"
|
||||||
|
|
||||||
|
- name: Reuse static-php-cli-hosted artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v2
|
||||||
|
with:
|
||||||
|
repo: crazywhalecc/static-php-cli-hosted
|
||||||
|
branch: master
|
||||||
|
workflow: build-spc-release.yml
|
||||||
|
name: "spc-${{ matrix.operating-system }}"
|
||||||
|
|
||||||
|
- name: "Archive Executable"
|
||||||
|
run: |
|
||||||
|
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
|
||||||
|
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: upload binaries to release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: ${{startsWith(github.ref, 'refs/tags/') }}
|
||||||
|
with:
|
||||||
|
files: ${{ env.filename }}
|
||||||
|
|
||||||
|
- name: "Upload Artifact"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
path: spc
|
||||||
|
name: spc-${{ matrix.operating-system }}
|
||||||
98
.github/workflows/tests.yml
vendored
Normal file
98
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
php-cs-fixer:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.1'
|
||||||
|
extensions: curl, openssl, mbstring
|
||||||
|
ini-values: memory_limit=-1
|
||||||
|
tools: pecl, composer, php-cs-fixer
|
||||||
|
|
||||||
|
- name: Run PHP-CS-Fixer fix
|
||||||
|
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||||
|
|
||||||
|
phpstan:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.1'
|
||||||
|
extensions: curl, openssl, mbstring
|
||||||
|
ini-values: memory_limit=-1
|
||||||
|
tools: composer
|
||||||
|
|
||||||
|
- name: Cache Composer packages
|
||||||
|
id: composer-cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: vendor
|
||||||
|
key: ${{ runner.os }}-phpstan-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-phpstan-
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
|
- name: Run phpstan
|
||||||
|
run: vendor/bin/phpstan analyse
|
||||||
|
|
||||||
|
phpunit:
|
||||||
|
name: PHPUnit (PHP ${{ matrix.php }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: '8.1'
|
||||||
|
- php: '8.2'
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "${{ matrix.php }}"
|
||||||
|
tools: pecl, composer
|
||||||
|
extensions: curl, openssl, mbstring
|
||||||
|
ini-values: memory_limit=-1
|
||||||
|
|
||||||
|
- name: Cache Composer packages
|
||||||
|
id: composer-cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: vendor
|
||||||
|
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-php-
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
|
- name: Run PHPUnit tests
|
||||||
|
run: |
|
||||||
|
vendor/bin/phpunit tests/ --no-coverage
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -4,8 +4,7 @@ docker/libraries/
|
|||||||
docker/extensions/
|
docker/extensions/
|
||||||
docker/source/
|
docker/source/
|
||||||
|
|
||||||
# Composer file
|
# Vendor files
|
||||||
composer.lock
|
|
||||||
/vendor/
|
/vendor/
|
||||||
|
|
||||||
# default source extract directory
|
# default source extract directory
|
||||||
@@ -17,11 +16,15 @@ composer.lock
|
|||||||
# default source build root directory
|
# default source build root directory
|
||||||
/buildroot/
|
/buildroot/
|
||||||
|
|
||||||
# php cs fixer cache file
|
# tools cache files
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
|
.phpunit.result.cache
|
||||||
|
|
||||||
# exclude self-runtime
|
# exclude self-runtime
|
||||||
/bin/*
|
/bin/*
|
||||||
!/bin/spc
|
!/bin/spc
|
||||||
!/bin/setup-runtime
|
!/bin/setup-runtime
|
||||||
!/bin/spc-alpine-docker
|
!/bin/spc-alpine-docker
|
||||||
|
|
||||||
|
# default test directory
|
||||||
|
/tests/var/
|
||||||
|
|||||||
@@ -65,5 +65,5 @@ return (new PhpCsFixer\Config())
|
|||||||
'phpdoc_var_without_name' => false,
|
'phpdoc_var_without_name' => false,
|
||||||
])
|
])
|
||||||
->setFinder(
|
->setFinder(
|
||||||
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
|
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
|
||||||
);
|
);
|
||||||
|
|||||||
45
README-en.md
45
README-en.md
@@ -1,15 +1,17 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
Compile A Statically Linked PHP With Swoole and other Extensions.
|
Build single static PHP binary, with PHP project together, with popular extensions included.
|
||||||
|
|
||||||
|
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed SAPI 😎
|
||||||
|
|
||||||
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI)
|
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI)
|
||||||
|
|
||||||
<img width="600" alt="截屏2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
<img width="600" alt="2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
||||||
|
|
||||||
You can also use the micro binary file to combine php binary and php source code into one for distribution!
|
You can also use the micro binary file to combine php binary and php source code into one for distribution!
|
||||||
This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro). (micro SAPI)
|
This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro). (micro SAPI)
|
||||||
|
|
||||||
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
<img width="600" alt="2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
||||||
|
|
||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
@@ -19,8 +21,6 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
|
|||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
> The project has renamed the `refactor` branch to the `main` branch, please pay attention to changing the branch name for dependent projects.
|
|
||||||
|
|
||||||
## Compilation Requirements
|
## Compilation Requirements
|
||||||
|
|
||||||
Yes, this project is written in PHP, pretty funny.
|
Yes, this project is written in PHP, pretty funny.
|
||||||
@@ -41,7 +41,7 @@ Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`
|
|||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
docs here: <https://static-php-cli.zhamao.me>.
|
docs here: <https://static-php.dev>.
|
||||||
|
|
||||||
## Simple Usage
|
## Simple Usage
|
||||||
|
|
||||||
@@ -49,13 +49,13 @@ Please first select the extension you want to compile based on the extension lis
|
|||||||
|
|
||||||
### Direct Download
|
### Direct Download
|
||||||
|
|
||||||
If you don't compile yourself, you can download pre-compiled artifact from Actions, or from self-hosted server: [Here](https://dl.zhamao.xin/static-php-cli/)
|
If you don't compile yourself, you can download pre-compiled artifact from Actions, or from self-hosted server: [Here](https://dl.static-php.dev/static-php-cli/common/)
|
||||||
|
|
||||||
> self-hosted server contains extensions: `bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
|
> self-hosted server contains extensions: `bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
|
||||||
|
|
||||||
### Supported Extensions
|
### Supported Extensions
|
||||||
|
|
||||||
[Supported Extension List](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
[Supported Extension List](https://static-php.dev/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.
|
||||||
|
|
||||||
@@ -126,6 +126,7 @@ Now we support `cli`, `micro`, `fpm`, you can use one or more of the following p
|
|||||||
- `--build-cli`: build static cli executable
|
- `--build-cli`: build static cli executable
|
||||||
- `--build-micro`: build static phpmicro self-extracted executable
|
- `--build-micro`: build static phpmicro self-extracted executable
|
||||||
- `--build-fpm`: build static fpm binary
|
- `--build-fpm`: build static fpm binary
|
||||||
|
- `--build-embed`: build embed (libphp)
|
||||||
- `--build-all`: build all
|
- `--build-all`: build all
|
||||||
|
|
||||||
If anything goes wrong, use `--debug` option to display full terminal output:
|
If anything goes wrong, use `--debug` option to display full terminal output:
|
||||||
@@ -194,27 +195,26 @@ Because php-fpm must specify a configuration file before running, the php-fpm co
|
|||||||
|
|
||||||
Specifying `php-fpm.conf` can use the command parameter `-y`, for example: `./php-fpm -y php-fpm.conf`.
|
Specifying `php-fpm.conf` can use the command parameter `-y`, for example: `./php-fpm -y php-fpm.conf`.
|
||||||
|
|
||||||
## Current Status
|
### Embed Usage
|
||||||
|
|
||||||
- [X] Basic CLI framework (by `symfony/console`)
|
When using the project parameters `--build-embed` or `--build-all`,
|
||||||
- [X] Linux support
|
the final compilation result will output a `libphp.a`, `php-config` and a series of header files,
|
||||||
- [X] macOS support
|
stored in `buildroot/`. You can introduce them in your other projects.
|
||||||
- [X] Exception handler
|
|
||||||
- [ ] Windows support
|
|
||||||
- [X] PHP 7.4 support
|
|
||||||
- [X] fpm support
|
|
||||||
|
|
||||||
More functions and features are coming soon, Bugs and TODOs: https://github.com/crazywhalecc/static-php-cli/issues/32
|
If you know [embed SAPI](https://github.com/php/php-src/tree/master/sapi/embed), you should know how to use it.
|
||||||
|
You may require the introduction of other libraries during compilation,
|
||||||
|
you can use `buildroot/bin/php-config` to obtain the compile-time configuration.
|
||||||
|
|
||||||
|
For an advanced example of how to use this feature, take a look at [how to use it to build a static version of FrankenPHP](https://github.com/dunglas/frankenphp/blob/main/docs/static.md).
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Currently, there are only a few supported extensions.
|
|
||||||
If the extension you need is missing, you can create an issue.
|
If the extension you need is missing, you can create an issue.
|
||||||
If you are familiar with this project, you are also welcome to initiate a pull request.
|
If you are familiar with this project, you are also welcome to initiate a pull request.
|
||||||
|
|
||||||
The basic principles for contributing are as follows:
|
The basic principles for contributing are as follows:
|
||||||
|
|
||||||
- This project uses php-cs-fixer and phpstan as code formatting tools. Before contributing, please run `composer analyze` and `composer cs-fix` on the updated code.
|
- This project uses php-cs-fixer and phpstan as code formatting tools. Before contributing, please run `composer analyse` and `composer cs-fix` on the updated code.
|
||||||
- If other open source libraries are involved, the corresponding licenses should be provided.
|
- If other open source libraries are involved, the corresponding licenses should be provided.
|
||||||
Also, configuration files should be sorted using the command `sort-config` after modification.
|
Also, configuration files should be sorted using the command `sort-config` after modification.
|
||||||
For more information about sorting commands, see the documentation.
|
For more information about sorting commands, see the documentation.
|
||||||
@@ -236,8 +236,9 @@ You can sponsor my project on [this page](https://github.com/crazywhalecc/crazyw
|
|||||||
|
|
||||||
## Open-Source License
|
## Open-Source License
|
||||||
|
|
||||||
This project is based on the tradition of using the MIT License for old versions,
|
This project itself is based on MIT License,
|
||||||
while the new version references source code from some other projects:
|
some newly added extensions and dependencies may originate from the following projects (including but not limited to),
|
||||||
|
and the headers of these code files will also be given additional instructions LICENSE and AUTHOR:
|
||||||
|
|
||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
|
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
|
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
|
||||||
@@ -253,4 +254,4 @@ and comply with the corresponding project's LICENSE.
|
|||||||
|
|
||||||
The refactoring branch of this project is written modularly.
|
The refactoring branch of this project is written modularly.
|
||||||
If you are interested in this project and want to join the development,
|
If you are interested in this project and want to join the development,
|
||||||
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation. (TODO)
|
you can refer to the [Contribution Guide](https://static-php.dev) of the documentation to contribute code or documentation.
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -1,6 +1,6 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
Compile A Statically Linked PHP With Swoole and other Extensions.
|
Build single static PHP binary, with PHP project together, with popular extensions included.
|
||||||
|
|
||||||
**If you are using English, see [English README](README-en.md).**
|
**If you are using English, see [English README](README-en.md).**
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
|||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
> 项目已重命名 `refactor` 分支为 `main` 分支,请依赖的项目注意更改分支名称。
|
> 项目名称是 static-php-cli,但其实支持 cli、fpm、micro 和 embed SAPI 😎
|
||||||
|
|
||||||
## 编译环境需求
|
## 编译环境需求
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
|||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
点击这里查看文档:<https://static-php-cli.zhamao.me>。
|
点击这里查看文档:<https://static-php.dev>。
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
@@ -48,13 +48,13 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
|||||||
|
|
||||||
### 自托管直接下载
|
### 自托管直接下载
|
||||||
|
|
||||||
如果你不想自行编译,可以从本项目现有的 Action 下载 Artifact,也可以从自托管的服务器下载:[进入](https://dl.zhamao.xin/static-php-cli/)
|
如果你不想自行编译,可以从本项目现有的 Action 下载 Artifact,也可以从自托管的服务器下载:[进入](https://dl.static-php.dev/static-php-cli/common/)
|
||||||
|
|
||||||
> 自托管的服务器默认包含的扩展有:`bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
|
> 自托管的服务器默认包含的扩展有:`bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
|
||||||
|
|
||||||
### 支持的扩展情况
|
### 支持的扩展情况
|
||||||
|
|
||||||
[扩展支持列表](https://static-php-cli.zhamao.me/zh/guide/extensions.html)
|
[扩展支持列表](https://static-php.dev/zh/guide/extensions.html)
|
||||||
|
|
||||||
> 如果这里没有你需要的扩展,可以提交 Issue。
|
> 如果这里没有你需要的扩展,可以提交 Issue。
|
||||||
|
|
||||||
@@ -120,6 +120,7 @@ chmod +x bin/spc
|
|||||||
- `--build-cli`:构建 cli 二进制
|
- `--build-cli`:构建 cli 二进制
|
||||||
- `--build-micro`:构建 phpmicro 自执行二进制
|
- `--build-micro`:构建 phpmicro 自执行二进制
|
||||||
- `--build-fpm`:构建 fpm
|
- `--build-fpm`:构建 fpm
|
||||||
|
- `--build-embed`:构建 embed(libphp)
|
||||||
- `--build-all`:构建所有
|
- `--build-all`:构建所有
|
||||||
|
|
||||||
如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误:
|
如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误:
|
||||||
@@ -181,21 +182,17 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
|||||||
|
|
||||||
指定 `php-fpm.conf` 可以使用命令参数 `-y`,例如:`./php-fpm -y php-fpm.conf`。
|
指定 `php-fpm.conf` 可以使用命令参数 `-y`,例如:`./php-fpm -y php-fpm.conf`。
|
||||||
|
|
||||||
## 项目支持情况
|
### 使用 php-embed
|
||||||
|
|
||||||
- [X] 基础结构编写(采用 `symfony/console`)
|
采用项目参数 `--build-embed` 或 `--build-all` 时,最后编译结果会输出一个 `libphp.a`、`php-config` 以及一系列头文件,存放在 `buildroot/`,你可以在你的其他代码中引入它们。
|
||||||
- [X] 错误处理
|
|
||||||
- [X] macOS 支持
|
|
||||||
- [ ] Windows 支持
|
|
||||||
- [X] Linux 支持
|
|
||||||
- [X] PHP 7.4 支持
|
|
||||||
- [X] fpm 支持
|
|
||||||
|
|
||||||
更多功能和特性正在陆续支持中,详见:https://github.com/crazywhalecc/static-php-cli/issues/32
|
如果你知道 [embed SAPI](https://github.com/php/php-src/tree/master/sapi/embed),你应该知道如何使用它。对于有可能编译用到引入其他库的问题,你可以使用 `buildroot/bin/php-config` 来获取编译时的配置。
|
||||||
|
|
||||||
|
另外,有关如何使用此功能的高级示例,请查看[如何使用它构建 FrankenPHP 的静态版本](https://github.com/dunglas/frankenphp/blob/main/docs/static.md)。
|
||||||
|
|
||||||
## 贡献
|
## 贡献
|
||||||
|
|
||||||
目前支持的扩展较少,如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉,也欢迎为本项目发起 Pull Request。
|
如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉,也欢迎为本项目发起 Pull Request。
|
||||||
|
|
||||||
贡献基本原则如下:
|
贡献基本原则如下:
|
||||||
|
|
||||||
@@ -214,7 +211,7 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
|||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
本项目依据旧版本惯例采用 MIT License 开源,自身的部分代码引用或修改自以下项目:
|
本项目依据旧版本惯例采用 MIT License 开源,部分扩展的集成编译命令参考或修改自以下项目:
|
||||||
|
|
||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)(木兰宽松许可证)
|
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)(木兰宽松许可证)
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)(Apache 2.0 LICENSE、SWOOLE-CLI LICENSE)
|
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)(Apache 2.0 LICENSE、SWOOLE-CLI LICENSE)
|
||||||
@@ -224,4 +221,4 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
|||||||
|
|
||||||
## 进阶
|
## 进阶
|
||||||
|
|
||||||
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。(TODO)
|
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php.dev) 贡献代码或文档。
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# set error-quit, verbose, non-variable-quit
|
# set error-quit, verbose, non-variable-quit
|
||||||
set -eu
|
set -eu
|
||||||
@@ -25,7 +25,7 @@ __DIR__=$(cd "$(dirname "$0")" && pwd)
|
|||||||
__PROJECT__=$(cd "${__DIR__}"/../ && pwd)
|
__PROJECT__=$(cd "${__DIR__}"/../ && pwd)
|
||||||
|
|
||||||
# set download dir
|
# set download dir
|
||||||
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/common/php-8.2.10-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
||||||
__COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar"
|
__COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar"
|
||||||
|
|
||||||
# use china mirror
|
# use china mirror
|
||||||
@@ -46,12 +46,16 @@ done
|
|||||||
|
|
||||||
case "$mirror" in
|
case "$mirror" in
|
||||||
china)
|
china)
|
||||||
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/common/php-8.2.10-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
||||||
__COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar"
|
__COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if ! command -v curl > /dev/null && command -v apk > /dev/null; then
|
||||||
|
apk add --no-cache curl
|
||||||
|
fi
|
||||||
|
|
||||||
test -d "${__PROJECT__}"/downloads || mkdir "${__PROJECT__}"/downloads
|
test -d "${__PROJECT__}"/downloads || mkdir "${__PROJECT__}"/downloads
|
||||||
# download static php binary
|
# download static php binary
|
||||||
test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o "${__PROJECT__}"/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; }
|
test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o "${__PROJECT__}"/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; }
|
||||||
|
|||||||
@@ -52,24 +52,52 @@ fi
|
|||||||
# Detect docker env is setup
|
# Detect docker env is setup
|
||||||
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
|
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
|
||||||
echo "Docker container does not exist. Building docker image ..."
|
echo "Docker container does not exist. Building docker image ..."
|
||||||
ALPINE_DOCKERFILE=$(cat << EOF
|
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH -f- . <<EOF
|
||||||
FROM $ALPINE_FROM
|
FROM $ALPINE_FROM
|
||||||
$SPC_USE_MIRROR
|
$SPC_USE_MIRROR
|
||||||
RUN apk update
|
RUN apk update; \
|
||||||
RUN apk add bash file wget cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils bison flex pkgconfig automake curl
|
apk add --no-cache \
|
||||||
RUN apk add build-base xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
|
autoconf \
|
||||||
RUN mkdir /app
|
automake \
|
||||||
|
bash \
|
||||||
|
binutils \
|
||||||
|
bison \
|
||||||
|
build-base \
|
||||||
|
cmake \
|
||||||
|
curl \
|
||||||
|
file \
|
||||||
|
flex \
|
||||||
|
g++ \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
jq \
|
||||||
|
libgcc \
|
||||||
|
libstdc++ \
|
||||||
|
linux-headers \
|
||||||
|
m4 \
|
||||||
|
make \
|
||||||
|
php82 \
|
||||||
|
php82-common \
|
||||||
|
php82-pcntl \
|
||||||
|
php82-phar \
|
||||||
|
php82-posix \
|
||||||
|
php82-sodium \
|
||||||
|
php82-tokenizer \
|
||||||
|
php82-dom \
|
||||||
|
php82-xml \
|
||||||
|
php82-xmlwriter \
|
||||||
|
composer \
|
||||||
|
pkgconfig \
|
||||||
|
wget \
|
||||||
|
xz ; \
|
||||||
|
ln -s /usr/bin/php82 /usr/bin/php
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD ./src /app/src
|
ADD ./src /app/src
|
||||||
ADD ./composer.json /app/composer.json
|
COPY ./composer.* /app/
|
||||||
ADD ./bin /app/bin
|
ADD ./bin /app/bin
|
||||||
RUN composer update --no-dev
|
RUN composer install --no-dev --classmap-authoritative
|
||||||
EOF
|
EOF
|
||||||
)
|
|
||||||
echo "$ALPINE_DOCKERFILE" > "$(pwd)"/Dockerfile
|
|
||||||
|
|
||||||
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH .
|
|
||||||
rm "$(pwd)"/Dockerfile
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if in ci (local terminal can execute with -it)
|
# Check if in ci (local terminal can execute with -it)
|
||||||
@@ -81,4 +109,4 @@ fi
|
|||||||
|
|
||||||
# Run docker
|
# Run docker
|
||||||
# shellcheck disable=SC2068
|
# shellcheck disable=SC2068
|
||||||
$DOCKER_EXECUTABLE run --rm "$INTERACT" -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@
|
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@
|
||||||
|
|||||||
18
box.json
Normal file
18
box.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"alias": "spc-php.phar",
|
||||||
|
"banner": false,
|
||||||
|
"blacklist": [
|
||||||
|
".github"
|
||||||
|
],
|
||||||
|
"directories": [
|
||||||
|
"config",
|
||||||
|
"src",
|
||||||
|
"vendor/psr",
|
||||||
|
"vendor/laravel/prompts",
|
||||||
|
"vendor/symfony",
|
||||||
|
"vendor/zhamao"
|
||||||
|
],
|
||||||
|
"git-commit-short": "git_commit_short",
|
||||||
|
"metadata": "ConsoleApplication::VERSION",
|
||||||
|
"output": "spc.phar"
|
||||||
|
}
|
||||||
@@ -13,15 +13,17 @@
|
|||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-pcntl": "*",
|
"ext-pcntl": "*",
|
||||||
"laravel/prompts": "^0.1.3",
|
"laravel/prompts": "^0.1.3",
|
||||||
"symfony/console": "^6 || ^5 || ^4",
|
"symfony/console": "^5.4 || ^6 || ^7",
|
||||||
"zhamao/logger": "^1.0"
|
"zhamao/logger": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"nunomaduro/collision": "*",
|
|
||||||
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
|
|
||||||
"phpstan/phpstan": "^1.1",
|
|
||||||
"captainhook/captainhook": "^5.10",
|
"captainhook/captainhook": "^5.10",
|
||||||
"captainhook/plugin-composer": "^5.3"
|
"captainhook/plugin-composer": "^5.3",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.25",
|
||||||
|
"humbug/box": "^4.3",
|
||||||
|
"nunomaduro/collision": "^7.8",
|
||||||
|
"phpstan/phpstan": "^1.10",
|
||||||
|
"phpunit/phpunit": "^10.3"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@@ -32,13 +34,19 @@
|
|||||||
"src/globals/functions.php"
|
"src/globals/functions.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"SPC\\Tests\\": "tests/SPC"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"bin/spc"
|
"bin/spc"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyse": "phpstan analyse --memory-limit 300M",
|
"analyse": "phpstan analyse --memory-limit 300M",
|
||||||
"cs-fix": "php-cs-fixer fix",
|
"cs-fix": "php-cs-fixer fix",
|
||||||
"test": "bin/phpunit --no-coverage"
|
"test": "vendor/bin/phpunit tests/ --no-coverage",
|
||||||
|
"build:phar": "vendor/bin/box compile"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"allow-plugins": {
|
"allow-plugins": {
|
||||||
|
|||||||
5950
composer.lock
generated
Normal file
5950
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -153,9 +153,16 @@
|
|||||||
},
|
},
|
||||||
"ldap": {
|
"ldap": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with",
|
"arg-type": "with-prefix",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"ldap"
|
"ldap"
|
||||||
|
],
|
||||||
|
"lib-suggests": [
|
||||||
|
"gmp",
|
||||||
|
"libsodium"
|
||||||
|
],
|
||||||
|
"ext-suggests": [
|
||||||
|
"openssl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mbregex": {
|
"mbregex": {
|
||||||
@@ -229,6 +236,9 @@
|
|||||||
"arg-type": "with",
|
"arg-type": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"openssl"
|
"openssl"
|
||||||
|
],
|
||||||
|
"ext-depends": [
|
||||||
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"pcntl": {
|
"pcntl": {
|
||||||
@@ -325,6 +335,18 @@
|
|||||||
"libxml2"
|
"libxml2"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"snappy": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "ext-snappy",
|
||||||
|
"cpp-extension": true,
|
||||||
|
"arg-type": "custom",
|
||||||
|
"lib-depends": [
|
||||||
|
"snappy"
|
||||||
|
],
|
||||||
|
"ext-suggest": [
|
||||||
|
"apcu"
|
||||||
|
]
|
||||||
|
},
|
||||||
"snmp": {
|
"snmp": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with",
|
"arg-type": "with",
|
||||||
@@ -449,9 +471,13 @@
|
|||||||
},
|
},
|
||||||
"xsl": {
|
"xsl": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with",
|
"arg-type": "with-prefix",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxslt"
|
"libxslt"
|
||||||
|
],
|
||||||
|
"ext-depends": [
|
||||||
|
"xml",
|
||||||
|
"dom"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"yaml": {
|
"yaml": {
|
||||||
@@ -486,4 +512,4 @@
|
|||||||
"zstd"
|
"zstd"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,14 +42,14 @@
|
|||||||
"curl"
|
"curl"
|
||||||
],
|
],
|
||||||
"lib-depends-unix": [
|
"lib-depends-unix": [
|
||||||
|
"openssl",
|
||||||
"zlib"
|
"zlib"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests": [
|
||||||
"libssh2",
|
"libssh2",
|
||||||
"brotli",
|
"brotli",
|
||||||
"nghttp2",
|
"nghttp2",
|
||||||
"zstd",
|
"zstd"
|
||||||
"openssl"
|
|
||||||
],
|
],
|
||||||
"lib-suggests-windows": [
|
"lib-suggests-windows": [
|
||||||
"zlib",
|
"zlib",
|
||||||
@@ -139,6 +139,18 @@
|
|||||||
"libxml2"
|
"libxml2"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ldap": {
|
||||||
|
"source": "ldap",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"liblber.a",
|
||||||
|
"libldap.a"
|
||||||
|
],
|
||||||
|
"lib-suggests": [
|
||||||
|
"openssl",
|
||||||
|
"gmp",
|
||||||
|
"libsodium"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libavif": {
|
"libavif": {
|
||||||
"source": "libavif",
|
"source": "libavif",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -279,20 +291,29 @@
|
|||||||
"libxml2"
|
"libxml2"
|
||||||
],
|
],
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libiconv"
|
"libiconv",
|
||||||
|
"zlib"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests": [
|
||||||
"xz",
|
"xz",
|
||||||
"zlib",
|
|
||||||
"icu"
|
"icu"
|
||||||
],
|
],
|
||||||
"lib-suggests-windows": [
|
"lib-suggests-windows": [
|
||||||
"icu",
|
"icu",
|
||||||
"xz",
|
"xz",
|
||||||
"zlib",
|
|
||||||
"pthreads4w"
|
"pthreads4w"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libxslt": {
|
||||||
|
"source": "libxslt",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libxslt.a",
|
||||||
|
"libexslt.a"
|
||||||
|
],
|
||||||
|
"lib-depends": [
|
||||||
|
"libxml2"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libyaml": {
|
"libyaml": {
|
||||||
"source": "libyaml",
|
"source": "libyaml",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -436,6 +457,22 @@
|
|||||||
"ncurses"
|
"ncurses"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"snappy": {
|
||||||
|
"source": "snappy",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libsnappy.a"
|
||||||
|
],
|
||||||
|
"headers-unix": [
|
||||||
|
"snappy-c.h",
|
||||||
|
"snappy-sinksource.h",
|
||||||
|
"snappy.h",
|
||||||
|
"snappy-stubs-internal.h",
|
||||||
|
"snappy-stubs-public.h"
|
||||||
|
],
|
||||||
|
"lib-depends": [
|
||||||
|
"zlib"
|
||||||
|
]
|
||||||
|
},
|
||||||
"sqlite": {
|
"sqlite": {
|
||||||
"source": "sqlite",
|
"source": "sqlite",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -502,4 +539,4 @@
|
|||||||
"zstd_errors.h"
|
"zstd_errors.h"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
|||||||
# Extension List
|
# Extension List
|
||||||
|
|
||||||
See: [Docs - Extensions](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
See: [Docs - Extensions](https://static-php.dev/en/guide/extensions.html)
|
||||||
|
|||||||
@@ -4,7 +4,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC;
|
namespace SPC;
|
||||||
|
|
||||||
use SPC\store\FileSystem;
|
use SPC\command\BuildCliCommand;
|
||||||
|
use SPC\command\BuildLibsCommand;
|
||||||
|
use SPC\command\dev\AllExtCommand;
|
||||||
|
use SPC\command\dev\PhpVerCommand;
|
||||||
|
use SPC\command\dev\SortConfigCommand;
|
||||||
|
use SPC\command\DoctorCommand;
|
||||||
|
use SPC\command\DownloadCommand;
|
||||||
|
use SPC\command\DumpLicenseCommand;
|
||||||
|
use SPC\command\ExtractCommand;
|
||||||
|
use SPC\command\MicroCombineCommand;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Symfony\Component\Console\Command\HelpCommand;
|
use Symfony\Component\Console\Command\HelpCommand;
|
||||||
use Symfony\Component\Console\Command\ListCommand;
|
use Symfony\Component\Console\Command\ListCommand;
|
||||||
@@ -12,38 +21,30 @@ use Symfony\Component\Console\Command\ListCommand;
|
|||||||
/**
|
/**
|
||||||
* static-php-cli console app entry
|
* static-php-cli console app entry
|
||||||
*/
|
*/
|
||||||
class ConsoleApplication extends Application
|
final class ConsoleApplication extends Application
|
||||||
{
|
{
|
||||||
public const VERSION = '2.0.0';
|
public const VERSION = '2.0-rc7';
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \ReflectionException
|
|
||||||
* @throws exception\FileSystemException
|
|
||||||
*/
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct('static-php-cli', self::VERSION);
|
parent::__construct('static-php-cli', self::VERSION);
|
||||||
|
|
||||||
global $argv;
|
$this->addCommands(
|
||||||
|
[
|
||||||
|
new BuildCliCommand(),
|
||||||
|
new BuildLibsCommand(),
|
||||||
|
new DoctorCommand(),
|
||||||
|
new DownloadCommand(),
|
||||||
|
new DumpLicenseCommand(),
|
||||||
|
new ExtractCommand(),
|
||||||
|
new MicroCombineCommand(),
|
||||||
|
|
||||||
// Detailed debugging errors are not displayed in the production environment. Only the error display provided by Symfony console is used.
|
// Dev commands
|
||||||
$this->setCatchExceptions(file_exists(ROOT_DIR . '/.prod') || !in_array('--debug', $argv));
|
new AllExtCommand(),
|
||||||
|
new PhpVerCommand(),
|
||||||
// Add subcommands by scanning the directory src/static-php-cli/command/
|
new SortConfigCommand(),
|
||||||
$commands = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/command', 'SPC\\command');
|
]
|
||||||
$phar = class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar');
|
);
|
||||||
$commands = array_filter($commands, function ($y) use ($phar) {
|
|
||||||
$archive_blacklist = [
|
|
||||||
'SPC\command\dev\SortConfigCommand',
|
|
||||||
'SPC\command\DeployCommand',
|
|
||||||
];
|
|
||||||
if ($phar && in_array($y, $archive_blacklist)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$reflection = new \ReflectionClass($y);
|
|
||||||
return !$reflection->isAbstract() && !$reflection->isInterface();
|
|
||||||
});
|
|
||||||
$this->addCommands(array_map(function ($x) { return new $x(); }, $commands));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getDefaultCommands(): array
|
protected function getDefaultCommands(): array
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ abstract class BuilderBase
|
|||||||
|
|
||||||
// build all libs
|
// build all libs
|
||||||
foreach ($this->libs as $lib) {
|
foreach ($this->libs as $lib) {
|
||||||
match ($lib->tryBuild()) {
|
match ($lib->tryBuild($this->getOption('rebuild', false))) {
|
||||||
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'),
|
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'),
|
||||||
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
|
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
|
||||||
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
|
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
|
||||||
@@ -227,12 +227,22 @@ abstract class BuilderBase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get PHP Version ID from php-src/main/php_version.h
|
* Get PHP Version ID from php-src/main/php_version.h
|
||||||
|
*
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public function getPHPVersionID(): int
|
public function getPHPVersionID(): int
|
||||||
{
|
{
|
||||||
|
if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
|
||||||
|
throw new WrongUsageException('PHP source files are not available, you need to download them first');
|
||||||
|
}
|
||||||
|
|
||||||
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
|
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
|
||||||
preg_match('/PHP_VERSION_ID (\d+)/', $file, $match);
|
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
|
||||||
return intval($match[1]);
|
return intval($match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,6 +262,9 @@ abstract class BuilderBase
|
|||||||
if (($type & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
if (($type & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
||||||
$ls[] = 'fpm';
|
$ls[] = 'fpm';
|
||||||
}
|
}
|
||||||
|
if (($type & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
|
||||||
|
$ls[] = 'embed';
|
||||||
|
}
|
||||||
return implode(', ', $ls);
|
return implode(', ', $ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace SPC\builder\extension;
|
|||||||
|
|
||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
use SPC\util\Util;
|
|
||||||
|
|
||||||
#[CustomExt('openssl')]
|
#[CustomExt('openssl')]
|
||||||
class openssl extends Extension
|
class openssl extends Extension
|
||||||
@@ -14,12 +13,13 @@ class openssl extends Extension
|
|||||||
public function patchBeforeMake(): bool
|
public function patchBeforeMake(): bool
|
||||||
{
|
{
|
||||||
// patch openssl3 with php8.0 bug
|
// patch openssl3 with php8.0 bug
|
||||||
if (file_exists(SOURCE_PATH . '/openssl/VERSION.dat') && Util::getPHPVersionID() < 80100) {
|
if (file_exists(SOURCE_PATH . '/openssl/VERSION.dat') && $this->builder->getPHPVersionID() < 80100) {
|
||||||
$openssl_c = file_get_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c');
|
$openssl_c = file_get_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c');
|
||||||
$openssl_c = preg_replace('/REGISTER_LONG_CONSTANT\s*\(\s*"OPENSSL_SSLV23_PADDING"\s*.+;/', '', $openssl_c);
|
$openssl_c = preg_replace('/REGISTER_LONG_CONSTANT\s*\(\s*"OPENSSL_SSLV23_PADDING"\s*.+;/', '', $openssl_c);
|
||||||
file_put_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c', $openssl_c);
|
file_put_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c', $openssl_c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/SPC/builder/extension/snappy.php
Normal file
33
src/SPC/builder/extension/snappy.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\builder\macos\MacOSBuilder;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('snappy')]
|
||||||
|
class snappy extends Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function patchBeforeConfigure(): bool
|
||||||
|
{
|
||||||
|
FileSystem::replaceFileRegex(
|
||||||
|
SOURCE_PATH . '/php-src/configure',
|
||||||
|
'/-lsnappy/',
|
||||||
|
$this->getLibFilesString() . ($this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++')
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ namespace SPC\builder\extension;
|
|||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
use SPC\util\Util;
|
|
||||||
|
|
||||||
#[CustomExt('swow')]
|
#[CustomExt('swow')]
|
||||||
class swow extends Extension
|
class swow extends Extension
|
||||||
@@ -25,7 +24,7 @@ class swow extends Extension
|
|||||||
*/
|
*/
|
||||||
public function patchBeforeBuildconf(): bool
|
public function patchBeforeBuildconf(): bool
|
||||||
{
|
{
|
||||||
if (Util::getPHPVersionID() >= 80000 && !is_link(SOURCE_PATH . '/php-src/ext/swow')) {
|
if ($this->builder->getPHPVersionID() >= 80000 && !is_link(SOURCE_PATH . '/php-src/ext/swow')) {
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D swow swow-src\ext');
|
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D swow swow-src\ext');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use SPC\builder\traits\UnixBuilderTrait;
|
|||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
|
|
||||||
class LinuxBuilder extends BuilderBase
|
class LinuxBuilder extends BuilderBase
|
||||||
@@ -52,7 +53,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
|
|
||||||
// ---------- set necessary compile environments ----------
|
// ---------- set necessary compile environments ----------
|
||||||
// set libc
|
// set libc
|
||||||
$this->libc = 'musl'; // SystemUtil::selectLibc($this->cc);
|
$this->libc = $this->getOption('cc', 'gcc') === 'musl-gcc' ? 'musl_wrapper' : 'musl'; // SystemUtil::selectLibc($this->cc);
|
||||||
// concurrency
|
// concurrency
|
||||||
$this->concurrency = SystemUtil::getCpuCount();
|
$this->concurrency = SystemUtil::getCpuCount();
|
||||||
// cflags
|
// cflags
|
||||||
@@ -179,6 +180,11 @@ class LinuxBuilder extends BuilderBase
|
|||||||
$zts = '';
|
$zts = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
|
||||||
|
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
|
||||||
|
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec(
|
->exec(
|
||||||
'./configure ' .
|
'./configure ' .
|
||||||
@@ -189,12 +195,13 @@ class LinuxBuilder extends BuilderBase
|
|||||||
'--disable-all ' .
|
'--disable-all ' .
|
||||||
'--disable-cgi ' .
|
'--disable-cgi ' .
|
||||||
'--disable-phpdbg ' .
|
'--disable-phpdbg ' .
|
||||||
'--enable-cli ' .
|
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
||||||
'--enable-fpm ' .
|
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
|
||||||
|
($enableEmbed ? '--enable-embed=static --disable-opcache-jit ' : '--disable-embed ') .
|
||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$maxExecutionTimers .
|
$maxExecutionTimers .
|
||||||
'--enable-micro=all-static ' .
|
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
|
||||||
$this->makeExtensionArgs() . ' ' .
|
$this->makeExtensionArgs() . ' ' .
|
||||||
$envs
|
$envs
|
||||||
);
|
);
|
||||||
@@ -203,26 +210,29 @@ class LinuxBuilder extends BuilderBase
|
|||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
|
|
||||||
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
if ($enableCli) {
|
||||||
logger()->info('building cli');
|
logger()->info('building cli');
|
||||||
$this->buildCli($extra_libs, $use_lld);
|
$this->buildCli($extra_libs, $use_lld);
|
||||||
}
|
}
|
||||||
if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
if ($enableFpm) {
|
||||||
logger()->info('building fpm');
|
logger()->info('building fpm');
|
||||||
$this->buildFpm($extra_libs, $use_lld);
|
$this->buildFpm($extra_libs, $use_lld);
|
||||||
}
|
}
|
||||||
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
if ($enableMicro) {
|
||||||
logger()->info('building micro');
|
logger()->info('building micro');
|
||||||
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
||||||
}
|
}
|
||||||
|
if ($enableEmbed) {
|
||||||
|
logger()->info('building embed');
|
||||||
|
if ($enableMicro) {
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
|
||||||
|
}
|
||||||
|
$this->buildEmbed($extra_libs, $use_lld);
|
||||||
|
}
|
||||||
|
|
||||||
if (php_uname('m') === $this->getOption('arch')) {
|
if (php_uname('m') === $this->getOption('arch')) {
|
||||||
$this->sanityCheck($build_target);
|
$this->sanityCheck($build_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phar_patched) {
|
|
||||||
SourcePatcher::patchMicro(['phar'], true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -280,6 +290,10 @@ class LinuxBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->deployBinary(BUILD_TARGET_MICRO);
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
||||||
|
|
||||||
|
if ($this->phar_patched) {
|
||||||
|
SourcePatcher::patchMicro(['phar'], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -306,4 +320,18 @@ class LinuxBuilder extends BuilderBase
|
|||||||
|
|
||||||
$this->deployBinary(BUILD_TARGET_FPM);
|
$this->deployBinary(BUILD_TARGET_FPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildEmbed(string $extra_libs, string $use_lld): void
|
||||||
|
{
|
||||||
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
|
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)),
|
||||||
|
'EXTRA_LIBS' => $extra_libs,
|
||||||
|
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static",
|
||||||
|
]);
|
||||||
|
|
||||||
|
shell()
|
||||||
|
->cd(SOURCE_PATH . '/php-src')
|
||||||
|
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
||||||
|
->exec('make INSTALL_ROOT=' . BUILD_ROOT_PATH . " -j{$this->concurrency} {$vars} install");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class SystemUtil
|
|||||||
|
|
||||||
public static function checkCCFlag(string $flag, string $cc): string
|
public static function checkCCFlag(string $flag, string $cc): string
|
||||||
{
|
{
|
||||||
[$ret] = shell()->execWithResult("echo | {$cc} -E -x c - {$flag}");
|
[$ret] = shell()->execWithResult("echo | {$cc} -E -x c - {$flag} 2>/dev/null");
|
||||||
if ($ret != 0) {
|
if ($ret != 0) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/linux/library/ldap.php
Normal file
12
src/SPC/builder/linux/library/ldap.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class ldap extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\ldap;
|
||||||
|
|
||||||
|
public const NAME = 'ldap';
|
||||||
|
}
|
||||||
@@ -19,21 +19,22 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
public function build(): void
|
public function build(): void
|
||||||
{
|
{
|
||||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
||||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
// $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
||||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
||||||
|
|
||||||
[, , $destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
FileSystem::resetDir($this->source_dir . '/build');
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
->exec(
|
->exec(
|
||||||
"{$this->builder->configure_env} " . ' cmake ' .
|
"{$this->builder->configure_env} " . ' cmake ' .
|
||||||
"{$this->builder->makeCmakeArgs()} " .
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DCMAKE_INSTALL_BINDIR=' . escapeshellarg(BUILD_ROOT_PATH . '/bin') . ' ' .
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||||
'-DIconv_IS_BUILT_IN=OFF ' .
|
'-DIconv_IS_BUILT_IN=OFF ' .
|
||||||
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
||||||
"-DLIBXML2_WITH_ICU={$enable_icu} " .
|
'-DLIBXML2_WITH_ICU=OFF ' .
|
||||||
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
|
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
|
||||||
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
||||||
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
||||||
@@ -41,15 +42,6 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
'..'
|
'..'
|
||||||
)
|
)
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec("make install DESTDIR={$destdir}");
|
->exec('make install');
|
||||||
|
|
||||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml2/libxml')) {
|
|
||||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml')) {
|
|
||||||
shell()->exec('rm -rf "' . BUILD_INCLUDE_PATH . '/libxml"');
|
|
||||||
}
|
|
||||||
$path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/libxml2/libxml');
|
|
||||||
$dst_path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/');
|
|
||||||
shell()->exec('mv "' . $path . '" "' . $dst_path . '"');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/SPC/builder/linux/library/libxslt.php
Normal file
15
src/SPC/builder/linux/library/libxslt.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gmp is a template library class for unix
|
||||||
|
*/
|
||||||
|
class libxslt extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libxslt;
|
||||||
|
|
||||||
|
public const NAME = 'libxslt';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/snappy.php
Normal file
12
src/SPC/builder/linux/library/snappy.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class snappy extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\snappy;
|
||||||
|
|
||||||
|
public const NAME = 'snappy';
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ use SPC\builder\traits\UnixBuilderTrait;
|
|||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
|
|
||||||
class MacOSBuilder extends BuilderBase
|
class MacOSBuilder extends BuilderBase
|
||||||
@@ -151,6 +152,11 @@ class MacOSBuilder extends BuilderBase
|
|||||||
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
||||||
$zts = $this->getOption('enable-zts', false) ? '--enable-zts --disable-zend-signals ' : '';
|
$zts = $this->getOption('enable-zts', false) ? '--enable-zts --disable-zend-signals ' : '';
|
||||||
|
|
||||||
|
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
|
||||||
|
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
|
||||||
|
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec(
|
->exec(
|
||||||
'./configure ' .
|
'./configure ' .
|
||||||
@@ -162,9 +168,10 @@ class MacOSBuilder extends BuilderBase
|
|||||||
'--disable-all ' .
|
'--disable-all ' .
|
||||||
'--disable-cgi ' .
|
'--disable-cgi ' .
|
||||||
'--disable-phpdbg ' .
|
'--disable-phpdbg ' .
|
||||||
'--enable-cli ' .
|
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
||||||
'--enable-fpm ' .
|
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
|
||||||
'--enable-micro ' .
|
($enableEmbed ? '--enable-embed=static ' : '--disable-embed ') .
|
||||||
|
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
|
||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$this->makeExtensionArgs() . ' ' .
|
$this->makeExtensionArgs() . ' ' .
|
||||||
@@ -175,26 +182,29 @@ class MacOSBuilder extends BuilderBase
|
|||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
|
|
||||||
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
if ($enableCli) {
|
||||||
logger()->info('building cli');
|
logger()->info('building cli');
|
||||||
$this->buildCli();
|
$this->buildCli();
|
||||||
}
|
}
|
||||||
if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
if ($enableFpm) {
|
||||||
logger()->info('building fpm');
|
logger()->info('building fpm');
|
||||||
$this->buildFpm();
|
$this->buildFpm();
|
||||||
}
|
}
|
||||||
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
if ($enableMicro) {
|
||||||
logger()->info('building micro');
|
logger()->info('building micro');
|
||||||
$this->buildMicro();
|
$this->buildMicro();
|
||||||
}
|
}
|
||||||
|
if ($enableEmbed) {
|
||||||
|
logger()->info('building embed');
|
||||||
|
if ($enableMicro) {
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
|
||||||
|
}
|
||||||
|
$this->buildEmbed();
|
||||||
|
}
|
||||||
|
|
||||||
if (php_uname('m') === $this->getOption('arch')) {
|
if (php_uname('m') === $this->getOption('arch')) {
|
||||||
$this->sanityCheck($build_target);
|
$this->sanityCheck($build_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phar_patched) {
|
|
||||||
SourcePatcher::patchMicro(['phar'], true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,7 +217,7 @@ class MacOSBuilder extends BuilderBase
|
|||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS need it)
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
||||||
@@ -237,7 +247,7 @@ class MacOSBuilder extends BuilderBase
|
|||||||
$vars = [
|
$vars = [
|
||||||
// with debug information, optimize for size, remove identifiers, patch fake cli for micro
|
// with debug information, optimize for size, remove identifiers, patch fake cli for micro
|
||||||
'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli,
|
'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli,
|
||||||
// link resolv library (macOS need it)
|
// link resolv library (macOS needs it)
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv",
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv",
|
||||||
];
|
];
|
||||||
if (!$this->getOption('no-strip', false)) {
|
if (!$this->getOption('no-strip', false)) {
|
||||||
@@ -248,6 +258,10 @@ class MacOSBuilder extends BuilderBase
|
|||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec("make -j{$this->concurrency} {$vars} micro");
|
->exec("make -j{$this->concurrency} {$vars} micro");
|
||||||
$this->deployBinary(BUILD_TARGET_MICRO);
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
||||||
|
|
||||||
|
if ($this->phar_patched) {
|
||||||
|
SourcePatcher::patchMicro(['phar'], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,7 +274,7 @@ class MacOSBuilder extends BuilderBase
|
|||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS need it)
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
||||||
@@ -270,4 +284,24 @@ class MacOSBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
$this->deployBinary(BUILD_TARGET_FPM);
|
$this->deployBinary(BUILD_TARGET_FPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildEmbed(): void
|
||||||
|
{
|
||||||
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
||||||
|
]);
|
||||||
|
|
||||||
|
shell()
|
||||||
|
->cd(SOURCE_PATH . '/php-src')
|
||||||
|
->exec('make INSTALL_ROOT=' . BUILD_ROOT_PATH . " -j{$this->concurrency} {$vars} install")
|
||||||
|
// Workaround for https://github.com/php/php-src/issues/12082
|
||||||
|
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o')
|
||||||
|
->exec('mkdir ' . BUILD_ROOT_PATH . '/lib/php-o')
|
||||||
|
->cd(BUILD_ROOT_PATH . '/lib/php-o')
|
||||||
|
->exec('ar x ' . BUILD_ROOT_PATH . '/lib/libphp.a')
|
||||||
|
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
|
||||||
|
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
|
||||||
|
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/macos/library/ldap.php
Normal file
12
src/SPC/builder/macos/library/ldap.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class ldap extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\ldap;
|
||||||
|
|
||||||
|
public const NAME = 'ldap';
|
||||||
|
}
|
||||||
15
src/SPC/builder/macos/library/libxslt.php
Normal file
15
src/SPC/builder/macos/library/libxslt.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gmp is a template library class for unix
|
||||||
|
*/
|
||||||
|
class libxslt extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libxslt;
|
||||||
|
|
||||||
|
public const NAME = 'libxslt';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/snappy.php
Normal file
12
src/SPC/builder/macos/library/snappy.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class snappy extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\snappy;
|
||||||
|
|
||||||
|
public const NAME = 'snappy';
|
||||||
|
}
|
||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\traits;
|
namespace SPC\builder\traits;
|
||||||
|
|
||||||
trait LibraryTrait
|
trait LibraryTrait {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -66,14 +66,23 @@ trait UnixBuilderTrait
|
|||||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||||
throw new RuntimeException('cli failed sanity check');
|
throw new RuntimeException('cli failed sanity check');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->exts as $ext) {
|
||||||
logger()->debug('testing ext: ' . $ext->getName());
|
logger()->debug('testing ext: ' . $ext->getName());
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $ext->getDistName() . '"', false);
|
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $ext->getDistName() . '"', false);
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
throw new RuntimeException('extension ' . $ext->getName() . ' failed compile check');
|
throw new RuntimeException('extension ' . $ext->getName() . ' failed compile check');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists(ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php')) {
|
if (file_exists(ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php')) {
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php ' . ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php');
|
// Trim additional content & escape special characters to allow inline usage
|
||||||
|
$test = str_replace(
|
||||||
|
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
|
||||||
|
['', '', '', '\"', '\$'],
|
||||||
|
file_get_contents(ROOT_DIR . '/src/globals/tests/' . $ext->getName() . '.php')
|
||||||
|
);
|
||||||
|
|
||||||
|
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"');
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
throw new RuntimeException('extension ' . $ext->getName() . ' failed sanity check');
|
throw new RuntimeException('extension ' . $ext->getName() . ' failed sanity check');
|
||||||
}
|
}
|
||||||
@@ -144,4 +153,26 @@ trait UnixBuilderTrait
|
|||||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->cmake_toolchain_file}";
|
"-DCMAKE_TOOLCHAIN_FILE={$this->cmake_toolchain_file}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate configure flags
|
||||||
|
*/
|
||||||
|
public function makeAutoconfFlags(int $flag = AUTOCONF_ALL): string
|
||||||
|
{
|
||||||
|
$extra = '';
|
||||||
|
// TODO: add auto pkg-config support
|
||||||
|
if (($flag & AUTOCONF_LIBS) === AUTOCONF_LIBS) {
|
||||||
|
$extra .= 'LIBS="' . BUILD_LIB_PATH . '" ';
|
||||||
|
}
|
||||||
|
if (($flag & AUTOCONF_CFLAGS) === AUTOCONF_CFLAGS) {
|
||||||
|
$extra .= 'CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
|
||||||
|
}
|
||||||
|
if (($flag & AUTOCONF_CPPFLAGS) === AUTOCONF_CPPFLAGS) {
|
||||||
|
$extra .= 'CPPFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
|
||||||
|
}
|
||||||
|
if (($flag & AUTOCONF_LDFLAGS) === AUTOCONF_LDFLAGS) {
|
||||||
|
$extra .= 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ';
|
||||||
|
}
|
||||||
|
return $extra;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ trait UnixLibraryTrait
|
|||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function patchPkgconfPrefix(array $files, int $patch_option = PKGCONF_PATCH_ALL): void
|
public function patchPkgconfPrefix(array $files, int $patch_option = PKGCONF_PATCH_ALL, ?array $custom_replace = null): void
|
||||||
{
|
{
|
||||||
logger()->info('Patching library [' . static::NAME . '] pkgconfig');
|
logger()->info('Patching library [' . static::NAME . '] pkgconfig');
|
||||||
foreach ($files as $name) {
|
foreach ($files as $name) {
|
||||||
@@ -81,6 +81,7 @@ trait UnixLibraryTrait
|
|||||||
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
|
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
|
||||||
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
|
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
|
||||||
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir=.*$/m', 'includedir=${prefix}/include', $file) : $file;
|
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir=.*$/m', 'includedir=${prefix}/include', $file) : $file;
|
||||||
|
$file = ($patch_option & PKGCONF_PATCH_CUSTOM) === PKGCONF_PATCH_CUSTOM && $custom_replace !== null ? preg_replace($custom_replace[0], $custom_replace[1], $file) : $file;
|
||||||
FileSystem::writeFile($realpath, $file);
|
FileSystem::writeFile($realpath, $file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ trait brotli
|
|||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
|
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
|
||||||
shell()->cd(BUILD_ROOT_PATH . '/lib')
|
shell()->cd(BUILD_ROOT_PATH . '/lib')
|
||||||
->exec('ln -s libbrotlicommon-static.a libbrotlicommon.a')
|
->exec('ln -s libbrotlicommon.a libbrotlicommon-static.a')
|
||||||
->exec('ln -s libbrotlidec-static.a libbrotlidec.a')
|
->exec('ln -s libbrotlidec.a libbrotlidec-static.a')
|
||||||
->exec('ln -s libbrotlienc-static.a libbrotlienc.a');
|
->exec('ln -s libbrotlienc.a libbrotlienc-static.a');
|
||||||
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
|
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
|
||||||
if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
|
if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
|
||||||
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
|
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ trait curl
|
|||||||
} else {
|
} else {
|
||||||
$extra .= '-DUSE_NGHTTP2=OFF ';
|
$extra .= '-DUSE_NGHTTP2=OFF ';
|
||||||
}
|
}
|
||||||
// TODO: ldap is not supported yet
|
// lib:ldap
|
||||||
$extra .= '-DCURL_DISABLE_LDAP=ON ';
|
$extra .= $this->builder->getLib('ldap') ? '-DCURL_DISABLE_LDAP=OFF ' : '-DCURL_DISABLE_LDAP=ON ';
|
||||||
// lib:zstd
|
// lib:zstd
|
||||||
$extra .= $this->builder->getLib('zstd') ? '-DCURL_ZSTD=ON ' : '-DCURL_ZSTD=OFF ';
|
$extra .= $this->builder->getLib('zstd') ? '-DCURL_ZSTD=ON ' : '-DCURL_ZSTD=OFF ';
|
||||||
// lib:idn2
|
// lib:idn2
|
||||||
@@ -51,6 +51,7 @@ trait curl
|
|||||||
FileSystem::resetDir($this->source_dir . '/build');
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
// compile!
|
// compile!
|
||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
|
->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt')
|
||||||
->exec("{$this->builder->configure_env} cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF {$extra} ..")
|
->exec("{$this->builder->configure_env} cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF {$extra} ..")
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
|||||||
39
src/SPC/builder/unix/library/ldap.php
Normal file
39
src/SPC/builder/unix/library/ldap.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
trait ldap
|
||||||
|
{
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$alt = '';
|
||||||
|
// openssl support
|
||||||
|
$alt .= $this->builder->getLib('openssl') && $this->builder->getExt('zlib') ? '--with-tls=openssl ' : '';
|
||||||
|
// gmp support
|
||||||
|
$alt .= $this->builder->getLib('gmp') ? '--with-mp=gmp ' : '';
|
||||||
|
// libsodium support
|
||||||
|
$alt .= $this->builder->getLib('libsodium') ? '--with-argon2=libsodium ' : '';
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
$this->builder->configure_env . ' ' .
|
||||||
|
$this->builder->makeAutoconfFlags(AUTOCONF_LDFLAGS | AUTOCONF_CPPFLAGS) .
|
||||||
|
' ./configure ' .
|
||||||
|
'--enable-static ' .
|
||||||
|
'--disable-shared ' .
|
||||||
|
'--disable-slapd ' .
|
||||||
|
'--disable-slurpd ' .
|
||||||
|
'--without-systemd ' .
|
||||||
|
'--without-cyrus-sasl ' .
|
||||||
|
$alt .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
// remove tests and doc to prevent compile failed with error: soelim not found
|
||||||
|
->exec('sed -i -e "s/SUBDIRS= include libraries clients servers tests doc/SUBDIRS= include libraries clients servers/g" Makefile')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
$this->patchPkgconfPrefix(['ldap.pc', 'lber.pc']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ trait libssh2
|
|||||||
"-DENABLE_ZLIB_COMPRESSION={$enable_zlib} " .
|
"-DENABLE_ZLIB_COMPRESSION={$enable_zlib} " .
|
||||||
'..'
|
'..'
|
||||||
)
|
)
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency} --target libssh2")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
$this->patchPkgconfPrefix(['libssh2.pc']);
|
$this->patchPkgconfPrefix(['libssh2.pc']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace SPC\builder\unix\library;
|
|||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
trait libwebp
|
trait libwebp
|
||||||
{
|
{
|
||||||
@@ -17,26 +18,22 @@ trait libwebp
|
|||||||
*/
|
*/
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
// CMake needs a clean build directory
|
||||||
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
shell()->cd($this->source_dir)
|
// Start build
|
||||||
->exec('./autogen.sh')
|
shell()->cd($this->source_dir . '/build')
|
||||||
->exec(
|
->exec(
|
||||||
"{$this->builder->configure_env} ./configure " .
|
"{$this->builder->configure_env} cmake " .
|
||||||
'--enable-static ' .
|
$this->builder->makeCmakeArgs() . ' ' .
|
||||||
'--disable-shared ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
'--prefix= ' .
|
'-DWEBP_BUILD_EXTRAS=ON ' .
|
||||||
'--enable-libwebpdecoder ' .
|
'..'
|
||||||
'--enable-libwebpextras ' .
|
|
||||||
'--disable-tiff ' .
|
|
||||||
'--disable-gl ' .
|
|
||||||
'--disable-sdl ' .
|
|
||||||
'--disable-wic'
|
|
||||||
)
|
)
|
||||||
->exec('make clean')
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
->exec('make install DESTDIR=' . $destdir);
|
// patch pkgconfig
|
||||||
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX);
|
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR);
|
||||||
|
$this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']);
|
||||||
$this->cleanLaFiles();
|
$this->cleanLaFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/SPC/builder/unix/library/libxslt.php
Normal file
35
src/SPC/builder/unix/library/libxslt.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
|
trait libxslt
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
"{$this->builder->configure_env} ./configure " .
|
||||||
|
'--enable-static --disable-shared ' .
|
||||||
|
'--without-python ' .
|
||||||
|
'--without-mem-debug ' .
|
||||||
|
'--without-crypto ' .
|
||||||
|
'--without-debug ' .
|
||||||
|
'--without-debugger ' .
|
||||||
|
'--with-libxml-prefix=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install DESTDIR=' . escapeshellarg(BUILD_ROOT_PATH));
|
||||||
|
$this->patchPkgconfPrefix(['libexslt.pc']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,15 +57,14 @@ trait postgresql
|
|||||||
'--with-ssl=openssl ' .
|
'--with-ssl=openssl ' .
|
||||||
'--with-readline ' .
|
'--with-readline ' .
|
||||||
'--with-libxml ' .
|
'--with-libxml ' .
|
||||||
|
($this->builder->getLib('ldap') ? '--with-ldap ' : '--without-ldap ') .
|
||||||
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
|
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
|
||||||
'--without-ldap ' .
|
|
||||||
'--without-libxslt ' .
|
'--without-libxslt ' .
|
||||||
'--without-lz4 ' .
|
'--without-lz4 ' .
|
||||||
'--without-zstd ' .
|
'--without-zstd ' .
|
||||||
'--without-perl ' .
|
'--without-perl ' .
|
||||||
'--without-python ' .
|
'--without-python ' .
|
||||||
'--without-pam ' .
|
'--without-pam ' .
|
||||||
'--without-ldap ' .
|
|
||||||
'--without-bonjour ' .
|
'--without-bonjour ' .
|
||||||
'--without-tcl '
|
'--without-tcl '
|
||||||
);
|
);
|
||||||
|
|||||||
34
src/SPC/builder/unix/library/snappy.php
Normal file
34
src/SPC/builder/unix/library/snappy.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
trait snappy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
FileSystem::resetDir($this->source_dir . '/cmake/build');
|
||||||
|
|
||||||
|
shell()->cd($this->source_dir . '/cmake/build')
|
||||||
|
->exec(
|
||||||
|
"{$this->builder->configure_env} cmake " .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
|
||||||
|
'-DSNAPPY_BUILD_TESTS=OFF ' .
|
||||||
|
'-DSNAPPY_BUILD_BENCHMARKS=OFF ' .
|
||||||
|
'../..'
|
||||||
|
)
|
||||||
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
|
->exec('make install');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ class BuildCliCommand extends BuildCommand
|
|||||||
$this->addOption('build-micro', null, null, 'build micro');
|
$this->addOption('build-micro', null, null, 'build micro');
|
||||||
$this->addOption('build-cli', null, null, 'build cli');
|
$this->addOption('build-cli', null, null, 'build cli');
|
||||||
$this->addOption('build-fpm', null, null, 'build fpm');
|
$this->addOption('build-fpm', null, null, 'build fpm');
|
||||||
$this->addOption('build-all', null, null, 'build cli, micro, fpm');
|
$this->addOption('build-embed', null, null, 'build embed');
|
||||||
|
$this->addOption('build-all', null, null, 'build cli, micro, fpm, embed');
|
||||||
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
|
$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('enable-zts', null, null, 'enable ZTS support');
|
||||||
$this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
|
$this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
|
||||||
@@ -40,16 +41,18 @@ class BuildCliCommand extends BuildCommand
|
|||||||
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
|
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
|
||||||
|
|
||||||
$rule = BUILD_TARGET_NONE;
|
$rule = BUILD_TARGET_NONE;
|
||||||
$rule = $rule | ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
|
||||||
$rule = $rule | ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
|
||||||
$rule = $rule | ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
|
||||||
$rule = $rule | ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
|
||||||
|
$rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
|
||||||
if ($rule === BUILD_TARGET_NONE) {
|
if ($rule === BUILD_TARGET_NONE) {
|
||||||
$this->output->writeln('<error>Please add at least one build target!</error>');
|
$this->output->writeln('<error>Please add at least one build target!</error>');
|
||||||
$this->output->writeln("<comment>\t--build-cli\tBuild php-cli SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-cli\tBuild php-cli SAPI</comment>");
|
||||||
$this->output->writeln("<comment>\t--build-micro\tBuild phpmicro SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-micro\tBuild phpmicro SAPI</comment>");
|
||||||
$this->output->writeln("<comment>\t--build-fpm\tBuild php-fpm SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-fpm\tBuild php-fpm SAPI</comment>");
|
||||||
$this->output->writeln("<comment>\t--build-all\tBuild all SAPI: cli, micro, fpm</comment>");
|
$this->output->writeln("<comment>\t--build-embed\tBuild embed SAPI/libphp</comment>");
|
||||||
|
$this->output->writeln("<comment>\t--build-all\tBuild all SAPI: cli, micro, fpm, embed</comment>");
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class BuildLibsCommand extends BuildCommand
|
|||||||
$this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated');
|
$this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated');
|
||||||
$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, 'Build all libs that static-php-cli needed');
|
$this->addOption('all', 'A', null, 'Build all libs that static-php-cli needed');
|
||||||
|
$this->addOption('rebuild', 'r', null, 'Delete old build and rebuild');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||||
|
|||||||
@@ -1,166 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command;
|
|
||||||
|
|
||||||
use SPC\store\FileSystem;
|
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
|
|
||||||
use function Laravel\Prompts\confirm;
|
|
||||||
use function Laravel\Prompts\text;
|
|
||||||
|
|
||||||
#[AsCommand('deploy', 'Deploy static-php-cli self to an .phar application')]
|
|
||||||
class DeployCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
public function configure(): void
|
|
||||||
{
|
|
||||||
$this->addArgument('target', InputArgument::OPTIONAL, 'The file or directory to pack.');
|
|
||||||
$this->addOption('auto-phar-fix', null, InputOption::VALUE_NONE, 'Automatically fix ini option.');
|
|
||||||
$this->addOption('overwrite', 'W', InputOption::VALUE_NONE, 'Overwrite existing files.');
|
|
||||||
$this->addOption('with-no-dev', 'D', InputOption::VALUE_NONE, 'Automatically use non-dev composer dependencies to reduce size');
|
|
||||||
$this->addOption('with-dev', 'd', InputOption::VALUE_NONE, 'Automatically use dev composer dependencies');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \PharException
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$composer = require ROOT_DIR . '/vendor/composer/installed.php';
|
|
||||||
if (($composer['root']['dev'] ?? false) === true) {
|
|
||||||
if (!$this->getOption('with-no-dev')) {
|
|
||||||
$this->output->writeln('<comment>Current static-php-cli dependencies have installed dev-dependencies</comment>');
|
|
||||||
$this->output->writeln('<comment>If you want to remove, you can choose "Yes" to run command "composer update --no-dev" to remove.</comment>');
|
|
||||||
$this->output->writeln('<comment>Or choose "No", just pack, deploy.</comment>');
|
|
||||||
$ask = confirm('Do you want to remove dev-dependencies to reduce size of phar file?');
|
|
||||||
} elseif (!$this->getOption('with-dev')) {
|
|
||||||
$ask = true;
|
|
||||||
} else {
|
|
||||||
$ask = false;
|
|
||||||
}
|
|
||||||
if ($ask) {
|
|
||||||
[$code] = shell()->execWithResult('composer update --no-dev');
|
|
||||||
if ($code !== 0) {
|
|
||||||
$this->output->writeln('<error>"composer update --no-dev" failed with exit code [' . $code . ']</error>');
|
|
||||||
$this->output->writeln('<error>You may need to run this command by your own.</error>');
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
$this->output->writeln('<info>Update successfully, you need to re-run deploy command to pack.</info>');
|
|
||||||
return static::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 首先得确认是不是关闭了readonly模式
|
|
||||||
if (ini_get('phar.readonly') == 1) {
|
|
||||||
if ($this->getOption('auto-phar-fix')) {
|
|
||||||
$ask = true;
|
|
||||||
} else {
|
|
||||||
$this->output->writeln('<comment>pack command needs "phar.readonly" = "Off" !</comment>');
|
|
||||||
$ask = confirm('Do you want to automatically set it and continue ?');
|
|
||||||
// $ask = $prompt->requireBool('<comment>pack command needs "phar.readonly" = "Off" !</comment>' . PHP_EOL . 'If you want to automatically set it and continue, just Enter', true);
|
|
||||||
}
|
|
||||||
if ($ask) {
|
|
||||||
global $argv;
|
|
||||||
$args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv'], ['--no-motd']);
|
|
||||||
if (function_exists('pcntl_exec')) {
|
|
||||||
$this->output->writeln('<info>Changing to phar.readonly=0 mode ...</info>');
|
|
||||||
if (pcntl_exec(PHP_BINARY, $args) === false) {
|
|
||||||
throw new \PharException('Switching to read write mode failed, please check the environment.');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->output->writeln('<info>Now running command in child process.</info>');
|
|
||||||
passthru(PHP_BINARY . ' -d phar.readonly=0 ' . implode(' ', $argv), $retcode);
|
|
||||||
exit($retcode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 获取路径
|
|
||||||
$path = WORKING_DIR;
|
|
||||||
// 如果是目录,则将目录下的所有文件打包
|
|
||||||
$phar_path = text('Please input the phar target filename', default: '/tmp/static-php-cli.phar');
|
|
||||||
// $phar_path = $prompt->requireArgument('target', 'Please input the phar target filename', 'static-php-cli.phar');
|
|
||||||
|
|
||||||
if (FileSystem::isRelativePath($phar_path)) {
|
|
||||||
$phar_path = WORKING_DIR . '/' . $phar_path;
|
|
||||||
}
|
|
||||||
if (file_exists($phar_path)) {
|
|
||||||
if (!$this->getOption('overwrite')) {
|
|
||||||
$this->output->writeln('<comment>The file "' . $phar_path . '" already exists.</comment>');
|
|
||||||
$ask = confirm('Do you want to overwrite it?');
|
|
||||||
} else {
|
|
||||||
$ask = true;
|
|
||||||
}
|
|
||||||
if (!$ask) {
|
|
||||||
$this->output->writeln('<comment>User canceled.</comment>');
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
@unlink($phar_path);
|
|
||||||
}
|
|
||||||
$phar = new \Phar($phar_path);
|
|
||||||
$phar->startBuffering();
|
|
||||||
|
|
||||||
$all = FileSystem::scanDirFiles($path, true, true);
|
|
||||||
|
|
||||||
$all = array_filter($all, function ($x) {
|
|
||||||
$dirs = preg_match('/(^(config|src|vendor)\\/|^(composer\\.json|README\\.md|source\\.json|LICENSE|README-en\\.md)$)/', $x);
|
|
||||||
return !($dirs !== 1);
|
|
||||||
});
|
|
||||||
sort($all);
|
|
||||||
$map = [];
|
|
||||||
foreach ($all as $v) {
|
|
||||||
$map[$v] = $path . '/' . $v;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->output->writeln('<info>Start packing files...</info>');
|
|
||||||
try {
|
|
||||||
foreach ($this->progress()->iterate($map) as $file => $origin_file) {
|
|
||||||
$phar->addFromString($file, php_strip_whitespace($origin_file));
|
|
||||||
}
|
|
||||||
// $phar->buildFromIterator(new SeekableArrayIterator($map, new ProgressBar($output)));
|
|
||||||
$phar->addFromString(
|
|
||||||
'.phar-entry.php',
|
|
||||||
str_replace(
|
|
||||||
'/../vendor/autoload.php',
|
|
||||||
'/vendor/autoload.php',
|
|
||||||
file_get_contents(ROOT_DIR . '/bin/spc')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$stub = '.phar-entry.php';
|
|
||||||
$phar->setStub($phar->createDefaultStub($stub));
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->output->writeln($e);
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
$phar->addFromString('.prod', 'true');
|
|
||||||
$phar->stopBuffering();
|
|
||||||
$this->output->writeln(PHP_EOL . 'Done! Phar file is generated at "' . $phar_path . '".');
|
|
||||||
if (file_exists(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx')) {
|
|
||||||
$this->output->writeln('Detected you have already compiled micro binary, I will make executable now for you!');
|
|
||||||
file_put_contents(
|
|
||||||
pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc',
|
|
||||||
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
|
|
||||||
file_get_contents($phar_path)
|
|
||||||
);
|
|
||||||
chmod(pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc', 0755);
|
|
||||||
$this->output->writeln('<info>Binary Executable: ' . pathinfo($phar_path, PATHINFO_DIRNAME) . '/spc</info>');
|
|
||||||
}
|
|
||||||
chmod($phar_path, 0755);
|
|
||||||
$this->output->writeln('<info>Phar Executable: ' . $phar_path . '</info>');
|
|
||||||
return static::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function progress(): ProgressBar
|
|
||||||
{
|
|
||||||
$progress = new ProgressBar($this->output, 0);
|
|
||||||
$progress->setBarCharacter('<fg=green>⚬</>');
|
|
||||||
$progress->setEmptyBarCharacter('<fg=red>⚬</>');
|
|
||||||
$progress->setProgressCharacter('<fg=green>➤</>');
|
|
||||||
$progress->setFormat(
|
|
||||||
"%current%/%max% [%bar%] %percent:3s%%\n🪅 %estimated:-20s% %memory:20s%" . PHP_EOL
|
|
||||||
);
|
|
||||||
return $progress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,11 @@ declare(strict_types=1);
|
|||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
use SPC\doctor\CheckListHandler;
|
use SPC\doctor\CheckListHandler;
|
||||||
|
use SPC\doctor\CheckResult;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||||
|
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||||
|
|
||||||
#[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
|
||||||
@@ -18,14 +22,65 @@ class DoctorCommand extends BaseCommand
|
|||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$checker = new CheckListHandler($this->input, $this->output);
|
$checker = new CheckListHandler();
|
||||||
$checker->runCheck($this->input->getOption('auto-fix') ? FIX_POLICY_AUTOFIX : FIX_POLICY_PROMPT);
|
|
||||||
|
$fix_policy = $this->input->getOption('auto-fix') ? FIX_POLICY_AUTOFIX : FIX_POLICY_PROMPT;
|
||||||
|
foreach ($checker->runChecks() as $check) {
|
||||||
|
if ($check->limit_os !== null && $check->limit_os !== PHP_OS_FAMILY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->output->write('Checking <comment>' . $check->item_name . '</comment> ... ');
|
||||||
|
|
||||||
|
$result = call_user_func($check->callback);
|
||||||
|
if ($result === null) {
|
||||||
|
$this->output->writeln('skipped');
|
||||||
|
} elseif ($result instanceof CheckResult) {
|
||||||
|
if ($result->isOK()) {
|
||||||
|
$this->output->writeln($result->getMessage() ?? 'ok');
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed
|
||||||
|
$this->output->writeln('<error>' . $result->getMessage() . '</error>');
|
||||||
|
switch ($fix_policy) {
|
||||||
|
case FIX_POLICY_DIE:
|
||||||
|
throw new RuntimeException('Some check items can not be fixed !');
|
||||||
|
case FIX_POLICY_PROMPT:
|
||||||
|
if ($result->getFixItem() !== '') {
|
||||||
|
$helper = new QuestionHelper();
|
||||||
|
$question = new ConfirmationQuestion('Do you want to fix it? [Y/n] ', true);
|
||||||
|
if ($helper->ask($this->input, $this->output, $question)) {
|
||||||
|
$checker->emitFix($this->output, $result);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException('You cancelled fix');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException('Some check items can not be fixed !');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIX_POLICY_AUTOFIX:
|
||||||
|
if ($result->getFixItem() !== '') {
|
||||||
|
$this->output->writeln('Automatically fixing ' . $result->getFixItem() . ' ...');
|
||||||
|
$checker->emitFix($this->output, $result);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException('Some check items can not be fixed !');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$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>');
|
||||||
|
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
pcntl_signal(SIGINT, SIG_IGN);
|
||||||
|
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,23 +6,68 @@ namespace SPC\command\dev;
|
|||||||
|
|
||||||
use SPC\command\BaseCommand;
|
use SPC\command\BaseCommand;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
|
use SPC\util\DependencyUtil;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
#[AsCommand('dev:ext-all', 'Dev command', ['list-ext'])]
|
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
|
||||||
class AllExtCommand extends BaseCommand
|
class AllExtCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
public function configure(): void
|
public function configure(): void
|
||||||
{
|
{
|
||||||
$this->addOption('line', 'l', null, 'Show with separate lines');
|
$this->addArgument('extensions', InputArgument::OPTIONAL, 'List of extensions that will be displayed, comma separated');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
$this->output->writeln(implode($this->input->getOption('line') ? PHP_EOL : ',', array_keys(Config::getExts())));
|
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions') ?? '')));
|
||||||
|
|
||||||
|
$style = new SymfonyStyle($this->input, $this->output);
|
||||||
|
$style->writeln($extensions ? 'Available extensions:' : 'Extensions:');
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach (Config::getExts() as $extension => $details) {
|
||||||
|
if ($extensions !== [] && !\in_array($extension, $extensions, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
|
||||||
|
} catch (WrongUsageException) {
|
||||||
|
$libraries = $not_included = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
|
||||||
|
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
|
||||||
|
|
||||||
|
$data[] = [
|
||||||
|
$extension,
|
||||||
|
implode(', ', $libraries),
|
||||||
|
implode(', ', $lib_suggests),
|
||||||
|
implode(',', $not_included),
|
||||||
|
implode(', ', $ext_suggests),
|
||||||
|
Config::getExt($extension, 'unix-only', false) ? 'true' : 'false',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data === []) {
|
||||||
|
$style->warning('Unknown extension selected: ' . implode(',', $extensions));
|
||||||
|
} else {
|
||||||
|
$style->table(
|
||||||
|
['Extension', 'lib-depends', 'lib-suggests', 'ext-depends', 'ext-suggests', 'unix-only'],
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\command\dev;
|
|
||||||
|
|
||||||
use SPC\command\BaseCommand;
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
use SPC\store\Config;
|
|
||||||
use SPC\util\DependencyUtil;
|
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
|
|
||||||
#[AsCommand('dev:ext-info', 'Dev command')]
|
|
||||||
class ExtInfoCommand extends BaseCommand
|
|
||||||
{
|
|
||||||
public function configure(): void
|
|
||||||
{
|
|
||||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extension name you need to get info');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws WrongUsageException
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
|
|
||||||
|
|
||||||
// 根据提供的扩展列表获取依赖库列表并编译
|
|
||||||
foreach ($extensions as $extension) {
|
|
||||||
$this->output->writeln('<comment>[ ' . $extension . ' ]</comment>');
|
|
||||||
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
|
|
||||||
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
|
|
||||||
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
|
|
||||||
$this->output->writeln("<info>lib-depends:\t" . implode(', ', $libraries) . '</info>');
|
|
||||||
$this->output->writeln("<info>lib-suggests:\t" . implode(', ', $lib_suggests) . '</info>');
|
|
||||||
$this->output->writeln("<info>ext-depends:\t" . implode(',', $not_included) . '</info>');
|
|
||||||
$this->output->writeln("<info>ext-suggests:\t" . implode(', ', $ext_suggests) . '</info>');
|
|
||||||
if (Config::getExt($extension, 'unix-only', false)) {
|
|
||||||
$this->output->writeln("<info>Unix only:\ttrue</info>");
|
|
||||||
}
|
|
||||||
$this->output->writeln('');
|
|
||||||
}
|
|
||||||
return static::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
|||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
#[AsCommand('dev:php-ver', 'Dev command')]
|
#[AsCommand('dev:php-version', 'Returns version of PHP located source directory', ['dev:php-ver'])]
|
||||||
class PhpVerCommand extends BaseCommand
|
class PhpVerCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||||
@@ -22,11 +22,19 @@ class PhpVerCommand extends BaseCommand
|
|||||||
{
|
{
|
||||||
// Find php from source/php-src
|
// Find php from source/php-src
|
||||||
$file = SOURCE_PATH . '/php-src/main/php_version.h';
|
$file = SOURCE_PATH . '/php-src/main/php_version.h';
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
$this->output->writeln('<error>PHP source not found, maybe you need to extract first ?</error>');
|
||||||
|
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
$result = preg_match('/#define PHP_VERSION "([^"]+)"/', file_get_contents($file), $match);
|
$result = preg_match('/#define PHP_VERSION "([^"]+)"/', file_get_contents($file), $match);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
$this->output->writeln('<error>PHP source not found, maybe you need to extract first ?</error>');
|
$this->output->writeln('<error>PHP source not found, maybe you need to extract first ?</error>');
|
||||||
|
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->output->writeln('<info>' . $match[1] . '</info>');
|
$this->output->writeln('<info>' . $match[1] . '</info>');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||||||
/**
|
/**
|
||||||
* Modify config file: sort lib, ext, source by name.
|
* Modify config file: sort lib, ext, source by name.
|
||||||
*/
|
*/
|
||||||
#[AsCommand('dev:sort-config', 'After config edited, sort it by alphabet', ['sort-config'])]
|
#[AsCommand('dev:sort-config', 'After config edited, sort it by alphabet', ['sort-config'], true)]
|
||||||
class SortConfigCommand extends BaseCommand
|
class SortConfigCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
public function configure(): void
|
public function configure(): void
|
||||||
@@ -34,7 +34,7 @@ class SortConfigCommand extends BaseCommand
|
|||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
|
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
|
||||||
ConfigValidator::validateLibs($file);
|
ConfigValidator::validateLibs($file);
|
||||||
ksort($file);
|
ksort($file);
|
||||||
if (!file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
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>');
|
$this->output->writeln('<error>Write file lib.json failed!</error>');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ class SortConfigCommand extends BaseCommand
|
|||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/source.json'), true);
|
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/source.json'), true);
|
||||||
ConfigValidator::validateSource($file);
|
ConfigValidator::validateSource($file);
|
||||||
uksort($file, fn ($a, $b) => $a === 'php-src' ? -1 : ($b === 'php-src' ? 1 : ($a < $b ? -1 : 1)));
|
uksort($file, fn ($a, $b) => $a === 'php-src' ? -1 : ($b === 'php-src' ? 1 : ($a < $b ? -1 : 1)));
|
||||||
if (!file_put_contents(ROOT_DIR . '/config/source.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
if (!file_put_contents(ROOT_DIR . '/config/source.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n")) {
|
||||||
$this->output->writeln('<error>Write file source.json failed!</error>');
|
$this->output->writeln('<error>Write file source.json failed!</error>');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ class SortConfigCommand extends BaseCommand
|
|||||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/ext.json'), true);
|
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/ext.json'), true);
|
||||||
ConfigValidator::validateExts($file);
|
ConfigValidator::validateExts($file);
|
||||||
ksort($file);
|
ksort($file);
|
||||||
if (!file_put_contents(ROOT_DIR . '/config/ext.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
if (!file_put_contents(ROOT_DIR . '/config/ext.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n")) {
|
||||||
$this->output->writeln('<error>Write file ext.json failed!</error>');
|
$this->output->writeln('<error>Write file ext.json failed!</error>');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,5 @@ class AsCheckItem
|
|||||||
public ?string $limit_os = null,
|
public ?string $limit_os = null,
|
||||||
public int $level = 100,
|
public int $level = 100,
|
||||||
public bool $manual = false,
|
public bool $manual = false,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,5 @@ namespace SPC\doctor;
|
|||||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||||
class AsFixItem
|
class AsFixItem
|
||||||
{
|
{
|
||||||
public function __construct(public string $name)
|
public function __construct(public string $name) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,105 +7,62 @@ namespace SPC\doctor;
|
|||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
|
||||||
|
|
||||||
class CheckListHandler
|
final class CheckListHandler
|
||||||
{
|
{
|
||||||
/** @var AsCheckItem[] */
|
/** @var AsCheckItem[] */
|
||||||
private array $check_list = [];
|
private array $check_list = [];
|
||||||
|
|
||||||
private array $fix_map = [];
|
private array $fix_map = [];
|
||||||
|
|
||||||
|
public function __construct() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @return array<AsCheckItem>
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
*/
|
||||||
public function __construct(private readonly InputInterface $input, private readonly OutputInterface $output, bool $include_manual = false)
|
public function runChecks(bool $include_manual = false): array
|
||||||
{
|
{
|
||||||
$this->loadCheckList($include_manual);
|
return $this->loadCheckList($include_manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function runSingleCheck(string $item_name, int $fix_policy = FIX_POLICY_DIE): void
|
public function emitFix(OutputInterface $output, CheckResult $result): void
|
||||||
{
|
{
|
||||||
foreach ($this->check_list as $item) {
|
pcntl_signal(SIGINT, function () use ($output) {
|
||||||
if ($item->item_name === $item_name) {
|
$output->writeln('<error>You cancelled fix</error>');
|
||||||
$this->check_list = [$item];
|
});
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->runCheck($fix_policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$fix_result = call_user_func($this->fix_map[$result->getFixItem()], ...$result->getFixParams());
|
||||||
* @throws RuntimeException
|
pcntl_signal(SIGINT, SIG_IGN);
|
||||||
*/
|
|
||||||
public function runCheck(int $fix_policy = FIX_POLICY_DIE): void
|
if ($fix_result) {
|
||||||
{
|
$output->writeln('<info>Fix done</info>');
|
||||||
foreach ($this->check_list as $item) {
|
} else {
|
||||||
if ($item->limit_os !== null && $item->limit_os !== PHP_OS_FAMILY) {
|
$output->writeln('<error>Fix failed</error>');
|
||||||
continue;
|
throw new RuntimeException('Some check item are not fixed');
|
||||||
}
|
|
||||||
$this->output->write('Checking <comment>' . $item->item_name . '</comment> ... ');
|
|
||||||
$result = call_user_func($item->callback);
|
|
||||||
if ($result === null) {
|
|
||||||
$this->output->writeln('skipped');
|
|
||||||
} elseif ($result instanceof CheckResult) {
|
|
||||||
if ($result->isOK()) {
|
|
||||||
$this->output->writeln($result->getMessage() ?? 'ok');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Failed
|
|
||||||
$this->output->writeln('<error>' . $result->getMessage() . '</error>');
|
|
||||||
switch ($fix_policy) {
|
|
||||||
case FIX_POLICY_DIE:
|
|
||||||
throw new RuntimeException('Some check items can not be fixed !');
|
|
||||||
case FIX_POLICY_PROMPT:
|
|
||||||
if ($result->getFixItem() !== '') {
|
|
||||||
$helper = new QuestionHelper();
|
|
||||||
$question = new ConfirmationQuestion('Do you want to fix it? [Y/n] ', true);
|
|
||||||
if ($helper->ask($this->input, $this->output, $question)) {
|
|
||||||
$this->emitFix($result);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException('You cancelled fix');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException('Some check items can not be fixed !');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FIX_POLICY_AUTOFIX:
|
|
||||||
if ($result->getFixItem() !== '') {
|
|
||||||
$this->output->writeln('Automatically fixing ' . $result->getFixItem() . ' ...');
|
|
||||||
$this->emitFix($result);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException('Some check items can not be fixed !');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Doctor check item list
|
* Load Doctor check item list
|
||||||
*
|
*
|
||||||
|
* @return array<AsCheckItem>
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
private function loadCheckList(bool $include_manual = false): void
|
private function loadCheckList(bool $include_manual = false): array
|
||||||
{
|
{
|
||||||
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\\doctor\\item') as $class) {
|
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\\doctor\\item') as $class) {
|
||||||
$ref = new \ReflectionClass($class);
|
$ref = new \ReflectionClass($class);
|
||||||
foreach ($ref->getMethods() as $method) {
|
foreach ($ref->getMethods() as $method) {
|
||||||
$attr = $method->getAttributes();
|
foreach ($method->getAttributes() as $a) {
|
||||||
foreach ($attr as $a) {
|
|
||||||
if (is_a($a->getName(), AsCheckItem::class, true)) {
|
if (is_a($a->getName(), AsCheckItem::class, true)) {
|
||||||
/** @var AsCheckItem $instance */
|
/** @var AsCheckItem $instance */
|
||||||
$instance = $a->newInstance();
|
$instance = $a->newInstance();
|
||||||
@@ -126,26 +83,10 @@ class CheckListHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sort check list by level
|
|
||||||
usort($this->check_list, fn ($a, $b) => $a->level > $b->level ? -1 : ($a->level == $b->level ? 0 : 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// sort check list by level
|
||||||
* @throws RuntimeException
|
usort($this->check_list, fn (AsCheckItem $a, AsCheckItem $b) => $a->level > $b->level ? -1 : ($a->level == $b->level ? 0 : 1));
|
||||||
*/
|
|
||||||
private function emitFix(CheckResult $result): void
|
return $this->check_list;
|
||||||
{
|
|
||||||
pcntl_signal(SIGINT, function () {
|
|
||||||
$this->output->writeln('<error>You cancelled fix</error>');
|
|
||||||
});
|
|
||||||
$fix = $this->fix_map[$result->getFixItem()];
|
|
||||||
$fix_result = call_user_func($fix, ...$result->getFixParams());
|
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
|
||||||
if ($fix_result) {
|
|
||||||
$this->output->writeln('<info>Fix done</info>');
|
|
||||||
} else {
|
|
||||||
$this->output->writeln('<error>Fix failed</error>');
|
|
||||||
throw new RuntimeException('Some check item are not fixed');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ namespace SPC\doctor;
|
|||||||
|
|
||||||
class CheckResult
|
class CheckResult
|
||||||
{
|
{
|
||||||
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = [])
|
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = []) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fail(string $message, string $fix_item = '', array $fix_params = []): CheckResult
|
public static function fail(string $message, string $fix_item = '', array $fix_params = []): CheckResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class LinuxMuslCheck
|
|||||||
// non-exist, need to recognize distro
|
// non-exist, need to recognize distro
|
||||||
$distro = SystemUtil::getOSRelease();
|
$distro = SystemUtil::getOSRelease();
|
||||||
return match ($distro['dist']) {
|
return match ($distro['dist']) {
|
||||||
'ubuntu', 'alpine', 'debian' => CheckResult::fail('musl-libc is not installed on your system', 'fix-musl', [$distro]),
|
'ubuntu', 'alpine', 'debian', 'rhel', 'almalinux' => CheckResult::fail('musl-libc is not installed on your system', 'fix-musl', [$distro]),
|
||||||
default => CheckResult::fail('musl-libc is not installed on your system'),
|
default => CheckResult::fail('musl-libc is not installed on your system'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -36,10 +36,18 @@ class LinuxMuslCheck
|
|||||||
#[AsFixItem('fix-musl')]
|
#[AsFixItem('fix-musl')]
|
||||||
public function fixMusl(array $distro): bool
|
public function fixMusl(array $distro): bool
|
||||||
{
|
{
|
||||||
|
$rhel_install = 'wget https://musl.libc.org/releases/musl-1.2.4.tar.gz && tar -zxvf musl-1.2.4.tar.gz && \
|
||||||
|
rm -f musl-1.2.4.tar.gz && cd musl-1.2.4 &&
|
||||||
|
if [[ ! "$PATH" =~ (^|:)"/usr/local/musl/bin"(:|$) ]]; then echo "export PATH=/usr/local/musl/bin:$PATH" >> ~/.bash_profile
|
||||||
|
fi && \
|
||||||
|
./configure --enable-wrapper=gcc && \
|
||||||
|
make -j && make install && cd .. && rm -rf musl-1.2.4';
|
||||||
$install_cmd = match ($distro['dist']) {
|
$install_cmd = match ($distro['dist']) {
|
||||||
'ubuntu', 'debian' => 'apt-get install musl musl-tools -y',
|
'ubuntu', 'debian' => 'apt-get install musl musl-tools -y',
|
||||||
'alpine' => 'apk add musl musl-utils musl-dev',
|
'alpine' => 'apk add musl musl-utils musl-dev',
|
||||||
default => throw new RuntimeException('Current linux distro is not supported for auto-install musl packages'),
|
'rhel' => $rhel_install,
|
||||||
|
'almalinux' => $rhel_install,
|
||||||
|
default => throw new RuntimeException('Current linux distro does not have an auto-install script for musl packages yet.'),
|
||||||
};
|
};
|
||||||
$prefix = '';
|
$prefix = '';
|
||||||
if (get_current_user() !== 'root') {
|
if (get_current_user() !== 'root') {
|
||||||
|
|||||||
@@ -28,16 +28,27 @@ class LinuxToolCheckList
|
|||||||
'git', 'autoconf', 'automake',
|
'git', 'autoconf', 'automake',
|
||||||
'tar', 'unzip', 'gzip',
|
'tar', 'unzip', 'gzip',
|
||||||
'bzip2', 'cmake', 'patch',
|
'bzip2', 'cmake', 'patch',
|
||||||
|
'xz',
|
||||||
|
];
|
||||||
|
|
||||||
|
public const TOOLS_RHEL = [
|
||||||
|
'perl', 'make', 'bison', 'flex',
|
||||||
|
'git', 'autoconf', 'automake',
|
||||||
|
'tar', 'unzip', 'gzip', 'gcc',
|
||||||
|
'bzip2', 'cmake', 'patch',
|
||||||
|
'xz', 'wget', // to get musl
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
/** @noinspection PhpUnused */
|
||||||
#[AsCheckItem('if necessary tools are installed', limit_os: 'Linux')]
|
#[AsCheckItem('if necessary tools are installed', limit_os: 'Linux', level: 999)]
|
||||||
public function checkCliTools(): ?CheckResult
|
public function checkCliTools(): ?CheckResult
|
||||||
{
|
{
|
||||||
$distro = SystemUtil::getOSRelease();
|
$distro = SystemUtil::getOSRelease();
|
||||||
|
|
||||||
$required = match ($distro['dist']) {
|
$required = match ($distro['dist']) {
|
||||||
'alpine' => self::TOOLS_ALPINE,
|
'alpine' => self::TOOLS_ALPINE,
|
||||||
|
'almalinux' => self::TOOLS_RHEL,
|
||||||
|
'rhel' => self::TOOLS_RHEL,
|
||||||
default => self::TOOLS_DEBIAN,
|
default => self::TOOLS_DEBIAN,
|
||||||
};
|
};
|
||||||
$missing = [];
|
$missing = [];
|
||||||
@@ -48,7 +59,11 @@ class LinuxToolCheckList
|
|||||||
}
|
}
|
||||||
if (!empty($missing)) {
|
if (!empty($missing)) {
|
||||||
return match ($distro['dist']) {
|
return match ($distro['dist']) {
|
||||||
'ubuntu', 'alpine', 'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
|
'ubuntu',
|
||||||
|
'alpine',
|
||||||
|
'rhel',
|
||||||
|
'almalinux',
|
||||||
|
'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'),
|
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -79,7 +94,9 @@ class LinuxToolCheckList
|
|||||||
$install_cmd = match ($distro['dist']) {
|
$install_cmd = match ($distro['dist']) {
|
||||||
'ubuntu', 'debian' => 'apt-get install -y',
|
'ubuntu', 'debian' => 'apt-get install -y',
|
||||||
'alpine' => 'apk add',
|
'alpine' => 'apk add',
|
||||||
default => throw new RuntimeException('Current linux distro is not supported for auto-install musl packages'),
|
'rhel' => 'dnf install -y',
|
||||||
|
'almalinux' => 'dnf install -y',
|
||||||
|
default => throw new RuntimeException('Current linux distro does not have an auto-install script for musl packages yet.'),
|
||||||
};
|
};
|
||||||
$prefix = '';
|
$prefix = '';
|
||||||
if (get_current_user() !== 'root') {
|
if (get_current_user() !== 'root') {
|
||||||
@@ -87,7 +104,9 @@ class LinuxToolCheckList
|
|||||||
logger()->warning('Current user is not root, using sudo for running command');
|
logger()->warning('Current user is not root, using sudo for running command');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $missing));
|
$is_rhel = in_array($distro['dist'], ['rhel', 'almalinux']);
|
||||||
|
$to_install = $is_rhel ? $missing : str_replace('xz', 'xz-utils', $missing);
|
||||||
|
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $to_install));
|
||||||
} catch (RuntimeException) {
|
} catch (RuntimeException) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class DownloaderException extends \Exception
|
class DownloaderException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace SPC\exception;
|
|||||||
|
|
||||||
class ExceptionHandler
|
class ExceptionHandler
|
||||||
{
|
{
|
||||||
protected mixed $whoops;
|
protected mixed $whoops = null;
|
||||||
|
|
||||||
private static ?ExceptionHandler $obj = null;
|
private static ?ExceptionHandler $obj = null;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class FileSystemException extends \Exception
|
class FileSystemException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class InvalidArgumentException extends \Exception
|
class InvalidArgumentException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class RuntimeException extends \Exception
|
class RuntimeException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class ValidationException extends \Exception
|
class ValidationException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\exception;
|
namespace SPC\exception;
|
||||||
|
|
||||||
class WrongUsageException extends \Exception
|
class WrongUsageException extends \Exception {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ class SourcePatcher
|
|||||||
}
|
}
|
||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
||||||
|
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
|
||||||
|
|
||||||
// call extension patch before make
|
// call extension patch before make
|
||||||
foreach ($builder->getExts() as $ext) {
|
foreach ($builder->getExts() as $ext) {
|
||||||
if ($ext->patchBeforeMake() === true) {
|
if ($ext->patchBeforeMake() === true) {
|
||||||
@@ -158,6 +160,8 @@ class SourcePatcher
|
|||||||
$cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak';
|
$cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak';
|
||||||
$micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c';
|
$micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c';
|
||||||
$micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak';
|
$micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak';
|
||||||
|
$embed_c = SOURCE_PATH . '/php-src/sapi/embed/php_embed.c';
|
||||||
|
$embed_c_bak = SOURCE_PATH . '/php-src/sapi/embed/php_embed.c.bak';
|
||||||
|
|
||||||
// Try to reverse backup file
|
// Try to reverse backup file
|
||||||
$find_str = 'const char HARDCODED_INI[] =';
|
$find_str = 'const char HARDCODED_INI[] =';
|
||||||
@@ -168,13 +172,14 @@ class SourcePatcher
|
|||||||
$patch_str = "const char HARDCODED_INI[] =\n{$patch_str}";
|
$patch_str = "const char HARDCODED_INI[] =\n{$patch_str}";
|
||||||
|
|
||||||
// Detect backup, if we have backup, it means we need to reverse first
|
// Detect backup, if we have backup, it means we need to reverse first
|
||||||
if (file_exists($cli_c_bak) || file_exists($micro_c_bak)) {
|
if (file_exists($cli_c_bak) || file_exists($micro_c_bak) || file_exists($embed_c_bak)) {
|
||||||
self::unpatchHardcodedINI();
|
self::unpatchHardcodedINI();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup it
|
// Backup it
|
||||||
$result = file_put_contents($cli_c_bak, file_get_contents($cli_c));
|
$result = file_put_contents($cli_c_bak, file_get_contents($cli_c));
|
||||||
$result = $result && file_put_contents($micro_c_bak, file_get_contents($micro_c));
|
$result = $result && file_put_contents($micro_c_bak, file_get_contents($micro_c));
|
||||||
|
$result = $result && file_put_contents($embed_c_bak, file_get_contents($embed_c));
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -182,6 +187,7 @@ class SourcePatcher
|
|||||||
// Patch it
|
// Patch it
|
||||||
FileSystem::replaceFileStr($cli_c, $find_str, $patch_str);
|
FileSystem::replaceFileStr($cli_c, $find_str, $patch_str);
|
||||||
FileSystem::replaceFileStr($micro_c, $find_str, $patch_str);
|
FileSystem::replaceFileStr($micro_c, $find_str, $patch_str);
|
||||||
|
FileSystem::replaceFileStr($embed_c, $find_str, $patch_str);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,13 +197,17 @@ class SourcePatcher
|
|||||||
$cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak';
|
$cli_c_bak = SOURCE_PATH . '/php-src/sapi/cli/php_cli.c.bak';
|
||||||
$micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c';
|
$micro_c = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c';
|
||||||
$micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak';
|
$micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak';
|
||||||
if (!file_exists($cli_c_bak) && !file_exists($micro_c_bak)) {
|
$embed_c = SOURCE_PATH . '/php-src/sapi/embed/php_embed.c';
|
||||||
|
$embed_c_bak = SOURCE_PATH . '/php-src/sapi/embed/php_embed.c.bak';
|
||||||
|
if (!file_exists($cli_c_bak) && !file_exists($micro_c_bak) && !file_exists($embed_c_bak)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$result = file_put_contents($cli_c, file_get_contents($cli_c_bak));
|
$result = file_put_contents($cli_c, file_get_contents($cli_c_bak));
|
||||||
$result = $result && file_put_contents($micro_c, file_get_contents($micro_c_bak));
|
$result = $result && file_put_contents($micro_c, file_get_contents($micro_c_bak));
|
||||||
|
$result = $result && file_put_contents($embed_c, file_get_contents($embed_c_bak));
|
||||||
@unlink($cli_c_bak);
|
@unlink($cli_c_bak);
|
||||||
@unlink($micro_c_bak);
|
@unlink($micro_c_bak);
|
||||||
|
@unlink($embed_c_bak);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,13 +35,16 @@ class PhpSource extends CustomSourceBase
|
|||||||
{
|
{
|
||||||
// 查找最新的小版本号
|
// 查找最新的小版本号
|
||||||
$info = json_decode(Downloader::curlExec(url: "https://www.php.net/releases/index.php?json&version={$major_version}"), true);
|
$info = json_decode(Downloader::curlExec(url: "https://www.php.net/releases/index.php?json&version={$major_version}"), true);
|
||||||
|
if (!isset($info['version'])) {
|
||||||
|
throw new DownloaderException("Version {$major_version} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
$version = $info['version'];
|
$version = $info['version'];
|
||||||
|
|
||||||
// 从官网直接下载
|
// 从官网直接下载
|
||||||
return [
|
return [
|
||||||
'type' => 'url',
|
'type' => 'url',
|
||||||
'url' => "https://www.php.net/distributions/php-{$version}.tar.gz",
|
'url' => "https://www.php.net/distributions/php-{$version}.tar.gz",
|
||||||
// 'url' => "https://mirrors.zhamao.xin/php/php-{$version}.tar.gz",
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ class CustomExt
|
|||||||
{
|
{
|
||||||
private static array $custom_ext_class = [];
|
private static array $custom_ext_class = [];
|
||||||
|
|
||||||
public function __construct(protected string $ext_name)
|
public function __construct(protected string $ext_name) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all custom extension classes
|
* Load all custom extension classes
|
||||||
|
|||||||
@@ -45,46 +45,58 @@ class LicenseDumper
|
|||||||
{
|
{
|
||||||
// mkdir first
|
// mkdir first
|
||||||
if (is_dir($target_dir) && !FileSystem::removeDir($target_dir)) {
|
if (is_dir($target_dir) && !FileSystem::removeDir($target_dir)) {
|
||||||
logger()->warning('Target dump directory is noe empty, be aware!');
|
logger()->warning('Target dump directory is not empty, be aware!');
|
||||||
}
|
}
|
||||||
FileSystem::createDir($target_dir);
|
FileSystem::createDir($target_dir);
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->exts as $ext) {
|
||||||
if (Config::getExt($ext, 'type') !== 'external') {
|
if (Config::getExt($ext, 'type') !== 'external') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$source_name = Config::getExt($ext, 'source');
|
$source_name = Config::getExt($ext, 'source');
|
||||||
$content = $this->getSourceLicense($source_name);
|
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
|
||||||
file_put_contents($target_dir . '/ext_' . $ext . '.txt', $content);
|
file_put_contents("{$target_dir}/ext_{$ext}_{$index}.txt", $license);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->libs as $lib) {
|
foreach ($this->libs as $lib) {
|
||||||
$source_name = Config::getLib($lib, 'source');
|
$source_name = Config::getLib($lib, 'source');
|
||||||
$content = $this->getSourceLicense($source_name);
|
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
|
||||||
file_put_contents($target_dir . '/lib_' . $lib . '.txt', $content);
|
file_put_contents("{$target_dir}/lib_{$lib}_{$index}.txt", $license);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->sources as $source) {
|
foreach ($this->sources as $source) {
|
||||||
file_put_contents($target_dir . '/src_' . $source . '.txt', $this->getSourceLicense($source));
|
foreach ($this->getSourceLicenses($source) as $index => $license) {
|
||||||
|
file_put_contents("{$target_dir}/src_{$source}_{$index}.txt", $license);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @return string[]
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
private function getSourceLicense(string $source_name): ?string
|
private function getSourceLicenses(string $source_name): iterable
|
||||||
{
|
{
|
||||||
$src = Config::getSource($source_name)['license'] ?? null;
|
$licenses = Config::getSource($source_name)['license'] ?? [];
|
||||||
if ($src === null) {
|
if ($licenses === []) {
|
||||||
throw new RuntimeException('source [' . $source_name . '] license meta is not exist');
|
throw new RuntimeException('source [' . $source_name . '] license meta not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
return match ($src['type']) {
|
if (!array_is_list($licenses)) {
|
||||||
'text' => $src['text'],
|
$licenses = [$licenses];
|
||||||
'file' => $this->loadSourceFile($source_name, $src['path'], Config::getSource($source_name)['path'] ?? null),
|
}
|
||||||
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
|
|
||||||
};
|
foreach ($licenses as $index => $license) {
|
||||||
|
yield ($license['suffix'] ?? $index) => match ($license['type']) {
|
||||||
|
'text' => $license['text'],
|
||||||
|
'file' => $this->loadSourceFile($source_name, $license['path'], Config::getSource($source_name)['path'] ?? null),
|
||||||
|
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,8 +105,9 @@ class LicenseDumper
|
|||||||
private function loadSourceFile(string $source_name, string $in_path, ?string $custom_base_path = null): string
|
private function loadSourceFile(string $source_name, string $in_path, ?string $custom_base_path = null): string
|
||||||
{
|
{
|
||||||
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
|
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
|
||||||
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] is not exist');
|
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
|
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\util;
|
|
||||||
|
|
||||||
class Util
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get current PHP version ID (downloaded)
|
|
||||||
*/
|
|
||||||
public static function getPHPVersionID(): int
|
|
||||||
{
|
|
||||||
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
|
|
||||||
preg_match('/PHP_VERSION_ID (\d+)/', $file, $match);
|
|
||||||
return intval($match[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -43,7 +43,8 @@ const BUILD_TARGET_NONE = 0; // no target
|
|||||||
const BUILD_TARGET_CLI = 1; // build cli
|
const BUILD_TARGET_CLI = 1; // build cli
|
||||||
const BUILD_TARGET_MICRO = 2; // build micro
|
const BUILD_TARGET_MICRO = 2; // build micro
|
||||||
const BUILD_TARGET_FPM = 4; // build fpm
|
const BUILD_TARGET_FPM = 4; // build fpm
|
||||||
const BUILD_TARGET_ALL = 7; // build all
|
const BUILD_TARGET_EMBED = 8; // build embed
|
||||||
|
const BUILD_TARGET_ALL = 15; // build all
|
||||||
|
|
||||||
// doctor error fix policy
|
// doctor error fix policy
|
||||||
const FIX_POLICY_DIE = 1; // die directly
|
const FIX_POLICY_DIE = 1; // die directly
|
||||||
@@ -55,6 +56,14 @@ const PKGCONF_PATCH_PREFIX = 1;
|
|||||||
const PKGCONF_PATCH_EXEC_PREFIX = 2;
|
const PKGCONF_PATCH_EXEC_PREFIX = 2;
|
||||||
const PKGCONF_PATCH_LIBDIR = 4;
|
const PKGCONF_PATCH_LIBDIR = 4;
|
||||||
const PKGCONF_PATCH_INCLUDEDIR = 8;
|
const PKGCONF_PATCH_INCLUDEDIR = 8;
|
||||||
const PKGCONF_PATCH_ALL = 15;
|
const PKGCONF_PATCH_CUSTOM = 16;
|
||||||
|
const PKGCONF_PATCH_ALL = 31;
|
||||||
|
|
||||||
|
// autoconf flags
|
||||||
|
const AUTOCONF_LIBS = 1;
|
||||||
|
const AUTOCONF_CFLAGS = 2;
|
||||||
|
const AUTOCONF_CPPFLAGS = 4;
|
||||||
|
const AUTOCONF_LDFLAGS = 8;
|
||||||
|
const AUTOCONF_ALL = 15;
|
||||||
|
|
||||||
ConsoleLogger::$date_format = 'H:i:s';
|
ConsoleLogger::$date_format = 'H:i:s';
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
assert(class_exists('\\DOMDocument'));
|
assert(class_exists('\\DOMDocument'));
|
||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
$doc->loadHtml("<html><head><meta charset=\"UTF-8\"><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body id='app'>Hello</body></html>");
|
$doc->loadHtml('<html><head><meta charset="UTF-8"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body id="app">Hello</body></html>');
|
||||||
assert($doc->getElementById('app')->nodeValue === 'Hello');
|
assert($doc->getElementById('app')->nodeValue === 'Hello');
|
||||||
|
|||||||
21
tests/SPC/doctor/CheckListHandlerTest.php
Normal file
21
tests/SPC/doctor/CheckListHandlerTest.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\doctor;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\doctor\CheckListHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class CheckListHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testRunChecksReturnsListOfCheck(): void
|
||||||
|
{
|
||||||
|
$list = new CheckListHandler();
|
||||||
|
|
||||||
|
$this->assertCount(6, $list->runChecks());
|
||||||
|
}
|
||||||
|
}
|
||||||
87
tests/SPC/util/LicenseDumperTest.php
Normal file
87
tests/SPC/util/LicenseDumperTest.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\util;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\store\Config;
|
||||||
|
use SPC\util\LicenseDumper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class LicenseDumperTest extends TestCase
|
||||||
|
{
|
||||||
|
private const DIRECTORY = '../../var/license-dump';
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
@rmdir(self::DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
array_map('unlink', glob(self::DIRECTORY . '/*.txt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDumpWithSingleLicense(): void
|
||||||
|
{
|
||||||
|
Config::$lib = [
|
||||||
|
'fake_lib' => [
|
||||||
|
'source' => 'fake_lib',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Config::$source = [
|
||||||
|
'fake_lib' => [
|
||||||
|
'license' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => 'license',
|
||||||
|
'suffix' => 'zend',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$dumper = new LicenseDumper();
|
||||||
|
$dumper->addLibs(['fake_lib']);
|
||||||
|
$dumper->dump(self::DIRECTORY);
|
||||||
|
|
||||||
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDumpWithMultipleLicenses(): void
|
||||||
|
{
|
||||||
|
Config::$lib = [
|
||||||
|
'fake_lib' => [
|
||||||
|
'source' => 'fake_lib',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Config::$source = [
|
||||||
|
'fake_lib' => [
|
||||||
|
'license' => [
|
||||||
|
[
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => 'license',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => 'license',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'text',
|
||||||
|
'text' => 'license',
|
||||||
|
'suffix' => 'zend',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$dumper = new LicenseDumper();
|
||||||
|
$dumper->addLibs(['fake_lib']);
|
||||||
|
$dumper->dump(self::DIRECTORY);
|
||||||
|
|
||||||
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
||||||
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
|
||||||
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user