Compare commits

..

134 Commits

Author SHA1 Message Date
Jerry Ma
29be3a2e39 set version to 2.0-rc7 2023-10-05 22:07:44 +08:00
crazywhalecc
fbe149bcac reuse static-php-cli-hosted workflows 2023-10-05 21:58:42 +08:00
crazywhalecc
92cafb36f6 fix bugs when building micro and embed at the same time 2023-10-01 10:01:45 +08:00
Joseph Bielawski
8636f2e7c9 Throw proper exception when PHP source is not available 2023-10-01 01:24:02 +08:00
crazywhalecc
8f43a09533 separate alternative libs 2023-10-01 01:19:35 +08:00
DubbleClick
654c5cba0c fix musl install on rhel 2023-10-01 01:19:35 +08:00
crazywhalecc
f9685b82a1 adjust tool check level 2023-10-01 01:19:35 +08:00
crazywhalecc
f2371d3702 bugfix: complete ldap support for macOS and Linux 2023-10-01 01:19:35 +08:00
crazywhalecc
fe39aecd72 adjust config order 2023-10-01 01:19:35 +08:00
crazywhalecc
68d176ad26 prevent c compiler not found error 2023-10-01 01:19:35 +08:00
crazywhalecc
d7627dd81a correct libc name for linux 2023-10-01 01:19:35 +08:00
crazywhalecc
a4e173f16d add configure flags for unix builder 2023-10-01 01:19:35 +08:00
DubbleClick
1437be3a9d gmp and libsodium for ldap if enabled
only enable openssl when zlib ext is also enabled (missing 'deflate' otherwise)
move back from source/php-src/ext/ldap to source/ldap (fix "LICENSE not found")
2023-10-01 01:19:35 +08:00
DubbleClick
059c32e59c add ext-ldap (openldap) support 2023-10-01 01:19:35 +08:00
DubbleClick
e3a4cd6e1d fix spelling mistake in README-en.md 2023-10-01 01:19:35 +08:00
DubbleClick
dd9a5d8316 add rhel and almalinux support 2023-10-01 01:19:35 +08:00
Joseph Bielawski
3b83c1fa7b Remove dead code from ConsoleApplication class 2023-09-30 13:52:29 +08:00
Rif'at Ahdi R
ff128df76b Update libwebp dependency (fix #208) 2023-09-29 16:07:59 +08:00
crazywhalecc
cd04a9ea4f change all related url to static-php.dev 2023-09-26 22:27:44 +08:00
Jerry Ma
3b793005fe Change domain 2023-09-26 18:32:18 +08:00
Jerry Ma
87e073a0b9 Change domain 2023-09-26 18:29:45 +08:00
crazywhalecc
db8aa15677 adjust micro's phar patch execution location 2023-09-25 10:35:31 +08:00
crazywhalecc
6ed9749732 cs fix and composer update 2023-09-23 17:03:20 +08:00
crazywhalecc
4e99211bc3 add hardcoded-ini option for embed SAPI 2023-09-17 12:21:06 +08:00
crazywhalecc
824748c2a7 remove download cache and minimize download sources 2023-09-16 15:15:46 +08:00
crazywhalecc
fe6a98b30d remove debug option 2023-09-16 15:15:46 +08:00
crazywhalecc
49149cebf1 Add new GH action to build binary SPC 2023-09-16 15:15:46 +08:00
Joseph Bielawski
7b6a1b4212 Simplify adding composer in bin/spc-alpine-docker
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2023-09-15 09:39:27 +08:00
Joseph Bielawski
965e7a25e2 Add composer.lock into repository 2023-09-15 09:39:27 +08:00
Kévin Dunglas
0c3885c33d fix(docker): php82-sodium is required 2023-09-14 10:02:54 +08:00
Joseph Bielawski
be32190829 Sanity check extensions by inline their test code 2023-09-13 23:42:10 +08:00
crazywhalecc
f1d5916090 remove unused old deploy command 2023-09-13 21:45:19 +08:00
Joseph Bielawski
b2ea479fac Remove the phar workflow temporary 2023-09-13 21:45:19 +08:00
Joseph Bielawski
16cc5df66d Temporary disable phar build in GH actions 2023-09-13 21:45:19 +08:00
Joseph Bielawski
a63e3f4575 Add version into phar 2023-09-13 21:45:19 +08:00
Joseph Bielawski
6b061e6332 Adjust box configuration for smaller phar size 2023-09-13 21:45:19 +08:00
Joseph Bielawski
4a17491aaa Initial code to get Box for phar building 2023-09-13 21:45:19 +08:00
Jerry Ma
06f29712e2 Update README.md 2023-09-13 10:03:31 +08:00
Kévin Dunglas
4b1d59c5a9 Link to FrankenPHP docs about embed SAPI in README-en.md 2023-09-13 10:03:31 +08:00
crazywhalecc
1a81fe6a0d change help message for dev:extensions 2023-09-12 23:30:23 +08:00
crazywhalecc
c63136d484 change dev:extensions argument to comma separated 2023-09-12 23:30:23 +08:00
crazywhalecc
4b500f2dd8 remove redundant libssh2 cmake build target option 2023-09-12 23:09:58 +08:00
crazywhalecc
9da20497cc fix ln src and dst for brotli 2023-09-12 22:53:47 +08:00
crazywhalecc
5efc15b404 fix libwebp pkgconfig patch, add custom patch argument 2023-09-12 22:52:20 +08:00
Joseph Bielawski
fa0740f216 Explicitly define application commands 2023-09-12 22:51:50 +08:00
Joseph Bielawski
52430cbdde Rework doctor command 2023-09-12 22:46:44 +08:00
crazywhalecc
01c4538ce0 update README for embed SAPI 2023-09-12 22:44:19 +08:00
Kévin Dunglas
3183ecceaf --disable-opcache-jit 2023-09-12 22:30:13 +08:00
Kévin Dunglas
dd2e7cc129 static opcache patch 2023-09-12 22:30:13 +08:00
Kévin Dunglas
adfa620ef4 Revert "always enable micro"
This reverts commit eb8cefd9ca.
2023-09-12 22:30:13 +08:00
Kévin Dunglas
1a32ddc70a Revert "temporary workaround for PECL certificate expiration"
This reverts commit 7c78003c9f.
2023-09-12 22:30:13 +08:00
Kévin Dunglas
4bfca6fe93 always enable micro 2023-09-12 22:30:13 +08:00
Kévin Dunglas
dbec043894 temporary workaround for PECL certificate expiration 2023-09-12 22:30:13 +08:00
Kévin Dunglas
727d78a689 Revert "fix: replace down URL"
This reverts commit 6eadbca21bf9a3b57058160a2f7ea8f4cc5f21dd.
2023-09-12 22:30:13 +08:00
Kévin Dunglas
9b1e784604 fix: replace down URL 2023-09-12 22:30:13 +08:00
Kévin Dunglas
50d44d8310 explicitly disable unneeded SAPIs 2023-09-12 22:30:13 +08:00
Kévin Dunglas
3b300698f3 use lixml GH mirror because gitlab.gnome.org is down 2023-09-12 22:30:13 +08:00
Kévin Dunglas
899eb94b8b remove useless ls 2023-09-12 22:30:13 +08:00
Kévin Dunglas
451a0c0e34 workaround for macOS 2023-09-12 22:30:13 +08:00
Kévin Dunglas
085c1a159c feat: add support for libphp and the embed SAPI 2023-09-12 22:30:13 +08:00
Joseph Bielawski
ca3f8a350d Prevent fatal error when php source files are missing 2023-09-12 18:19:32 +08:00
crazywhalecc
5025850f71 fix Alpine docker install packages 2023-09-12 12:45:51 +08:00
crazywhalecc
fe2f658e08 dev:sort-config add \n at the end of json 2023-09-12 00:24:01 +08:00
crazywhalecc
00a49c662b add build:libs option --rebuild 2023-09-11 23:47:02 +08:00
Jerry Ma
be8eb90b86 cs fix (#166) 2023-09-08 22:12:59 +08:00
Jerry Ma
54e98666e7 Update ConsoleApplication.php 2023-09-08 22:03:40 +08:00
Joseph Bielawski
e8b277ad0d Prevent unknown extension call 2023-09-07 19:05:00 +08:00
Joseph Bielawski
3bd037f48f Rework style of dev command showing extensions details 2023-09-07 19:05:00 +08:00
Joseph Bielawski
4d0e825b43 Adjust dependencies in composer.json file
Removed unsupported Symfony versions
Bump minimal version of dev dependencies to the latest supported
2023-09-06 21:29:04 +08:00
Jerry Ma
b14179a8de Update README-en.md 2023-09-06 16:26:51 +08:00
Jerry Ma
01111c51ee Update README.md 2023-09-06 16:26:22 +08:00
Jerry Ma
e7230d9f50 Update README-en.md 2023-09-06 16:13:43 +08:00
Jerry Ma
c22c5617ad Update README.md 2023-09-06 16:05:38 +08:00
Joseph Bielawski
cae7bb1dda Add GH Action for tests 2023-09-06 15:47:10 +08:00
Joseph Bielawski
c0830a9e1f Allow setting suffix for licence name 2023-09-06 09:53:45 +08:00
Joseph Bielawski
33798ff108 Add simple unit test 2023-09-06 01:00:24 +08:00
Joseph Bielawski
8d348b9e14 Allow setting multiple license in extensions, libraries & sources 2023-09-06 01:00:24 +08:00
Joseph Bielawski
3d2f6e4c3a Sort lib definition 2023-09-04 23:12:13 +08:00
Joseph Bielawski
88e9639482 Fix operator precedence 2023-09-04 23:12:13 +08:00
Joseph Bielawski
0381a1c412 Adjust extension definition after review 2023-09-04 23:12:13 +08:00
Joseph Bielawski
fdc3a7a04b Add snappy extension 2023-09-04 23:12:13 +08:00
crazywhalecc
6de5c1dab0 Remove unused source libressl 2023-08-31 20:27:46 +08:00
Kévin Dunglas
dc28ce0899 fix: curl dependency on openssl 2023-08-31 20:05:37 +08:00
Kévin Dunglas
9286153742 fix: linxml build on macOS 2023-08-29 14:28:12 +08:00
crazywhalecc
f90892c92f fix curl in musl-gcc bug, fix #88 2023-08-27 03:24:32 +08:00
crazywhalecc
5359f3a79a fix webp compile to cmake, fix #95 2023-08-27 03:08:12 +08:00
crazywhalecc
42fbf18bba update license 2023-08-27 00:25:51 +08:00
crazywhalecc
ed227ce00e fix linux libxml2 #75 issue 2023-08-27 00:25:51 +08:00
crazywhalecc
6c49d35aec add libxslt compile command 2023-08-27 00:25:51 +08:00
crazywhalecc
238fd7fc74 add libxslt source 2023-08-27 00:25:51 +08:00
Kévin Dunglas
1ebc58664e ci: remove useless step and dump Compose autoloader 2023-08-26 17:58:34 +08:00
Kévin Dunglas
bcf64cbeef fix: throw if the PHP version doesn't exist 2023-08-26 13:58:09 +08:00
Kévin Dunglas
dc12d4d982 fix: ExceptionHandler:: must not be accessed before initialization 2023-08-26 13:57:43 +08:00
Kévin Dunglas
42e5877a7f fix: check of xz 2023-08-26 13:57:18 +08:00
Kévin Dunglas
a8924ac4fe fix: setup-runtime portability 2023-08-26 13:53:52 +08:00
Jerry Ma
7fb27c0c29 fix reference error 2023-08-23 10:42:53 +08:00
Kévin Dunglas
3d9a3194b2 hide warning 2023-08-22 23:37:34 +08:00
Kévin Dunglas
e7e0ac006f more optims 2023-08-22 23:37:34 +08:00
Kévin Dunglas
cf35a270bb minor: read Dockerfile from stdin 2023-08-22 23:37:34 +08:00
crazywhalecc
3e7ef49bde update README 2023-08-22 18:33:34 +08:00
crazywhalecc
100d31791a fix linux builder cpp link option 2023-08-22 18:19:04 +08:00
Kévin Dunglas
15905c063a fix: use apt-get instead of apt 2023-08-22 09:59:47 +08:00
Kévin Dunglas
4c46f6a762 fix: error when source doesn't exist 2023-08-22 09:56:47 +08:00
Kévin Dunglas
f4327c8c81 fix 2023-08-22 01:50:13 +08:00
Kévin Dunglas
4a4b0e209c detect PHP 8.1+ 2023-08-22 01:50:13 +08:00
Kévin Dunglas
60e06737d7 fix: disable Zend Signals and enable Zend Max Execution Timers for ZTS builds 2023-08-22 01:50:13 +08:00
Kévin Dunglas
d326154241 fix: musl detection on non-x86_64 2023-08-22 00:56:59 +08:00
crazywhalecc
4766ae146f change swoole-pgsql as alternative 2023-08-21 18:31:51 +08:00
kocoten1992
21a4ba7478 add swoole pgsql (--enable-swoole-pgsql) 2023-08-21 18:31:51 +08:00
crazywhalecc
dfdeab70f1 add buildroot bin PATH 2023-08-21 18:10:09 +08:00
crazywhalecc
c8fa767576 Do some code quality check and fix #126 2023-08-21 18:10:09 +08:00
Jerry Ma
9c57ed6439 Update README-en.md 2023-08-20 20:32:28 +08:00
Jerry Ma
585826b438 Update README.md 2023-08-20 20:32:07 +08:00
Kévin Dunglas
cf22949f3b minor: prevent warning when installing cmake with Homebrew 2023-08-20 20:30:07 +08:00
crazywhalecc
a00f8945ba add glfw support for macOS 2023-08-19 00:27:20 +08:00
crazywhalecc
2bc02bdaac add glfw support for macOS 2023-08-19 00:27:20 +08:00
Chuong
b97327d6d7 mongodb source.json change from tgz to zip
since ver https://github.com/mongodb/mongo-php-driver/releases/tag/1.16.2

they don't support tgz anymore.
2023-08-18 17:57:08 +08:00
crazywhalecc
61d1507a4d add redis-session support 2023-08-09 11:01:36 +08:00
crazywhalecc
a6f07051c3 update readme about version and dependencies 2023-08-08 20:35:25 +08:00
crazywhalecc
75417d15b7 change laravel/prompts version 2023-08-08 20:30:06 +08:00
crazywhalecc
4bab7ecfab add laravel/prompts support, and change deploy commands and exception handlers 2023-08-08 20:30:06 +08:00
crazywhalecc
7298e2441b remove list-ext command, use all-ext and alias to support its function 2023-08-08 19:24:11 +08:00
Jerry Ma
1ed104d2f6 Update README-en.md 2023-08-07 11:38:22 +08:00
Jerry Ma
cf6125b9cc Update README.md 2023-08-07 11:38:12 +08:00
crazywhalecc
f2cfe33cdd remove gotop (Why I needed it?) 2023-08-06 12:33:26 +08:00
crazywhalecc
a1e4125ded replace symfony console return values 2023-08-06 10:44:36 +08:00
Viktor Szépe
7a1433a994 Fix output of ExtractCommand 2023-08-06 10:32:15 +08:00
crazywhalecc
460238a6b0 add hardcoded ini injection on build process 2023-08-02 22:16:33 +08:00
crazywhalecc
2a197487d5 add php 8.3 support for phpmicro 2023-08-01 23:45:51 +08:00
crazywhalecc
51ce2befd8 add library, extension patches in separate classes 2023-08-01 23:42:02 +08:00
crazywhalecc
e909dd15b0 add library, extension patch methods base 2023-08-01 23:42:02 +08:00
crazywhalecc
aaf712be3c add comments 2023-08-01 23:42:02 +08:00
crazywhalecc
725e6b25dc Fix #111 2023-07-29 19:02:19 +08:00
crazywhalecc
ea322c0d3b add extract command, add -U option (custom download source 2023-07-28 00:29:19 +08:00
145 changed files with 8806 additions and 1557 deletions

View File

@@ -40,11 +40,6 @@ jobs:
steps:
- 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
- id: cache-composer-deps
uses: actions/cache@v3
@@ -54,7 +49,7 @@ jobs:
# If there's no Composer cache, install dependencies
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
run: composer update --no-dev
run: composer update --no-dev --classmap-authoritative
# Cache downloaded source
- id: cache-download

View File

@@ -54,7 +54,7 @@ jobs:
# If there's no Composer cache, install dependencies
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
run: composer update --no-dev
run: composer update --no-dev --classmap-authoritative
# Cache downloaded source
- id: cache-download

47
.github/workflows/release-build.yml vendored Normal file
View 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
View 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
View File

@@ -4,8 +4,7 @@ docker/libraries/
docker/extensions/
docker/source/
# Composer file
composer.lock
# Vendor files
/vendor/
# default source extract directory
@@ -17,11 +16,15 @@ composer.lock
# default source build root directory
/buildroot/
# php cs fixer cache file
# tools cache files
.php-cs-fixer.cache
.phpunit.result.cache
# exclude self-runtime
/bin/*
!/bin/spc
!/bin/setup-runtime
!/bin/spc-alpine-docker
# default test directory
/tests/var/

View File

@@ -65,5 +65,5 @@ return (new PhpCsFixer\Config())
'phpdoc_var_without_name' => false,
])
->setFinder(
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
);

View File

@@ -1,17 +1,19 @@
# 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)
<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!
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">
[![Version](https://img.shields.io/badge/Version-2.0--rc3-pink.svg?style=flat-square)]()
[![Version](https://img.shields.io/badge/Version-2.0--rc5-pink.svg?style=flat-square)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]()
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
@@ -19,12 +21,10 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> The project has renamed the `refactor` branch to the `main` branch, please pay attention to changing the branch name for dependent projects.
## Compilation Requirements
Yes, this project is written in PHP, pretty funny.
But static-php-cli runtime only requires an environment above PHP 8.0 and `tokenizer`, `iconv` extension.
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension.
Here is the architecture support status, where `CI` represents support for GitHub Action builds,
`Local` represents support for local builds, and blank represents not currently supported.
@@ -37,11 +37,11 @@ Here is the architecture support status, where `CI` represents support for GitHu
> macOS-arm64 is not supported for GitHub Actions, if you are going to build on arm, you can build it manually on your own machine.
Currently supported PHP versions for compilation are: `7.4`, `8.0`, `8.1`, `8.2`.
Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`.
## Docs
docs here: <https://static-php-cli.zhamao.me>.
docs here: <https://static-php.dev>.
## Simple Usage
@@ -49,13 +49,13 @@ Please first select the extension you want to compile based on the extension lis
### 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`
### 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.
@@ -117,7 +117,7 @@ chmod +x bin/spc
You can also use the parameter `--with-php=x.y` to specify the downloaded PHP version, currently supports 7.4 ~ 8.2:
```bash
# Using PHP >= 8.0 is recommended, because 7.4 cannot use phpmicro
# Using PHP >= 8.0 is recommended, because PHP7 cannot use phpmicro
./bin/spc fetch --with-php=8.2 --all
```
@@ -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-micro`: build static phpmicro self-extracted executable
- `--build-fpm`: build static fpm binary
- `--build-embed`: build embed (libphp)
- `--build-all`: build all
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`.
## Current Status
### Embed Usage
- [X] Basic CLI framework (by `symfony/console`)
- [X] Linux support
- [X] macOS support
- [X] Exception handler
- [ ] Windows support
- [X] PHP 7.4 support
- [X] fpm support
When using the project parameters `--build-embed` or `--build-all`,
the final compilation result will output a `libphp.a`, `php-config` and a series of header files,
stored in `buildroot/`. You can introduce them in your other projects.
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
Currently, there are only a few supported extensions.
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.
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.
Also, configuration files should be sorted using the command `sort-config` after modification.
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
This project is based on the tradition of using the MIT License for old versions,
while the new version references source code from some other projects:
This project itself is based on MIT License,
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)
- [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.
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.

View File

@@ -1,6 +1,6 @@
# 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).**
@@ -12,19 +12,19 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
[![Version](https://img.shields.io/badge/Version-2.0--rc3-pink.svg?style=flat-square)]()
[![Version](https://img.shields.io/badge/Version-2.0--rc5-pink.svg?style=flat-square)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]()
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> 项目已重命名 `refactor` 分支为 `main` 分支,请依赖的项目注意更改分支名称。
> 项目名称是 static-php-cli但其实支持 cli、fpm、micro 和 embed SAPI 😎
## 编译环境需求
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 tokenizer 扩展和 PHP 版本大于等于 8.0 即可。
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。
下面是架构支持情况,`CI` 代表支持 GitHub Action 构建,`Local` 代表支持本地构建,空 代表暂不支持。
@@ -36,11 +36,11 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
> macOS-arm64 因 GitHub 暂未提供 arm runner如果要构建 arm 二进制,可以使用手动构建。
目前支持编译的 PHP 版本为:`7.4``8.0``8.1``8.2`
目前支持编译的 PHP 版本为:`7.3``7.4``8.0``8.1``8.2``8.3`
## 文档
点击这里查看文档:<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`
### 支持的扩展情况
[扩展支持列表](https://static-php-cli.zhamao.me/zh/guide/extensions.html)
[扩展支持列表](https://static-php.dev/zh/guide/extensions.html)
> 如果这里没有你需要的扩展,可以提交 Issue。
@@ -108,10 +108,10 @@ chmod +x bin/spc
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
```
你也可以使用参数 `--with-php=x.y` 来指定下载的 PHP 版本,目前支持 7.4 ~ 8.2
你也可以使用参数 `--with-php=x.y` 来指定下载的 PHP 版本,目前支持 7.3 ~ 8.3
```bash
# 优先考虑使用 >= 8.0 的 PHP 版本
# 优先考虑使用 >= 8.0 的 PHP 版本,因为 phpmicro 不支持在 PHP7 中构建
./bin/spc fetch --with-php=8.2 --all
```
@@ -120,6 +120,7 @@ chmod +x bin/spc
- `--build-cli`:构建 cli 二进制
- `--build-micro`:构建 phpmicro 自执行二进制
- `--build-fpm`:构建 fpm
- `--build-embed`:构建 embedlibphp
- `--build-all`:构建所有
如果出现了任何错误,可以使用 `--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-embed
- [X] 基础结构编写(采用 `symfony/console`
- [X] 错误处理
- [X] macOS 支持
- [ ] Windows 支持
- [X] Linux 支持
- [X] PHP 7.4 支持
- [X] fpm 支持
采用项目参数 `--build-embed``--build-all` 时,最后编译结果会输出一个 `libphp.a``php-config` 以及一系列头文件,存放在 `buildroot/`,你可以在你的其他代码中引入它们。
更多功能和特性正在陆续支持中详见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)(木兰宽松许可证)
- [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) 贡献代码或文档。

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
# set error-quit, verbose, non-variable-quit
set -eu
@@ -22,10 +22,10 @@ esac
# set project dir
__DIR__=$(cd "$(dirname "$0")" && pwd)
__PROJECT__=$(cd ${__DIR__}/../ && pwd)
__PROJECT__=$(cd "${__DIR__}"/../ && pwd)
# 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"
# use china mirror
@@ -46,23 +46,27 @@ done
case "$mirror" in
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"
;;
esac
test -d ${__PROJECT__}/downloads || mkdir ${__PROJECT__}/downloads
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
# 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 ${__DIR__}/php || { tar -xf ${__PROJECT__}/downloads/runtime.tar.gz -C ${__DIR__}/ ; }
chmod +x ${__DIR__}/php
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 "${__DIR__}"/php || { tar -xf "${__PROJECT__}"/downloads/runtime.tar.gz -C "${__DIR__}"/ ; }
chmod +x "${__DIR__}"/php
# download composer
test -f ${__DIR__}/composer || curl -#fSL -o ${__DIR__}/composer "$__COMPOSER_URL__"
chmod +x ${__DIR__}/composer
test -f "${__DIR__}"/composer || curl -#fSL -o "${__DIR__}"/composer "$__COMPOSER_URL__"
chmod +x "${__DIR__}"/composer
# sanity check for php and composer
${__DIR__}/php -v >/dev/null || { echo "Failed to run php" && exit 1; }
${__DIR__}/php ${__DIR__}/composer --version >/dev/null || { echo "Failed to run composer" && exit 1; }
"${__DIR__}"/php -v >/dev/null || { echo "Failed to run php" && exit 1; }
"${__DIR__}"/php "${__DIR__}"/composer --version >/dev/null || { echo "Failed to run composer" && exit 1; }
echo "Setup runtime OK!"
echo "runtime bin path needs to add manually by command below:"

View File

@@ -1,6 +1,9 @@
#!/usr/bin/env php
<?php
use SPC\ConsoleApplication;
use SPC\exception\ExceptionHandler;
require_once __DIR__ . '/../vendor/autoload.php';
// 防止 Micro 打包状态下不支持中文的显示(虽然这个项目目前好像没输出过中文?)
@@ -8,9 +11,8 @@ if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
exec('CHCP 65001');
}
// 跑,反正一条命令跑就对了
try {
(new \SPC\ConsoleApplication())->run();
(new ConsoleApplication())->run();
} catch (Exception $e) {
\SPC\exception\ExceptionHandler::getInstance()->handle($e);
ExceptionHandler::getInstance()->handle($e);
}

View File

@@ -2,18 +2,18 @@
# This file is using docker to run commands
self_dir=$(cd "$(dirname "$0")";pwd)
# Detect docker can run
if ! which docker >/dev/null; then
echo "Docker is not installed, please install docker first !"
exit 1
fi
DOCKER_EXECUTABLE="docker"
# shellcheck disable=SC2046
if [ $(id -u) -ne 0 ]; then
if ! docker info > /dev/null 2>&1; then
if [ "$SPC_USE_SUDO" != "yes" ]; then
echo "Docker command requires sudo"
# shellcheck disable=SC2039
echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again'
exit 1
fi
@@ -33,6 +33,7 @@ x86_64)
;;
aarch64)
ALPINE_FROM=multiarch/alpine:aarch64-edge
# shellcheck disable=SC2039
echo -e "\e[033m* Using different arch needs to setup qemu-static for docker !\e[0m"
$DOCKER_EXECUTABLE run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null
;;
@@ -51,24 +52,52 @@ fi
# Detect docker env is setup
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
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
$SPC_USE_MIRROR
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
RUN apk add build-base xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
RUN mkdir /app
RUN apk update; \
apk add --no-cache \
autoconf \
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
ADD ./src /app/src
ADD ./composer.json /app/composer.json
COPY ./composer.* /app/
ADD ./bin /app/bin
RUN composer update --no-dev
RUN composer install --no-dev --classmap-authoritative
EOF
)
echo "$ALPINE_DOCKERFILE" > $(pwd)/Dockerfile
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH .
rm $(pwd)/Dockerfile
fi
# Check if in ci (local terminal can execute with -it)
@@ -79,4 +108,5 @@ else
fi
# Run docker
$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 $@
# 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 $@

18
box.json Normal file
View 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"
}

View File

@@ -9,20 +9,21 @@
}
],
"require": {
"php": ">= 8.0",
"ext-tokenizer": "*",
"ext-iconv": "*",
"symfony/console": "^6 || ^5 || ^4",
"zhamao/logger": "^1.0",
"crazywhalecc/cli-helper": "^0.1.0",
"nunomaduro/collision": "*",
"ext-pcntl": "*"
"php": ">= 8.1",
"ext-mbstring": "*",
"ext-pcntl": "*",
"laravel/prompts": "^0.1.3",
"symfony/console": "^5.4 || ^6 || ^7",
"zhamao/logger": "^1.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
"phpstan/phpstan": "^1.1",
"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": {
"psr-4": {
@@ -33,13 +34,19 @@
"src/globals/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"SPC\\Tests\\": "tests/SPC"
}
},
"bin": [
"bin/spc"
],
"scripts": {
"analyse": "phpstan analyse --memory-limit 300M",
"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": {
"allow-plugins": {

5950
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -53,19 +53,6 @@
"sockets"
]
},
"memcached": {
"type": "external",
"source": "memcached",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"libmemcached"
],
"ext-depends": [
"session",
"zlib"
]
},
"exif": {
"type": "builtin"
},
@@ -113,6 +100,14 @@
"gettext"
]
},
"glfw": {
"type": "external",
"arg-type": "custom",
"source": "ext-glfw",
"lib-depends": [
"glfw"
]
},
"gmp": {
"type": "builtin",
"arg-type": "with-prefix",
@@ -158,9 +153,16 @@
},
"ldap": {
"type": "builtin",
"arg-type": "with",
"arg-type": "with-prefix",
"lib-depends": [
"ldap"
],
"lib-suggests": [
"gmp",
"libsodium"
],
"ext-suggests": [
"openssl"
]
},
"mbregex": {
@@ -188,6 +190,19 @@
"session"
]
},
"memcached": {
"type": "external",
"source": "memcached",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"libmemcached"
],
"ext-depends": [
"session",
"zlib"
]
},
"mongodb": {
"type": "external",
"source": "mongodb",
@@ -208,7 +223,10 @@
},
"mysqlnd": {
"type": "builtin",
"arg-type-windows": "with"
"arg-type-windows": "with",
"lib-depends": [
"zlib"
]
},
"opcache": {
"type": "builtin"
@@ -218,6 +236,9 @@
"arg-type": "with",
"lib-depends": [
"openssl"
],
"ext-depends": [
"zlib"
]
},
"pcntl": {
@@ -295,7 +316,10 @@
"redis": {
"type": "external",
"source": "redis",
"arg-type": "custom"
"arg-type": "custom",
"ext-suggests": [
"session"
]
},
"session": {
"type": "builtin"
@@ -311,6 +335,18 @@
"libxml2"
]
},
"snappy": {
"type": "external",
"source": "ext-snappy",
"cpp-extension": true,
"arg-type": "custom",
"lib-depends": [
"snappy"
],
"ext-suggest": [
"apcu"
]
},
"snmp": {
"type": "builtin",
"arg-type": "with",
@@ -362,7 +398,8 @@
"openssl"
],
"ext-suggests": [
"curl"
"curl",
"pgsql"
],
"unix-only": true
},
@@ -434,9 +471,13 @@
},
"xsl": {
"type": "builtin",
"arg-type": "with",
"arg-type": "with-prefix",
"lib-depends": [
"libxslt"
],
"ext-depends": [
"xml",
"dom"
]
},
"yaml": {

View File

@@ -42,14 +42,14 @@
"curl"
],
"lib-depends-unix": [
"openssl",
"zlib"
],
"lib-suggests": [
"libssh2",
"brotli",
"nghttp2",
"zstd",
"openssl"
"zstd"
],
"lib-suggests-windows": [
"zlib",
@@ -84,6 +84,18 @@
"brotli"
]
},
"glfw": {
"source": "ext-glfw",
"static-libs-unix": [
"libglfw3.a"
],
"frameworks": [
"CoreVideo",
"OpenGL",
"Cocoa",
"IOKit"
]
},
"gmp": {
"source": "gmp",
"static-libs-unix": [
@@ -127,6 +139,18 @@
"libxml2"
]
},
"ldap": {
"source": "ldap",
"static-libs-unix": [
"liblber.a",
"libldap.a"
],
"lib-suggests": [
"openssl",
"gmp",
"libsodium"
]
},
"libavif": {
"source": "libavif",
"static-libs-unix": [
@@ -188,6 +212,13 @@
"libmcrypt.a"
]
},
"libmemcached": {
"source": "libmemcached",
"static-libs-unix": [
"libmemcached.a",
"libmemcachedutil.a"
]
},
"libpng": {
"source": "libpng",
"static-libs-unix": [
@@ -260,20 +291,29 @@
"libxml2"
],
"lib-depends": [
"libiconv"
"libiconv",
"zlib"
],
"lib-suggests": [
"xz",
"zlib",
"icu"
],
"lib-suggests-windows": [
"icu",
"xz",
"zlib",
"pthreads4w"
]
},
"libxslt": {
"source": "libxslt",
"static-libs-unix": [
"libxslt.a",
"libexslt.a"
],
"lib-depends": [
"libxml2"
]
},
"libyaml": {
"source": "libyaml",
"static-libs-unix": [
@@ -417,6 +457,22 @@
"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": {
"source": "sqlite",
"static-libs-unix": [
@@ -462,13 +518,6 @@
"zconf.h"
]
},
"libmemcached": {
"source": "libmemcached",
"static-libs-unix": [
"libmemcached.a",
"libmemcachedutil.a"
]
},
"zstd": {
"source": "zstd",
"static-libs-unix": [
@@ -490,4 +539,4 @@
"zstd_errors.h"
]
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
# 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)

View File

@@ -4,47 +4,49 @@ declare(strict_types=1);
namespace SPC;
use SPC\command\DeployCommand;
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\Command\Command;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
/**
* spc 应用究级入口
* static-php-cli console app entry
*/
class ConsoleApplication extends Application
final class ConsoleApplication extends Application
{
public const VERSION = '2.0-rc3';
public const VERSION = '2.0-rc7';
/**
* @throws \ReflectionException
* @throws exception\FileSystemException
*/
public function __construct()
{
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(),
// 生产环境不显示详细的调试错误,只使用 symfony console 自带的错误显示
$this->setCatchExceptions(file_exists(ROOT_DIR . '/.prod') || !in_array('--debug', $argv));
// 通过扫描目录 src/static-php-cli/command/ 添加子命令
$commands = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/command', 'SPC\\command');
$this->addCommands(array_map(function ($x) { return new $x(); }, array_filter($commands, function ($y) {
if (is_a($y, DeployCommand::class, true) && (class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar'))) {
return false;
}
$reflection = new \ReflectionClass($y);
return !$reflection->isAbstract() && !$reflection->isInterface();
})));
// Dev commands
new AllExtCommand(),
new PhpVerCommand(),
new SortConfigCommand(),
]
);
}
/**
* 重载以去除一些不必要的默认命令
*/
protected function getDefaultCommands(): array
{
return [new HelpCommand(), new ListCommand()];

View File

@@ -9,48 +9,38 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceExtractor;
use SPC\util\CustomExt;
use SPC\util\DependencyUtil;
abstract class BuilderBase
{
/** @var bool 是否启用 ZTS 线程安全 */
public bool $zts = false;
/** @var string 编译目标架构 */
public string $arch;
/** @var string GNU 格式的编译目标架构 */
public string $gnu_arch;
/** @var int 编译进程数 */
/** @var int Concurrency */
public int $concurrency = 1;
/** @var array<string, LibraryBase> 要编译的 libs 列表 */
/** @var array<string, LibraryBase> libraries */
protected array $libs = [];
/** @var array<string, Extension> 要编译的扩展列表 */
/** @var array<string, Extension> extensions */
protected array $exts = [];
/** @var array<int, string> 要编译的扩展列表(仅名字列表,用于最后生成编译的扩展列表给 micro */
protected array $plain_extensions = [];
/** @var bool 本次编译是否只编译 libs不编译 PHP */
/** @var bool compile libs only (just mark it) */
protected bool $libs_only = false;
/** @var bool 是否 strip 最终的二进制 */
protected bool $strip = true;
/** @var array<string, mixed> compile options */
protected array $options = [];
/**
* 构建指定列表的 libs
* Build libraries
*
* @param array<string> $libraries Libraries to build
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function buildLibs(array $libraries): void
{
// 通过扫描目录查找 lib
// search all supported libs
$support_lib_list = [];
$classes = FileSystem::getClassesPsr4(
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
@@ -62,19 +52,22 @@ abstract class BuilderBase
}
}
// 如果传入了空则默认检查和安置所有支持的liblibraries为要build的support_lib_list为支持的列表
// if no libs specified, compile all supported libs
if ($libraries === [] && $this->isLibsOnly()) {
$libraries = array_keys($support_lib_list);
}
// pkg-config must be compiled first, whether it is specified or not
if (!in_array('pkg-config', $libraries)) {
array_unshift($libraries, 'pkg-config');
}
// 排序 libs根据依赖计算一个新的列表出来
// append dependencies
$libraries = DependencyUtil::getLibsByDeps($libraries);
// 过滤不支持的库后添加
// add lib object for builder
foreach ($libraries as $library) {
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new RuntimeException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
}
@@ -82,16 +75,17 @@ abstract class BuilderBase
$this->addLib($lib);
}
// 计算依赖,经过这里的遍历,如果没有抛出异常,说明依赖符合要求,可以继续下面的
// calculate and check dependencies
foreach ($this->libs as $lib) {
$lib->calcDependency();
}
$this->initSource(libs: $libraries);
// extract sources
SourceExtractor::initSource(libs: $libraries);
// 构建库
// build all libs
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_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
@@ -101,9 +95,9 @@ abstract class BuilderBase
}
/**
* 添加要编译的 Lib 库
* Add library to build.
*
* @param LibraryBase $library Lib 库对象
* @param LibraryBase $library Library object
*/
public function addLib(LibraryBase $library): void
{
@@ -111,9 +105,7 @@ abstract class BuilderBase
}
/**
* 获取要编译的 Lib 库对象
*
* @param string $name 库名称
* Get library object by name.
*/
public function getLib(string $name): ?LibraryBase
{
@@ -121,9 +113,7 @@ abstract class BuilderBase
}
/**
* 添加要编译的扩展
*
* @param Extension $extension 扩展对象
* Add extension to build.
*/
public function addExt(Extension $extension): void
{
@@ -131,9 +121,7 @@ abstract class BuilderBase
}
/**
* 获取要编译的扩展对象
*
* @param string $name 扩展名称
* Get extension object by name.
*/
public function getExt(string $name): ?Extension
{
@@ -141,7 +129,7 @@ abstract class BuilderBase
}
/**
* 获取所有要编译的扩展对象
* Get all extension objects.
*
* @return Extension[]
*/
@@ -151,10 +139,9 @@ abstract class BuilderBase
}
/**
* 检查 C++ 扩展是否存在
* Check if there is a cpp extension.
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function hasCppExtension(): bool
@@ -172,7 +159,7 @@ abstract class BuilderBase
}
/**
* 设置本次 Builder 是否为仅编译库的模式
* Set libs only mode.
*/
public function setLibsOnly(bool $status = true): void
{
@@ -180,19 +167,21 @@ abstract class BuilderBase
}
/**
* 检验 ext 扩展列表是否合理,并声明 Extension 对象,检查扩展的依赖
* Verify the list of "ext" extensions for validity and declare an Extension object to check the dependencies of the extensions.
*
* @throws FileSystemException
* @throws RuntimeException
* @throws \ReflectionException
* @throws WrongUsageException
*/
public function proveExts(array $extensions): void
{
CustomExt::loadCustomExt();
$this->initSource(sources: ['php-src']);
SourceExtractor::initSource(sources: ['php-src']);
if ($this->getPHPVersionID() >= 80000) {
$this->initSource(sources: ['micro']);
SourceExtractor::initSource(sources: ['micro']);
}
$this->initSource(exts: $extensions);
SourceExtractor::initSource(exts: $extensions);
foreach ($extensions as $extension) {
$class = CustomExt::getExtClass($extension);
$ext = new $class($extension, $this);
@@ -200,27 +189,23 @@ abstract class BuilderBase
}
foreach ($this->exts as $ext) {
// 检查下依赖就行了,作用是导入依赖给 Extension 对象,今后可以对库依赖进行选择性处理
$ext->checkDependency();
}
$this->plain_extensions = $extensions;
}
/**
* 开始构建 PHP
* Start to build PHP
*
* @param int $build_target 规则
* @param bool $bloat 保留
* @param int $build_target Build target, see BUILD_TARGET_*
*/
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false);
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
/**
* 生成依赖的扩展编译启用参数
* 例如 --enable-mbstring
* Generate extension enable arguments for configure.
* e.g. --enable-mbstring
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function makeExtensionArgs(): string
{
@@ -233,7 +218,7 @@ abstract class BuilderBase
}
/**
* 返回是否只编译 libs 的模式
* Get libs only mode.
*/
public function isLibsOnly(): bool
{
@@ -241,15 +226,30 @@ abstract class BuilderBase
}
/**
* 获取当前即将编译的 PHP 的版本 ID五位数那个
* Get PHP Version ID from php-src/main/php_version.h
*
* @throws RuntimeException
* @throws WrongUsageException
*/
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');
preg_match('/PHP_VERSION_ID (\d+)/', $file, $match);
return intval($match[1]);
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
return intval($match[1]);
}
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
}
/**
* Get build type name string to display.
*
* @param int $type Build target type
*/
public function getBuildTypeName(int $type): string
{
$ls = [];
@@ -262,16 +262,52 @@ abstract class BuilderBase
if (($type & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
$ls[] = 'fpm';
}
if (($type & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
$ls[] = 'embed';
}
return implode(', ', $ls);
}
public function setStrip(bool $strip): void
/**
* Get builder options (maybe changed by user)
*
* @param string $key Option key
* @param mixed $default If not exists, return this value
*/
public function getOption(string $key, mixed $default = null): mixed
{
$this->strip = $strip;
return $this->options[$key] ?? $default;
}
/**
* 检查是否存在 lib 库对应的源码,如果不存在,则抛出异常
* Get all builder options
*/
public function getOptions(): array
{
return $this->options;
}
/**
* Set builder options if not exists.
*/
public function setOptionIfNotExist(string $key, mixed $value): void
{
if (!isset($this->options[$key])) {
$this->options[$key] = $value;
}
}
/**
* Set builder options.
*/
public function setOption(string $key, mixed $value): void
{
$this->options[$key] = $value;
}
/**
* Check if all libs are downloaded.
* If not, throw exception.
*
* @throws RuntimeException
*/
@@ -292,52 +328,4 @@ abstract class BuilderBase
);
}
}
protected function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null): void
{
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
throw new WrongUsageException('Download lock file "downloads/.lock.json" not found, maybe you need to download sources first ?');
}
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true);
$sources_extracted = [];
// source check exist
if (is_array($sources)) {
foreach ($sources as $source) {
$sources_extracted[$source] = true;
}
}
// lib check source exist
if (is_array($libs)) {
foreach ($libs as $lib) {
// get source name for lib
$source = Config::getLib($lib, 'source');
$sources_extracted[$source] = true;
}
}
// ext check source exist
if (is_array($exts)) {
foreach ($exts as $ext) {
// get source name for ext
if (Config::getExt($ext, 'type') !== 'external') {
continue;
}
$source = Config::getExt($ext, 'source');
$sources_extracted[$source] = true;
}
}
// start check
foreach ($sources_extracted as $source => $item) {
if (!isset($lock[$source])) {
throw new WrongUsageException('Source [' . $source . '] not downloaded, you should download it first !');
}
// check source dir exist
$check = $lock[$source]['move_path'] === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $lock[$source]['move_path'];
if (!is_dir($check)) {
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$source]['filename'] ?? $lock[$source]['dirname']), $lock[$source]['move_path']);
}
}
}
}

View File

@@ -6,7 +6,7 @@ namespace SPC\builder;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\macos\MacOSBuilder;
use SPC\builder\windows\WindowsBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use Symfony\Component\Console\Input\InputInterface;
@@ -17,7 +17,9 @@ use Symfony\Component\Console\Input\InputInterface;
class BuilderProvider
{
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function makeBuilderByInput(InputInterface $input): BuilderBase
{
@@ -27,18 +29,8 @@ class BuilderProvider
// vs_ver: $input->getOption('vs-ver'),
// arch: $input->getOption('arch'),
// ),
'Darwin' => new MacOSBuilder(
cc: $input->getOption('cc'),
cxx: $input->getOption('cxx'),
arch: $input->getOption('arch'),
zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false,
),
'Linux' => new LinuxBuilder(
cc: $input->getOption('cc'),
cxx: $input->getOption('cxx'),
arch: $input->getOption('arch'),
zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false,
),
'Darwin' => new MacOSBuilder($input->getOptions()),
'Linux' => new LinuxBuilder($input->getOptions()),
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
};
}

View File

@@ -34,7 +34,7 @@ class Extension
/**
* 获取开启该扩展的 PHP 编译添加的参数
*
* @throws FileSystemException|RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getConfigureArg(): string
@@ -56,7 +56,6 @@ class Extension
* 根据 ext 的 arg-type 获取对应开启的参数,一般都是 --enable-xxx 和 --with-xxx
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function getEnableArg(): string
@@ -136,6 +135,33 @@ class Extension
return '';
}
/**
* Patch code before ./buildconf
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeBuildconf(): bool
{
return false;
}
/**
* Patch code before ./configure
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeConfigure(): bool
{
return false;
}
/**
* Patch code before make
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeMake(): bool
{
return false;
}
/**
* @throws RuntimeException
*/

View File

@@ -7,20 +7,16 @@ namespace SPC\builder;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
/**
* Lib 库的基类操作对象
*/
abstract class LibraryBase
{
/** @var string lib 依赖名称,必须重写 */
/** @var string */
public const NAME = 'unknown';
/** @var string lib 依赖的根目录 */
protected string $source_dir;
/** @var array 依赖列表 */
protected array $dependencies = [];
/**
@@ -35,7 +31,7 @@ abstract class LibraryBase
}
/**
* 获取 lib 库的根目录
* Get current lib source root dir.
*/
public function getSourceDir(): string
{
@@ -43,10 +39,9 @@ abstract class LibraryBase
}
/**
* 获取当前 lib 库的所有依赖列表
* Get current lib dependencies.
*
* @param bool $recursive 是否递归获取(默认为 False
* @return array<string, LibraryBase> 依赖的 Map
* @return array<string, LibraryBase>
*/
public function getDependencies(bool $recursive = false): array
{
@@ -55,7 +50,6 @@ abstract class LibraryBase
return $this->dependencies;
}
// 下面为递归获取依赖列表,根据依赖顺序
$deps = [];
$added = 1;
@@ -78,20 +72,21 @@ abstract class LibraryBase
}
/**
* 计算依赖列表,不符合依赖将抛出异常
* Calculate dependencies for current library.
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function calcDependency(): void
{
// 先从配置文件添加依赖,这里根据不同的操作系统分别选择不同的元信息
// Add dependencies from the configuration file. Here, choose different metadata based on the operating system.
/*
选择规则:
如果是 Windows 系统,则依次尝试有无 lib-depends-windowslib-depends-winlib-depends
如果是 macOS 系统,则依次尝试 lib-depends-darwinlib-depends-unixlib-depends
如果是 Linux 系统,则依次尝试 lib-depends-linuxlib-depends-unixlib-depends
*/
Rules:
If it is a Windows system, try the following dependencies in order: lib-depends-windows, lib-depends-win, lib-depends.
If it is a macOS system, try the following dependencies in order: lib-depends-darwin, lib-depends-unix, lib-depends.
If it is a Linux system, try the following dependencies in order: lib-depends-linux, lib-depends-unix, lib-depends.
*/
foreach (Config::getLib(static::NAME, 'lib-depends', []) as $dep_name) {
$this->addLibraryDependency($dep_name);
}
@@ -101,11 +96,10 @@ abstract class LibraryBase
}
/**
* 获取当前库编译出来获取到的静态库文件列表
* Get config static libs.
*
* @return string[] 获取编译出来后的需要的静态库文件列表
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function getStaticLibs(): array
{
@@ -113,11 +107,10 @@ abstract class LibraryBase
}
/**
* 获取当前 lib 编译出来的 C Header 文件列表
* Get config headers.
*
* @return string[] 获取编译出来后需要的 C Header 文件列表
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function getHeaders(): array
{
@@ -125,73 +118,84 @@ abstract class LibraryBase
}
/**
* 证明该库是否已编译好且就绪,如果没有就绪,内部会调用 build 来进行构建该库
* Try to build this library, before build, we check first.
*
* BUILD_STATUS_OK if build success
* BUILD_STATUS_ALREADY if already built
* BUILD_STATUS_FAILED if build failed
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function tryBuild(bool $force_build = false): int
{
// 传入 true表明直接编译
// force means just build
if ($force_build) {
logger()->info('Building required library [' . static::NAME . ']');
$this->patchBeforeBuild();
$this->build();
return BUILD_STATUS_OK;
}
// 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态
// check if these libraries exist, if not, invoke compilation and return the result status
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// 头文件同理
// header files the same
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// pkg-config 做特殊处理,如果是 pkg-config 就检查有没有 pkg-config 二进制
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if ($this instanceof MacOSLibraryBase && static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
// 到这里说明所有的文件都存在,就跳过编译
// if all the files exist at this point, skip the compilation process
return BUILD_STATUS_ALREADY;
}
/**
* 获取构建当前 lib 的 Builder 对象
* Patch before build, overwrite this and return true to patch libs.
*/
public function patchBeforeBuild(): bool
{
return false;
}
/**
* Get current builder object.
*/
abstract public function getBuilder(): BuilderBase;
/**
* 构建该库需要调用的命令和操作
* Build this library.
*
* @throws RuntimeException
*/
abstract protected function build();
/**
* 添加 lib 库的依赖库
* Add lib dependency
*
* @param string $name 依赖名称
* @param bool $optional 是否是可选依赖(默认为 False
* @throws RuntimeException
*/
protected function addLibraryDependency(string $name, bool $optional = false): void
{
// Log::i("add $name as dep of {$this->name}");
$dep_lib = $this->getBuilder()->getLib($name);
if (!$dep_lib) {
if (!$optional) {
throw new RuntimeException(static::NAME . " requires library {$name}");
}
logger()->debug('enabling ' . static::NAME . " without {$name}");
} else {
if ($dep_lib) {
$this->dependencies[$name] = $dep_lib;
return;
}
if (!$optional) {
throw new RuntimeException(static::NAME . " requires library {$name}");
}
logger()->debug('enabling ' . static::NAME . " without {$name}");
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('bz2')]
class bz2 extends Extension
{
/**
* @throws FileSystemException
* @throws WrongUsageException
*/
public function patchBeforeConfigure(): bool
{
$frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lbz2/', $this->getLibFilesString() . $frameworks);
return true;
}
}

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('curl')]
class curl extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeBuildconf(): bool
{
logger()->info('patching before-configure for curl checks');
$file1 = "AC_DEFUN([PHP_CHECK_LIBRARY], [\n $3\n])";
$files = FileSystem::readFile(SOURCE_PATH . '/php-src/ext/curl/config.m4');
$file2 = 'AC_DEFUN([PHP_CHECK_LIBRARY], [
save_old_LDFLAGS=$LDFLAGS
ac_stuff="$5"
save_ext_shared=$ext_shared
ext_shared=yes
PHP_EVAL_LIBLINE([$]ac_stuff, LDFLAGS)
AC_CHECK_LIB([$1],[$2],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
$3
],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
unset ac_cv_lib_$1[]_$2
$4
])dnl
])';
file_put_contents(SOURCE_PATH . '/php-src/ext/curl/config.m4', $file1 . "\n" . $files . "\n" . $file2);
return true;
}
/**
* @throws FileSystemException
* @throws WrongUsageException
*/
public function patchBeforeConfigure(): bool
{
$frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lcurl/', $this->getLibFilesString() . $frameworks);
return true;
}
}

View File

@@ -5,6 +5,8 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('event')]
@@ -23,4 +25,13 @@ class event extends Extension
}
return $arg;
}
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString());
return true;
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('glfw')]
class glfw extends Extension
{
/**
* @throws RuntimeException
*/
public function patchBeforeBuildconf(): bool
{
FileSystem::copyDir(SOURCE_PATH . '/ext-glfw', SOURCE_PATH . '/php-src/ext/glfw');
return true;
}
public function getUnixConfigureArg(): string
{
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('iconv')]
class iconv extends Extension
{
public function patchBeforeConfigure(): bool
{
// macOS need to link iconv dynamically, we add it to extra-libs
$extra_libs = $this->builder->getOption('extra-libs', '');
if (!str_contains($extra_libs, '-liconv')) {
$extra_libs .= ' -liconv';
}
$this->builder->setOption('extra-libs', $extra_libs);
return true;
}
}

View File

@@ -10,6 +10,17 @@ use SPC\util\CustomExt;
#[CustomExt('imagick')]
class imagick extends Extension
{
public function patchBeforeBuildconf(): bool
{
// linux need to link library manually, we add it to extra-libs
$extra_libs = $this->builder->getOption('extra-libs', '');
if (!str_contains($extra_libs, 'libMagickCore')) {
$extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a';
}
$this->builder->setOption('extra-libs', $extra_libs);
return true;
}
public function getUnixConfigureArg(): string
{
return '--with-imagick=' . BUILD_ROOT_PATH;

View File

@@ -5,6 +5,8 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('memcache')]
@@ -14,4 +16,35 @@ class memcache extends Extension
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
}
/**
* @throws FileSystemException
*/
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/src ; then',
'if test -d $abs_srcdir/main ; then'
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'export CPPFLAGS="$CPPFLAGS $INCLUDES"',
'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"'
);
// add for in-tree building
file_put_contents(
SOURCE_PATH . '/php-src/ext/memcache/php_memcache.h',
<<<'EOF'
#ifndef PHP_MEMCACHE_H
#define PHP_MEMCACHE_H
extern zend_module_entry memcache_module_entry;
#define phpext_memcache_ptr &memcache_module_entry
#endif
EOF
);
return true;
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('openssl')]
class openssl extends Extension
{
public function patchBeforeMake(): bool
{
// patch openssl3 with php8.0 bug
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 = 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);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('pdo_sqlite')]
class pdo_sqlite extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/sqlite3_column_table_name=yes/',
'sqlite3_column_table_name=no'
);
return true;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('pgsql')]
class pgsql extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lpq/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('readline')]
class readline extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lncurses/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -12,7 +12,12 @@ class redis extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-redis --disable-redis-session';
$arg = '--enable-redis';
if (!$this->builder->getExt('session')) {
$arg .= ' --disable-redis-session';
} else {
$arg .= ' --enable-redis-session';
}
if ($this->builder->getLib('zstd')) {
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
}

View 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 . '"';
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('ssh2')]
class ssh2 extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lssh2/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -13,6 +13,7 @@ class swoole extends Extension
public function getUnixConfigureArg(): string
{
$arg = '--enable-swoole';
$arg .= $this->builder->getExt('pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql';
$arg .= $this->builder->getLib('openssl') ? ' --enable-openssl' : ' --disable-openssl --without-openssl';
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
// curl hook is buggy for static php

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\util\CustomExt;
#[CustomExt('swow')]
@@ -17,4 +18,20 @@ class swow extends Extension
$arg .= $this->builder->getLib('curl') ? ' --enable-swow-curl' : ' --disable-swow-curl';
return $arg;
}
/**
* @throws RuntimeException
*/
public function patchBeforeBuildconf(): bool
{
if ($this->builder->getPHPVersionID() >= 80000 && !is_link(SOURCE_PATH . '/php-src/ext/swow')) {
if (PHP_OS_FAMILY === 'Windows') {
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D swow swow-src\ext');
} else {
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s swow-src/ext swow');
}
return true;
}
return false;
}
}

View File

@@ -10,96 +10,94 @@ use SPC\builder\traits\UnixBuilderTrait;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
/**
* Linux 系统环境下的构建器
*/
class LinuxBuilder extends BuilderBase
{
/** 编译的 Unix 工具集 */
/** Unix compatible builder methods */
use UnixBuilderTrait;
/** @var string[] Linux 环境下编译依赖的命令 */
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
/** @var string 使用的 libc */
/** @var string Using libc [musl,glibc] */
public string $libc;
/** @var array 特殊架构下的 cflags */
/** @var array Tune cflags */
public array $tune_c_flags;
/** @var string pkg-config 环境变量 */
/** @var string pkg-config env, including PKG_CONFIG_PATH, PKG_CONFIG */
public string $pkgconf_env;
/** @var string 交叉编译变量 */
public string $cross_compile_prefix = '';
public string $note_section = "Je pense, donc je suis\0";
/** @var bool Micro patch phar flag */
private bool $phar_patched = false;
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null, bool $zts = false)
public function __construct(array $options = [])
{
// 初始化一些默认参数
$this->cc = $cc ?? match (SystemUtil::getOSRelease()['dist']) {
$this->options = $options;
// ---------- set necessary options ----------
// set C Compiler (default: alpine: gcc, others: musl-gcc)
$this->setOptionIfNotExist('cc', match (SystemUtil::getOSRelease()['dist']) {
'alpine' => 'gcc',
default => 'musl-gcc'
};
$this->cxx = $cxx ?? 'g++';
$this->arch = $arch ?? php_uname('m');
$this->gnu_arch = arch2gnu($this->arch);
$this->zts = $zts;
$this->libc = 'musl'; // SystemUtil::selectLibc($this->cc);
});
// set C++ Compiler (default: g++)
$this->setOptionIfNotExist('cxx', 'g++');
// set arch (default: current)
$this->setOptionIfNotExist('arch', php_uname('m'));
$this->setOptionIfNotExist('gnu-arch', arch2gnu($this->getOption('arch')));
// 根据 CPU 线程数设置编译进程数
// ---------- set necessary compile environments ----------
// set libc
$this->libc = $this->getOption('cc', 'gcc') === 'musl-gcc' ? 'musl_wrapper' : 'musl'; // SystemUtil::selectLibc($this->cc);
// concurrency
$this->concurrency = SystemUtil::getCpuCount();
// 设置 cflags
$this->arch_c_flags = SystemUtil::getArchCFlags($this->cc, $this->arch);
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->cxx, $this->arch);
$this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->arch), $this->cc);
// 设置 cmake
// cflags
$this->arch_c_flags = SystemUtil::getArchCFlags($this->getOption('cc'), $this->getOption('arch'));
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->getOption('cxx'), $this->getOption('arch'));
$this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->getOption('arch')), $this->getOption('cc'));
// cmake toolchain
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile(
os: 'Linux',
target_arch: $this->arch,
cflags: $this->arch_c_flags,
cc: $this->cc,
cxx: $this->cxx
'Linux',
$this->getOption('arch'),
$this->arch_c_flags,
$this->getOption('cc'),
$this->getOption('cxx'),
);
// 设置 pkgconfig
$this->pkgconf_env = 'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"';
// 设置 configure 依赖的环境变量
$this->configure_env =
$this->pkgconf_env . ' ' .
"CC='{$this->cc}' " .
"CXX='{$this->cxx}' " .
(php_uname('m') === $this->arch ? '' : "CFLAGS='{$this->arch_c_flags}'");
// 交叉编译依赖的TODO
if (php_uname('m') !== $this->arch) {
// pkg-config
$vars = [
'PKG_CONFIG' => BUILD_ROOT_PATH . '/bin/pkg-config',
'PKG_CONFIG_PATH' => BUILD_LIB_PATH . '/pkgconfig',
];
$this->pkgconf_env = SystemUtil::makeEnvVarString($vars);
// configure environment
$this->configure_env = SystemUtil::makeEnvVarString([
...$vars,
'CC' => $this->getOption('cc'),
'CXX' => $this->getOption('cxx'),
'PATH' => BUILD_ROOT_PATH . '/bin:' . getenv('PATH'),
]);
// cross-compile does not support yet
/*if (php_uname('m') !== $this->arch) {
$this->cross_compile_prefix = SystemUtil::getCrossCompilePrefix($this->cc, $this->arch);
logger()->info('using cross compile prefix: ' . $this->cross_compile_prefix);
$this->configure_env .= " CROSS_COMPILE='{$this->cross_compile_prefix}'";
}
}*/
$missing = [];
foreach (self::REQUIRED_COMMANDS as $cmd) {
if (SystemUtil::findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
throw new WrongUsageException('missing system commands: ' . implode(', ', $missing));
}
// 创立 pkg-config 和放头文件的目录
// create pkgconfig and include dir (some libs cannot create them automatically)
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function makeAutoconfArgs(string $name, array $libSpecs): string
{
$ret = '';
@@ -124,32 +122,22 @@ class LinuxBuilder extends BuilderBase
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $with_clean = false, bool $bloat = false)
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
if (!$bloat) {
$extra_libs = implode(' ', $this->getAllStaticLibFiles());
// ---------- Update extra-libs ----------
$extra_libs = $this->getOption('extra-libs', '');
// non-bloat linking
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
logger()->info('bloat linking');
$extra_libs = implode(
' ',
array_map(
fn ($x) => "-Xcompiler {$x}",
array_filter($this->getAllStaticLibFiles())
)
);
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", array_filter($this->getAllStaticLibFiles())));
}
// add libstdc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCppExtension() ? '-lstdc++ ' : '');
$this->setOption('extra-libs', $extra_libs);
if ($this->hasCppExtension()) {
$extra_libs .= ' -lstdc++';
}
if ($this->getExt('imagick')) {
$extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a';
}
$envs = $this->pkgconf_env . ' ' .
"CC='{$this->cc}' " .
"CXX='{$this->cxx}' ";
$cflags = $this->arch_c_flags;
$use_lld = '';
@@ -159,7 +147,7 @@ class LinuxBuilder extends BuilderBase
$cflags .= ' -static-libgcc -I"' . BUILD_INCLUDE_PATH . '"';
break;
case 'musl':
if (str_ends_with($this->cc, 'clang') && SystemUtil::findCommand('lld')) {
if (str_ends_with($this->getOption('cc'), 'clang') && SystemUtil::findCommand('lld')) {
$use_lld = '-Xcompiler -fuse-ld=lld';
}
break;
@@ -167,20 +155,36 @@ class LinuxBuilder extends BuilderBase
throw new WrongUsageException('libc ' . $this->libc . ' is not implemented yet');
}
$envs = "{$envs} CFLAGS='{$cflags}' LIBS='-ldl -lpthread'";
$envs = $this->pkgconf_env . ' ' . SystemUtil::makeEnvVarString([
'CC' => $this->getOption('cc'),
'CXX' => $this->getOption('cxx'),
'CFLAGS' => $cflags,
'LIBS' => '-ldl -lpthread',
'PATH' => BUILD_ROOT_PATH . '/bin:' . getenv('PATH'),
]);
SourcePatcher::patchPHPBuildconf($this);
SourcePatcher::patchBeforeBuildconf($this);
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
SourcePatcher::patchPHPConfigure($this);
SourcePatcher::patchBeforeConfigure($this);
if ($this->getPHPVersionID() < 80000) {
$json_74 = '--enable-json ';
$phpVersionID = $this->getPHPVersionID();
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '';
if ($this->getOption('enable-zts', false)) {
$maxExecutionTimers = $phpVersionID >= 80100 ? '--enable-zend-max-execution-timers ' : '';
$zts = '--enable-zts --disable-zend-signals ';
} else {
$json_74 = '';
$maxExecutionTimers = '';
$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')
->exec(
'./configure ' .
@@ -191,74 +195,75 @@ class LinuxBuilder extends BuilderBase
'--disable-all ' .
'--disable-cgi ' .
'--disable-phpdbg ' .
'--enable-cli ' .
'--enable-fpm ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
($enableEmbed ? '--enable-embed=static --disable-opcache-jit ' : '--disable-embed ') .
$json_74 .
'--enable-micro=all-static ' .
($this->zts ? '--enable-zts' : '') . ' ' .
$zts .
$maxExecutionTimers .
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
$this->makeExtensionArgs() . ' ' .
$envs
);
SourcePatcher::patchPHPAfterConfigure($this);
SourcePatcher::patchBeforeMake($this);
file_put_contents('/tmp/comment', $this->note_section);
// 清理
$this->cleanMake();
if ($bloat) {
logger()->info('bloat linking');
$extra_libs = "-Wl,--whole-archive {$extra_libs} -Wl,--no-whole-archive";
}
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
if ($enableCli) {
logger()->info('building cli');
$this->buildCli($extra_libs, $use_lld);
}
if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
if ($enableFpm) {
logger()->info('building fpm');
$this->buildFpm($extra_libs, $use_lld);
}
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro($extra_libs, $use_lld, $cflags);
}
if (php_uname('m') === $this->arch) {
$this->sanityCheck($build_target);
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 ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
if (php_uname('m') === $this->getOption('arch')) {
$this->sanityCheck($build_target);
}
}
/**
* Build cli sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildCli(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 -j' . $this->concurrency .
' 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' " .
'cli'
);
->exec("make -j{$this->concurrency} {$vars} cli");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')->exec('strip --strip-all php');
}
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')
->exec("{$this->cross_compile_prefix}objcopy --only-keep-debug php php.debug")
->exec('elfedit --output-osabi linux php')
->exec("{$this->cross_compile_prefix}strip --strip-all php")
->exec("{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php.debug --remove-section=.note php");
$this->deployBinary(BUILD_TARGET_CLI);
}
/**
* Build phpmicro sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildMicro(string $extra_libs, string $use_lld, string $cflags): void
{
@@ -270,43 +275,63 @@ class LinuxBuilder extends BuilderBase
SourcePatcher::patchMicro(['phar']);
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = SystemUtil::makeEnvVarString([
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . $enable_fake_cli,
'EXTRA_LIBS' => $extra_libs,
'EXTRA_LDFLAGS_PROGRAM' => "{$cflags} {$use_lld} -all-static",
]);
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec(
"make -j{$this->concurrency} " .
'EXTRA_CFLAGS=' . quote('-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags))) . ' ' .
'EXTRA_LIBS=' . quote($extra_libs) . ' ' .
'EXTRA_LDFLAGS_PROGRAM=' . quote("{$cflags} {$use_lld}" . ' -all-static', "'") . ' ' .
'micro'
);
->exec("make -j{$this->concurrency} {$vars} micro");
shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec("{$this->cross_compile_prefix}strip --strip-all micro.sfx");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec('strip --strip-all micro.sfx');
}
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
}
}
/**
* 构建 fpm
* Build fpm sapi
*
* @throws FileSystemException|RuntimeException
* @throws FileSystemException
* @throws RuntimeException
*/
public function buildFpm(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 -j' . $this->concurrency .
' 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' " .
'fpm'
);
->exec("make -j{$this->concurrency} {$vars} fpm");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')->exec('strip --strip-all php-fpm');
}
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')
->exec("{$this->cross_compile_prefix}objcopy --only-keep-debug php-fpm php-fpm.debug")
->exec('elfedit --output-osabi linux php-fpm')
->exec("{$this->cross_compile_prefix}strip --strip-all php-fpm")
->exec("{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php-fpm.debug --remove-section=.note php-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");
}
}

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\builder\linux;
use JetBrains\PhpStorm\ArrayShape;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
@@ -13,7 +12,7 @@ class SystemUtil
{
use UnixSystemUtilTrait;
#[ArrayShape(['dist' => 'mixed|string', 'ver' => 'mixed|string'])]
/** @noinspection PhpMissingBreakStatementInspection */
public static function getOSRelease(): array
{
$ret = [
@@ -81,6 +80,8 @@ class SystemUtil
/**
* @throws RuntimeException
* @throws WrongUsageException
* @throws WrongUsageException
*/
public static function getArchCFlags(string $cc, string $arch): string
{
@@ -120,7 +121,7 @@ class SystemUtil
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) {
return '';
}
@@ -129,6 +130,7 @@ class SystemUtil
/**
* @throws RuntimeException
* @noinspection PhpUnused
*/
public static function getCrossCompilePrefix(string $cc, string $arch): string
{
@@ -159,6 +161,7 @@ class SystemUtil
return null;
}
/** @noinspection PhpUnused */
public static function findStaticLibs(array $names): ?array
{
$ret = [];
@@ -187,6 +190,7 @@ class SystemUtil
return null;
}
/** @noinspection PhpUnused */
public static function findHeaders(array $names): ?array
{
$ret = [];

View File

@@ -8,7 +8,9 @@ use SPC\builder\BuilderBase;
use SPC\builder\LibraryBase;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\traits\UnixLibraryTrait;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
abstract class LinuxLibraryBase extends LibraryBase
{
@@ -37,12 +39,15 @@ abstract class LinuxLibraryBase extends LibraryBase
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function tryBuild(bool $force_build = false): int
{
// 传入 true表明直接编译
if ($force_build) {
logger()->info('Building required library [' . static::NAME . ']');
$this->patchBeforeBuild();
$this->build();
return BUILD_STATUS_OK;
}
@@ -70,7 +75,7 @@ abstract class LinuxLibraryBase extends LibraryBase
return BUILD_STATUS_ALREADY;
}
protected function makeFakePkgconfs()
protected function makeFakePkgconfs(): void
{
$workspace = BUILD_ROOT_PATH;
if ($workspace === '/') {

View File

@@ -8,7 +8,7 @@ class icu extends LinuxLibraryBase
{
public const NAME = 'icu';
protected function build()
protected function build(): void
{
$root = BUILD_ROOT_PATH;
$cppflag = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1"';

View 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';
}

View File

@@ -20,35 +20,54 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\SourcePatcher;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
class libpng extends LinuxLibraryBase
{
public const NAME = 'libpng';
/**
* @throws RuntimeException
* @throws FileSystemException
*/
public function build()
public function patchBeforeBuild(): bool
{
$optimizations = match ($this->builder->arch) {
FileSystem::replaceFileStr(
SOURCE_PATH . '/libpng/configure',
'-lz',
BUILD_LIB_PATH . '/libz.a'
);
if (SystemUtil::getOSRelease()['dist'] === 'alpine') {
FileSystem::replaceFileStr(
SOURCE_PATH . '/libpng/configure',
'-lm',
'/usr/lib/libm.a'
);
}
return true;
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function build(): void
{
$optimizations = match ($this->builder->getOption('arch')) {
'x86_64' => '--enable-intel-sse ',
'arm64' => '--enable-arm-neon ',
default => '',
};
// patch configure
SourcePatcher::patchUnixLibpng();
shell()->cd($this->source_dir)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
"{$this->builder->configure_env} ./configure " .
"--host={$this->builder->gnu_arch}-unknown-linux " .
"--host={$this->builder->getOption('gnu-arch')}-unknown-linux " .
'--disable-shared ' .
'--enable-static ' .
'--enable-hardware-optimizations ' .

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
@@ -13,25 +14,27 @@ class libxml2 extends LinuxLibraryBase
/**
* @throws RuntimeException
* @throws FileSystemException
*/
public function build()
public function build(): void
{
$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';
[$lib, $include, $destdir] = SEPARATED_PATH;
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')
->exec(
"{$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 ' .
'-DCMAKE_INSTALL_BINDIR=' . escapeshellarg(BUILD_ROOT_PATH . '/bin') . ' ' .
'-DLIBXML2_WITH_ICONV=ON ' .
'-DIconv_IS_BUILT_IN=OFF ' .
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
"-DLIBXML2_WITH_ICU={$enable_icu} " .
'-DLIBXML2_WITH_ICU=OFF ' .
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
'-DLIBXML2_WITH_PYTHON=OFF ' .
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
@@ -39,15 +42,6 @@ class libxml2 extends LinuxLibraryBase
'..'
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
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 . '"');
}
->exec('make install');
}
}

View 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';
}

View File

@@ -20,11 +20,20 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class nghttp2 extends LinuxLibraryBase
{
public const NAME = 'nghttp2';
public function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function build(): void
{
$args = $this->builder->makeAutoconfArgs(static::NAME, [
'zlib' => null,
@@ -49,7 +58,7 @@ class nghttp2 extends LinuxLibraryBase
"{$this->builder->configure_env} ./configure " .
'--enable-static ' .
'--disable-shared ' .
"--host={$this->builder->gnu_arch}-unknown-linux " .
"--host={$this->builder->getOption('gnu-arch')}-unknown-linux " .
'--enable-lib-only ' .
'--with-boost=no ' .
$args . ' ' .

View File

@@ -23,26 +23,28 @@ namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class openssl extends LinuxLibraryBase
{
public const NAME = 'openssl';
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function build()
public function build(): void
{
[$lib,$include,$destdir] = SEPARATED_PATH;
[,,$destdir] = SEPARATED_PATH;
$extra = '';
$ex_lib = '-ldl -pthread';
$env = $this->builder->pkgconf_env . " CFLAGS='{$this->builder->arch_c_flags}'";
$env .= " CC='{$this->builder->cc} -static -idirafter " . BUILD_INCLUDE_PATH .
$env .= " CC='{$this->builder->getOption('cc')} -static -idirafter " . BUILD_INCLUDE_PATH .
' -idirafter /usr/include/ ' .
' -idirafter /usr/include/' . $this->builder->arch . '-linux-gnu/ ' .
' -idirafter /usr/include/' . $this->builder->getOption('arch') . '-linux-gnu/ ' .
"' ";
// lib:zlib
$zlib = $this->builder->getLib('zlib');
@@ -58,7 +60,7 @@ class openssl extends LinuxLibraryBase
$ex_lib = trim($ex_lib);
$clang_postfix = SystemUtil::getCCType($this->builder->cc) === 'clang' ? '-clang' : '';
$clang_postfix = SystemUtil::getCCType($this->builder->getOption('cc')) === 'clang' ? '-clang' : '';
shell()->cd($this->source_dir)
->exec(
@@ -68,7 +70,7 @@ class openssl extends LinuxLibraryBase
'-static ' .
"{$zlib_extra}" .
'no-legacy ' .
"linux-{$this->builder->arch}{$clang_postfix}"
"linux-{$this->builder->getOption('arch')}{$clang_postfix}"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View 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';
}

View File

@@ -10,59 +10,60 @@ use SPC\builder\traits\UnixBuilderTrait;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
/**
* macOS 系统环境下的构建器
* 源于 Config但因为感觉叫 Config 不太合适,就换成了 Builder
*/
class MacOSBuilder extends BuilderBase
{
/** 编译的 Unix 工具集 */
/** Unix compatible builder methods */
use UnixBuilderTrait;
/** @var bool 标记是否 patch phar */
/** @var bool Micro patch phar flag */
private bool $phar_patched = false;
/**
* @param null|string $cc C编译器名称如果不传入则默认使用clang
* @param null|string $cxx C++编译器名称如果不传入则默认使用clang++
* @param null|string $arch 当前架构,如果不传入则默认使用当前系统架构
* @throws RuntimeException
* @throws WrongUsageException
* @throws FileSystemException
*/
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null, bool $zts = false)
public function __construct(array $options = [])
{
// 如果是 Debug 模式,才使用 set -x 显示每条执行的命令
$this->set_x = defined('DEBUG_MODE') ? 'set -x' : 'true';
// 初始化一些默认参数
$this->cc = $cc ?? 'clang';
$this->cxx = $cxx ?? 'clang++';
$this->arch = $arch ?? php_uname('m');
$this->gnu_arch = arch2gnu($this->arch);
$this->zts = $zts;
// 根据 CPU 线程数设置编译进程数
$this->concurrency = SystemUtil::getCpuCount();
// 设置 cflags
$this->arch_c_flags = SystemUtil::getArchCFlags($this->arch);
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->arch);
// 设置 cmake
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->arch, $this->arch_c_flags);
// 设置 configure 依赖的环境变量
$this->configure_env =
'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" ' .
'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' .
"CC='{$this->cc}' " .
"CXX='{$this->cxx}' " .
"CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration -Os'";
$this->options = $options;
// 创立 pkg-config 和放头文件的目录
// ---------- set necessary options ----------
// set C Compiler (default: clang)
$this->setOptionIfNotExist('cc', 'clang');
// set C++ Composer (default: clang++)
$this->setOptionIfNotExist('cxx', 'clang++');
// set arch (default: current)
$this->setOptionIfNotExist('arch', php_uname('m'));
$this->setOptionIfNotExist('gnu-arch', arch2gnu($this->getOption('arch')));
// ---------- set necessary compile environments ----------
// concurrency
$this->concurrency = SystemUtil::getCpuCount();
// cflags
$this->arch_c_flags = SystemUtil::getArchCFlags($this->getOption('arch'));
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->getOption('arch'));
// cmake toolchain
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->getOption('arch'), $this->arch_c_flags);
// configure environment
$this->configure_env = SystemUtil::makeEnvVarString([
'PKG_CONFIG' => BUILD_ROOT_PATH . '/bin/pkg-config',
'PKG_CONFIG_PATH' => BUILD_LIB_PATH . '/pkgconfig/',
'CC' => $this->getOption('cc'),
'CXX' => $this->getOption('cxx'),
'CFLAGS' => "{$this->arch_c_flags} -Wimplicit-function-declaration -Os",
'PATH' => BUILD_ROOT_PATH . '/bin:' . getenv('PATH'),
]);
// create pkgconfig and include dir (some libs cannot create them automatically)
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
}
/**
* 生成库构建采用的 autoconf 参数列表
* [deprecated] 生成库构建采用的 autoconf 参数列表
*
* @param string $name 要构建的 lib 库名,传入仅供输出日志
* @param array $lib_specs 依赖的 lib 库的 autoconf 文件
@@ -76,7 +77,6 @@ class MacOSBuilder extends BuilderBase
$arr = $arr ?? [];
$disableArgs = $arr[0] ?? null;
$prefix = $arr[1] ?? null;
if ($lib instanceof MacOSLibraryBase) {
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
$ret .= '--with-' . $libName . '=yes ';
@@ -89,9 +89,11 @@ class MacOSBuilder extends BuilderBase
}
/**
* 返回 macOS 系统依赖的框架列表
* Get dynamically linked macOS frameworks
*
* @param bool $asString 是否以字符串形式返回(默认为 False
* @param bool $asString If true, return as string
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getFrameworks(bool $asString = false): array|string
{
@@ -118,113 +120,120 @@ class MacOSBuilder extends BuilderBase
}
/**
* Just start to build statically linked php binary
*
* @param int $build_target build target
* @param bool $bloat just raw add all lib files
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false): void
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
$extra_libs = $this->getFrameworks(true) . ' ' . ($this->hasCppExtension() ? '-lc++ ' : '');
if (!$bloat) {
$extra_libs .= implode(' ', $this->getAllStaticLibFiles());
// ---------- Update extra-libs ----------
$extra_libs = $this->getOption('extra-libs', '');
// add macOS frameworks
$extra_libs .= (empty($extra_libs) ? '' : ' ') . $this->getFrameworks(true);
// add libc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCppExtension() ? '-lc++ ' : '');
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
logger()->info('bloat linking');
$extra_libs .= implode(
' ',
array_map(
fn ($x) => "-Wl,-force_load,{$x}",
array_filter($this->getAllStaticLibFiles())
)
);
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles())));
}
$this->setOption('extra-libs', $extra_libs);
// patch before configure
SourcePatcher::patchPHPBuildconf($this);
SourcePatcher::patchBeforeBuildconf($this);
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
SourcePatcher::patchPHPConfigure($this);
SourcePatcher::patchBeforeConfigure($this);
if ($this->getLib('libxml2') || $this->getExt('iconv')) {
$extra_libs .= ' -liconv';
}
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
$zts = $this->getOption('enable-zts', false) ? '--enable-zts --disable-zend-signals ' : '';
if ($this->getPHPVersionID() < 80000) {
$json_74 = '--enable-json ';
} else {
$json_74 = '';
}
$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')
->exec(
'./configure ' .
'--prefix= ' .
'--with-valgrind=no ' . // 不检测内存泄漏
'--with-valgrind=no ' . // Not detect memory leak
'--enable-shared=no ' .
'--enable-static=yes ' .
"CFLAGS='{$this->arch_c_flags} -Werror=unknown-warning-option' " .
'--disable-all ' .
'--disable-cgi ' .
'--disable-phpdbg ' .
'--enable-cli ' .
'--enable-fpm ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
($enableEmbed ? '--enable-embed=static ' : '--disable-embed ') .
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
$json_74 .
'--enable-micro ' .
($this->zts ? '--enable-zts' : '') . ' ' .
$zts .
$this->makeExtensionArgs() . ' ' .
$this->configure_env
);
SourcePatcher::patchPHPAfterConfigure($this);
SourcePatcher::patchBeforeMake($this);
$this->cleanMake();
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
if ($enableCli) {
logger()->info('building cli');
$this->buildCli($extra_libs);
$this->buildCli();
}
if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
if ($enableFpm) {
logger()->info('building fpm');
$this->buildFpm($extra_libs);
$this->buildFpm();
}
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro($extra_libs);
$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->arch) {
if (php_uname('m') === $this->getOption('arch')) {
$this->sanityCheck($build_target);
}
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
}
}
/**
* 构建 cli
* Build cli sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildCli(string $extra_libs): void
public function buildCli(): 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 = shell()->cd(SOURCE_PATH . '/php-src');
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli");
if ($this->strip) {
$shell->exec("make -j{$this->concurrency} {$vars} cli");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php');
}
$this->deployBinary(BUILD_TARGET_CLI);
}
/**
* 构建 phpmicro
* Build phpmicro sapi
*
* @throws FileSystemException|RuntimeException
*/
public function buildMicro(string $extra_libs): void
public function buildMicro(): void
{
if ($this->getPHPVersionID() < 80000) {
throw new RuntimeException('phpmicro only support PHP >= 8.0!');
@@ -234,24 +243,65 @@ class MacOSBuilder extends BuilderBase
SourcePatcher::patchMicro(['phar']);
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = [
// with debug information, optimize for size, remove identifiers, patch fake cli for micro
'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli,
// link resolv library (macOS needs it)
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv",
];
if (!$this->getOption('no-strip', false)) {
$vars['STRIP'] = 'dsymutil -f ';
}
$vars = SystemUtil::makeEnvVarString($vars);
shell()->cd(SOURCE_PATH . '/php-src')
->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" " . ($this->strip ? 'STRIP="dsymutil -f " ' : '') . 'micro');
->exec("make -j{$this->concurrency} {$vars} micro");
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
}
}
/**
* 构建 fpm
* Build fpm sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildFpm(string $extra_libs): void
public function buildFpm(): 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 = shell()->cd(SOURCE_PATH . '/php-src');
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" fpm");
if ($this->strip) {
$shell->exec("make -j{$this->concurrency} {$vars} fpm");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip sapi/fpm/php-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');
}
}

View File

@@ -10,11 +10,11 @@ use SPC\exception\WrongUsageException;
class SystemUtil
{
/** macOS 兼容 unix 的系统工具 */
/** Unix System Util Compatible */
use UnixSystemUtilTrait;
/**
* 获取系统 CPU 逻辑内核数
* Get Logic CPU Count for macOS
*
* @throws RuntimeException
*/
@@ -29,9 +29,10 @@ class SystemUtil
}
/**
* 获取不同架构对应的 cflags 参数
* Get Target Arch CFlags
*
* @param string $arch 架构名称
* @param string $arch Arch Name
* @return string return Arch CFlags string
* @throws WrongUsageException
*/
public static function getArchCFlags(string $arch): string

View File

@@ -8,6 +8,8 @@ use SPC\builder\BuilderBase;
use SPC\builder\LibraryBase;
use SPC\builder\macos\MacOSBuilder;
use SPC\builder\traits\UnixLibraryTrait;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
abstract class MacOSLibraryBase extends LibraryBase
@@ -27,7 +29,8 @@ abstract class MacOSLibraryBase extends LibraryBase
}
/**
* 获取当前 lib 库依赖的 macOS framework
* @throws WrongUsageException
* @throws FileSystemException
*/
public function getFrameworks(): array
{

View File

@@ -20,19 +20,30 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\store\SourcePatcher;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
class curl extends MacOSLibraryBase
{
use \SPC\builder\unix\library\curl {
build as unixBuild;
}
use \SPC\builder\unix\library\curl;
public const NAME = 'curl';
protected function build()
/**
* @throws FileSystemException
*/
public function patchBeforeBuild(): bool
{
SourcePatcher::patchCurlMacOS();
$this->unixBuild();
FileSystem::replaceFileRegex(
SOURCE_PATH . '/curl/CMakeLists.txt',
'/NOT COREFOUNDATION_FRAMEWORK/m',
'FALSE'
);
FileSystem::replaceFileRegex(
SOURCE_PATH . '/curl/CMakeLists.txt',
'/NOT SYSTEMCONFIGURATION_FRAMEWORK/m',
'FALSE'
);
return true;
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
class glfw extends MacOSLibraryBase
{
public const NAME = 'glfw';
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
// compile
shell()->cd(SOURCE_PATH . '/ext-glfw/vendor/glfw')
->exec("{$this->builder->configure_env} cmake . {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF")
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
// patch pkgconf
$this->patchPkgconfPrefix(['glfw3.pc']);
}
}

View File

@@ -8,7 +8,7 @@ class icu extends MacOSLibraryBase
{
public const NAME = 'icu';
protected function build()
protected function build(): void
{
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir . '/source')

View 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';
}

View File

@@ -1,39 +1,30 @@
<?php
/**
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
*
* lwmbs is licensed under Mulan PSL v2. You can use this
* software according to the terms and conditions of the
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
*/
declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
class libffi extends MacOSLibraryBase
{
public const NAME = 'libffi';
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
[$lib, , $destdir] = SEPARATED_PATH;
[, , $destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static ' .
'--disable-shared ' .
"--host={$this->builder->arch}-apple-darwin " .
"--target={$this->builder->arch}-apple-darwin " .
"--host={$this->builder->getOption('arch')}-apple-darwin " .
"--target={$this->builder->getOption('arch')}-apple-darwin " .
'--prefix= ' // use prefix=/
)
->exec('make clean')

View File

@@ -11,7 +11,7 @@ class libmemcached extends MacOSLibraryBase
{
public const NAME = 'libmemcached';
public function build()
public function build(): void
{
$rootdir = BUILD_ROOT_PATH;

View File

@@ -22,6 +22,7 @@ namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class libpng extends MacOSLibraryBase
{
@@ -30,10 +31,11 @@ class libpng extends MacOSLibraryBase
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build()
protected function build(): void
{
$optimizations = match ($this->builder->arch) {
$optimizations = match ($this->builder->getOption('arch')) {
'x86_64' => '--enable-intel-sse ',
'arm64' => '--enable-arm-neon ',
default => '',
@@ -43,7 +45,7 @@ class libpng extends MacOSLibraryBase
->exec('chmod +x ./install-sh')
->exec(
"{$this->builder->configure_env} ./configure " .
"--host={$this->builder->gnu_arch}-apple-darwin " .
"--host={$this->builder->getOption('gnu-arch')}-apple-darwin " .
'--disable-shared ' .
'--enable-static ' .
'--enable-hardware-optimizations ' .

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
@@ -13,14 +14,22 @@ class libxml2 extends MacOSLibraryBase
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build()
protected function build(): void
{
// macOS need to link iconv dynamically, we add it to extra-libs
$extra_libs = $this->builder->getOption('extra-libs', '');
if (!str_contains($extra_libs, '-liconv')) {
$extra_libs .= ' -liconv';
}
$this->builder->setOption('extra-libs', $extra_libs);
$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';
[$lib, $include, $destdir] = SEPARATED_PATH;
[, , $destdir] = SEPARATED_PATH;
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')

View 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';
}

View File

@@ -20,11 +20,18 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
class nghttp2 extends MacOSLibraryBase
{
public const NAME = 'nghttp2';
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
$args = $this->builder->makeAutoconfArgs(static::NAME, [
'zlib' => null,
@@ -49,7 +56,7 @@ class nghttp2 extends MacOSLibraryBase
"{$this->builder->configure_env} " . ' ./configure ' .
'--enable-static ' .
'--disable-shared ' .
"--host={$this->builder->gnu_arch}-apple-darwin " .
"--host={$this->builder->getOption('gnu-arch')}-apple-darwin " .
'--enable-lib-only ' .
'--with-boost=no ' .
$args . ' ' .

View File

@@ -20,11 +20,20 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class openssl extends MacOSLibraryBase
{
public const NAME = 'openssl';
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build(): void
{
[$lib,,$destdir] = SEPARATED_PATH;
@@ -43,7 +52,7 @@ class openssl extends MacOSLibraryBase
'--prefix=/ ' . // use prefix=/
"--libdir={$lib} " .
'--openssldir=/System/Library/OpenSSL ' .
"darwin64-{$this->builder->arch}-cc"
"darwin64-{$this->builder->getOption('arch')}-cc"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View 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';
}

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace SPC\builder\traits;
trait LibraryTrait
{
}
trait LibraryTrait {}

View File

@@ -7,31 +7,27 @@ namespace SPC\builder\traits;
use SPC\builder\linux\LinuxBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait UnixBuilderTrait
{
/** @var string 设置的命令前缀,设置为 set -x 可以在终端打印命令 */
public string $set_x = 'set -x';
/** @var string C 编译器命令 */
public string $cc;
/** @var string C++ 编译器命令 */
public string $cxx;
/** @var string cflags 参数 */
/** @var string cflags */
public string $arch_c_flags;
/** @var string C++ flags 参数 */
/** @var string C++ flags */
public string $arch_cxx_flags;
/** @var string cmake toolchain file */
public string $cmake_toolchain_file;
/** @var string configure 环境依赖的变量 */
/** @var string configure environments */
public string $configure_env;
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public function getAllStaticLibFiles(): array
{
$libs = [];
@@ -70,14 +66,23 @@ trait UnixBuilderTrait
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new RuntimeException('cli failed sanity check');
}
foreach ($this->exts as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $ext->getDistName() . '"', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $ext->getName() . ' failed compile check');
}
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) {
throw new RuntimeException('extension ' . $ext->getName() . ' failed sanity check');
}
@@ -125,7 +130,7 @@ trait UnixBuilderTrait
}
/**
* 清理编译好的文件
* Run php clean
*
* @throws RuntimeException
*/
@@ -141,11 +146,33 @@ trait UnixBuilderTrait
public function makeCmakeArgs(): string
{
[$lib, $include] = SEPARATED_PATH;
$extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . $this->cc . ' ' : '';
$extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . $this->getOption('cc') . ' ' : '';
return $extra . '-DCMAKE_BUILD_TYPE=Release ' .
'-DCMAKE_INSTALL_PREFIX=/ ' .
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
"-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;
}
}

View File

@@ -7,6 +7,7 @@ namespace SPC\builder\traits;
use SPC\builder\LibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait UnixLibraryTrait
@@ -16,6 +17,7 @@ trait UnixLibraryTrait
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
{
@@ -43,6 +45,11 @@ trait UnixLibraryTrait
return implode($sep, $ret);
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function makeAutoconfEnv(string $prefix = null): string
{
if ($prefix === null) {
@@ -59,7 +66,7 @@ trait UnixLibraryTrait
* @throws FileSystemException
* @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');
foreach ($files as $name) {
@@ -74,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_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_CUSTOM) === PKGCONF_PATCH_CUSTOM && $custom_replace !== null ? preg_replace($custom_replace[0], $custom_replace[1], $file) : $file;
FileSystem::writeFile($realpath, $file);
}
}
@@ -82,7 +90,7 @@ trait UnixLibraryTrait
* remove libtool archive files
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function cleanLaFiles(): void
{

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\traits;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
/**
@@ -14,11 +15,12 @@ trait UnixSystemUtilTrait
/**
* 生成 toolchain.cmake用于 cmake 构建
*
* @param string $os 操作系统代号
* @param string $target_arch 目标架构
* @param string $cflags CFLAGS 参数
* @param null|string $cc CC 参数(默认空)
* @param null|string $cxx CXX 参数(默认空)
* @param string $os 操作系统代号
* @param string $target_arch 目标架构
* @param string $cflags CFLAGS 参数
* @param null|string $cc CC 参数(默认空)
* @param null|string $cxx CXX 参数(默认空)
* @throws FileSystemException
*/
public static function makeCmakeToolchainFile(
string $os,
@@ -76,4 +78,20 @@ CMAKE;
}
return null;
}
/**
* @param array $vars Variables, like: ["CFLAGS" => "-Ixxx"]
* @return string like: CFLAGS="-Ixxx"
*/
public static function makeEnvVarString(array $vars): string
{
$str = '';
foreach ($vars as $key => $value) {
if ($str !== '') {
$str .= ' ';
}
$str .= $key . '=' . escapeshellarg($value);
}
return $str;
}
}

View File

@@ -4,10 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait brotli
{
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
FileSystem::resetDir($this->source_dir . '/build-dir');
@@ -22,9 +28,9 @@ trait brotli
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
shell()->cd(BUILD_ROOT_PATH . '/lib')
->exec('ln -s libbrotlicommon-static.a libbrotlicommon.a')
->exec('ln -s libbrotlidec-static.a libbrotlidec.a')
->exec('ln -s libbrotlienc-static.a libbrotlienc.a');
->exec('ln -s libbrotlicommon.a libbrotlicommon-static.a')
->exec('ln -s libbrotlidec.a libbrotlidec-static.a')
->exec('ln -s libbrotlienc.a libbrotlienc-static.a');
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'))) {
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);

View File

@@ -4,11 +4,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait curl
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
$extra = '';
// lib:openssl
@@ -33,8 +39,8 @@ trait curl
} else {
$extra .= '-DUSE_NGHTTP2=OFF ';
}
// TODO: ldap is not supported yet
$extra .= '-DCURL_DISABLE_LDAP=ON ';
// lib:ldap
$extra .= $this->builder->getLib('ldap') ? '-DCURL_DISABLE_LDAP=OFF ' : '-DCURL_DISABLE_LDAP=ON ';
// lib:zstd
$extra .= $this->builder->getLib('zstd') ? '-DCURL_ZSTD=ON ' : '-DCURL_ZSTD=OFF ';
// lib:idn2
@@ -45,6 +51,7 @@ trait curl
FileSystem::resetDir($this->source_dir . '/build');
// compile
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("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);

View File

@@ -4,11 +4,19 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait freetype
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build(): void
{
$suggested = $this->builder->getLib('libpng') ? '--with-png' : '--without-png';
$suggested .= ' ';
@@ -27,9 +35,8 @@ trait freetype
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['freetype2.pc']);
FileSystem::replaceFile(
FileSystem::replaceFileStr(
BUILD_ROOT_PATH . '/lib/pkgconfig/freetype2.pc',
REPLACE_FILE_STR,
' -L/lib ',
' -L' . BUILD_ROOT_PATH . '/lib '
);

View File

@@ -4,9 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait gmp
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(

View File

@@ -4,10 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait imagemagick
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
$extra = '--without-jxl --without-xml --without-zstd --without-x --disable-openmp ';
@@ -46,9 +52,8 @@ trait imagemagick
];
$this->patchPkgconfPrefix($filelist);
foreach ($filelist as $file) {
FileSystem::replaceFile(
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/pkgconfig/' . $file,
REPLACE_FILE_PREG,
'#includearchdir=/include/ImageMagick-7#m',
'includearchdir=${prefix}/include/ImageMagick-7'
);

View 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']);
}
}

View File

@@ -4,11 +4,19 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait libavif
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build(): void
{
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');

View File

@@ -4,11 +4,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libevent
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');
@@ -29,6 +35,5 @@ trait libevent
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec('make install');
// patch pkgconfig
}
}

View File

@@ -6,7 +6,7 @@ namespace SPC\builder\unix\library;
trait libiconv
{
protected function build()
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;

View File

@@ -4,11 +4,19 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait libjpeg
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build(): void
{
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');

View File

@@ -6,7 +6,7 @@ namespace SPC\builder\unix\library;
trait libsodium
{
protected function build()
protected function build(): void
{
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir)

View File

@@ -4,11 +4,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libssh2
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
$enable_zlib = $this->builder->getLib('zlib') !== null ? 'ON' : 'OFF';
@@ -23,7 +29,7 @@ trait libssh2
"-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);
$this->patchPkgconfPrefix(['libssh2.pc']);
}

View File

@@ -4,30 +4,36 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
trait libwebp
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)
->exec('./autogen.sh')
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');
// Start build
shell()->cd($this->source_dir . '/build')
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static ' .
'--disable-shared ' .
'--prefix= ' .
'--enable-libwebpdecoder ' .
'--enable-libwebpextras ' .
'--disable-tiff ' .
'--disable-gl ' .
'--disable-sdl ' .
'--disable-wic'
"{$this->builder->configure_env} cmake " .
$this->builder->makeCmakeArgs() . ' ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DWEBP_BUILD_EXTRAS=ON ' .
'..'
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . $destdir);
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX);
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
// patch pkgconfig
$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();
}
}

View 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']);
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
@@ -11,8 +12,9 @@ trait libyaml
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build()
protected function build(): void
{
// prepare cmake/config.h.in
if (!is_file(SOURCE_PATH . '/libyaml/cmake/config.h.in')) {

View File

@@ -4,11 +4,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libzip
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
$extra = '';
// lib:bzip2

View File

@@ -6,7 +6,7 @@ namespace SPC\builder\unix\library;
trait ncurses
{
protected function build()
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(

View File

@@ -4,9 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait onig
{
protected function build()
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;

View File

@@ -6,20 +6,16 @@ namespace SPC\builder\unix\library;
trait pkgconfig
{
protected function build()
protected function build(): void
{
$macos_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' .
"CC='{$this->builder->cc}' " .
"CXX='{$this->builder->cxx}' " .
"CC='{$this->builder->getOption('cc')}' " .
"CXX='{$this->builder->getOption('cxx')}' " .
"CFLAGS='{$this->builder->arch_c_flags} -Wimplicit-function-declaration' ";
$linux_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig" ' .
"CC='{$this->builder->cc}' " .
"CXX='{$this->builder->cxx}' ";
"CC='{$this->builder->getOption('cc')}' " .
"CXX='{$this->builder->getOption('cxx')}' ";
$extra = match (PHP_OS_FAMILY) {
'Darwin' => '',
default => '--with-internal-glib ',
};
shell()->cd($this->source_dir)
->exec(
match (PHP_OS_FAMILY) {
@@ -29,7 +25,7 @@ trait pkgconfig
'./configure ' .
'--disable-shared ' .
'--enable-static ' .
$extra .
'--with-internal-glib ' .
'--prefix=' . BUILD_ROOT_PATH . ' ' .
'--without-sysroot ' .
'--without-system-include-path ' .

View File

@@ -15,7 +15,7 @@ trait postgresql
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build()
protected function build(): void
{
$builddir = BUILD_ROOT_PATH;
$env = $this->builder->configure_env;
@@ -57,15 +57,14 @@ trait postgresql
'--with-ssl=openssl ' .
'--with-readline ' .
'--with-libxml ' .
($this->builder->getLib('ldap') ? '--with-ldap ' : '--without-ldap ') .
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
'--without-ldap ' .
'--without-libxslt ' .
'--without-lz4 ' .
'--without-zstd ' .
'--without-perl ' .
'--without-python ' .
'--without-pam ' .
'--without-ldap ' .
'--without-bonjour ' .
'--without-tcl '
);

View File

@@ -4,9 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait readline
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(

View 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');
}
}

View File

@@ -6,7 +6,7 @@ namespace SPC\builder\unix\library;
trait sqlite
{
protected function build()
protected function build(): void
{
shell()->cd($this->source_dir)
->exec("{$this->builder->configure_env} ./configure --enable-static --disable-shared --prefix=")

View File

@@ -4,16 +4,23 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait xz
{
public function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
public function build(): void
{
shell()->cd($this->source_dir)
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static ' .
'--disable-shared ' .
"--host={$this->builder->gnu_arch}-unknown-linux " .
"--host={$this->builder->getOption('gnu-arch')}-unknown-linux " .
'--disable-scripts ' .
'--disable-doc ' .
'--with-libiconv ' .

View File

@@ -4,9 +4,16 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
trait zlib
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;

View File

@@ -4,11 +4,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait zstd
{
protected function build()
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
FileSystem::resetDir($this->source_dir . '/build/cmake/build');
shell()->cd($this->source_dir . '/build/cmake/build')

View File

@@ -17,16 +17,8 @@ abstract class BaseCommand extends Command
{
protected bool $no_motd = false;
/**
* 输入
*/
protected InputInterface $input;
/**
* 输出
*
* 一般来说同样会是 ConsoleOutputInterface
*/
protected OutputInterface $output;
public function __construct(string $name = null)
@@ -36,12 +28,12 @@ abstract class BaseCommand extends Command
$this->addOption('no-motd', null, null, 'Disable motd');
}
public function initialize(InputInterface $input, OutputInterface $output)
public function initialize(InputInterface $input, OutputInterface $output): void
{
if ($input->getOption('no-motd')) {
$this->no_motd = true;
}
// 注册全局错误处理器
set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) {
$tips = [
E_WARNING => ['PHP Warning: ', 'warning'],
@@ -77,6 +69,9 @@ abstract class BaseCommand extends Command
}
}
/**
* @throws WrongUsageException
*/
abstract public function handle(): int;
protected function execute(InputInterface $input, OutputInterface $output): int
@@ -91,9 +86,8 @@ abstract class BaseCommand extends Command
foreach ($msg as $v) {
logger()->error($v);
}
return self::FAILURE;
return static::FAILURE;
} catch (\Throwable $e) {
// 不开 debug 模式就不要再显示复杂的调试栈信息了
if ($this->getOption('debug')) {
ExceptionHandler::getInstance()->handle($e);
} else {
@@ -102,10 +96,10 @@ abstract class BaseCommand extends Command
logger()->error($v);
}
}
return self::FAILURE;
return static::FAILURE;
}
}
return self::SUCCESS;
return static::SUCCESS;
}
protected function getOption(string $name): mixed
@@ -118,11 +112,6 @@ abstract class BaseCommand extends Command
return $this->input->getArgument($name);
}
/**
* 是否应该执行
*
* @return bool 返回 true 以继续执行,返回 false 以中断执行
*/
protected function shouldExecute(): bool
{
return true;

View File

@@ -7,6 +7,7 @@ namespace SPC\command;
use SPC\builder\BuilderProvider;
use SPC\exception\ExceptionHandler;
use SPC\exception\WrongUsageException;
use SPC\store\SourcePatcher;
use SPC\util\DependencyUtil;
use SPC\util\LicenseDumper;
use Symfony\Component\Console\Attribute\AsCommand;
@@ -17,44 +18,47 @@ use ZM\Logger\ConsoleColor;
#[AsCommand('build', 'build CLI binary')]
class BuildCliCommand extends BuildCommand
{
public function configure()
public function configure(): void
{
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
$this->addOption('build-micro', null, null, 'build micro');
$this->addOption('build-cli', null, null, 'build cli');
$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('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-micro-fake-cli', null, null, 'Enable phpmicro fake cli');
}
public function handle(): int
{
// 从参数中获取要编译的 libraries并转换为数组
// transform string to array
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
// 从参数中获取要编译的 extensions并转换为数组
// transform string to array
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
define('BUILD_ALL_STATIC', true);
$rule = BUILD_TARGET_NONE;
$rule = $rule | ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
$rule = $rule | ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
$rule = $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-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : 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) {
$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-micro\tBuild phpmicro 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>");
return 1;
$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;
}
try {
// 构建对象
// create builder
$builder = BuilderProvider::makeBuilderByInput($this->input);
// 根据提供的扩展列表获取依赖库列表并编译
// calculate dependencies
[$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions, $libraries);
/* @phpstan-ignore-next-line */
logger()->info('Build target: ' . ConsoleColor::yellow($builder->getBuildTypeName($rule)));
@@ -66,17 +70,30 @@ class BuildCliCommand extends BuildCommand
logger()->warning('some extensions will be enabled due to dependencies: ' . implode(',', $not_included));
}
sleep(2);
// 编译和检查库是否完整
// compile libraries
$builder->buildLibs($libraries);
// 执行扩展检测
// check extensions
$builder->proveExts($extensions);
// strip
$builder->setStrip(!$this->getOption('no-strip'));
// 构建
$builder->buildPHP($rule, $this->getOption('bloat'));
// 统计时间
// Process -I option
$custom_ini = [];
foreach ($this->input->getOption('with-hardcoded-ini') as $value) {
[$source_name, $ini_value] = explode('=', $value, 2);
$custom_ini[$source_name] = $ini_value;
logger()->info('Adding hardcoded INI [' . $source_name . ' = ' . $ini_value . ']');
}
if (!empty($custom_ini)) {
SourcePatcher::patchHardcodedINI($custom_ini);
}
// start to build
$builder->buildPHP($rule);
// compile stopwatch :P
$time = round(microtime(true) - START_TIME, 3);
logger()->info('Build complete, used ' . $time . ' s !');
// ---------- When using bin/spc-alpine-docker, the build root path is different from the host system ----------
$build_root_path = BUILD_ROOT_PATH;
$cwd = getcwd();
$fixed = '';
@@ -94,17 +111,19 @@ class BuildCliCommand extends BuildCommand
if (($rule & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
logger()->info('Static php-fpm binary path' . $fixed . ': ' . $build_root_path . '/bin/php-fpm');
}
// 导出相关元数据
// export metadata
file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
file_put_contents(BUILD_ROOT_PATH . '/build-libraries.json', json_encode($libraries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
// 导出 LICENSE
// export licenses
$dumper = new LicenseDumper();
$dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
logger()->info('License path' . $fixed . ': ' . $build_root_path . '/license/');
return 0;
return static::SUCCESS;
} catch (WrongUsageException $e) {
// WrongUsageException is not an exception, it's a user error, so we just print the error message
logger()->critical($e->getMessage());
return 1;
return static::FAILURE;
} catch (\Throwable $e) {
if ($this->getOption('debug')) {
ExceptionHandler::getInstance()->handle($e);
@@ -112,7 +131,7 @@ class BuildCliCommand extends BuildCommand
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
logger()->critical('Please check with --debug option to see more details.');
}
return 1;
return static::FAILURE;
}
}
}

View File

@@ -12,7 +12,6 @@ abstract class BuildCommand extends BaseCommand
{
parent::__construct($name);
// 根据运行的操作系统分配允许不同的命令行参数Windows 需要额外的 VS 和 SDK等*nix 需要提供架构
switch (PHP_OS_FAMILY) {
case 'Windows':
$this->addOption('with-sdk-binary-dir', null, InputOption::VALUE_REQUIRED, 'path to binary sdk');
@@ -29,9 +28,7 @@ abstract class BuildCommand extends BaseCommand
break;
}
// 是否在编译 make 前清除旧的文件
$this->addOption('with-clean', null, null, 'fresh build, `make clean` before `make`');
// 是否采用强制链接,让链接器强制加载静态库文件
$this->addOption('bloat', null, null, 'add all libraries into binary');
}
}

View File

@@ -15,14 +15,15 @@ use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand('build:libs', 'Build dependencies')]
class BuildLibsCommand extends BuildCommand
{
public function configure()
public function configure(): void
{
$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('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)
public function initialize(InputInterface $input, OutputInterface $output): void
{
// --all 等于 ""
if ($input->getOption('all')) {
@@ -63,7 +64,7 @@ class BuildLibsCommand extends BuildCommand
$time = round(microtime(true) - START_TIME, 3);
logger()->info('Build libs complete, used ' . $time . ' s !');
return 0;
return static::SUCCESS;
} catch (\Throwable $e) {
if ($this->getOption('debug')) {
ExceptionHandler::getInstance()->handle($e);
@@ -71,7 +72,7 @@ class BuildLibsCommand extends BuildCommand
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
logger()->critical('Please check with --debug option to see more details.');
}
return 1;
return static::FAILURE;
}
}
}

View File

@@ -1,131 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\command;
use CliHelper\Tools\ArgFixer;
use CliHelper\Tools\DataProvider;
use CliHelper\Tools\SeekableArrayIterator;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
#[AsCommand('deploy', 'Deploy static-php-cli self to an .phar application')]
class DeployCommand extends BaseCommand
{
public function configure()
{
$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.');
}
public function handle(): int
{
// 第一阶段流程如果没有写path将会提示输入要打包的path
$prompt = new ArgFixer($this->input, $this->output);
// 首先得确认是不是关闭了readonly模式
if (ini_get('phar.readonly') == 1) {
if ($this->getOption('auto-phar-fix')) {
$ask = true;
} else {
$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']);
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('切换到读写模式失败,请检查环境。');
}
} 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 = $prompt->requireArgument('target', 'Please input the phar target filename', 'static-php-cli.phar');
if (DataProvider::isRelativePath($phar_path)) {
$phar_path = '/tmp/' . $phar_path;
}
if (file_exists($phar_path)) {
$ask = $this->getOption('overwrite') ? true : $prompt->requireBool('<comment>The file "' . $phar_path . '" already exists, do you want to overwrite it?</comment>' . PHP_EOL . 'If you want to, just Enter');
if (!$ask) {
$this->output->writeln('<comment>User canceled.</comment>');
return 1;
}
@unlink($phar_path);
}
$phar = new \Phar($phar_path);
$phar->startBuffering();
$all = DataProvider::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 1;
}
$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 0;
}
private function progress(int $max = 0): ProgressBar
{
$progress = new ProgressBar($this->output, $max);
$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;
}
}

Some files were not shown because too many files have changed in this diff Show More