mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-04 07:15:38 +08:00
Compare commits
75 Commits
2.1.0-beta
...
2.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4d8e5e4d2 | ||
|
|
88796bc017 | ||
|
|
e23daaa355 | ||
|
|
71017361b5 | ||
|
|
d202de3f50 | ||
|
|
03510073c6 | ||
|
|
8e58592a6e | ||
|
|
96dd5ba87b | ||
|
|
d4c0290195 | ||
|
|
f5d1df5407 | ||
|
|
9664709f21 | ||
|
|
b46655ecfe | ||
|
|
842e0add29 | ||
|
|
254764761d | ||
|
|
5f6c1a0f40 | ||
|
|
d5dcd193cf | ||
|
|
5012da96be | ||
|
|
df0e37cd0f | ||
|
|
4ab7b6bfdc | ||
|
|
f498250001 | ||
|
|
3945ac037b | ||
|
|
b0d8b00fcc | ||
|
|
62b0bf8af0 | ||
|
|
905e080770 | ||
|
|
097ecd3fb0 | ||
|
|
b9359759dd | ||
|
|
50fe366c42 | ||
|
|
9dd89e6b02 | ||
|
|
c03220d1ee | ||
|
|
9db843ab66 | ||
|
|
304973d9bc | ||
|
|
ab386f820c | ||
|
|
4adf1f5e2e | ||
|
|
b4ae87585c | ||
|
|
ae3298472d | ||
|
|
d241cb993e | ||
|
|
8376122634 | ||
|
|
a30e054d7d | ||
|
|
78f4317660 | ||
|
|
3ac3dab6c8 | ||
|
|
1a7e436ee1 | ||
|
|
f11b36ab3c | ||
|
|
e2ef195a84 | ||
|
|
645e2a9fc2 | ||
|
|
d59b8457c6 | ||
|
|
a2d1262cbf | ||
|
|
2f9a1e8601 | ||
|
|
b239f60fe4 | ||
|
|
983521e225 | ||
|
|
aeed04a5ec | ||
|
|
faed569e8a | ||
|
|
49ddb3ec13 | ||
|
|
71c0387ab0 | ||
|
|
e5d2d5e689 | ||
|
|
be2394b39b | ||
|
|
158298b96c | ||
|
|
ffa84f8b91 | ||
|
|
0954ddcc96 | ||
|
|
d9bd96af71 | ||
|
|
2649dcd05c | ||
|
|
939db75268 | ||
|
|
227bf73870 | ||
|
|
05e3898e7a | ||
|
|
9777c9aa93 | ||
|
|
b8d8461e61 | ||
|
|
b977543c72 | ||
|
|
4d87cd11cc | ||
|
|
957daf0547 | ||
|
|
3dae904122 | ||
|
|
e835196972 | ||
|
|
52ed0e2cee | ||
|
|
1e898d271d | ||
|
|
39754cde59 | ||
|
|
a6f7b938e1 | ||
|
|
0ad501af9a |
53
.github/workflows/release-build.yml
vendored
53
.github/workflows/release-build.yml
vendored
@@ -15,14 +15,15 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
php-version:
|
php-version:
|
||||||
- "8.1"
|
- "8.2"
|
||||||
micro-version:
|
micro-version:
|
||||||
- "8.1.26"
|
- "8.2.16"
|
||||||
operating-system:
|
operating-system:
|
||||||
- "linux-x86_64"
|
- "linux-x86_64"
|
||||||
- "macos-x86_64"
|
- "macos-x86_64"
|
||||||
- "linux-aarch64"
|
- "linux-aarch64"
|
||||||
- "macos-aarch64"
|
- "macos-aarch64"
|
||||||
|
- "windows-x64"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v4"
|
uses: "actions/checkout@v4"
|
||||||
@@ -59,31 +60,51 @@ jobs:
|
|||||||
|
|
||||||
- name: "Download minimal combination"
|
- name: "Download minimal combination"
|
||||||
run: |
|
run: |
|
||||||
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ matrix.micro-version }}-micro-${{ matrix.operating-system }}.tar.gz -o tmp.tgz
|
if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
|
||||||
tar -zxvf tmp.tgz
|
curl https://dl.static-php.dev/static-php-cli/windows/spc-min/php-${{ matrix.micro-version }}-micro-win.zip -o tmp.zip
|
||||||
|
unzip tmp.zip
|
||||||
|
else
|
||||||
|
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ matrix.micro-version }}-micro-${{ matrix.operating-system }}.tar.gz -o tmp.tgz
|
||||||
|
tar -zxvf tmp.tgz
|
||||||
|
fi
|
||||||
|
|
||||||
- name: "Generate Executable"
|
- name: "Generate Executable"
|
||||||
run: |
|
run: |
|
||||||
cat micro.sfx spc.phar > spc
|
bin/spc micro:combine spc.phar -M micro.sfx -O spc -I "memory_limit=2G"
|
||||||
chmod +x spc
|
if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
|
||||||
|
mv spc spc.exe
|
||||||
|
else
|
||||||
|
chmod +x spc
|
||||||
|
fi
|
||||||
|
|
||||||
- name: "Archive Executable"
|
- name: "Archive Executable"
|
||||||
run: |
|
run: |
|
||||||
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
|
if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
|
||||||
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
|
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
|
||||||
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
|
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
|
||||||
if [ "${{ matrix.operating-system }}" == "linux-x86_64" ]; then
|
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
|
||||||
./spc dev:extensions
|
if [ "${{ matrix.operating-system }}" == "linux-x86_64" ]; then
|
||||||
|
./spc dev:extensions
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "filename=spc-${{ matrix.operating-system }}.exe" >> $GITHUB_ENV
|
||||||
|
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: "Copy file"
|
- name: "Copy file"
|
||||||
run: "mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS"
|
run: |
|
||||||
|
if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
|
||||||
|
mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS
|
||||||
|
else
|
||||||
|
mkdir dist/ && cp spc.exe dist/${{ env.filename }}
|
||||||
|
echo "SUFFIX=.exe" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
- name: upload binaries to release
|
- name: upload binaries to release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
if: ${{startsWith(github.ref, 'refs/tags/') }}
|
if: ${{startsWith(github.ref, 'refs/tags/') }}
|
||||||
with:
|
with:
|
||||||
files: ${{ env.filename }}
|
files: dist/${{ env.filename }}
|
||||||
|
|
||||||
- name: "Deploy to Self-Hosted Server"
|
- name: "Deploy to Self-Hosted Server"
|
||||||
if: github.repository == 'crazywhalecc/static-php-cli'
|
if: github.repository == 'crazywhalecc/static-php-cli'
|
||||||
@@ -100,5 +121,5 @@ jobs:
|
|||||||
- name: "Upload Artifact"
|
- name: "Upload Artifact"
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: spc
|
path: spc${{ env.SUFFIX }}
|
||||||
name: spc-${{ matrix.operating-system }}
|
name: spc-${{ matrix.operating-system }}${{ env.SUFFIX }}
|
||||||
|
|||||||
15
.github/workflows/tests.yml
vendored
15
.github/workflows/tests.yml
vendored
@@ -129,6 +129,13 @@ jobs:
|
|||||||
extensions: curl, openssl, mbstring
|
extensions: curl, openssl, mbstring
|
||||||
ini-values: memory_limit=-1
|
ini-values: memory_limit=-1
|
||||||
|
|
||||||
|
- name: "Use test token if exists"
|
||||||
|
if: matrix.os != 'windows-latest'
|
||||||
|
run: |
|
||||||
|
if [ "${{ secrets.TEST_GH_TOKEN }}" != "" ]; then
|
||||||
|
echo "GITHUB_TOKEN=${{ secrets.TEST_GH_TOKEN }}" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
- name: "Cache Composer packages"
|
- name: "Cache Composer packages"
|
||||||
id: composer-cache
|
id: composer-cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -152,7 +159,13 @@ jobs:
|
|||||||
run: bin/spc doctor --auto-fix
|
run: bin/spc doctor --auto-fix
|
||||||
|
|
||||||
- name: "Run Build Tests (download)"
|
- name: "Run Build Tests (download)"
|
||||||
run: bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --with-php=${{ matrix.php }} --debug
|
uses: nick-fields/retry@v3
|
||||||
|
with:
|
||||||
|
timeout_minutes: 10
|
||||||
|
max_attempts: 3
|
||||||
|
retry_on: error
|
||||||
|
command: |
|
||||||
|
bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug
|
||||||
|
|
||||||
- name: "Run Build Tests (build)"
|
- name: "Run Build Tests (build)"
|
||||||
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php libs_cmd) --build-cli --build-micro --build-fpm --debug
|
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php libs_cmd) --build-cli --build-micro --build-fpm --debug
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,6 +16,9 @@ docker/source/
|
|||||||
# default source build root directory
|
# default source build root directory
|
||||||
/buildroot/
|
/buildroot/
|
||||||
|
|
||||||
|
# default package root directory
|
||||||
|
/pkgroot/
|
||||||
|
|
||||||
# tools cache files
|
# tools cache files
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
|||||||
63
README-zh.md
63
README-zh.md
@@ -1,10 +1,11 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
[]()
|
[](README.md)
|
||||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
[](README-zh.md)
|
||||||
[]()
|
[](https://github.com/crazywhalecc/static-php-cli/releases)
|
||||||
[]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html))
|
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||||
[](https://discord.gg/RNpegEYW)
|
[](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
|
||||||
|
[](https://static-php.dev/zh/guide/extensions.html)
|
||||||
|
|
||||||
**static-php-cli**是一个用于静态编译、构建 PHP 解释器的工具,支持众多流行扩展。
|
**static-php-cli**是一个用于静态编译、构建 PHP 解释器的工具,支持众多流行扩展。
|
||||||
|
|
||||||
@@ -12,9 +13,6 @@
|
|||||||
|
|
||||||
**static-php-cli**也支持将 PHP 代码和 PHP 运行时打包为一个文件并运行。
|
**static-php-cli**也支持将 PHP 代码和 PHP 运行时打包为一个文件并运行。
|
||||||
|
|
||||||
- [README - English](./README.md)
|
|
||||||
- [README - 中文](./README-zh.md)
|
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
static-php-cli(简称 `spc`)有许多特性:
|
static-php-cli(简称 `spc`)有许多特性:
|
||||||
@@ -22,11 +20,12 @@ static-php-cli(简称 `spc`)有许多特性:
|
|||||||
- :handbag: 构建独立的单文件 PHP 解释器,无需任何依赖
|
- :handbag: 构建独立的单文件 PHP 解释器,无需任何依赖
|
||||||
- :hamburger: 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自执行二进制(将 PHP 代码和 PHP 解释器打包为一个文件)
|
- :hamburger: 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自执行二进制(将 PHP 代码和 PHP 解释器打包为一个文件)
|
||||||
- :pill: 提供一键检查和修复编译环境的 Doctor 模块
|
- :pill: 提供一键检查和修复编译环境的 Doctor 模块
|
||||||
- :zap: 支持多个系统:`Linux`、`macOS`、`FreeBSD`、[`Windows (WIP)`](https://github.com/crazywhalecc/static-php-cli/pull/301)
|
- :zap: 支持多个系统:`Linux`、`macOS`、`FreeBSD`、`Windows`
|
||||||
- :wrench: 高度自定义的代码 patch 功能
|
- :wrench: 高度自定义的代码 patch 功能
|
||||||
- :books: 自带编译依赖管理
|
- :books: 自带编译依赖管理
|
||||||
- 📦 提供由自身编译的独立 `spc` 二进制(使用 spc 和 [box](https://github.com/box-project/box) 构建)
|
- 📦 提供由自身编译的独立 `spc` 二进制(使用 spc 和 [box](https://github.com/box-project/box) 构建)
|
||||||
- :fire: 支持大量 [扩展](https://static-php.dev/zh/guide/extensions.html)
|
- :fire: 支持大量 [扩展](https://static-php.dev/zh/guide/extensions.html)
|
||||||
|
- :floppy_disk: 整合 UPX 工具(减小二进制文件体积)
|
||||||
|
|
||||||
**静态 php-cli:**
|
**静态 php-cli:**
|
||||||
|
|
||||||
@@ -48,16 +47,18 @@ static-php-cli(简称 `spc`)有许多特性:
|
|||||||
- [扩展组合 - bulk](https://dl.static-php.dev/static-php-cli/bulk/):bulk 组合包含了 [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) 个扩展,体积为 70MB 左右。
|
- [扩展组合 - bulk](https://dl.static-php.dev/static-php-cli/bulk/):bulk 组合包含了 [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) 个扩展,体积为 70MB 左右。
|
||||||
- [扩展组合 - minimal](https://dl.static-php.dev/static-php-cli/minimal/):minimal 组合包含了 [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) 个扩展,体积为 6MB 左右。
|
- [扩展组合 - minimal](https://dl.static-php.dev/static-php-cli/minimal/):minimal 组合包含了 [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) 个扩展,体积为 6MB 左右。
|
||||||
|
|
||||||
|
对于 Windows 系统,目前支持的扩展较少,故仅提供 SPC 自身运行的最小扩展组合的 `cli` 和 `micro`:[扩展组合 - spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/)。
|
||||||
|
|
||||||
## 使用 static-php-cli 构建 PHP
|
## 使用 static-php-cli 构建 PHP
|
||||||
|
|
||||||
### 编译环境需求
|
### 编译环境需求
|
||||||
|
|
||||||
- PHP >= 8.1(这是 spc 自身需要的版本,不是支持的构建版本)
|
- PHP >= 8.1(这是 spc 自身需要的版本,不是支持的构建版本)
|
||||||
- 扩展:`mbstring,pcntl,posix,tokenizer,phar`
|
- 扩展:`mbstring,tokenizer,phar`
|
||||||
- 系统安装了 `curl` 和 `git`
|
- 系统安装了 `curl` 和 `git`
|
||||||
|
|
||||||
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
||||||
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。
|
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含上面提到的扩展和 PHP 版本大于等于 8.1 即可。
|
||||||
|
|
||||||
下面是架构支持情况,:octocat: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。
|
下面是架构支持情况,:octocat: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。
|
||||||
|
|
||||||
@@ -65,10 +66,26 @@ static-php-cli(简称 `spc`)有许多特性:
|
|||||||
|---------|----------------------|----------------------|
|
|---------|----------------------|----------------------|
|
||||||
| macOS | :octocat: :computer: | :octocat: :computer: |
|
| macOS | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Linux | :octocat: :computer: | :octocat: :computer: |
|
| Linux | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Windows | | |
|
| Windows | :computer: | |
|
||||||
| FreeBSD | :computer: | :computer: |
|
| FreeBSD | :computer: | :computer: |
|
||||||
|
|
||||||
目前支持编译的 PHP 版本为:`7.3`,`7.4`,`8.0`,`8.1`,`8.2`,`8.3`。
|
当前支持编译的 PHP 版本:
|
||||||
|
|
||||||
|
> :warning: 支持,但可能不再提供修复
|
||||||
|
>
|
||||||
|
> :heavy_check_mark: 支持
|
||||||
|
>
|
||||||
|
> :x: 不支持
|
||||||
|
|
||||||
|
| PHP Version | Status | Comment |
|
||||||
|
|-------------|--------------------|------------------------------|
|
||||||
|
| 7.2 | :x: | |
|
||||||
|
| 7.3 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
|
||||||
|
| 7.4 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
|
||||||
|
| 8.0 | :heavy_check_mark: | PHP 官方已停止 8.0 的维护 |
|
||||||
|
| 8.1 | :heavy_check_mark: | |
|
||||||
|
| 8.2 | :heavy_check_mark: | |
|
||||||
|
| 8.3 | :heavy_check_mark: | |
|
||||||
|
|
||||||
### 支持的扩展
|
### 支持的扩展
|
||||||
|
|
||||||
@@ -108,10 +125,16 @@ curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-a
|
|||||||
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
||||||
# macOS aarch64 (Apple)
|
# macOS aarch64 (Apple)
|
||||||
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
||||||
|
# Windows (x86_64, win10 build 17063 or later)
|
||||||
|
curl.exe -o spc.exe https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-windows-x64.exe
|
||||||
|
|
||||||
# add x perm
|
# Add execute perm (Linux and macOS only)
|
||||||
chmod +x ./spc
|
chmod +x ./spc
|
||||||
|
|
||||||
|
# Run (Linux and macOS)
|
||||||
./spc --version
|
./spc --version
|
||||||
|
# Run (Windows powershell)
|
||||||
|
.\spc.exe --version
|
||||||
```
|
```
|
||||||
|
|
||||||
自托管 `spc` 由 GitHub Actions 构建,你也可以从 Actions 直接下载:[此处](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml)。
|
自托管 `spc` 由 GitHub Actions 构建,你也可以从 Actions 直接下载:[此处](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml)。
|
||||||
@@ -150,14 +173,16 @@ bin/spc --version
|
|||||||
# 拉取所有依赖库
|
# 拉取所有依赖库
|
||||||
./bin/spc download --all
|
./bin/spc download --all
|
||||||
# 只拉取编译指定扩展需要的所有依赖(推荐)
|
# 只拉取编译指定扩展需要的所有依赖(推荐)
|
||||||
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite"
|
||||||
# 下载编译不同版本的 PHP (--with-php=x.y,推荐 7.3 ~ 8.3)
|
# 下载编译不同版本的 PHP (--with-php=x.y,推荐 7.3 ~ 8.3)
|
||||||
./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1
|
./bin/spc download --for-extensions="openssl,curl,mbstring" --with-php=8.1
|
||||||
|
|
||||||
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
|
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
|
||||||
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
|
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
|
||||||
# 编译线程安全版本 (--enable-zts)
|
# 编译线程安全版本 (--enable-zts)
|
||||||
./bin/spc build curl,phar --enable-zts --build-cli
|
./bin/spc build "curl,phar" --enable-zts --build-cli
|
||||||
|
# 编译后使用 UPX 减小可执行文件体积 (--with-upx-pack) (至少压缩至原来的 30~50%)
|
||||||
|
./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack
|
||||||
```
|
```
|
||||||
|
|
||||||
其中,目前支持构建 cli,micro,fpm 和 embed,使用以下参数的一个或多个来指定编译的 SAPI:
|
其中,目前支持构建 cli,micro,fpm 和 embed,使用以下参数的一个或多个来指定编译的 SAPI:
|
||||||
@@ -171,7 +196,7 @@ bin/spc --version
|
|||||||
如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误:
|
如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
./bin/spc build "openssl,pcntl,mbstring" --debug --build-all
|
||||||
./bin/spc download --all --debug
|
./bin/spc download --all --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -250,7 +275,7 @@ bin/spc micro:combine my-app.phar -I "memory_limit=4G" -I "disable_functions=sys
|
|||||||
|
|
||||||
## 赞助本项目
|
## 赞助本项目
|
||||||
|
|
||||||
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。
|
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。你捐赠的一部分将会被用于维护 **static-php.dev** 服务器。
|
||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
|
|||||||
70
README.md
70
README.md
@@ -1,10 +1,11 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
[]()
|
[](README-zh.md)
|
||||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
[](README.md)
|
||||||
[]()
|
[](https://github.com/crazywhalecc/static-php-cli/releases)
|
||||||
[]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html))
|
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||||
[](https://discord.gg/RNpegEYW)
|
[](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
|
||||||
|
[](https://static-php.dev/en/guide/extensions.html)
|
||||||
|
|
||||||
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
|
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
|
||||||
with popular extensions.
|
with popular extensions.
|
||||||
@@ -14,9 +15,6 @@ Static PHP built by **static-php-cli** supports `cli`, `fpm`, `embed` and `micro
|
|||||||
**static-php-cli** also has the ability to package PHP projects
|
**static-php-cli** also has the ability to package PHP projects
|
||||||
along with the PHP interpreter into one single executable file.
|
along with the PHP interpreter into one single executable file.
|
||||||
|
|
||||||
- [README - English](./README.md)
|
|
||||||
- [README - 中文](./README-zh.md)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
static-php-cli (you can call it `spc`) has a lot of features:
|
static-php-cli (you can call it `spc`) has a lot of features:
|
||||||
@@ -29,6 +27,7 @@ static-php-cli (you can call it `spc`) has a lot of features:
|
|||||||
- :books: Build dependency management
|
- :books: Build dependency management
|
||||||
- 📦 Provide `spc` own standalone executable (built by spc and [box](https://github.com/box-project/box))
|
- 📦 Provide `spc` own standalone executable (built by spc and [box](https://github.com/box-project/box))
|
||||||
- :fire: Support many popular [extensions](https://static-php.dev/en/guide/extensions.html)
|
- :fire: Support many popular [extensions](https://static-php.dev/en/guide/extensions.html)
|
||||||
|
- :floppy_disk: UPX integration (significantly reduces binary size)
|
||||||
|
|
||||||
**Single-file standalone php-cli:**
|
**Single-file standalone php-cli:**
|
||||||
|
|
||||||
@@ -54,16 +53,19 @@ which can be downloaded directly according to your needs.
|
|||||||
- [Extension-Combination - bulk](https://dl.static-php.dev/static-php-cli/bulk/): `bulk` contains [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) extensions and is about 70MB in size.
|
- [Extension-Combination - bulk](https://dl.static-php.dev/static-php-cli/bulk/): `bulk` contains [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) extensions and is about 70MB in size.
|
||||||
- [Extension-Combination - minimal](https://dl.static-php.dev/static-php-cli/minimal/): `minimal` contains [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) extensions and is about 6MB in size.
|
- [Extension-Combination - minimal](https://dl.static-php.dev/static-php-cli/minimal/): `minimal` contains [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) extensions and is about 6MB in size.
|
||||||
|
|
||||||
|
For Windows systems, there are currently fewer extensions supported,
|
||||||
|
so only `cli` and `micro` that run the minimum extension combination of SPC itself are provided: [Extension-Combination - spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/).
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
### Compilation Requirements
|
### Compilation Requirements
|
||||||
|
|
||||||
- PHP >= 8.1 (This is the version required by spc itself, not the build version)
|
|
||||||
- Extension: `mbstring,pcntl,posix,tokenizer,phar`
|
|
||||||
- Supported OS with `curl` and `git` installed
|
|
||||||
|
|
||||||
You can say I made a PHP builder written in PHP, pretty funny.
|
You can say I made a PHP builder written in PHP, pretty funny.
|
||||||
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension.
|
But static-php-cli runtime only requires an environment above PHP 8.1 and extensions mentioned below.
|
||||||
|
|
||||||
|
- PHP >= 8.1 (This is the version required by spc itself, not the build version)
|
||||||
|
- Extension: `mbstring,tokenizer,phar`
|
||||||
|
- Supported OS with `curl` and `git` installed
|
||||||
|
|
||||||
Here is the supported OS and arch, where :octocat: represents support for GitHub Action builds,
|
Here is the supported OS and arch, where :octocat: represents support for GitHub Action builds,
|
||||||
:computer: represents support for local manual builds, and blank represents not currently supported.
|
:computer: represents support for local manual builds, and blank represents not currently supported.
|
||||||
@@ -75,7 +77,23 @@ Here is the supported OS and arch, where :octocat: represents support for GitHub
|
|||||||
| Windows | :computer: | |
|
| Windows | :computer: | |
|
||||||
| FreeBSD | :computer: | :computer: |
|
| FreeBSD | :computer: | :computer: |
|
||||||
|
|
||||||
Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`.
|
Currently supported PHP versions for compilation:
|
||||||
|
|
||||||
|
> :warning: supported but not maintained
|
||||||
|
>
|
||||||
|
> :heavy_check_mark: supported
|
||||||
|
>
|
||||||
|
> :x: not supported
|
||||||
|
|
||||||
|
| PHP Version | Status | Comment |
|
||||||
|
|-------------|--------------------|---------------------------------------------------|
|
||||||
|
| 7.2 | :x: | |
|
||||||
|
| 7.3 | :warning: | phpmicro and some extensions not supported on 7.x |
|
||||||
|
| 7.4 | :warning: | phpmicro and some extensions not supported on 7.x |
|
||||||
|
| 8.0 | :heavy_check_mark: | PHP official has stopped maintenance of 8.0 |
|
||||||
|
| 8.1 | :heavy_check_mark: | |
|
||||||
|
| 8.2 | :heavy_check_mark: | |
|
||||||
|
| 8.3 | :heavy_check_mark: | |
|
||||||
|
|
||||||
### Supported Extensions
|
### Supported Extensions
|
||||||
|
|
||||||
@@ -118,10 +136,16 @@ curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-a
|
|||||||
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
||||||
# macOS aarch64 (Apple)
|
# macOS aarch64 (Apple)
|
||||||
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
||||||
|
# Windows (x86_64, win10 build 17063 or later)
|
||||||
|
curl.exe -o spc.exe https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-windows-x64.exe
|
||||||
|
|
||||||
# add x perm
|
# Add execute perm (Linux and macOS only)
|
||||||
chmod +x ./spc
|
chmod +x ./spc
|
||||||
|
|
||||||
|
# Run (Linux and macOS)
|
||||||
./spc --version
|
./spc --version
|
||||||
|
# Run (Windows powershell)
|
||||||
|
.\spc.exe --version
|
||||||
```
|
```
|
||||||
|
|
||||||
Self-hosted `spc` is built by GitHub Actions, you can also download from Actions artifacts [here](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml).
|
Self-hosted `spc` is built by GitHub Actions, you can also download from Actions artifacts [here](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml).
|
||||||
@@ -151,7 +175,7 @@ bin/spc --version
|
|||||||
|
|
||||||
Basic usage for building php with some extensions:
|
Basic usage for building php with some extensions:
|
||||||
|
|
||||||
> If you are using the packaged `spc` binary, you need to replace `bin/spc` with `./spc` in the following commands.
|
> If you are using the packaged standalone `spc` binary, you need to replace `bin/spc` with `./spc` or `.\spc.exe` in the following commands.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check system tool dependencies, auto-fix them if possible
|
# Check system tool dependencies, auto-fix them if possible
|
||||||
@@ -160,14 +184,16 @@ Basic usage for building php with some extensions:
|
|||||||
# fetch all libraries
|
# fetch all libraries
|
||||||
./bin/spc download --all
|
./bin/spc download --all
|
||||||
# only fetch necessary sources by needed extensions (recommended)
|
# only fetch necessary sources by needed extensions (recommended)
|
||||||
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite"
|
||||||
# download different PHP version (--with-php=x.y, recommend 7.3 ~ 8.3)
|
# download different PHP version (--with-php=x.y, recommend 7.3 ~ 8.3)
|
||||||
./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1
|
./bin/spc download --for-extensions="openssl,curl,mbstring" --with-php=8.1
|
||||||
|
|
||||||
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
|
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
|
||||||
./bin/spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-cli --build-micro
|
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
|
||||||
# build thread-safe (ZTS) version (--enable-zts)
|
# build thread-safe (ZTS) version (--enable-zts)
|
||||||
./bin/spc build curl,phar --enable-zts --build-cli
|
./bin/spc build "curl,phar" --enable-zts --build-cli
|
||||||
|
# build, pack executable with UPX (--with-upx-pack) (reduce binary size for 30~50%)
|
||||||
|
./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more of the following parameters to specify the compiled SAPI:
|
Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more of the following parameters to specify the compiled SAPI:
|
||||||
@@ -181,7 +207,7 @@ Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more o
|
|||||||
If anything goes wrong, use `--debug` option to display full terminal output:
|
If anything goes wrong, use `--debug` option to display full terminal output:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
./bin/spc build "openssl,pcntl,mbstring" --debug --build-all
|
||||||
./bin/spc download --all --debug
|
./bin/spc download --all --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -274,7 +300,7 @@ Now there is a [static-php](https://github.com/static-php) organization, which i
|
|||||||
|
|
||||||
## Sponsor this project
|
## Sponsor this project
|
||||||
|
|
||||||
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md).
|
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md). A portion of your donation will be used to maintain the **static-php.dev** server.
|
||||||
|
|
||||||
## Open-Source License
|
## Open-Source License
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ if (-not(Test-Path $PHP_Exec)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
& "$PHP_Exec" ("bin/spc") @args
|
& "$PHP_Exec" ("bin/spc") @args
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
|||||||
1
box.json
1
box.json
@@ -14,6 +14,5 @@
|
|||||||
"vendor/zhamao"
|
"vendor/zhamao"
|
||||||
],
|
],
|
||||||
"git-commit-short": "git_commit_short",
|
"git-commit-short": "git_commit_short",
|
||||||
"metadata": "ConsoleApplication::VERSION",
|
|
||||||
"output": "spc.phar"
|
"output": "spc.phar"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,10 @@
|
|||||||
"captainhook/captainhook": "^5.10",
|
"captainhook/captainhook": "^5.10",
|
||||||
"captainhook/plugin-composer": "^5.3",
|
"captainhook/plugin-composer": "^5.3",
|
||||||
"friendsofphp/php-cs-fixer": "^3.25",
|
"friendsofphp/php-cs-fixer": "^3.25",
|
||||||
"humbug/box": "^4.3",
|
"humbug/box": "^4.5",
|
||||||
"nunomaduro/collision": "^7.8",
|
"nunomaduro/collision": "^7.8",
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.10",
|
||||||
"phpunit/phpunit": "^10.3"
|
"phpunit/phpunit": "^10.3 || ^9"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
940
composer.lock
generated
940
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,15 @@
|
|||||||
{
|
{
|
||||||
|
"amqp": {
|
||||||
|
"type": "external",
|
||||||
|
"arg-type": "custom",
|
||||||
|
"source": "amqp",
|
||||||
|
"lib-depends": [
|
||||||
|
"librabbitmq"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"openssl"
|
||||||
|
]
|
||||||
|
},
|
||||||
"apcu": {
|
"apcu": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "apcu"
|
"source": "apcu"
|
||||||
@@ -24,6 +35,10 @@
|
|||||||
"arg-type": "with",
|
"arg-type": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"curl"
|
"curl"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"zlib",
|
||||||
|
"openssl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dba": {
|
"dba": {
|
||||||
@@ -37,6 +52,9 @@
|
|||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2",
|
"libxml2",
|
||||||
"zlib"
|
"zlib"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"xml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"event": {
|
"event": {
|
||||||
@@ -59,8 +77,11 @@
|
|||||||
"ffi": {
|
"ffi": {
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"lib-depends": [
|
"lib-depends-unix": [
|
||||||
"libffi"
|
"libffi"
|
||||||
|
],
|
||||||
|
"lib-depends-windows": [
|
||||||
|
"libffi-win"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fileinfo": {
|
"fileinfo": {
|
||||||
@@ -95,7 +116,7 @@
|
|||||||
},
|
},
|
||||||
"gettext": {
|
"gettext": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with",
|
"arg-type": "with-prefix",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"gettext"
|
"gettext"
|
||||||
]
|
]
|
||||||
@@ -119,8 +140,12 @@
|
|||||||
"iconv": {
|
"iconv": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with-prefix",
|
"arg-type": "with-prefix",
|
||||||
"lib-depends": [
|
"arg-type-windows": "with",
|
||||||
|
"lib-depends-unix": [
|
||||||
"libiconv"
|
"libiconv"
|
||||||
|
],
|
||||||
|
"lib-depends-windows": [
|
||||||
|
"libiconv-win"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"igbinary": {
|
"igbinary": {
|
||||||
@@ -313,13 +338,6 @@
|
|||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "protobuf"
|
"source": "protobuf"
|
||||||
},
|
},
|
||||||
"pspell": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"aspell"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"rar": {
|
"rar": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "rar",
|
"source": "rar",
|
||||||
@@ -354,9 +372,11 @@
|
|||||||
"simplexml": {
|
"simplexml": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"arg-type-windows": "with",
|
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"xml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"snappy": {
|
"snappy": {
|
||||||
@@ -371,18 +391,14 @@
|
|||||||
"apcu"
|
"apcu"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"snmp": {
|
|
||||||
"type": "builtin",
|
|
||||||
"arg-type": "with",
|
|
||||||
"lib-depends": [
|
|
||||||
"net-snmp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"soap": {
|
"soap": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"xml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"sockets": {
|
"sockets": {
|
||||||
@@ -398,6 +414,7 @@
|
|||||||
"sqlite3": {
|
"sqlite3": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with-prefix",
|
"arg-type": "with-prefix",
|
||||||
|
"arg-type-windows": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"sqlite"
|
"sqlite"
|
||||||
]
|
]
|
||||||
@@ -417,8 +434,13 @@
|
|||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "ext-ssh2",
|
"source": "ext-ssh2",
|
||||||
"arg-type": "with-prefix",
|
"arg-type": "with-prefix",
|
||||||
|
"arg-type-windows": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libssh2"
|
"libssh2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"openssl",
|
||||||
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"swoole": {
|
"swoole": {
|
||||||
@@ -493,8 +515,7 @@
|
|||||||
"unix-only": true
|
"unix-only": true
|
||||||
},
|
},
|
||||||
"sysvshm": {
|
"sysvshm": {
|
||||||
"type": "builtin",
|
"type": "builtin"
|
||||||
"unix-only": true
|
|
||||||
},
|
},
|
||||||
"tidy": {
|
"tidy": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
@@ -506,6 +527,14 @@
|
|||||||
"tokenizer": {
|
"tokenizer": {
|
||||||
"type": "builtin"
|
"type": "builtin"
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "ext-uuid",
|
||||||
|
"arg-type": "with-prefix",
|
||||||
|
"lib-depends": [
|
||||||
|
"libuuid"
|
||||||
|
]
|
||||||
|
},
|
||||||
"uv": {
|
"uv": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "ext-uv",
|
"source": "ext-uv",
|
||||||
@@ -539,6 +568,9 @@
|
|||||||
"arg-type-windows": "with",
|
"arg-type-windows": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"iconv"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"xmlreader": {
|
"xmlreader": {
|
||||||
@@ -546,6 +578,10 @@
|
|||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"xml",
|
||||||
|
"dom"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"xmlwriter": {
|
"xmlwriter": {
|
||||||
@@ -553,6 +589,9 @@
|
|||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
|
],
|
||||||
|
"ext-depends-windows": [
|
||||||
|
"xml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"xsl": {
|
"xsl": {
|
||||||
|
|||||||
104
config/lib.json
104
config/lib.json
@@ -36,7 +36,7 @@
|
|||||||
"libcurl.a"
|
"libcurl.a"
|
||||||
],
|
],
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
"libcurl.lib"
|
"libcurl_a.lib"
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
"curl"
|
"curl"
|
||||||
@@ -45,19 +45,21 @@
|
|||||||
"openssl",
|
"openssl",
|
||||||
"zlib"
|
"zlib"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-depends-windows": [
|
||||||
|
"openssl",
|
||||||
|
"zlib",
|
||||||
|
"libssh2",
|
||||||
|
"nghttp2"
|
||||||
|
],
|
||||||
|
"lib-suggests-unix": [
|
||||||
"libssh2",
|
"libssh2",
|
||||||
"brotli",
|
"brotli",
|
||||||
"nghttp2",
|
"nghttp2",
|
||||||
"zstd"
|
"zstd"
|
||||||
],
|
],
|
||||||
"lib-suggests-windows": [
|
"lib-suggests-windows": [
|
||||||
"zlib",
|
|
||||||
"libssh2",
|
|
||||||
"brotli",
|
"brotli",
|
||||||
"nghttp2",
|
"zstd"
|
||||||
"zstd",
|
|
||||||
"openssl"
|
|
||||||
],
|
],
|
||||||
"frameworks": [
|
"frameworks": [
|
||||||
"CoreFoundation",
|
"CoreFoundation",
|
||||||
@@ -83,6 +85,22 @@
|
|||||||
"brotli"
|
"brotli"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"gettext": {
|
||||||
|
"source": "gettext",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libintl.a"
|
||||||
|
],
|
||||||
|
"lib-depends": [
|
||||||
|
"libiconv"
|
||||||
|
],
|
||||||
|
"lib-suggests": [
|
||||||
|
"ncurses",
|
||||||
|
"libxml2"
|
||||||
|
],
|
||||||
|
"frameworks": [
|
||||||
|
"CoreFoundation"
|
||||||
|
]
|
||||||
|
},
|
||||||
"glfw": {
|
"glfw": {
|
||||||
"source": "ext-glfw",
|
"source": "ext-glfw",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -129,7 +147,8 @@
|
|||||||
"libpng",
|
"libpng",
|
||||||
"libjpeg",
|
"libjpeg",
|
||||||
"libwebp",
|
"libwebp",
|
||||||
"freetype"
|
"freetype",
|
||||||
|
"libtiff"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests": [
|
||||||
"zstd",
|
"zstd",
|
||||||
@@ -215,6 +234,17 @@
|
|||||||
"ffitarget.h"
|
"ffitarget.h"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libffi-win": {
|
||||||
|
"source": "libffi-win",
|
||||||
|
"static-libs-windows": [
|
||||||
|
"libffi.lib"
|
||||||
|
],
|
||||||
|
"headers-windows": [
|
||||||
|
"ffi.h",
|
||||||
|
"ffitarget.h",
|
||||||
|
"fficonfig.h"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libiconv": {
|
"libiconv": {
|
||||||
"source": "libiconv",
|
"source": "libiconv",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -227,6 +257,13 @@
|
|||||||
"localcharset.h"
|
"localcharset.h"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libiconv-win": {
|
||||||
|
"source": "libiconv-win",
|
||||||
|
"static-libs-windows": [
|
||||||
|
"libiconv.lib",
|
||||||
|
"libiconv_a.lib"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libjpeg": {
|
"libjpeg": {
|
||||||
"source": "libjpeg",
|
"source": "libjpeg",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -268,6 +305,18 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"librabbitmq": {
|
||||||
|
"source": "librabbitmq",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"librabbitmq.a"
|
||||||
|
],
|
||||||
|
"static-libs-windows": [
|
||||||
|
"rabbitmq.4.lib"
|
||||||
|
],
|
||||||
|
"lib-depends": [
|
||||||
|
"openssl"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libsodium": {
|
"libsodium": {
|
||||||
"source": "libsodium",
|
"source": "libsodium",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -294,6 +343,18 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libtiff": {
|
||||||
|
"source": "libtiff",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libtiff.a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"libuuid": {
|
||||||
|
"source": "libuuid",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libuuid.a"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libuv": {
|
"libuv": {
|
||||||
"source": "libuv",
|
"source": "libuv",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -316,21 +377,25 @@
|
|||||||
"libxml2.a"
|
"libxml2.a"
|
||||||
],
|
],
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
[
|
"libxml2s.lib",
|
||||||
"libxml2s.lib",
|
"libxml2_a.lib"
|
||||||
"libxml2_a.lib"
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
"libxml2"
|
"libxml2"
|
||||||
],
|
],
|
||||||
"lib-depends": [
|
"lib-depends-unix": [
|
||||||
"libiconv"
|
"libiconv"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests-unix": [
|
||||||
"xz",
|
"xz",
|
||||||
"icu",
|
"icu",
|
||||||
"zlib"
|
"zlib"
|
||||||
|
],
|
||||||
|
"lib-depends-windows": [
|
||||||
|
"libiconv-win"
|
||||||
|
],
|
||||||
|
"lib-suggests-windows": [
|
||||||
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"libxslt": {
|
"libxslt": {
|
||||||
@@ -411,10 +476,8 @@
|
|||||||
"libonig.a"
|
"libonig.a"
|
||||||
],
|
],
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
[
|
"onig.lib",
|
||||||
"onig.lib",
|
"onig_a.lib"
|
||||||
"onig_a.lib"
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
"oniggnu.h",
|
"oniggnu.h",
|
||||||
@@ -491,7 +554,10 @@
|
|||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
"libsqlite3.a"
|
"libsqlite3.a"
|
||||||
],
|
],
|
||||||
"headers-unix": [
|
"static-libs-windows": [
|
||||||
|
"libsqlite3_a.lib"
|
||||||
|
],
|
||||||
|
"headers": [
|
||||||
"sqlite3.h",
|
"sqlite3.h",
|
||||||
"sqlite3ext.h"
|
"sqlite3ext.h"
|
||||||
]
|
]
|
||||||
|
|||||||
46
config/pkg.json
Normal file
46
config/pkg.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"musl-toolchain-aarch64-linux": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz"
|
||||||
|
},
|
||||||
|
"musl-toolchain-x86_64-linux": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz"
|
||||||
|
},
|
||||||
|
"nasm-x86_64-win": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
|
||||||
|
"extract-files": {
|
||||||
|
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
|
||||||
|
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strawberry-perl-x86_64-win": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip"
|
||||||
|
},
|
||||||
|
"upx-aarch64-linux": {
|
||||||
|
"type": "ghrel",
|
||||||
|
"repo": "upx/upx",
|
||||||
|
"match": "upx.+-arm64_linux\\.tar\\.xz",
|
||||||
|
"extract-files": {
|
||||||
|
"upx": "{pkg_root_path}/bin/upx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"upx-x86_64-linux": {
|
||||||
|
"type": "ghrel",
|
||||||
|
"repo": "upx/upx",
|
||||||
|
"match": "upx.+-amd64_linux\\.tar\\.xz",
|
||||||
|
"extract-files": {
|
||||||
|
"upx": "{pkg_root_path}/bin/upx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"upx-x86_64-win": {
|
||||||
|
"type": "ghrel",
|
||||||
|
"repo": "upx/upx",
|
||||||
|
"match": "upx.+-win64\\.zip",
|
||||||
|
"extract-files": {
|
||||||
|
"upx-*-win64/upx.exe": "{pkg_root_path}/bin/upx.exe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,16 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"amqp": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/amqp",
|
||||||
|
"path": "php-src/ext/amqp",
|
||||||
|
"filename": "amqp.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"apcu": {
|
"apcu": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/APCu",
|
"url": "https://pecl.php.net/get/APCu",
|
||||||
@@ -100,6 +110,16 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ext-uuid": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/uuid",
|
||||||
|
"path": "php-src/ext/uuid",
|
||||||
|
"filename": "uuid.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ext-uv": {
|
"ext-uv": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/uv",
|
"url": "https://pecl.php.net/get/uv",
|
||||||
@@ -129,6 +149,15 @@
|
|||||||
"path": "LICENSE.TXT"
|
"path": "LICENSE.TXT"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"gettext": {
|
||||||
|
"type": "filelist",
|
||||||
|
"url": "https://ftp.gnu.org/pub/gnu/gettext/",
|
||||||
|
"regex": "/href=\"(?<file>gettext-(?<version>[^\"]+)\\.tar\\.xz)\"/",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "COPYING"
|
||||||
|
}
|
||||||
|
},
|
||||||
"gmp": {
|
"gmp": {
|
||||||
"type": "ghtagtar",
|
"type": "ghtagtar",
|
||||||
"repo": "alisw/GMP",
|
"repo": "alisw/GMP",
|
||||||
@@ -236,6 +265,15 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libffi-win": {
|
||||||
|
"type": "git",
|
||||||
|
"rev": "master",
|
||||||
|
"url": "https://github.com/static-php/libffi-win.git",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libiconv": {
|
"libiconv": {
|
||||||
"type": "filelist",
|
"type": "filelist",
|
||||||
"url": "https://ftp.gnu.org/gnu/libiconv/",
|
"url": "https://ftp.gnu.org/gnu/libiconv/",
|
||||||
@@ -245,6 +283,15 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libiconv-win": {
|
||||||
|
"type": "git",
|
||||||
|
"rev": "master",
|
||||||
|
"url": "https://github.com/static-php/libiconv-win.git",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "source/COPYING"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libjpeg": {
|
"libjpeg": {
|
||||||
"type": "ghtar",
|
"type": "ghtar",
|
||||||
"repo": "libjpeg-turbo/libjpeg-turbo",
|
"repo": "libjpeg-turbo/libjpeg-turbo",
|
||||||
@@ -280,6 +327,15 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"librabbitmq": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/alanxz/rabbitmq-c.git",
|
||||||
|
"rev": "master",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libsodium": {
|
"libsodium": {
|
||||||
"type": "ghrel",
|
"type": "ghrel",
|
||||||
"repo": "jedisct1/libsodium",
|
"repo": "jedisct1/libsodium",
|
||||||
@@ -298,6 +354,24 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libtiff": {
|
||||||
|
"type": "filelist",
|
||||||
|
"url": "https://download.osgeo.org/libtiff/",
|
||||||
|
"regex": "/href=\"(?<file>tiff-(?<version>[^\"]+)\\.tar\\.xz)\"/",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE.md"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libuuid": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cloudbase/libuuid.git",
|
||||||
|
"rev": "master",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "COPYING"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libuv": {
|
"libuv": {
|
||||||
"type": "ghtar",
|
"type": "ghtar",
|
||||||
"repo": "libuv/libuv",
|
"repo": "libuv/libuv",
|
||||||
@@ -322,7 +396,7 @@
|
|||||||
},
|
},
|
||||||
"libxml2": {
|
"libxml2": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://github.com/GNOME/libxml2/archive/refs/tags/v2.9.14.tar.gz",
|
"url": "https://github.com/GNOME/libxml2/archive/refs/tags/v2.12.5.tar.gz",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "Copyright"
|
"path": "Copyright"
|
||||||
@@ -431,7 +505,7 @@
|
|||||||
},
|
},
|
||||||
"postgresql": {
|
"postgresql": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://ftp.postgresql.org/pub/source/v16.1/postgresql-16.1.tar.gz",
|
"url": "https://ftp.postgresql.org/pub/source/v16.2/postgresql-16.2.tar.bz2",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "COPYRIGHT"
|
"path": "COPYRIGHT"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace SPC;
|
|||||||
|
|
||||||
use SPC\command\BuildCliCommand;
|
use SPC\command\BuildCliCommand;
|
||||||
use SPC\command\BuildLibsCommand;
|
use SPC\command\BuildLibsCommand;
|
||||||
|
use SPC\command\DeleteDownloadCommand;
|
||||||
use SPC\command\dev\AllExtCommand;
|
use SPC\command\dev\AllExtCommand;
|
||||||
use SPC\command\dev\PhpVerCommand;
|
use SPC\command\dev\PhpVerCommand;
|
||||||
use SPC\command\dev\SortConfigCommand;
|
use SPC\command\dev\SortConfigCommand;
|
||||||
@@ -13,6 +14,7 @@ use SPC\command\DoctorCommand;
|
|||||||
use SPC\command\DownloadCommand;
|
use SPC\command\DownloadCommand;
|
||||||
use SPC\command\DumpLicenseCommand;
|
use SPC\command\DumpLicenseCommand;
|
||||||
use SPC\command\ExtractCommand;
|
use SPC\command\ExtractCommand;
|
||||||
|
use SPC\command\InstallPkgCommand;
|
||||||
use SPC\command\MicroCombineCommand;
|
use SPC\command\MicroCombineCommand;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Symfony\Component\Console\Command\HelpCommand;
|
use Symfony\Component\Console\Command\HelpCommand;
|
||||||
@@ -23,7 +25,7 @@ use Symfony\Component\Console\Command\ListCommand;
|
|||||||
*/
|
*/
|
||||||
final class ConsoleApplication extends Application
|
final class ConsoleApplication extends Application
|
||||||
{
|
{
|
||||||
public const VERSION = '2.1.0-beta.2';
|
public const VERSION = '2.1.4';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -35,6 +37,8 @@ final class ConsoleApplication extends Application
|
|||||||
new BuildLibsCommand(),
|
new BuildLibsCommand(),
|
||||||
new DoctorCommand(),
|
new DoctorCommand(),
|
||||||
new DownloadCommand(),
|
new DownloadCommand(),
|
||||||
|
new InstallPkgCommand(),
|
||||||
|
new DeleteDownloadCommand(),
|
||||||
new DumpLicenseCommand(),
|
new DumpLicenseCommand(),
|
||||||
new ExtractCommand(),
|
new ExtractCommand(),
|
||||||
new MicroCombineCommand(),
|
new MicroCombineCommand(),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use SPC\exception\FileSystemException;
|
|||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\SourceExtractor;
|
use SPC\store\SourceManager;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
abstract class BuilderBase
|
abstract class BuilderBase
|
||||||
@@ -144,15 +144,15 @@ abstract class BuilderBase
|
|||||||
{
|
{
|
||||||
CustomExt::loadCustomExt();
|
CustomExt::loadCustomExt();
|
||||||
$this->emitPatchPoint('before-php-extract');
|
$this->emitPatchPoint('before-php-extract');
|
||||||
SourceExtractor::initSource(sources: ['php-src']);
|
SourceManager::initSource(sources: ['php-src']);
|
||||||
$this->emitPatchPoint('after-php-extract');
|
$this->emitPatchPoint('after-php-extract');
|
||||||
if ($this->getPHPVersionID() >= 80000) {
|
if ($this->getPHPVersionID() >= 80000) {
|
||||||
$this->emitPatchPoint('before-micro-extract');
|
$this->emitPatchPoint('before-micro-extract');
|
||||||
SourceExtractor::initSource(sources: ['micro']);
|
SourceManager::initSource(sources: ['micro']);
|
||||||
$this->emitPatchPoint('after-micro-extract');
|
$this->emitPatchPoint('after-micro-extract');
|
||||||
}
|
}
|
||||||
$this->emitPatchPoint('before-exts-extract');
|
$this->emitPatchPoint('before-exts-extract');
|
||||||
SourceExtractor::initSource(exts: $extensions);
|
SourceManager::initSource(exts: $extensions);
|
||||||
$this->emitPatchPoint('after-exts-extract');
|
$this->emitPatchPoint('after-exts-extract');
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
$class = CustomExt::getExtClass($extension);
|
$class = CustomExt::getExtClass($extension);
|
||||||
@@ -231,6 +231,30 @@ abstract class BuilderBase
|
|||||||
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
|
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PHP version from archive file name.
|
||||||
|
*
|
||||||
|
* @param null|string $file php-*.*.*.tar.gz filename, read from lockfile if empty
|
||||||
|
*/
|
||||||
|
public function getPHPVersionFromArchive(?string $file = null): false|string
|
||||||
|
{
|
||||||
|
if ($file === null) {
|
||||||
|
$lock = file_exists(DOWNLOAD_PATH . '/.lock.json') ? file_get_contents(DOWNLOAD_PATH . '/.lock.json') : false;
|
||||||
|
if ($lock === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$lock = json_decode($lock, true);
|
||||||
|
$file = $lock['php-src']['filename'] ?? null;
|
||||||
|
if ($file === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (preg_match('/php-(\d+\.\d+\.\d+)/', $file, $match)) {
|
||||||
|
return $match[1];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get build type name string to display.
|
* Get build type name string to display.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -185,8 +185,11 @@ class Extension
|
|||||||
file_get_contents(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php')
|
file_get_contents(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php')
|
||||||
);
|
);
|
||||||
|
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"');
|
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"');
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
|
if ($this->builder->getOption('debug')) {
|
||||||
|
var_dump($out);
|
||||||
|
}
|
||||||
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
|
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +212,7 @@ class Extension
|
|||||||
// Trim additional content & escape special characters to allow inline usage
|
// Trim additional content & escape special characters to allow inline usage
|
||||||
$test = str_replace(
|
$test = str_replace(
|
||||||
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
|
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
|
||||||
['', '', '', '\"', '\$'],
|
['', '', '', '\"', '$'],
|
||||||
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))
|
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
35
src/SPC/builder/extension/amqp.php
Normal file
35
src/SPC/builder/extension/amqp.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('amqp')]
|
||||||
|
class amqp extends Extension
|
||||||
|
{
|
||||||
|
public function patchBeforeMake(): bool
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
FileSystem::replaceFileRegex(BUILD_INCLUDE_PATH . '\amqp.h', '/^#warning.*/m', '');
|
||||||
|
FileSystem::replaceFileRegex(BUILD_INCLUDE_PATH . '\amqp_framing.h', '/^#warning.*/m', '');
|
||||||
|
FileSystem::replaceFileRegex(BUILD_INCLUDE_PATH . '\amqp_ssl_socket.h', '/^#warning.*/m', '');
|
||||||
|
FileSystem::replaceFileRegex(BUILD_INCLUDE_PATH . '\amqp_tcp_socket.h', '/^#warning.*/m', '');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--with-amqp';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace SPC\builder\extension;
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
|
use SPC\builder\macos\MacOSBuilder;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
@@ -34,4 +35,16 @@ class event extends Extension
|
|||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString());
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function patchBeforeMake(): bool
|
||||||
|
{
|
||||||
|
// Prevent event extension compile error on macOS
|
||||||
|
if ($this->builder instanceof MacOSBuilder) {
|
||||||
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,4 +14,9 @@ class ffi extends Extension
|
|||||||
{
|
{
|
||||||
return '--with-ffi --enable-zend-signals';
|
return '--with-ffi --enable-zend-signals';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--with-ffi';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/SPC/builder/extension/gettext.php
Normal file
40
src/SPC/builder/extension/gettext.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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('gettext')]
|
||||||
|
class gettext extends Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function patchBeforeBuildconf(): bool
|
||||||
|
{
|
||||||
|
if ($this->builder instanceof MacOSBuilder) {
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gettext/config.m4', 'AC_CHECK_LIB($GETTEXT_CHECK_IN_LIB', 'AC_CHECK_LIB(intl');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function patchBeforeConfigure(): bool
|
||||||
|
{
|
||||||
|
if ($this->builder instanceof MacOSBuilder) {
|
||||||
|
$frameworks = ' ' . $this->builder->getFrameworks(true) . ' ';
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lintl', $this->getLibFilesString() . $frameworks);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,4 +31,16 @@ class mbregex extends Extension
|
|||||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function runCliCheckWindows(): void
|
||||||
|
{
|
||||||
|
[$ret, $out] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "mbstring"', false);
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli does not contain mbstring !');
|
||||||
|
}
|
||||||
|
$out = implode("\n", $out);
|
||||||
|
if (!str_contains($out, 'regex')) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ class mbstring extends Extension
|
|||||||
$arg = '--enable-mbstring';
|
$arg = '--enable-mbstring';
|
||||||
if ($this->builder->getExt('mbregex') === null) {
|
if ($this->builder->getExt('mbregex') === null) {
|
||||||
$arg .= ' --disable-mbregex';
|
$arg .= ' --disable-mbregex';
|
||||||
|
} else {
|
||||||
|
$arg .= ' --enable-mbregex';
|
||||||
}
|
}
|
||||||
return $arg;
|
return $arg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class swoole extends Extension
|
|||||||
// enable swoole
|
// enable swoole
|
||||||
$arg = '--enable-swoole';
|
$arg = '--enable-swoole';
|
||||||
|
|
||||||
// commonly-used feature: coroutine-time, thread-context
|
// commonly-used feature: coroutine-time, disable-thread-context
|
||||||
$arg .= ' --enable-swoole-coro-time --enable-thread-context';
|
$arg .= ' --enable-swoole-coro-time --disable-thread-context';
|
||||||
|
|
||||||
// required feature: curl, openssl (but curl hook is buggy for php 8.0)
|
// required feature: curl, openssl (but curl hook is buggy for php 8.0)
|
||||||
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
|
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace SPC\builder\extension;
|
|||||||
|
|
||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
#[CustomExt('xml')]
|
#[CustomExt('xml')]
|
||||||
@@ -33,4 +34,25 @@ class xml extends Extension
|
|||||||
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '"';
|
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '"';
|
||||||
return $arg;
|
return $arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function patchBeforeBuildconf(): bool
|
||||||
|
{
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/win32/build/config.w32', 'dllmain.c ', '');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
$arg = match ($this->name) {
|
||||||
|
'xml' => '--with-xml',
|
||||||
|
'soap' => '--enable-soap',
|
||||||
|
'xmlreader' => '--enable-xmlreader',
|
||||||
|
'xmlwriter' => '--enable-xmlwriter',
|
||||||
|
'dom' => '--with-dom',
|
||||||
|
'simplexml' => '--with-simplexml',
|
||||||
|
default => throw new RuntimeException('Not accept non-xml extension'),
|
||||||
|
};
|
||||||
|
$arg .= ' --with-libxml';
|
||||||
|
return $arg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,27 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
|
// upx pack and strip for micro
|
||||||
|
if ($this->getOption('with-upx-pack', false)) {
|
||||||
|
FileSystem::replaceFileRegex(
|
||||||
|
SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag',
|
||||||
|
'/POST_MICRO_BUILD_COMMANDS=.*/',
|
||||||
|
'POST_MICRO_BUILD_COMMANDS=\$(STRIP) \$(MICRO_STRIP_FLAGS) \$(SAPI_MICRO_PATH) && ' . $this->getOption('upx-exec') . ' --best \$(SAPI_MICRO_PATH)',
|
||||||
|
);
|
||||||
|
} elseif (!$this->getOption('no-strip', false)) {
|
||||||
|
FileSystem::replaceFileRegex(
|
||||||
|
SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag',
|
||||||
|
'/POST_MICRO_BUILD_COMMANDS=.*/',
|
||||||
|
'POST_MICRO_BUILD_COMMANDS=\$(STRIP) \$(MICRO_STRIP_FLAGS) \$(SAPI_MICRO_PATH)',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
FileSystem::replaceFileRegex(
|
||||||
|
SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag',
|
||||||
|
'/POST_MICRO_BUILD_COMMANDS=.*/',
|
||||||
|
'POST_MICRO_BUILD_COMMANDS=true',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec(
|
->exec(
|
||||||
"{$this->getOption('ld_library_path')} " .
|
"{$this->getOption('ld_library_path')} " .
|
||||||
@@ -236,7 +257,11 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
||||||
->exec("make -j{$this->concurrency} {$vars} cli");
|
->exec("make -j{$this->concurrency} {$vars} cli");
|
||||||
|
|
||||||
if (!$this->getOption('no-strip', false)) {
|
if ($this->getOption('with-upx-pack')) {
|
||||||
|
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')
|
||||||
|
->exec('strip --strip-all php')
|
||||||
|
->exec($this->getOption('upx-exec') . ' --best php');
|
||||||
|
} elseif (!$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('strip --strip-all php');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,10 +292,6 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
||||||
->exec("make -j{$this->concurrency} {$vars} micro");
|
->exec("make -j{$this->concurrency} {$vars} micro");
|
||||||
|
|
||||||
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);
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
||||||
|
|
||||||
if ($this->phar_patched) {
|
if ($this->phar_patched) {
|
||||||
@@ -291,10 +312,13 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
||||||
->exec("make -j{$this->concurrency} {$vars} fpm");
|
->exec("make -j{$this->concurrency} {$vars} fpm");
|
||||||
|
|
||||||
if (!$this->getOption('no-strip', false)) {
|
if ($this->getOption('with-upx-pack')) {
|
||||||
|
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')
|
||||||
|
->exec('strip --strip-all php-fpm')
|
||||||
|
->exec($this->getOption('upx-exec') . ' --best php-fpm');
|
||||||
|
} elseif (!$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('strip --strip-all php-fpm');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->deployBinary(BUILD_TARGET_FPM);
|
$this->deployBinary(BUILD_TARGET_FPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,11 +110,7 @@ class SystemUtil
|
|||||||
public static function getTuneCFlags(string $arch): array
|
public static function getTuneCFlags(string $arch): array
|
||||||
{
|
{
|
||||||
return match ($arch) {
|
return match ($arch) {
|
||||||
'x86_64' => [
|
'x86_64', 'arm64', 'aarch64' => [],
|
||||||
'-march=corei7',
|
|
||||||
'-mtune=core-avx2',
|
|
||||||
],
|
|
||||||
'arm64', 'aarch64' => [],
|
|
||||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/linux/library/gettext.php
Normal file
12
src/SPC/builder/linux/library/gettext.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class gettext extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\gettext;
|
||||||
|
|
||||||
|
public const NAME = 'gettext';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/librabbitmq.php
Normal file
12
src/SPC/builder/linux/library/librabbitmq.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class librabbitmq extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\librabbitmq;
|
||||||
|
|
||||||
|
public const NAME = 'librabbitmq';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/libtiff.php
Normal file
12
src/SPC/builder/linux/library/libtiff.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class libtiff extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libtiff;
|
||||||
|
|
||||||
|
public const NAME = 'libtiff';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/libuuid.php
Normal file
12
src/SPC/builder/linux/library/libuuid.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class libuuid extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libuuid;
|
||||||
|
|
||||||
|
public const NAME = 'libuuid';
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
*/
|
*/
|
||||||
public function build(): void
|
public function build(): void
|
||||||
{
|
{
|
||||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
$enable_zlib = $this->builder->getLib('zlib') ? ('ON -DZLIB_LIBRARY=' . BUILD_LIB_PATH . '/libz.a -DZLIB_INCLUDE_DIR=' . BUILD_INCLUDE_PATH) : 'OFF';
|
||||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
||||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
'cmake ' .
|
'cmake ' .
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'-DCMAKE_INSTALL_LIBDIR=' . BUILD_LIB_PATH . ' ' .
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
'-DIconv_IS_BUILT_IN=OFF ' .
|
'-DIconv_IS_BUILT_IN=OFF ' .
|
||||||
|
|||||||
12
src/SPC/builder/macos/library/gettext.php
Normal file
12
src/SPC/builder/macos/library/gettext.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class gettext extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\gettext;
|
||||||
|
|
||||||
|
public const NAME = 'gettext';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/librabbitmq.php
Normal file
12
src/SPC/builder/macos/library/librabbitmq.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class librabbitmq extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\librabbitmq;
|
||||||
|
|
||||||
|
public const NAME = 'librabbitmq';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/libtiff.php
Normal file
12
src/SPC/builder/macos/library/libtiff.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class libtiff extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libtiff;
|
||||||
|
|
||||||
|
public const NAME = 'libtiff';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/libuuid.php
Normal file
12
src/SPC/builder/macos/library/libuuid.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class libuuid extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libuuid;
|
||||||
|
|
||||||
|
public const NAME = 'libuuid';
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ class libxml2 extends MacOSLibraryBase
|
|||||||
*/
|
*/
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
$enable_zlib = $this->builder->getLib('zlib') ? ('ON -DZLIB_LIBRARY=' . BUILD_LIB_PATH . '/libz.a -DZLIB_INCLUDE_DIR=' . BUILD_INCLUDE_PATH) : 'OFF';
|
||||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
||||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ class libxml2 extends MacOSLibraryBase
|
|||||||
// '--debug-find ' .
|
// '--debug-find ' .
|
||||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'-DCMAKE_INSTALL_LIBDIR=' . BUILD_LIB_PATH . ' ' .
|
||||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use SPC\exception\RuntimeException;
|
|||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourceExtractor;
|
use SPC\store\SourceManager;
|
||||||
use SPC\util\DependencyUtil;
|
use SPC\util\DependencyUtil;
|
||||||
|
|
||||||
abstract class UnixBuilderBase extends BuilderBase
|
abstract class UnixBuilderBase extends BuilderBase
|
||||||
@@ -107,7 +107,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
// if no libs specified, compile all supported libs
|
// if no libs specified, compile all supported libs
|
||||||
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
||||||
$libraries = array_keys($support_lib_list);
|
$libraries = array_keys($support_lib_list);
|
||||||
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries);
|
$sorted_libraries = DependencyUtil::getLibs($libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pkg-config must be compiled first, whether it is specified or not
|
// pkg-config must be compiled first, whether it is specified or not
|
||||||
@@ -134,7 +134,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
$this->emitPatchPoint('before-libs-extract');
|
$this->emitPatchPoint('before-libs-extract');
|
||||||
|
|
||||||
// extract sources
|
// extract sources
|
||||||
SourceExtractor::initSource(libs: $sorted_libraries);
|
SourceManager::initSource(libs: $sorted_libraries);
|
||||||
|
|
||||||
$this->emitPatchPoint('after-libs-extract');
|
$this->emitPatchPoint('after-libs-extract');
|
||||||
|
|
||||||
|
|||||||
28
src/SPC/builder/unix/library/gettext.php
Normal file
28
src/SPC/builder/unix/library/gettext.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
trait gettext
|
||||||
|
{
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$extra = $this->builder->getLib('ncurses') ? ('--with-libncurses-prefix=' . BUILD_ROOT_PATH . ' ') : '';
|
||||||
|
$extra .= $this->builder->getLib('libxml2') ? ('--with-libxml2-prefix=' . BUILD_ROOT_PATH . ' ') : '';
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
'./configure ' .
|
||||||
|
'--enable-static ' .
|
||||||
|
'--disable-shared ' .
|
||||||
|
'--disable-java ' .
|
||||||
|
'--disable-c+ ' .
|
||||||
|
$extra .
|
||||||
|
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'--prefix=' . BUILD_ROOT_PATH
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install');
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/SPC/builder/unix/library/librabbitmq.php
Normal file
35
src/SPC/builder/unix/library/librabbitmq.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
trait librabbitmq
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
// CMake needs a clean build directory
|
||||||
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
|
// Start build
|
||||||
|
shell()->cd($this->source_dir . '/build')
|
||||||
|
->exec(
|
||||||
|
'cmake ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DBUILD_STATIC_LIBS=ON ' .
|
||||||
|
'..'
|
||||||
|
)
|
||||||
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
|
->exec('make install');
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/SPC/builder/unix/library/libtiff.php
Normal file
30
src/SPC/builder/unix/library/libtiff.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
|
trait libtiff
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
'./configure ' .
|
||||||
|
'--enable-static --disable-shared ' .
|
||||||
|
'--disable-cxx ' .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
$this->patchPkgconfPrefix(['libtiff-4.pc']);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/SPC/builder/unix/library/libuuid.php
Normal file
38
src/SPC/builder/unix/library/libuuid.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
trait libuuid
|
||||||
|
{
|
||||||
|
public function patchBeforeBuild(): bool
|
||||||
|
{
|
||||||
|
FileSystem::replaceFileStr($this->source_dir . '/configure', '-${am__api_version}', '');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec('chmod +x configure')
|
||||||
|
->exec('chmod +x install-sh')
|
||||||
|
->exec(
|
||||||
|
'./configure ' .
|
||||||
|
'--enable-static --disable-shared ' .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
$this->patchPkgconfPrefix(['uuid.pc']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ trait ncurses
|
|||||||
'--without-tests ' .
|
'--without-tests ' .
|
||||||
'--without-dlsym ' .
|
'--without-dlsym ' .
|
||||||
'--without-debug ' .
|
'--without-debug ' .
|
||||||
'-enable-symlinks' .
|
'-enable-symlinks ' .
|
||||||
'--bindir=' . BUILD_ROOT_PATH . '/bin ' .
|
'--bindir=' . BUILD_ROOT_PATH . '/bin ' .
|
||||||
'--includedir=' . BUILD_ROOT_PATH . '/include ' .
|
'--includedir=' . BUILD_ROOT_PATH . '/include ' .
|
||||||
'--libdir=' . BUILD_ROOT_PATH . '/lib ' .
|
'--libdir=' . BUILD_ROOT_PATH . '/lib ' .
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ trait pkgconfig
|
|||||||
'--disable-shared ' .
|
'--disable-shared ' .
|
||||||
'--enable-static ' .
|
'--enable-static ' .
|
||||||
'--with-internal-glib ' .
|
'--with-internal-glib ' .
|
||||||
|
'--disable-host-tool ' .
|
||||||
|
'--with-pic ' .
|
||||||
'--prefix=' . BUILD_ROOT_PATH . ' ' .
|
'--prefix=' . BUILD_ROOT_PATH . ' ' .
|
||||||
'--without-sysroot ' .
|
'--without-sysroot ' .
|
||||||
'--without-system-include-path ' .
|
'--without-system-include-path ' .
|
||||||
@@ -29,6 +31,7 @@ trait pkgconfig
|
|||||||
)
|
)
|
||||||
->exec('make clean')
|
->exec('make clean')
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
->exec('make install');
|
->exec('make install-exec');
|
||||||
|
shell()->exec('strip ' . BUILD_ROOT_PATH . '/bin/pkg-config');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,11 +58,17 @@ trait postgresql
|
|||||||
|
|
||||||
FileSystem::resetDir($this->source_dir . '/build');
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
|
|
||||||
# 有静态链接配置 参考文件: src/interfaces/libpq/Makefile
|
$version = $this->getVersion();
|
||||||
shell()->cd($this->source_dir . '/build')
|
// 16.1 workaround
|
||||||
->exec('sed -i.backup "s/invokes exit\'; exit 1;/invokes exit\';/" ../src/interfaces/libpq/Makefile')
|
if (version_compare($version, '16.1') >= 0) {
|
||||||
->exec('sed -i.backup "278 s/^/# /" ../src/Makefile.shlib')
|
# 有静态链接配置 参考文件: src/interfaces/libpq/Makefile
|
||||||
->exec('sed -i.backup "402 s/^/# /" ../src/Makefile.shlib');
|
shell()->cd($this->source_dir . '/build')
|
||||||
|
->exec('sed -i.backup "s/invokes exit\'; exit 1;/invokes exit\';/" ../src/interfaces/libpq/Makefile')
|
||||||
|
->exec('sed -i.backup "278 s/^/# /" ../src/Makefile.shlib')
|
||||||
|
->exec('sed -i.backup "402 s/^/# /" ../src/Makefile.shlib');
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException('Unsupported version for postgresql: ' . $version . ' !');
|
||||||
|
}
|
||||||
|
|
||||||
// configure
|
// configure
|
||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
@@ -101,4 +107,17 @@ trait postgresql
|
|||||||
->exec("rm -rf {$builddir}/lib/*.so")
|
->exec("rm -rf {$builddir}/lib/*.so")
|
||||||
->exec("rm -rf {$builddir}/lib/*.dylib");
|
->exec("rm -rf {$builddir}/lib/*.dylib");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getVersion(): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$file = FileSystem::readFile($this->source_dir . '/meson.build');
|
||||||
|
if (preg_match("/^\\s+version:\\s?'(.*)'/m", $file, $match)) {
|
||||||
|
return $match[1];
|
||||||
|
}
|
||||||
|
return 'unknown';
|
||||||
|
} catch (FileSystemException) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\exception\RuntimeException;
|
|||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourceExtractor;
|
use SPC\store\SourceManager;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
use SPC\util\DependencyUtil;
|
use SPC\util\DependencyUtil;
|
||||||
|
|
||||||
@@ -72,6 +72,27 @@ class WindowsBuilder extends BuilderBase
|
|||||||
|
|
||||||
$zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no ';
|
$zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no ';
|
||||||
|
|
||||||
|
// with-upx-pack for phpmicro
|
||||||
|
$makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32');
|
||||||
|
if ($this->getOption('with-upx-pack', false)) {
|
||||||
|
if (!file_exists($makefile . '.originfile')) {
|
||||||
|
copy($makefile, $makefile . '.originfile');
|
||||||
|
FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', "_MICRO_UPX = {$this->getOption('upx-exec')} --best $(MICRO_SFX)\n$(MICRO_SFX):");
|
||||||
|
FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)");
|
||||||
|
}
|
||||||
|
} elseif (file_exists($makefile . '.originfile')) {
|
||||||
|
copy($makefile . '.originfile', $makefile);
|
||||||
|
unlink($makefile . '.originfile');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($logo = $this->getOption('with-micro-logo')) !== null) {
|
||||||
|
// realpath
|
||||||
|
$logo = realpath($logo);
|
||||||
|
$micro_logo = '--enable-micro-logo=' . $logo . ' ';
|
||||||
|
} else {
|
||||||
|
$micro_logo = '';
|
||||||
|
}
|
||||||
|
|
||||||
cmd()->cd(SOURCE_PATH . '\php-src')
|
cmd()->cd(SOURCE_PATH . '\php-src')
|
||||||
->exec(
|
->exec(
|
||||||
"{$this->sdk_prefix} configure.bat --task-args \"" .
|
"{$this->sdk_prefix} configure.bat --task-args \"" .
|
||||||
@@ -81,7 +102,7 @@ class WindowsBuilder extends BuilderBase
|
|||||||
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
|
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
|
||||||
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
|
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
|
||||||
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
|
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
|
||||||
($enableMicro ? '--enable-micro=yes ' : '--enable-micro=no ') .
|
($enableMicro ? ('--enable-micro=yes ' . $micro_logo) : '--enable-micro=no ') .
|
||||||
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
|
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
|
||||||
"{$this->makeExtensionArgs()} " .
|
"{$this->makeExtensionArgs()} " .
|
||||||
$zts .
|
$zts .
|
||||||
@@ -150,6 +171,8 @@ class WindowsBuilder extends BuilderBase
|
|||||||
$makefile = FileSystem::readFile(SOURCE_PATH . '\php-src\Makefile');
|
$makefile = FileSystem::readFile(SOURCE_PATH . '\php-src\Makefile');
|
||||||
if ($this->getPHPVersionID() >= 80200 && str_contains($makefile, 'FIBER_ASM_ARCH')) {
|
if ($this->getPHPVersionID() >= 80200 && str_contains($makefile, 'FIBER_ASM_ARCH')) {
|
||||||
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ARCH)_ms_pe_masm.obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ARCH)_ms_pe_masm.obj' . "\r\n\r\n";
|
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ARCH)_ms_pe_masm.obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ARCH)_ms_pe_masm.obj' . "\r\n\r\n";
|
||||||
|
} elseif ($this->getPHPVersionID() >= 80400 && str_contains($makefile, 'FIBER_ASM_ABI')) {
|
||||||
|
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ABI).obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ABI).obj' . "\r\n\r\n";
|
||||||
}
|
}
|
||||||
FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile);
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile);
|
||||||
|
|
||||||
@@ -164,10 +187,12 @@ class WindowsBuilder extends BuilderBase
|
|||||||
SourcePatcher::patchMicro(['phar']);
|
SourcePatcher::patchMicro(['phar']);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_micro_wrapper.bat --task-args micro");
|
try {
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_micro_wrapper.bat --task-args micro");
|
||||||
if ($this->phar_patched) {
|
} finally {
|
||||||
SourcePatcher::patchMicro(['phar'], true);
|
if ($this->phar_patched) {
|
||||||
|
SourcePatcher::patchMicro(['phar'], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->deployBinary(BUILD_TARGET_MICRO);
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
||||||
@@ -190,7 +215,7 @@ class WindowsBuilder extends BuilderBase
|
|||||||
// if no libs specified, compile all supported libs
|
// if no libs specified, compile all supported libs
|
||||||
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
||||||
$libraries = array_keys($support_lib_list);
|
$libraries = array_keys($support_lib_list);
|
||||||
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries);
|
$sorted_libraries = DependencyUtil::getLibs($libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add lib object for builder
|
// add lib object for builder
|
||||||
@@ -209,7 +234,7 @@ class WindowsBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extract sources
|
// extract sources
|
||||||
SourceExtractor::initSource(libs: $sorted_libraries);
|
SourceManager::initSource(libs: $sorted_libraries);
|
||||||
|
|
||||||
// build all libs
|
// build all libs
|
||||||
foreach ($this->libs as $lib) {
|
foreach ($this->libs as $lib) {
|
||||||
@@ -291,6 +316,12 @@ class WindowsBuilder extends BuilderBase
|
|||||||
BUILD_TARGET_MICRO => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\micro.sfx",
|
BUILD_TARGET_MICRO => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\micro.sfx",
|
||||||
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// with-upx-pack for cli
|
||||||
|
if ($this->getOption('with-upx-pack', false) && $type === BUILD_TARGET_CLI) {
|
||||||
|
cmd()->exec($this->getOption('upx-exec') . ' --best ' . escapeshellarg($src));
|
||||||
|
}
|
||||||
|
|
||||||
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
||||||
FileSystem::createDir(BUILD_ROOT_PATH . '\bin');
|
FileSystem::createDir(BUILD_ROOT_PATH . '\bin');
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ use SPC\builder\BuilderBase;
|
|||||||
use SPC\builder\LibraryBase;
|
use SPC\builder\LibraryBase;
|
||||||
use SPC\builder\windows\WindowsBuilder;
|
use SPC\builder\windows\WindowsBuilder;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
abstract class WindowsLibraryBase extends LibraryBase
|
abstract class WindowsLibraryBase extends LibraryBase
|
||||||
@@ -22,6 +24,36 @@ abstract class WindowsLibraryBase extends LibraryBase
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
|
||||||
|
{
|
||||||
|
$libs = [$this];
|
||||||
|
if ($recursive) {
|
||||||
|
array_unshift($libs, ...array_values($this->getDependencies(recursive: true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sep = match ($style) {
|
||||||
|
'autoconf' => ' ',
|
||||||
|
'cmake' => ';',
|
||||||
|
default => throw new RuntimeException('style only support autoconf and cmake'),
|
||||||
|
};
|
||||||
|
$ret = [];
|
||||||
|
foreach ($libs as $lib) {
|
||||||
|
$libFiles = [];
|
||||||
|
foreach ($lib->getStaticLibs() as $name) {
|
||||||
|
$name = str_replace(' ', '\ ', FileSystem::convertPath(BUILD_LIB_PATH . "/{$name}"));
|
||||||
|
$name = str_replace('"', '\"', $name);
|
||||||
|
$libFiles[] = $name;
|
||||||
|
}
|
||||||
|
array_unshift($ret, implode($sep, $libFiles));
|
||||||
|
}
|
||||||
|
return implode($sep, $ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a nmake wrapper file.
|
* Create a nmake wrapper file.
|
||||||
*
|
*
|
||||||
|
|||||||
24
src/SPC/builder/windows/library/curl.php
Normal file
24
src/SPC/builder/windows/library/curl.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class curl extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'curl';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
cmd()->cd($this->source_dir . '\winbuild')
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('nmake'),
|
||||||
|
'/f Makefile.vc WITH_DEVEL=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'WITH_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'mode=static RTLIBCFG=static WITH_SSL=static WITH_NGHTTP2=static WITH_SSH2=static ENABLE_IPV6=yes WITH_ZLIB=static MACHINE=x64 DEBUG=no'
|
||||||
|
);
|
||||||
|
FileSystem::copyDir($this->source_dir . '\include\curl', BUILD_INCLUDE_PATH . '\curl');
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/SPC/builder/windows/library/libffi_win.php
Normal file
46
src/SPC/builder/windows/library/libffi_win.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\builder\windows\SystemUtil;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class libffi_win extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'libffi-win';
|
||||||
|
|
||||||
|
protected function build()
|
||||||
|
{
|
||||||
|
$vs_ver_dir = match (SystemUtil::findVisualStudio()['version']) {
|
||||||
|
'vs17' => '/win32/vs17_x64',
|
||||||
|
'vs16' => '/win32/vs16_x64',
|
||||||
|
default => throw new RuntimeException('Current VS version is not supported yet!'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir . $vs_ver_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('msbuild'),
|
||||||
|
'libffi-msvc.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'
|
||||||
|
);
|
||||||
|
FileSystem::createDir(BUILD_LIB_PATH);
|
||||||
|
FileSystem::createDir(BUILD_INCLUDE_PATH);
|
||||||
|
copy($this->source_dir . $vs_ver_dir . '\x64\Release\libffi.lib', BUILD_LIB_PATH . '\libffi.lib');
|
||||||
|
copy($this->source_dir . $vs_ver_dir . '\x64\Release\libffi.pdb', BUILD_LIB_PATH . '\libffi.pdb');
|
||||||
|
copy($this->source_dir . '\include\ffi.h', BUILD_INCLUDE_PATH . '\ffi.h');
|
||||||
|
|
||||||
|
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\ffi.h', '#define LIBFFI_H', "#define LIBFFI_H\n#define FFI_BUILDING");
|
||||||
|
copy($this->source_dir . '\src\x86\ffitarget.h', BUILD_INCLUDE_PATH . '\ffitarget.h');
|
||||||
|
copy($this->source_dir . '\fficonfig.h', BUILD_INCLUDE_PATH . '\fficonfig.h');
|
||||||
|
|
||||||
|
// copy($this->source_dir . '\msvc_build\out\static-Release\X64\libffi.lib', BUILD_LIB_PATH . '\libffi.lib');
|
||||||
|
// copy($this->source_dir . '\msvc_build\include\ffi.h', BUILD_INCLUDE_PATH . '\ffi.h');
|
||||||
|
// copy($this->source_dir . '\msvc_build\include\fficonfig.h', BUILD_INCLUDE_PATH . '\fficonfig.h');
|
||||||
|
// copy($this->source_dir . '\src\x86\ffitarget.h', BUILD_INCLUDE_PATH . '\ffitarget.h');
|
||||||
|
|
||||||
|
// FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\ffi.h', '..\..\src\x86\ffitarget.h', 'ffitarget.h');
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/SPC/builder/windows/library/libiconv_win.php
Normal file
35
src/SPC/builder/windows/library/libiconv_win.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\builder\windows\SystemUtil;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class libiconv_win extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'libiconv-win';
|
||||||
|
|
||||||
|
protected function build()
|
||||||
|
{
|
||||||
|
$vs_ver_dir = match (SystemUtil::findVisualStudio()['version']) {
|
||||||
|
'vs17' => '/MSVC17',
|
||||||
|
'vs16' => '/MSVC16',
|
||||||
|
default => throw new RuntimeException('Current VS version is not supported yet!'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir . $vs_ver_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('msbuild'),
|
||||||
|
'libiconv.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'
|
||||||
|
);
|
||||||
|
FileSystem::createDir(BUILD_LIB_PATH);
|
||||||
|
FileSystem::createDir(BUILD_INCLUDE_PATH);
|
||||||
|
copy($this->source_dir . $vs_ver_dir . '\x64\lib\libiconv.lib', BUILD_LIB_PATH . '\libiconv.lib');
|
||||||
|
copy($this->source_dir . $vs_ver_dir . '\x64\lib\libiconv_a.lib', BUILD_LIB_PATH . '\libiconv_a.lib');
|
||||||
|
copy($this->source_dir . '\source\include\iconv.h', BUILD_INCLUDE_PATH . '\iconv.h');
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/SPC/builder/windows/library/librabbitmq.php
Normal file
36
src/SPC/builder/windows/library/librabbitmq.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class librabbitmq extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'librabbitmq';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DBUILD_STATIC_LIBS=ON ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
rename(BUILD_LIB_PATH . '\librabbitmq.4.lib', BUILD_LIB_PATH . '\rabbitmq.4.lib');
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/SPC/builder/windows/library/libssh2.php
Normal file
38
src/SPC/builder/windows/library/libssh2.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class libssh2 extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'libssh2';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DBUILD_STATIC_LIBS=ON ' .
|
||||||
|
'-DBUILD_TESTING=OFF ' .
|
||||||
|
"-DENABLE_ZLIB_COMPRESSION={$zlib} " .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/SPC/builder/windows/library/libxml2.php
Normal file
44
src/SPC/builder/windows/library/libxml2.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class libxml2 extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'libxml2';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DBUILD_STATIC_LIBS=ON ' .
|
||||||
|
"-DLIBXML2_WITH_ZLIB={$zlib} " .
|
||||||
|
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
||||||
|
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||||
|
'-DIconv_LIBRARY=' . BUILD_LIB_PATH . ' ' .
|
||||||
|
'-DIconv_INCLUDE_DIR=' . BUILD_INCLUDE_PATH . ' ' .
|
||||||
|
'-DLIBXML2_WITH_LZMA=OFF ' . // xz not supported yet
|
||||||
|
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
||||||
|
'-DLIBXML2_WITH_TESTS=OFF ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
copy(BUILD_LIB_PATH . '\libxml2s.lib', BUILD_LIB_PATH . '\libxml2_a.lib');
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/SPC/builder/windows/library/nghttp2.php
Normal file
37
src/SPC/builder/windows/library/nghttp2.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class nghttp2 extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'nghttp2';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DENABLE_SHARED_LIB=OFF ' .
|
||||||
|
'-DENABLE_STATIC_LIB=ON ' .
|
||||||
|
'-DENABLE_STATIC_CRT=ON ' .
|
||||||
|
'-DENABLE_LIB_ONLY=ON ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/SPC/builder/windows/library/onig.php
Normal file
37
src/SPC/builder/windows/library/onig.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class onig extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'onig';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DBUILD_STATIC_LIBS=ON ' .
|
||||||
|
'-DMSVC_STATIC_RUNTIME=ON ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
copy(BUILD_LIB_PATH . '/onig.lib', BUILD_LIB_PATH . '/onig_a.lib');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@ class openssl extends WindowsLibraryBase
|
|||||||
|
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
$perl = file_exists(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe') ? (BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe') : SystemUtil::findCommand('perl.exe');
|
$perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe';
|
||||||
|
$perl = file_exists($perl_path_native) ? ($perl_path_native) : SystemUtil::findCommand('perl.exe');
|
||||||
if ($perl === null) {
|
if ($perl === null) {
|
||||||
throw new RuntimeException('You need to install perl first! (easiest way is using static-php-cli command "doctor")');
|
throw new RuntimeException('You need to install perl first! (easiest way is using static-php-cli command "doctor")');
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/SPC/builder/windows/library/sqlite.php
Normal file
21
src/SPC/builder/windows/library/sqlite.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
class sqlite extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'sqlite';
|
||||||
|
|
||||||
|
public function patchBeforeBuild(): bool
|
||||||
|
{
|
||||||
|
copy(ROOT_DIR . '/src/globals/extra/Makefile-sqlite', $this->source_dir . '/Makefile');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
cmd()->cd($this->source_dir)->execWithWrapper($this->builder->makeSimpleWrapper('nmake'), 'PREFIX=' . BUILD_ROOT_PATH . ' install-static');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,11 +56,6 @@ abstract class BaseCommand extends Command
|
|||||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||||
return true;
|
return true;
|
||||||
}, E_ALL | E_STRICT);
|
}, E_ALL | E_STRICT);
|
||||||
if ($input->getOption('debug')) {
|
|
||||||
global $ob_logger;
|
|
||||||
$ob_logger = new ConsoleLogger(LogLevel::DEBUG);
|
|
||||||
define('DEBUG_MODE', true);
|
|
||||||
}
|
|
||||||
$version = ConsoleApplication::VERSION;
|
$version = ConsoleApplication::VERSION;
|
||||||
if (!$this->no_motd) {
|
if (!$this->no_motd) {
|
||||||
echo " _ _ _ _
|
echo " _ _ _ _
|
||||||
@@ -83,6 +78,14 @@ abstract class BaseCommand extends Command
|
|||||||
$this->input = $input;
|
$this->input = $input;
|
||||||
$this->output = $output;
|
$this->output = $output;
|
||||||
|
|
||||||
|
global $ob_logger;
|
||||||
|
if ($input->getOption('debug')) {
|
||||||
|
$ob_logger = new ConsoleLogger(LogLevel::DEBUG, decorated: !$input->getOption('no-ansi'));
|
||||||
|
define('DEBUG_MODE', true);
|
||||||
|
} else {
|
||||||
|
$ob_logger = new ConsoleLogger(decorated: !$input->getOption('no-ansi'));
|
||||||
|
}
|
||||||
|
|
||||||
// windows fallback
|
// windows fallback
|
||||||
Prompt::fallbackWhen(PHP_OS_FAMILY === 'Windows');
|
Prompt::fallbackWhen(PHP_OS_FAMILY === 'Windows');
|
||||||
ConfirmPrompt::fallbackUsing(function (ConfirmPrompt $prompt) use ($input, $output) {
|
ConfirmPrompt::fallbackUsing(function (ConfirmPrompt $prompt) use ($input, $output) {
|
||||||
|
|||||||
@@ -23,20 +23,22 @@ class BuildCliCommand extends BuildCommand
|
|||||||
{
|
{
|
||||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
|
$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('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
||||||
$this->addOption('build-micro', null, null, 'build micro');
|
$this->addOption('build-micro', null, null, 'Build micro SAPI');
|
||||||
$this->addOption('build-cli', null, null, 'build cli');
|
$this->addOption('build-cli', null, null, 'Build cli SAPI');
|
||||||
$this->addOption('build-fpm', null, null, 'build fpm');
|
$this->addOption('build-fpm', null, null, 'Build fpm SAPI');
|
||||||
$this->addOption('build-embed', null, null, 'build embed');
|
$this->addOption('build-embed', null, null, 'Build embed SAPI');
|
||||||
$this->addOption('build-all', null, null, 'build cli, micro, fpm, embed');
|
$this->addOption('build-all', null, null, 'Build all SAPI');
|
||||||
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
|
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
|
||||||
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
||||||
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
|
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
|
||||||
$this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
|
$this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
|
||||||
$this->addOption('with-micro-fake-cli', null, null, 'Enable phpmicro fake cli');
|
$this->addOption('with-micro-fake-cli', null, null, 'Let phpmicro\'s PHP_SAPI use "cli" instead of "micro"');
|
||||||
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
||||||
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
||||||
$this->addOption('with-added-patch', 'P', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Inject patch script outside');
|
$this->addOption('with-added-patch', 'P', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Inject patch script outside');
|
||||||
$this->addOption('without-micro-ext-test', null, null, 'Disable phpmicro with extension test code');
|
$this->addOption('without-micro-ext-test', null, null, 'Disable phpmicro with extension test code');
|
||||||
|
$this->addOption('with-upx-pack', null, null, 'Compress / pack binary using UPX tool (linux/windows only)');
|
||||||
|
$this->addOption('with-micro-logo', null, InputOption::VALUE_REQUIRED, 'Use custom .ico for micro.sfx (windows only)');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
@@ -58,30 +60,79 @@ class BuildCliCommand extends BuildCommand
|
|||||||
$this->output->writeln("<comment>\t--build-all\tBuild all SAPI: cli, micro, fpm, embed</comment>");
|
$this->output->writeln("<comment>\t--build-all\tBuild all SAPI: cli, micro, fpm, embed</comment>");
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
if ($rule === BUILD_TARGET_ALL) {
|
||||||
|
logger()->warning('--build-all option makes `--no-strip` always true, be aware!');
|
||||||
|
}
|
||||||
|
if (($rule & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO && $this->getOption('with-micro-logo')) {
|
||||||
|
$logo = $this->getOption('with-micro-logo');
|
||||||
|
if (!file_exists($logo)) {
|
||||||
|
logger()->error('Logo file ' . $logo . ' not exist !');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check upx
|
||||||
|
$suffix = PHP_OS_FAMILY === 'Windows' ? '.exe' : '';
|
||||||
|
if ($this->getOption('with-upx-pack')) {
|
||||||
|
// only available for linux for now
|
||||||
|
if (!in_array(PHP_OS_FAMILY, ['Linux', 'Windows'])) {
|
||||||
|
logger()->error('UPX is only available on Linux and Windows!');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
// need to install this manually
|
||||||
|
if (!file_exists(PKG_ROOT_PATH . '/bin/upx' . $suffix)) {
|
||||||
|
global $argv;
|
||||||
|
logger()->error('upx does not exist, please install it first:');
|
||||||
|
logger()->error('');
|
||||||
|
logger()->error("\t" . $argv[0] . ' install-pkg upx');
|
||||||
|
logger()->error('');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
// exclusive with no-strip
|
||||||
|
if ($this->getOption('no-strip')) {
|
||||||
|
logger()->warning('--with-upx-pack conflicts with --no-strip, --no-strip won\'t work!');
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// create builder
|
// create builder
|
||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
// calculate dependencies
|
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||||
[$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions, $libraries);
|
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
||||||
|
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||||
|
|
||||||
// print info
|
// print info
|
||||||
$indent_texts = [
|
$indent_texts = [
|
||||||
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
||||||
'Build SAPI' => $builder->getBuildTypeName($rule),
|
'Build SAPI' => $builder->getBuildTypeName($rule),
|
||||||
'Extensions (' . count($extensions) . ')' => implode(', ', $extensions),
|
'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
|
||||||
'Libraries (' . count($libraries) . ')' => implode(', ', $libraries),
|
'Libraries (' . count($libraries) . ')' => implode(',', $libraries),
|
||||||
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
|
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
|
||||||
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
|
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
|
||||||
];
|
];
|
||||||
if (!empty($this->input->getOption('with-hardcoded-ini'))) {
|
if (!empty($this->input->getOption('with-hardcoded-ini'))) {
|
||||||
$indent_texts['Hardcoded INI'] = $this->input->getOption('with-hardcoded-ini');
|
$indent_texts['Hardcoded INI'] = $this->input->getOption('with-hardcoded-ini');
|
||||||
}
|
}
|
||||||
$this->printFormatInfo($indent_texts);
|
if ($this->input->getOption('disable-opcache-jit')) {
|
||||||
|
$indent_texts['Opcache JIT'] = 'disabled';
|
||||||
|
}
|
||||||
|
if ($this->input->getOption('with-upx-pack') && in_array(PHP_OS_FAMILY, ['Linux', 'Windows'])) {
|
||||||
|
$indent_texts['UPX Pack'] = 'enabled';
|
||||||
|
$builder->setOption('upx-exec', FileSystem::convertPath(PKG_ROOT_PATH . '/bin/upx' . $suffix));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$ver = $builder->getPHPVersion();
|
||||||
|
$indent_texts['PHP Version'] = $ver;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
if (($ver = $builder->getPHPVersionFromArchive()) !== false) {
|
||||||
|
$indent_texts['PHP Version'] = $ver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($not_included)) {
|
if (!empty($not_included)) {
|
||||||
logger()->warning('Some extensions will be enabled due to dependencies: ' . implode(',', $not_included));
|
$indent_texts['Extra Exts (' . count($not_included) . ')'] = implode(', ', $not_included);
|
||||||
}
|
}
|
||||||
logger()->info('Build will start after 2s ...');
|
$this->printFormatInfo($indent_texts);
|
||||||
|
logger()->notice('Build will start after 2s ...');
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
|
||||||
if ($this->input->getOption('with-clean')) {
|
if ($this->input->getOption('with-clean')) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class BuildLibsCommand extends BuildCommand
|
|||||||
// 只编译 library 的情况下,标记
|
// 只编译 library 的情况下,标记
|
||||||
$builder->setLibsOnly();
|
$builder->setLibsOnly();
|
||||||
// 编译和检查库完整
|
// 编译和检查库完整
|
||||||
$libraries = DependencyUtil::getLibsByDeps($libraries);
|
$libraries = DependencyUtil::getLibs($libraries);
|
||||||
$builder->buildLibs($libraries);
|
$builder->buildLibs($libraries);
|
||||||
|
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
|
|||||||
86
src/SPC/command/DeleteDownloadCommand.php
Normal file
86
src/SPC/command/DeleteDownloadCommand.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use SPC\exception\DownloaderException;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
#[AsCommand('del-download', 'Remove locked download source or package using name', ['delete-download', 'del-down'])]
|
||||||
|
class DeleteDownloadCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
public function configure(): void
|
||||||
|
{
|
||||||
|
$this->addArgument('sources', InputArgument::REQUIRED, 'The sources/packages will be deleted, comma separated');
|
||||||
|
$this->addOption('all', 'A', null, 'Delete all downloaded and locked sources/packages');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||||
|
{
|
||||||
|
if ($input->getOption('all')) {
|
||||||
|
$input->setArgument('sources', '');
|
||||||
|
}
|
||||||
|
parent::initialize($input, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// get source list that will be downloaded
|
||||||
|
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||||
|
if (empty($sources)) {
|
||||||
|
logger()->notice('Removing downloads/ directory ...');
|
||||||
|
FileSystem::removeDir(DOWNLOAD_PATH);
|
||||||
|
logger()->info('Removed downloads/ dir!');
|
||||||
|
return static::SUCCESS;
|
||||||
|
}
|
||||||
|
$chosen_sources = $sources;
|
||||||
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
|
||||||
|
foreach ($chosen_sources as $source) {
|
||||||
|
$source = trim($source);
|
||||||
|
if (!isset($lock[$source])) {
|
||||||
|
logger()->warning("Source/Package [{$source}] not locked or not downloaded, skipped.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// remove download file/dir if exists
|
||||||
|
if ($lock[$source]['source_type'] === 'archive') {
|
||||||
|
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['filename']))) {
|
||||||
|
logger()->info('Deleting file ' . $path);
|
||||||
|
unlink($path);
|
||||||
|
} else {
|
||||||
|
logger()->warning("Source/Package [{$source}] file not found, skip deleting file.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['dirname']))) {
|
||||||
|
logger()->info('Deleting dir ' . $path);
|
||||||
|
FileSystem::removeDir($path);
|
||||||
|
} else {
|
||||||
|
logger()->warning("Source/Package [{$source}] directory not found, skip deleting dir.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove locked sources
|
||||||
|
unset($lock[$source]);
|
||||||
|
}
|
||||||
|
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||||
|
logger()->info('Delete success!');
|
||||||
|
return static::SUCCESS;
|
||||||
|
} catch (DownloaderException $e) {
|
||||||
|
logger()->error($e->getMessage());
|
||||||
|
return static::FAILURE;
|
||||||
|
} catch (WrongUsageException $e) {
|
||||||
|
logger()->critical($e->getMessage());
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,26 +36,60 @@ class DownloadCommand extends BaseCommand
|
|||||||
$this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"');
|
$this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"');
|
||||||
$this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive');
|
$this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive');
|
||||||
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
|
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
|
||||||
|
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
|
||||||
$this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions');
|
$this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions');
|
||||||
|
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_REQUIRED, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||||
{
|
{
|
||||||
if (
|
// mode: --all
|
||||||
$input->getOption('all')
|
if ($input->getOption('all')) {
|
||||||
|| $input->getOption('clean')
|
$input->setArgument('sources', implode(',', array_keys(Config::getSources())));
|
||||||
|| $input->getOption('from-zip')
|
parent::initialize($input, $output);
|
||||||
|| $input->getOption('for-extensions')
|
return;
|
||||||
) {
|
}
|
||||||
|
// mode: --clean and --from-zip
|
||||||
|
if ($input->getOption('clean') || $input->getOption('from-zip')) {
|
||||||
$input->setArgument('sources', '');
|
$input->setArgument('sources', '');
|
||||||
|
parent::initialize($input, $output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// mode: normal
|
||||||
|
if (!empty($input->getArgument('sources'))) {
|
||||||
|
$final_sources = array_map('trim', array_filter(explode(',', $input->getArgument('sources'))));
|
||||||
|
} else {
|
||||||
|
$final_sources = [];
|
||||||
|
}
|
||||||
|
// mode: --for-extensions
|
||||||
|
if ($for_ext = $input->getOption('for-extensions')) {
|
||||||
|
$ext = array_map('trim', array_filter(explode(',', $for_ext)));
|
||||||
|
$sources = $this->calculateSourcesByExt($ext, !$input->getOption('without-suggestions'));
|
||||||
|
if (PHP_OS_FAMILY !== 'Windows') {
|
||||||
|
array_unshift($sources, 'pkg-config');
|
||||||
|
}
|
||||||
|
array_unshift($sources, 'php-src', 'micro');
|
||||||
|
$final_sources = array_merge($final_sources, array_diff($sources, $final_sources));
|
||||||
|
}
|
||||||
|
// mode: --for-libs
|
||||||
|
if ($for_lib = $input->getOption('for-libs')) {
|
||||||
|
$lib = array_map('trim', array_filter(explode(',', $for_lib)));
|
||||||
|
$sources = $this->calculateSourcesByLib($lib, !$input->getOption('without-suggestions'));
|
||||||
|
$final_sources = array_merge($final_sources, array_diff($sources, $final_sources));
|
||||||
|
}
|
||||||
|
if (!empty($final_sources)) {
|
||||||
|
$input->setArgument('sources', implode(',', $final_sources));
|
||||||
}
|
}
|
||||||
parent::initialize($input, $output);
|
parent::initialize($input, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws DownloaderException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
@@ -107,20 +141,12 @@ class DownloadCommand extends BaseCommand
|
|||||||
Config::$source['openssl']['regex'] = '/href="(?<file>openssl-(?<version>1.[^"]+)\.tar\.gz)\"/';
|
Config::$source['openssl']['regex'] = '/href="(?<file>openssl-(?<version>1.[^"]+)\.tar\.gz)\"/';
|
||||||
}
|
}
|
||||||
|
|
||||||
// --for-extensions
|
$chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||||
if ($for_ext = $this->getOption('for-extensions')) {
|
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
|
||||||
$ext = array_map('trim', array_filter(explode(',', $for_ext)));
|
|
||||||
$sources = $this->calculateSourcesByExt($ext, !$this->getOption('without-suggestions'));
|
if ($this->getOption('all')) {
|
||||||
array_unshift($sources, 'php-src', 'micro', 'pkg-config');
|
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
|
||||||
} else {
|
|
||||||
// get source list that will be downloaded
|
|
||||||
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
|
||||||
if (empty($sources)) {
|
|
||||||
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
|
|
||||||
$sources = array_keys(Config::getSources());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$chosen_sources = $sources;
|
|
||||||
|
|
||||||
// Process -U options
|
// Process -U options
|
||||||
$custom_urls = [];
|
$custom_urls = [];
|
||||||
@@ -151,7 +177,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
Downloader::downloadSource($source, $new_config, true);
|
Downloader::downloadSource($source, $new_config, true);
|
||||||
} else {
|
} else {
|
||||||
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
|
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
|
||||||
Downloader::downloadSource($source, Config::getSource($source));
|
Downloader::downloadSource($source, Config::getSource($source), in_array($source, $force_list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
@@ -166,6 +192,10 @@ class DownloadCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
private function downloadFromZip(string $path): int
|
private function downloadFromZip(string $path): int
|
||||||
{
|
{
|
||||||
if (!file_exists($path)) {
|
if (!file_exists($path)) {
|
||||||
@@ -191,8 +221,10 @@ class DownloadCommand extends BaseCommand
|
|||||||
if (PHP_OS_FAMILY !== 'Windows') {
|
if (PHP_OS_FAMILY !== 'Windows') {
|
||||||
$abs_path = realpath($path);
|
$abs_path = realpath($path);
|
||||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
||||||
|
} else {
|
||||||
|
// Windows TODO
|
||||||
|
throw new WrongUsageException('Windows currently does not support --from-zip !');
|
||||||
}
|
}
|
||||||
// Windows TODO
|
|
||||||
|
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
throw new RuntimeException('.lock.json not exist in "downloads/"');
|
throw new RuntimeException('.lock.json not exist in "downloads/"');
|
||||||
@@ -208,13 +240,14 @@ class DownloadCommand extends BaseCommand
|
|||||||
/**
|
/**
|
||||||
* Calculate the sources by extensions
|
* Calculate the sources by extensions
|
||||||
*
|
*
|
||||||
* @param array $extensions extension list
|
* @param array $extensions extension list
|
||||||
|
* @param bool $include_suggests include suggested libs and extensions (default: true)
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array
|
private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array
|
||||||
{
|
{
|
||||||
[$extensions, $libraries] = $include_suggests ? DependencyUtil::getAllExtLibsByDeps($extensions) : DependencyUtil::getExtLibsByDeps($extensions);
|
[$extensions, $libraries] = $include_suggests ? DependencyUtil::getExtsAndLibs($extensions, [], true, true) : DependencyUtil::getExtsAndLibs($extensions);
|
||||||
$sources = [];
|
$sources = [];
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
if (Config::getExt($extension, 'type') === 'external') {
|
if (Config::getExt($extension, 'type') === 'external') {
|
||||||
@@ -226,4 +259,22 @@ class DownloadCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
return array_values(array_unique($sources));
|
return array_values(array_unique($sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the sources by libraries
|
||||||
|
*
|
||||||
|
* @param array $libs library list
|
||||||
|
* @param bool $include_suggests include suggested libs (default: true)
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
private function calculateSourcesByLib(array $libs, bool $include_suggests = true): array
|
||||||
|
{
|
||||||
|
$libs = DependencyUtil::getLibs($libs, $include_suggests);
|
||||||
|
$sources = [];
|
||||||
|
foreach ($libs as $library) {
|
||||||
|
$sources[] = Config::getLib($library, 'source');
|
||||||
|
}
|
||||||
|
return array_values(array_unique($sources));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class DumpLicenseCommand extends BaseCommand
|
|||||||
{
|
{
|
||||||
$this->addOption('for-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null);
|
$this->addOption('for-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null);
|
||||||
$this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src');
|
$this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src');
|
||||||
$this->addOption('by-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null);
|
$this->addOption('for-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null);
|
||||||
$this->addOption('by-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null);
|
$this->addOption('for-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null);
|
||||||
$this->addOption('dump-dir', null, InputOption::VALUE_REQUIRED, 'Change dump directory', BUILD_ROOT_PATH . '/license');
|
$this->addOption('dump-dir', null, InputOption::VALUE_REQUIRED, 'Change dump directory', BUILD_ROOT_PATH . '/license');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class DumpLicenseCommand extends BaseCommand
|
|||||||
// 从参数中获取要编译的 extensions,并转换为数组
|
// 从参数中获取要编译的 extensions,并转换为数组
|
||||||
$extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions'))));
|
$extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions'))));
|
||||||
// 根据提供的扩展列表获取依赖库列表并编译
|
// 根据提供的扩展列表获取依赖库列表并编译
|
||||||
[$extensions, $libraries] = DependencyUtil::getExtLibsByDeps($extensions);
|
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions);
|
||||||
$dumper->addExts($extensions);
|
$dumper->addExts($extensions);
|
||||||
$dumper->addLibs($libraries);
|
$dumper->addLibs($libraries);
|
||||||
if (!$this->getOption('without-php')) {
|
if (!$this->getOption('without-php')) {
|
||||||
@@ -52,22 +52,22 @@ class DumpLicenseCommand extends BaseCommand
|
|||||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
if ($this->getOption('by-libs') !== null) {
|
if ($this->getOption('for-libs') !== null) {
|
||||||
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('by-libs'))));
|
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('for-libs'))));
|
||||||
$libraries = DependencyUtil::getLibsByDeps($libraries);
|
$libraries = DependencyUtil::getLibs($libraries);
|
||||||
$dumper->addLibs($libraries);
|
$dumper->addLibs($libraries);
|
||||||
$dumper->dump($this->getOption('dump-dir'));
|
$dumper->dump($this->getOption('dump-dir'));
|
||||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
if ($this->getOption('by-sources') !== null) {
|
if ($this->getOption('for-sources') !== null) {
|
||||||
$sources = array_map('trim', array_filter(explode(',', $this->getOption('by-sources'))));
|
$sources = array_map('trim', array_filter(explode(',', $this->getOption('for-sources'))));
|
||||||
$dumper->addSources($sources);
|
$dumper->addSources($sources);
|
||||||
$dumper->dump($this->getOption('dump-dir'));
|
$dumper->dump($this->getOption('dump-dir'));
|
||||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
$this->output->writeln('You must use one of "--for-extensions=", "--by-libs=", "--by-sources=" to dump');
|
$this->output->writeln('You must use one of "--for-extensions=", "--for-libs=", "--for-sources=" to dump');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ use SPC\builder\traits\UnixSystemUtilTrait;
|
|||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\SourceExtractor;
|
use SPC\store\SourceManager;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
|
||||||
#[AsCommand('extract', 'Extract required sources')]
|
#[AsCommand('extract', 'Extract required sources', ['extract-source'])]
|
||||||
class ExtractCommand extends BaseCommand
|
class ExtractCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
use UnixSystemUtilTrait;
|
use UnixSystemUtilTrait;
|
||||||
@@ -34,7 +34,7 @@ class ExtractCommand extends BaseCommand
|
|||||||
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
|
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
SourceExtractor::initSource(sources: $sources);
|
SourceManager::initSource(sources: $sources);
|
||||||
logger()->info('Extract done !');
|
logger()->info('Extract done !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
86
src/SPC/command/InstallPkgCommand.php
Normal file
86
src/SPC/command/InstallPkgCommand.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
|
use SPC\exception\DownloaderException;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Config;
|
||||||
|
use SPC\store\PackageManager;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
|
||||||
|
#[AsCommand('install-pkg', 'Install additional packages', ['i', 'install-package'])]
|
||||||
|
class InstallPkgCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
use UnixSystemUtilTrait;
|
||||||
|
|
||||||
|
public function configure(): void
|
||||||
|
{
|
||||||
|
$this->addArgument('packages', InputArgument::REQUIRED, 'The packages will be installed, comma separated');
|
||||||
|
$this->addOption('shallow-clone', null, null, 'Clone shallow');
|
||||||
|
$this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Use shallow-clone can reduce git resource download
|
||||||
|
if ($this->getOption('shallow-clone')) {
|
||||||
|
define('GIT_SHALLOW_CLONE', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process -U options
|
||||||
|
$custom_urls = [];
|
||||||
|
foreach ($this->input->getOption('custom-url') as $value) {
|
||||||
|
[$pkg_name, $url] = explode(':', $value, 2);
|
||||||
|
$custom_urls[$pkg_name] = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$chosen_pkgs = array_map('trim', array_filter(explode(',', $this->getArgument('packages'))));
|
||||||
|
|
||||||
|
// Download them
|
||||||
|
f_mkdir(DOWNLOAD_PATH);
|
||||||
|
$ni = 0;
|
||||||
|
$cnt = count($chosen_pkgs);
|
||||||
|
|
||||||
|
foreach ($chosen_pkgs as $pkg) {
|
||||||
|
++$ni;
|
||||||
|
if (isset($custom_urls[$pkg])) {
|
||||||
|
$config = Config::getPkg($pkg);
|
||||||
|
$new_config = [
|
||||||
|
'type' => 'url',
|
||||||
|
'url' => $custom_urls[$pkg],
|
||||||
|
];
|
||||||
|
if (isset($config['extract'])) {
|
||||||
|
$new_config['extract'] = $config['extract'];
|
||||||
|
}
|
||||||
|
if (isset($config['filename'])) {
|
||||||
|
$new_config['filename'] = $config['filename'];
|
||||||
|
}
|
||||||
|
logger()->info("Installing source {$pkg} from custom url [{$ni}/{$cnt}]");
|
||||||
|
PackageManager::installPackage($pkg, $new_config);
|
||||||
|
} else {
|
||||||
|
logger()->info("Fetching package {$pkg} [{$ni}/{$cnt}]");
|
||||||
|
PackageManager::installPackage($pkg, Config::getPkg($pkg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
|
logger()->info('Install packages complete, used ' . $time . ' s !');
|
||||||
|
return static::SUCCESS;
|
||||||
|
} catch (DownloaderException $e) {
|
||||||
|
logger()->error($e->getMessage());
|
||||||
|
return static::FAILURE;
|
||||||
|
} catch (WrongUsageException $e) {
|
||||||
|
logger()->critical($e->getMessage());
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,8 +15,6 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
use function Laravel\Prompts\table;
|
|
||||||
|
|
||||||
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
|
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
|
||||||
class AllExtCommand extends BaseCommand
|
class AllExtCommand extends BaseCommand
|
||||||
{
|
{
|
||||||
@@ -61,7 +59,7 @@ class AllExtCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
|
[, $libraries, $not_included] = DependencyUtil::getExtsAndLibs([$extension]);
|
||||||
} catch (WrongUsageException) {
|
} catch (WrongUsageException) {
|
||||||
$libraries = $not_included = [];
|
$libraries = $not_included = [];
|
||||||
}
|
}
|
||||||
@@ -88,7 +86,8 @@ class AllExtCommand extends BaseCommand
|
|||||||
if ($data === []) {
|
if ($data === []) {
|
||||||
$style->warning('Unknown extension selected: ' . implode(',', $extensions));
|
$style->warning('Unknown extension selected: ' . implode(',', $extensions));
|
||||||
} else {
|
} else {
|
||||||
table($columns, $data);
|
$func = PHP_OS_FAMILY === 'Windows' ? [$style, 'table'] : '\Laravel\Prompts\table';
|
||||||
|
call_user_func($func, $columns, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ class SortConfigCommand extends BaseCommand
|
|||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'pkg':
|
||||||
|
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/pkg.json'), true);
|
||||||
|
ConfigValidator::validatePkgs($file);
|
||||||
|
ksort($file);
|
||||||
|
if (!file_put_contents(ROOT_DIR . '/config/pkg.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n")) {
|
||||||
|
$this->output->writeln('<error>Write file pkg.json failed!</error>');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$this->output->writeln("<error>invalid config name: {$name}</error>");
|
$this->output->writeln("<error>invalid config name: {$name}</error>");
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class BSDToolCheckList
|
|||||||
$prefix = '';
|
$prefix = '';
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
shell(true)->exec("ASSUME_ALWAYS_YES=yes {$prefix} pkg install -y " . implode(' ', $missing));
|
shell(true)->exec("ASSUME_ALWAYS_YES=yes {$prefix}pkg install -y " . implode(' ', $missing));
|
||||||
} catch (RuntimeException) {
|
} catch (RuntimeException) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use SPC\exception\RuntimeException;
|
|||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Downloader;
|
use SPC\store\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\store\PackageManager;
|
||||||
|
|
||||||
class LinuxMuslCheck
|
class LinuxMuslCheck
|
||||||
{
|
{
|
||||||
@@ -84,7 +85,6 @@ class LinuxMuslCheck
|
|||||||
|
|
||||||
/** @noinspection PhpUnused */
|
/** @noinspection PhpUnused */
|
||||||
/**
|
/**
|
||||||
* @throws DownloaderException
|
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
@@ -98,15 +98,10 @@ class LinuxMuslCheck
|
|||||||
logger()->warning('Current user is not root, using sudo for running command');
|
logger()->warning('Current user is not root, using sudo for running command');
|
||||||
}
|
}
|
||||||
$arch = arch2gnu(php_uname('m'));
|
$arch = arch2gnu(php_uname('m'));
|
||||||
$musl_compile_source = [
|
PackageManager::installPackage("musl-toolchain-{$arch}-linux");
|
||||||
'type' => 'url',
|
$pkg_root = PKG_ROOT_PATH . "/musl-toolchain-{$arch}-linux";
|
||||||
'url' => "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/{$arch}-musl-toolchain.tgz",
|
shell()->exec("{$prefix}cp -rf {$pkg_root}/* /usr/local/musl");
|
||||||
];
|
FileSystem::removeDir($pkg_root);
|
||||||
logger()->info('Downloading ' . $musl_compile_source['url']);
|
|
||||||
Downloader::downloadSource('musl-compile', $musl_compile_source);
|
|
||||||
logger()->info('Extracting musl-cross');
|
|
||||||
FileSystem::extractSource('musl-compile', DOWNLOAD_PATH . "/{$arch}-musl-toolchain.tgz");
|
|
||||||
shell()->exec($prefix . 'cp -rf ' . SOURCE_PATH . '/musl-compile/* /usr/local/musl');
|
|
||||||
return true;
|
return true;
|
||||||
} catch (RuntimeException) {
|
} catch (RuntimeException) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class MacOSToolCheckList
|
|||||||
'gzip',
|
'gzip',
|
||||||
'bzip2',
|
'bzip2',
|
||||||
'cmake',
|
'cmake',
|
||||||
|
'glibtoolize',
|
||||||
];
|
];
|
||||||
|
|
||||||
#[AsCheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)]
|
#[AsCheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)]
|
||||||
@@ -72,8 +73,14 @@ class MacOSToolCheckList
|
|||||||
#[AsFixItem('build-tools')]
|
#[AsFixItem('build-tools')]
|
||||||
public function fixBuildTools(array $missing): bool
|
public function fixBuildTools(array $missing): bool
|
||||||
{
|
{
|
||||||
|
$replacement = [
|
||||||
|
'glibtoolize' => 'libtool',
|
||||||
|
];
|
||||||
foreach ($missing as $cmd) {
|
foreach ($missing as $cmd) {
|
||||||
try {
|
try {
|
||||||
|
if (isset($replacement[$cmd])) {
|
||||||
|
$cmd = $replacement[$cmd];
|
||||||
|
}
|
||||||
shell(true)->exec('brew install --formula ' . escapeshellarg($cmd));
|
shell(true)->exec('brew install --formula ' . escapeshellarg($cmd));
|
||||||
} catch (RuntimeException) {
|
} catch (RuntimeException) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use SPC\doctor\AsCheckItem;
|
|||||||
use SPC\doctor\AsFixItem;
|
use SPC\doctor\AsFixItem;
|
||||||
use SPC\doctor\CheckResult;
|
use SPC\doctor\CheckResult;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\store\Downloader;
|
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\store\PackageManager;
|
||||||
|
|
||||||
class WindowsToolCheckList
|
class WindowsToolCheckList
|
||||||
{
|
{
|
||||||
@@ -64,8 +64,9 @@ class WindowsToolCheckList
|
|||||||
#[AsCheckItem('if perl(strawberry) installed', limit_os: 'Windows', level: 994)]
|
#[AsCheckItem('if perl(strawberry) installed', limit_os: 'Windows', level: 994)]
|
||||||
public function checkPerl(): ?CheckResult
|
public function checkPerl(): ?CheckResult
|
||||||
{
|
{
|
||||||
if (file_exists(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe')) {
|
$arch = arch2gnu(php_uname('m'));
|
||||||
return CheckResult::ok(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe');
|
if (file_exists(PKG_ROOT_PATH . '\strawberry-perl-' . $arch . '-win\perl\bin\perl.exe')) {
|
||||||
|
return CheckResult::ok(PKG_ROOT_PATH . '\strawberry-perl-' . $arch . '-win\perl\bin\perl.exe');
|
||||||
}
|
}
|
||||||
if (($path = SystemUtil::findCommand('perl.exe')) === null) {
|
if (($path = SystemUtil::findCommand('perl.exe')) === null) {
|
||||||
return CheckResult::fail('perl not found in path.', 'install-perl');
|
return CheckResult::fail('perl not found in path.', 'install-perl');
|
||||||
@@ -91,32 +92,15 @@ class WindowsToolCheckList
|
|||||||
#[AsFixItem('install-nasm')]
|
#[AsFixItem('install-nasm')]
|
||||||
public function installNasm(): bool
|
public function installNasm(): bool
|
||||||
{
|
{
|
||||||
// The hardcoded version here is to be consistent with the version compiled by `musl-cross-toolchain`.
|
PackageManager::installPackage('nasm-x86_64-win');
|
||||||
$nasm_ver = '2.16.01';
|
|
||||||
$nasm_dist = "nasm-{$nasm_ver}";
|
|
||||||
$source = [
|
|
||||||
'type' => 'url',
|
|
||||||
'url' => "https://www.nasm.us/pub/nasm/releasebuilds/{$nasm_ver}/win64/{$nasm_dist}-win64.zip",
|
|
||||||
];
|
|
||||||
logger()->info('Downloading ' . $source['url']);
|
|
||||||
Downloader::downloadSource('nasm', $source);
|
|
||||||
FileSystem::extractSource('nasm', DOWNLOAD_PATH . "\\{$nasm_dist}-win64.zip");
|
|
||||||
copy(SOURCE_PATH . "\\nasm\\{$nasm_dist}\\nasm.exe", PHP_SDK_PATH . '\bin\nasm.exe');
|
|
||||||
copy(SOURCE_PATH . "\\nasm\\{$nasm_dist}\\ndisasm.exe", PHP_SDK_PATH . '\bin\ndisasm.exe');
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[AsFixItem('install-perl')]
|
#[AsFixItem('install-perl')]
|
||||||
public function installPerl(): bool
|
public function installPerl(): bool
|
||||||
{
|
{
|
||||||
$url = 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip';
|
$arch = arch2gnu(php_uname('m'));
|
||||||
$source = [
|
PackageManager::installPackage("strawberry-perl-{$arch}-win");
|
||||||
'type' => 'url',
|
|
||||||
'url' => $url,
|
|
||||||
];
|
|
||||||
logger()->info("Downloading {$url}");
|
|
||||||
Downloader::downloadSource('strawberry-perl', $source);
|
|
||||||
FileSystem::extractSource('strawberry-perl', DOWNLOAD_PATH . '\strawberry-perl-5.38.0.1-64bit-portable.zip', '../buildroot/perl');
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ use SPC\exception\WrongUsageException;
|
|||||||
*/
|
*/
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
|
public static ?array $pkg = null;
|
||||||
|
|
||||||
public static ?array $source = null;
|
public static ?array $source = null;
|
||||||
|
|
||||||
public static ?array $lib = null;
|
public static ?array $lib = null;
|
||||||
@@ -31,6 +33,19 @@ class Config
|
|||||||
return self::$source[$name] ?? null;
|
return self::$source[$name] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read pkg from pkg.json
|
||||||
|
*
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function getPkg(string $name): ?array
|
||||||
|
{
|
||||||
|
if (self::$pkg === null) {
|
||||||
|
self::$pkg = FileSystem::loadConfigArray('pkg');
|
||||||
|
}
|
||||||
|
return self::$pkg[$name] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据不同的操作系统分别选择不同的 lib 库依赖项
|
* 根据不同的操作系统分别选择不同的 lib 库依赖项
|
||||||
* 如果 key 为 null,那么直接返回整个 meta。
|
* 如果 key 为 null,那么直接返回整个 meta。
|
||||||
|
|||||||
@@ -246,6 +246,96 @@ class Downloader
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws DownloaderException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
|
||||||
|
{
|
||||||
|
if ($pkg === null) {
|
||||||
|
$pkg = Config::getPkg($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pkg === null) {
|
||||||
|
logger()->warning('Package {name} unknown. Skipping.', ['name' => $name]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dir(DOWNLOAD_PATH)) {
|
||||||
|
FileSystem::createDir(DOWNLOAD_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load lock file
|
||||||
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
|
$lock = [];
|
||||||
|
} else {
|
||||||
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
}
|
||||||
|
// If lock file exists, skip downloading
|
||||||
|
if (isset($lock[$name]) && !$force) {
|
||||||
|
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
|
||||||
|
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['filename']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
|
||||||
|
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['dirname']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($pkg['type']) {
|
||||||
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
|
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'ghtar': // GitHub Release (tar)
|
||||||
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
|
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
|
[$url, $filename] = self::getFromFileList($name, $pkg);
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'url': // Direct download URL
|
||||||
|
$url = $pkg['url'];
|
||||||
|
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
||||||
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'git': // Git repo
|
||||||
|
self::downloadGit($name, $pkg['url'], $pkg['rev'], $pkg['extract'] ?? null);
|
||||||
|
break;
|
||||||
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
|
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source');
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
||||||
|
(new $class())->fetch($force);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new DownloaderException('unknown source type: ' . $pkg['type']);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
// Because sometimes files downloaded through the command line are not automatically deleted after a failure.
|
||||||
|
// Here we need to manually delete the file if it is detected to exist.
|
||||||
|
if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
||||||
|
logger()->warning('Deleting download file: ' . $filename);
|
||||||
|
unlink(DOWNLOAD_PATH . '/' . $filename);
|
||||||
|
}
|
||||||
|
throw new DownloaderException('Download failed! ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download source by name and meta.
|
* Download source by name and meta.
|
||||||
*
|
*
|
||||||
@@ -321,7 +411,7 @@ class Downloader
|
|||||||
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source');
|
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source');
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
||||||
(new $class())->fetch();
|
(new $class())->fetch($force);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class FileSystem
|
|||||||
*/
|
*/
|
||||||
public static function loadConfigArray(string $config, ?string $config_dir = null): array
|
public static function loadConfigArray(string $config, ?string $config_dir = null): array
|
||||||
{
|
{
|
||||||
$whitelist = ['ext', 'lib', 'source'];
|
$whitelist = ['ext', 'lib', 'source', 'pkg'];
|
||||||
if (!in_array($config, $whitelist)) {
|
if (!in_array($config, $whitelist)) {
|
||||||
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
|
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
|
||||||
}
|
}
|
||||||
@@ -138,6 +138,37 @@ class FileSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function extractPackage(string $name, string $filename, ?string $extract_path = null): void
|
||||||
|
{
|
||||||
|
if ($extract_path !== null) {
|
||||||
|
// replace
|
||||||
|
$extract_path = self::replacePathVariable($extract_path);
|
||||||
|
$extract_path = self::isRelativePath($extract_path) ? (WORKING_DIR . '/' . $extract_path) : $extract_path;
|
||||||
|
} else {
|
||||||
|
$extract_path = PKG_ROOT_PATH . '/' . $name;
|
||||||
|
}
|
||||||
|
logger()->info("extracting {$name} package to {$extract_path} ...");
|
||||||
|
$target = self::convertPath($extract_path);
|
||||||
|
|
||||||
|
if (!is_dir($dir = dirname($target))) {
|
||||||
|
self::createDir($dir);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
self::extractArchive($filename, $target);
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
f_passthru('rmdir /s /q ' . $target);
|
||||||
|
} else {
|
||||||
|
f_passthru('rm -rf ' . $target);
|
||||||
|
}
|
||||||
|
throw new FileSystemException('Cannot extract package ' . $name, $e->getCode(), $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解压缩下载的资源包到 source 目录
|
* 解压缩下载的资源包到 source 目录
|
||||||
*
|
*
|
||||||
@@ -152,52 +183,26 @@ class FileSystem
|
|||||||
if (self::$_extract_hook === []) {
|
if (self::$_extract_hook === []) {
|
||||||
SourcePatcher::init();
|
SourcePatcher::init();
|
||||||
}
|
}
|
||||||
if (!is_dir(SOURCE_PATH)) {
|
|
||||||
self::createDir(SOURCE_PATH);
|
|
||||||
}
|
|
||||||
if ($move_path !== null) {
|
if ($move_path !== null) {
|
||||||
$move_path = SOURCE_PATH . '/' . $move_path;
|
$move_path = SOURCE_PATH . '/' . $move_path;
|
||||||
|
} else {
|
||||||
|
$move_path = SOURCE_PATH . "/{$name}";
|
||||||
|
}
|
||||||
|
$target = self::convertPath($move_path);
|
||||||
|
logger()->info("extracting {$name} source to {$target}" . ' ...');
|
||||||
|
if (!is_dir($dir = dirname($target))) {
|
||||||
|
self::createDir($dir);
|
||||||
}
|
}
|
||||||
logger()->info("extracting {$name} source to " . ($move_path ?? SOURCE_PATH . "/{$name}") . ' ...');
|
|
||||||
try {
|
try {
|
||||||
$target = self::convertPath($move_path ?? (SOURCE_PATH . "/{$name}"));
|
self::extractArchive($filename, $target);
|
||||||
// Git source, just move
|
|
||||||
if (is_dir(self::convertPath($filename))) {
|
|
||||||
self::copyDir(self::convertPath($filename), $target);
|
|
||||||
self::emitSourceExtractHook($name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (f_mkdir(directory: $target, recursive: true) !== true) {
|
|
||||||
throw new FileSystemException('create ' . $name . 'source dir failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
|
|
||||||
match (self::extname($filename)) {
|
|
||||||
'tar', 'xz', 'txz' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
|
||||||
'tgz', 'gz' => f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1"),
|
|
||||||
'bz2' => f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1"),
|
|
||||||
'zip' => f_passthru("unzip {$filename} -d {$target}"),
|
|
||||||
default => throw new FileSystemException('unknown archive format: ' . $filename),
|
|
||||||
};
|
|
||||||
} elseif (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
// use php-sdk-binary-tools/bin/7za.exe
|
|
||||||
$_7z = self::convertPath(PHP_SDK_PATH . '/bin/7za.exe');
|
|
||||||
f_mkdir(SOURCE_PATH . "/{$name}", recursive: true);
|
|
||||||
match (self::extname($filename)) {
|
|
||||||
'tar' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
|
||||||
'xz', 'txz', 'gz', 'tgz', 'bz2' => f_passthru("\"{$_7z}\" x -so {$filename} | tar -f - -x -C {$target} --strip-components 1"),
|
|
||||||
'zip' => f_passthru("\"{$_7z}\" x {$filename} -o{$target} -y"),
|
|
||||||
default => throw new FileSystemException("unknown archive format: {$filename}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
self::emitSourceExtractHook($name);
|
self::emitSourceExtractHook($name);
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
f_passthru('rmdir /s /q ' . SOURCE_PATH . "/{$name}");
|
f_passthru('rmdir /s /q ' . $target);
|
||||||
} else {
|
} else {
|
||||||
f_passthru('rm -r ' . SOURCE_PATH . "/{$name}");
|
f_passthru('rm -rf ' . $target);
|
||||||
}
|
}
|
||||||
throw new FileSystemException('Cannot extract source ' . $name, $e->getCode(), $e);
|
throw new FileSystemException('Cannot extract source ' . $name . ': ' . $e->getMessage(), $e->getCode(), $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +219,14 @@ class FileSystem
|
|||||||
return str_replace('/', DIRECTORY_SEPARATOR, $path);
|
return str_replace('/', DIRECTORY_SEPARATOR, $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function convertWinPathToMinGW(string $path): string
|
||||||
|
{
|
||||||
|
if (preg_match('/^[A-Za-z]:/', $path)) {
|
||||||
|
$path = '/' . strtolower(substr($path, 0, 1)) . '/' . str_replace('\\', '/', substr($path, 2));
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归或非递归扫描目录,可返回相对目录的文件列表或绝对目录的文件列表
|
* 递归或非递归扫描目录,可返回相对目录的文件列表或绝对目录的文件列表
|
||||||
*
|
*
|
||||||
@@ -227,8 +240,12 @@ class FileSystem
|
|||||||
{
|
{
|
||||||
$dir = self::convertPath($dir);
|
$dir = self::convertPath($dir);
|
||||||
// 不是目录不扫,直接 false 处理
|
// 不是目录不扫,直接 false 处理
|
||||||
|
if (!file_exists($dir)) {
|
||||||
|
logger()->debug('Scan dir failed, no such file or directory.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) {
|
||||||
logger()->warning('Scan dir failed, no such directory.');
|
logger()->warning('Scan dir failed, not directory.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logger()->debug('scanning directory ' . $dir);
|
logger()->debug('scanning directory ' . $dir);
|
||||||
@@ -317,8 +334,12 @@ class FileSystem
|
|||||||
$dir = FileSystem::convertPath($dir);
|
$dir = FileSystem::convertPath($dir);
|
||||||
logger()->debug('Removing path recursively: "' . $dir . '"');
|
logger()->debug('Removing path recursively: "' . $dir . '"');
|
||||||
// 不是目录不扫,直接 false 处理
|
// 不是目录不扫,直接 false 处理
|
||||||
|
if (!file_exists($dir)) {
|
||||||
|
logger()->debug('Scan dir failed, no such file or directory.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) {
|
||||||
logger()->warning('Scan dir failed, no such directory.');
|
logger()->warning('Scan dir failed, not directory.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logger()->debug('scanning directory ' . $dir);
|
logger()->debug('scanning directory ' . $dir);
|
||||||
@@ -403,6 +424,63 @@ class FileSystem
|
|||||||
return strlen($path) > 0 && $path[0] !== '/';
|
return strlen($path) > 0 && $path[0] !== '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function replacePathVariable(string $path): string
|
||||||
|
{
|
||||||
|
$replacement = [
|
||||||
|
'{pkg_root_path}' => PKG_ROOT_PATH,
|
||||||
|
'{php_sdk_path}' => defined('PHP_SDK_PATH') ? PHP_SDK_PATH : WORKING_DIR . '/php-sdk-binary-tools',
|
||||||
|
'{working_dir}' => WORKING_DIR,
|
||||||
|
'{download_path}' => DOWNLOAD_PATH,
|
||||||
|
'{source_path}' => SOURCE_PATH,
|
||||||
|
];
|
||||||
|
return str_replace(array_keys($replacement), array_values($replacement), $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
private static function extractArchive(string $filename, string $target): void
|
||||||
|
{
|
||||||
|
// Git source, just move
|
||||||
|
if (is_dir(self::convertPath($filename))) {
|
||||||
|
self::copyDir(self::convertPath($filename), $target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create base dir
|
||||||
|
if (f_mkdir(directory: $target, recursive: true) !== true) {
|
||||||
|
throw new FileSystemException('create ' . $target . ' dir failed');
|
||||||
|
}
|
||||||
|
if (!file_exists($filename)) {
|
||||||
|
throw new FileSystemException('File not exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
|
||||||
|
match (self::extname($filename)) {
|
||||||
|
'tar', 'xz', 'txz' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
||||||
|
'tgz', 'gz' => f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1"),
|
||||||
|
'bz2' => f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1"),
|
||||||
|
'zip' => f_passthru("unzip {$filename} -d {$target}"),
|
||||||
|
default => throw new FileSystemException('unknown archive format: ' . $filename),
|
||||||
|
};
|
||||||
|
} elseif (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
// use php-sdk-binary-tools/bin/7za.exe
|
||||||
|
$_7z = self::convertPath(PHP_SDK_PATH . '/bin/7za.exe');
|
||||||
|
|
||||||
|
// Windows notes: I hate windows tar.......
|
||||||
|
// When extracting .tar.gz like libxml2, it shows a symlink error and returns code[1].
|
||||||
|
// Related posts: https://answers.microsoft.com/en-us/windows/forum/all/tar-on-windows-fails-to-extract-archive-containing/0ee9a7ea-9b1f-4fef-86a9-5d9dc35cea2f
|
||||||
|
// And MinGW tar.exe cannot work on temporarily storage ??? (GitHub Actions hosted runner)
|
||||||
|
// Yeah, I will be an MS HATER !
|
||||||
|
match (self::extname($filename)) {
|
||||||
|
'tar' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
||||||
|
'xz', 'txz', 'gz', 'tgz', 'bz2' => cmd()->execWithResult("\"{$_7z}\" x -so {$filename} | tar -f - -x -C \"{$target}\" --strip-components 1"),
|
||||||
|
'zip' => f_passthru("\"{$_7z}\" x {$filename} -o{$target} -y"),
|
||||||
|
default => throw new FileSystemException("unknown archive format: {$filename}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
|
|||||||
67
src/SPC/store/PackageManager.php
Normal file
67
src/SPC/store/PackageManager.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\store;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
|
||||||
|
class PackageManager
|
||||||
|
{
|
||||||
|
public static function installPackage(string $pkg_name, ?array $config = null, bool $force = false): void
|
||||||
|
{
|
||||||
|
if ($config === null) {
|
||||||
|
$config = Config::getPkg($pkg_name);
|
||||||
|
}
|
||||||
|
if ($config === null) {
|
||||||
|
$arch = arch2gnu(php_uname('m'));
|
||||||
|
$os = match (PHP_OS_FAMILY) {
|
||||||
|
'Linux' => 'linux',
|
||||||
|
'Windows' => 'win',
|
||||||
|
'BSD' => 'freebsd',
|
||||||
|
'Darwin' => 'macos',
|
||||||
|
default => throw new WrongUsageException('Unsupported OS!'),
|
||||||
|
};
|
||||||
|
$config = Config::getPkg("{$pkg_name}-{$arch}-{$os}");
|
||||||
|
}
|
||||||
|
if ($config === null) {
|
||||||
|
throw new WrongUsageException("Package [{$pkg_name}] does not exist, please check the name and correct it !");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download package
|
||||||
|
Downloader::downloadPackage($pkg_name, $config, $force);
|
||||||
|
// After download, read lock file name
|
||||||
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true);
|
||||||
|
$filename = DOWNLOAD_PATH . '/' . ($lock[$pkg_name]['filename'] ?? $lock[$pkg_name]['dirname']);
|
||||||
|
$extract = $lock[$pkg_name]['move_path'] === null ? (PKG_ROOT_PATH . '/' . $pkg_name) : $lock[$pkg_name]['move_path'];
|
||||||
|
FileSystem::extractPackage($pkg_name, $filename, $extract);
|
||||||
|
|
||||||
|
// if contains extract-files, we just move this file to destination, and remove extract dir
|
||||||
|
if (is_array($config['extract-files'] ?? null) && is_assoc_array($config['extract-files'])) {
|
||||||
|
$scandir = FileSystem::scanDirFiles($extract, true, true);
|
||||||
|
foreach ($config['extract-files'] as $file => $target) {
|
||||||
|
$target = FileSystem::convertPath(FileSystem::replacePathVariable($target));
|
||||||
|
if (!is_dir($dir = dirname($target))) {
|
||||||
|
f_mkdir($dir, 0755, true);
|
||||||
|
}
|
||||||
|
logger()->debug("Moving package [{$pkg_name}] file {$file} to {$target}");
|
||||||
|
// match pattern, needs to scan dir
|
||||||
|
$file = FileSystem::convertPath($file);
|
||||||
|
$found = false;
|
||||||
|
foreach ($scandir as $item) {
|
||||||
|
if (match_pattern($file, $item)) {
|
||||||
|
$file = $item;
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($found === false) {
|
||||||
|
throw new FileSystemException('Unable to find extract-files item: ' . $file);
|
||||||
|
}
|
||||||
|
rename(FileSystem::convertPath($extract . '/' . $file), $target);
|
||||||
|
}
|
||||||
|
FileSystem::removeDir($extract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use SPC\exception\FileSystemException;
|
|||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
|
||||||
class SourceExtractor
|
class SourceManager
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
@@ -106,7 +106,7 @@ class SourcePatcher
|
|||||||
}
|
}
|
||||||
$patch_list = $list ?? $default;
|
$patch_list = $list ?? $default;
|
||||||
$patches = [];
|
$patches = [];
|
||||||
$serial = ['80', '81', '82', '83'];
|
$serial = ['80', '81', '82', '83', '84'];
|
||||||
foreach ($patch_list as $patchName) {
|
foreach ($patch_list as $patchName) {
|
||||||
if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) {
|
if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) {
|
||||||
$patches[] = "sapi/micro/patches/{$patchName}.patch";
|
$patches[] = "sapi/micro/patches/{$patchName}.patch";
|
||||||
@@ -197,7 +197,6 @@ class SourcePatcher
|
|||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
|
||||||
}
|
}
|
||||||
if ($builder instanceof UnixBuilderBase) {
|
if ($builder instanceof UnixBuilderBase) {
|
||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
|
||||||
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ abstract class CustomSourceBase
|
|||||||
{
|
{
|
||||||
public const NAME = 'unknown';
|
public const NAME = 'unknown';
|
||||||
|
|
||||||
abstract public function fetch();
|
abstract public function fetch(bool $force = false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ namespace SPC\store\source;
|
|||||||
use JetBrains\PhpStorm\ArrayShape;
|
use JetBrains\PhpStorm\ArrayShape;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Downloader;
|
use SPC\store\Downloader;
|
||||||
|
|
||||||
class PhpSource extends CustomSourceBase
|
class PhpSource extends CustomSourceBase
|
||||||
@@ -16,13 +15,12 @@ class PhpSource extends CustomSourceBase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(): void
|
public function fetch(bool $force = false): void
|
||||||
{
|
{
|
||||||
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1';
|
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1';
|
||||||
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major));
|
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace SPC\store\source;
|
|||||||
|
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\store\Downloader;
|
use SPC\store\Downloader;
|
||||||
|
|
||||||
class PostgreSQLSource extends CustomSourceBase
|
class PostgreSQLSource extends CustomSourceBase
|
||||||
@@ -15,12 +14,11 @@ class PostgreSQLSource extends CustomSourceBase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(): void
|
public function fetch(bool $force = false): void
|
||||||
{
|
{
|
||||||
Downloader::downloadSource('postgresql', self::getLatestInfo());
|
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -70,4 +70,12 @@ class ConfigValidator
|
|||||||
{
|
{
|
||||||
is_array($data) || throw new ValidationException('ext.json is broken');
|
is_array($data) || throw new ValidationException('ext.json is broken');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public static function validatePkgs(mixed $data): void
|
||||||
|
{
|
||||||
|
is_array($data) || throw new ValidationException('pkg.json is broken');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,90 +5,164 @@ declare(strict_types=1);
|
|||||||
namespace SPC\util;
|
namespace SPC\util;
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 依赖处理工具类,包含处理扩展、库的依赖列表顺序等
|
* Dependency processing tool class, including processing extensions, library dependency list order, etc.
|
||||||
*/
|
*/
|
||||||
class DependencyUtil
|
class DependencyUtil
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Obtain the dependent lib list according to the required ext list, and sort according to the dependency
|
* Convert platform extensions to library dependencies and suggestions.
|
||||||
*
|
*
|
||||||
* @param array $exts extensions list
|
|
||||||
* @param array $additional_libs List of additional libraries to add to activate the extra library features triggered by lib-suggests
|
|
||||||
* @return array Returns an array containing three arrays, [extensions, libraries, not included extensions]
|
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public static function getExtLibsByDeps(array $exts, array $additional_libs = []): array
|
public static function platExtToLibs(): array
|
||||||
{
|
{
|
||||||
$sorted = [];
|
$exts = Config::getExts();
|
||||||
$visited = [];
|
$libs = Config::getLibs();
|
||||||
$not_included_exts = [];
|
$dep_list = [];
|
||||||
foreach ($exts as $ext) {
|
foreach ($exts as $ext_name => $ext) {
|
||||||
if (!isset($visited[$ext])) {
|
// convert ext-depends value to ext@xxx
|
||||||
self::visitExtDeps($ext, $visited, $sorted);
|
$ext_depends = Config::getExt($ext_name, 'ext-depends', []);
|
||||||
}
|
$ext_depends = array_map(fn ($x) => "ext@{$x}", $ext_depends);
|
||||||
|
// convert ext-suggests value to ext@xxx
|
||||||
|
$ext_suggests = Config::getExt($ext_name, 'ext-suggests', []);
|
||||||
|
$ext_suggests = array_map(fn ($x) => "ext@{$x}", $ext_suggests);
|
||||||
|
// merge ext-depends with lib-depends
|
||||||
|
$lib_depends = Config::getExt($ext_name, 'lib-depends', []);
|
||||||
|
$depends = array_merge($ext_depends, $lib_depends);
|
||||||
|
// merge ext-suggests with lib-suggests
|
||||||
|
$lib_suggests = Config::getExt($ext_name, 'lib-suggests', []);
|
||||||
|
$suggests = array_merge($ext_suggests, $lib_suggests);
|
||||||
|
$dep_list["ext@{$ext_name}"] = [
|
||||||
|
'depends' => $depends,
|
||||||
|
'suggests' => $suggests,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
$sorted_suggests = [];
|
foreach ($libs as $lib_name => $lib) {
|
||||||
$visited_suggests = [];
|
$dep_list[$lib_name] = [
|
||||||
$final = [];
|
'depends' => Config::getLib($lib_name, 'lib-depends', []),
|
||||||
foreach ($exts as $ext) {
|
'suggests' => Config::getLib($lib_name, 'lib-suggests', []),
|
||||||
if (!isset($visited_suggests[$ext])) {
|
];
|
||||||
self::visitExtAllDeps($ext, $visited_suggests, $sorted_suggests);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
foreach ($sorted_suggests as $suggest) {
|
// here is an array that only contains dependency map
|
||||||
if (in_array($suggest, $sorted)) {
|
return $dep_list;
|
||||||
$final[] = $suggest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$libs = $additional_libs;
|
|
||||||
|
|
||||||
foreach ($final as $ext) {
|
|
||||||
if (!in_array($ext, $exts)) {
|
|
||||||
$not_included_exts[] = $ext;
|
|
||||||
}
|
|
||||||
foreach (Config::getExt($ext, 'lib-depends', []) as $lib) {
|
|
||||||
if (!in_array($lib, $libs)) {
|
|
||||||
$libs[] = $lib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [$final, self::getLibsByDeps($libs), $not_included_exts];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 lib 库的依赖关系进行一个排序,同时返回多出来的依赖列表
|
|
||||||
*
|
|
||||||
* @param array $libs 要排序的 libs 列表
|
|
||||||
* @return array 排序后的列表
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public static function getLibsByDeps(array $libs): array
|
public static function getLibs(array $libs, bool $include_suggested_libs = false): array
|
||||||
{
|
{
|
||||||
$sorted = [];
|
$dep_list = self::platExtToLibs();
|
||||||
$visited = [];
|
|
||||||
|
|
||||||
// 遍历所有
|
if ($include_suggested_libs) {
|
||||||
foreach ($libs as $lib) {
|
foreach ($dep_list as $name => $obj) {
|
||||||
if (!isset($visited[$lib])) {
|
foreach ($obj['suggests'] as $id => $suggest) {
|
||||||
self::visitLibDeps($lib, $visited, $sorted);
|
if (!str_starts_with($suggest, 'ext@')) {
|
||||||
|
$dep_list[$name]['depends'][] = $suggest;
|
||||||
|
array_splice($dep_list[$name]['suggests'], $id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$final = self::doVisitPlat($libs, $dep_list);
|
||||||
|
|
||||||
|
$libs_final = [];
|
||||||
|
foreach ($final as $item) {
|
||||||
|
if (!str_starts_with($item, 'ext@')) {
|
||||||
|
$libs_final[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $libs_final;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException|WrongUsageException
|
||||||
|
*/
|
||||||
|
public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array
|
||||||
|
{
|
||||||
|
$dep_list = self::platExtToLibs();
|
||||||
|
|
||||||
|
// include suggested extensions
|
||||||
|
if ($include_suggested_exts) {
|
||||||
|
// check every deps suggests contains ext@
|
||||||
|
foreach ($dep_list as $name => $obj) {
|
||||||
|
foreach ($obj['suggests'] as $id => $suggest) {
|
||||||
|
if (str_starts_with($suggest, 'ext@')) {
|
||||||
|
$dep_list[$name]['depends'][] = $suggest;
|
||||||
|
array_splice($dep_list[$name]['suggests'], $id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// include suggested libraries
|
||||||
|
if ($include_suggested_libs) {
|
||||||
|
// check every deps suggests
|
||||||
|
foreach ($dep_list as $name => $obj) {
|
||||||
|
foreach ($obj['suggests'] as $id => $suggest) {
|
||||||
|
if (!str_starts_with($suggest, 'ext@')) {
|
||||||
|
$dep_list[$name]['depends'][] = $suggest;
|
||||||
|
array_splice($dep_list[$name]['suggests'], $id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert ext_name to ext@ext_name
|
||||||
|
$origin_exts = $exts;
|
||||||
|
$exts = array_map(fn ($x) => "ext@{$x}", $exts);
|
||||||
|
$exts = array_merge($exts, $additional_libs);
|
||||||
|
|
||||||
|
$final = self::doVisitPlat($exts, $dep_list);
|
||||||
|
|
||||||
|
// revert array
|
||||||
|
$exts_final = [];
|
||||||
|
$libs_final = [];
|
||||||
|
$not_included_final = [];
|
||||||
|
foreach ($final as $item) {
|
||||||
|
if (str_starts_with($item, 'ext@')) {
|
||||||
|
$tmp = substr($item, 4);
|
||||||
|
if (!in_array($tmp, $origin_exts)) {
|
||||||
|
$not_included_final[] = $tmp;
|
||||||
|
}
|
||||||
|
$exts_final[] = $tmp;
|
||||||
|
} else {
|
||||||
|
$libs_final[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [$exts_final, $libs_final, $not_included_final];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
private static function doVisitPlat(array $deps, array $dep_list): array
|
||||||
|
{
|
||||||
|
// default: get extension exts and libs sorted by dep_list
|
||||||
|
$sorted = [];
|
||||||
|
$visited = [];
|
||||||
|
foreach ($deps as $ext_name) {
|
||||||
|
if (!isset($dep_list[$ext_name])) {
|
||||||
|
$ext_name = str_starts_with($ext_name, 'ext@') ? ('Extension [' . substr($ext_name, 4) . ']') : ('Library [' . $ext_name . ']');
|
||||||
|
throw new WrongUsageException("{$ext_name} not exist !");
|
||||||
|
}
|
||||||
|
if (!isset($visited[$ext_name])) {
|
||||||
|
self::visitPlatDeps($ext_name, $dep_list, $visited, $sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
$sorted_suggests = [];
|
$sorted_suggests = [];
|
||||||
$visited_suggests = [];
|
$visited_suggests = [];
|
||||||
$final = [];
|
$final = [];
|
||||||
foreach ($libs as $lib) {
|
foreach ($deps as $ext_name) {
|
||||||
if (!isset($visited_suggests[$lib])) {
|
if (!isset($visited_suggests[$ext_name])) {
|
||||||
self::visitLibAllDeps($lib, $visited_suggests, $sorted_suggests);
|
self::visitPlatAllDeps($ext_name, $dep_list, $visited_suggests, $sorted_suggests);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($sorted_suggests as $suggest) {
|
foreach ($sorted_suggests as $suggest) {
|
||||||
@@ -99,49 +173,7 @@ class DependencyUtil
|
|||||||
return $final;
|
return $final;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAllExtLibsByDeps(array $exts): array
|
private static function visitPlatAllDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void
|
||||||
{
|
|
||||||
$sorted = [];
|
|
||||||
$visited = [];
|
|
||||||
$not_included_exts = [];
|
|
||||||
foreach ($exts as $ext) {
|
|
||||||
if (!isset($visited[$ext])) {
|
|
||||||
self::visitExtAllDeps($ext, $visited, $sorted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$libs = [];
|
|
||||||
foreach ($sorted as $ext) {
|
|
||||||
if (!in_array($ext, $exts)) {
|
|
||||||
$not_included_exts[] = $ext;
|
|
||||||
}
|
|
||||||
foreach (array_merge(Config::getExt($ext, 'lib-depends', []), Config::getExt($ext, 'lib-suggests', [])) as $dep) {
|
|
||||||
if (!in_array($dep, $libs)) {
|
|
||||||
$libs[] = $dep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [$sorted, self::getAllLibsByDeps($libs), $not_included_exts];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAllLibsByDeps(array $libs): array
|
|
||||||
{
|
|
||||||
$sorted = [];
|
|
||||||
$visited = [];
|
|
||||||
|
|
||||||
foreach ($libs as $lib) {
|
|
||||||
if (!isset($visited[$lib])) {
|
|
||||||
self::visitLibAllDeps($lib, $visited, $sorted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws WrongUsageException
|
|
||||||
*/
|
|
||||||
private static function visitLibAllDeps(string $lib_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
{
|
||||||
// 如果已经识别到了,那就不管
|
// 如果已经识别到了,那就不管
|
||||||
if (isset($visited[$lib_name])) {
|
if (isset($visited[$lib_name])) {
|
||||||
@@ -149,37 +181,13 @@ class DependencyUtil
|
|||||||
}
|
}
|
||||||
$visited[$lib_name] = true;
|
$visited[$lib_name] = true;
|
||||||
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
||||||
foreach (array_merge(Config::getLib($lib_name, 'lib-depends', []), Config::getLib($lib_name, 'lib-suggests', [])) as $dep) {
|
foreach (array_merge($dep_list[$lib_name]['depends'], $dep_list[$lib_name]['suggests']) as $dep) {
|
||||||
self::visitLibDeps($dep, $visited, $sorted);
|
self::visitPlatAllDeps($dep, $dep_list, $visited, $sorted);
|
||||||
}
|
}
|
||||||
$sorted[] = $lib_name;
|
$sorted[] = $lib_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static function visitPlatDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws WrongUsageException
|
|
||||||
*/
|
|
||||||
private static function visitExtAllDeps(string $ext_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
|
||||||
// 如果已经识别到了,那就不管
|
|
||||||
if (isset($visited[$ext_name])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$visited[$ext_name] = true;
|
|
||||||
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
|
||||||
foreach (array_merge(Config::getExt($ext_name, 'ext-depends', []), Config::getExt($ext_name, 'ext-suggests', [])) as $dep) {
|
|
||||||
self::visitExtDeps($dep, $visited, $sorted);
|
|
||||||
}
|
|
||||||
$sorted[] = $ext_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws WrongUsageException
|
|
||||||
*/
|
|
||||||
private static function visitLibDeps(string $lib_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
{
|
||||||
// 如果已经识别到了,那就不管
|
// 如果已经识别到了,那就不管
|
||||||
if (isset($visited[$lib_name])) {
|
if (isset($visited[$lib_name])) {
|
||||||
@@ -187,26 +195,9 @@ class DependencyUtil
|
|||||||
}
|
}
|
||||||
$visited[$lib_name] = true;
|
$visited[$lib_name] = true;
|
||||||
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
||||||
foreach (Config::getLib($lib_name, 'lib-depends', []) as $dep) {
|
foreach ($dep_list[$lib_name]['depends'] as $dep) {
|
||||||
self::visitLibDeps($dep, $visited, $sorted);
|
self::visitPlatDeps($dep, $dep_list, $visited, $sorted);
|
||||||
}
|
}
|
||||||
$sorted[] = $lib_name;
|
$sorted[] = $lib_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws WrongUsageException
|
|
||||||
*/
|
|
||||||
private static function visitExtDeps(string $ext_name, array &$visited, array &$sorted): void
|
|
||||||
{
|
|
||||||
if (isset($visited[$ext_name])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$visited[$ext_name] = true;
|
|
||||||
foreach (Config::getExt($ext_name, 'ext-depends', []) as $dep) {
|
|
||||||
self::visitExtDeps($dep, $visited, $sorted);
|
|
||||||
}
|
|
||||||
$sorted[] = $ext_name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ define('START_TIME', microtime(true));
|
|||||||
define('BUILD_ROOT_PATH', FileSystem::convertPath(is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot')));
|
define('BUILD_ROOT_PATH', FileSystem::convertPath(is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot')));
|
||||||
define('SOURCE_PATH', FileSystem::convertPath(is_string($a = getenv('SOURCE_PATH')) ? $a : (WORKING_DIR . '/source')));
|
define('SOURCE_PATH', FileSystem::convertPath(is_string($a = getenv('SOURCE_PATH')) ? $a : (WORKING_DIR . '/source')));
|
||||||
define('DOWNLOAD_PATH', FileSystem::convertPath(is_string($a = getenv('DOWNLOAD_PATH')) ? $a : (WORKING_DIR . '/downloads')));
|
define('DOWNLOAD_PATH', FileSystem::convertPath(is_string($a = getenv('DOWNLOAD_PATH')) ? $a : (WORKING_DIR . '/downloads')));
|
||||||
|
define('PKG_ROOT_PATH', FileSystem::convertPath(is_string($a = getenv('PKG_ROOT_PATH')) ? $a : (WORKING_DIR . '/pkgroot')));
|
||||||
define('BUILD_BIN_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_BIN_PATH')) ? $a : (BUILD_ROOT_PATH . '/bin')));
|
define('BUILD_BIN_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_BIN_PATH')) ? $a : (BUILD_ROOT_PATH . '/bin')));
|
||||||
define('BUILD_LIB_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_LIB_PATH')) ? $a : (BUILD_ROOT_PATH . '/lib')));
|
define('BUILD_LIB_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_LIB_PATH')) ? $a : (BUILD_ROOT_PATH . '/lib')));
|
||||||
define('BUILD_INCLUDE_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_INCLUDE_PATH')) ? $a : (BUILD_ROOT_PATH . '/include')));
|
define('BUILD_INCLUDE_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_INCLUDE_PATH')) ? $a : (BUILD_ROOT_PATH . '/include')));
|
||||||
|
|||||||
69
src/globals/extra/Makefile-sqlite
Normal file
69
src/globals/extra/Makefile-sqlite
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
|
||||||
|
CC=cl.exe /nologo
|
||||||
|
AR=lib.exe /nologo
|
||||||
|
LINK=link.exe /nologo
|
||||||
|
|
||||||
|
!IF "" == "$(MACHINE)"
|
||||||
|
MACHINE=x64
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
!IF "" == "$(CRT)"
|
||||||
|
CRT=vc15
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
!IF "" == "$(PREFIX)"
|
||||||
|
PREFIX="$(CRT)-$(MACHINE)"
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
COMMON_CFLAGS=/D SQLITE_THREADSAFE=1 /DSQLITE_ENABLE_FTS3=1 /D SQLITE_ENABLE_FTS4=1 /D SQLITE_ENABLE_FTS5=1 /D SQLITE_ENABLE_JSON1=1 /D SQLITE_ENABLE_COLUMN_METADATA=1 /D SQLITE_CORE=1
|
||||||
|
!IF "$(DEBUG)"=="1"
|
||||||
|
SQLITE3_STATIC_BASE=libsqlite3_a_debug
|
||||||
|
SQLITE3_DLL_BASE=libsqlite3_debug
|
||||||
|
SQLITE3_EXE_BASE=sqlite3
|
||||||
|
CFLAGS=$(COMMON_CFLAGS) /Zi /MDd /Od /W3
|
||||||
|
LDFLAGS=/DEBUG /GUARD:CF /INCREMENTAL:NO
|
||||||
|
!ELSE
|
||||||
|
SQLITE3_STATIC_BASE=libsqlite3_a
|
||||||
|
SQLITE3_DLL_BASE=libsqlite3
|
||||||
|
SQLITE3_EXE_BASE=sqlite3
|
||||||
|
CFLAGS=$(COMMON_CFLAGS) /Zi /MT /guard:cf /Zc:inline /Qspectre /Ox /W3 /GF /GL /Gw
|
||||||
|
LDFLAGS=/GUARD:CF /INCREMENTAL:NO /NXCOMPAT /DYNAMICBASE
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
|
||||||
|
all: $(SQLITE3_STATIC_BASE).lib $(SQLITE3_EXE_BASE).exe $(SQLITE3_DLL_BASE).dll
|
||||||
|
|
||||||
|
install: all
|
||||||
|
if not exist $(PREFIX)\bin mkdir $(PREFIX)\bin
|
||||||
|
if not exist $(PREFIX)\include mkdir $(PREFIX)\include
|
||||||
|
if not exist $(PREFIX)\lib mkdir $(PREFIX)\lib
|
||||||
|
copy /Y sqlite3.h $(PREFIX)\include
|
||||||
|
copy /Y sqlite3ext.h $(PREFIX)\include
|
||||||
|
copy /Y $(SQLITE3_STATIC_BASE).lib $(PREFIX)\lib
|
||||||
|
copy /Y $(SQLITE3_STATIC_BASE).pdb $(PREFIX)\lib
|
||||||
|
copy /Y $(SQLITE3_DLL_BASE).lib $(PREFIX)\lib
|
||||||
|
copy /Y $(SQLITE3_DLL_BASE).pdb $(PREFIX)\bin
|
||||||
|
copy /Y $(SQLITE3_DLL_BASE).dll $(PREFIX)\bin
|
||||||
|
copy /Y $(SQLITE3_EXE_BASE).exe $(PREFIX)\bin
|
||||||
|
copy /Y $(SQLITE3_EXE_BASE).pdb $(PREFIX)\bin
|
||||||
|
|
||||||
|
install-static: $(SQLITE3_STATIC_BASE).lib
|
||||||
|
if not exist $(PREFIX)\include mkdir $(PREFIX)\include
|
||||||
|
if not exist $(PREFIX)\lib mkdir $(PREFIX)\lib
|
||||||
|
copy /Y sqlite3.h $(PREFIX)\include
|
||||||
|
copy /Y sqlite3ext.h $(PREFIX)\include
|
||||||
|
copy /Y $(SQLITE3_STATIC_BASE).lib $(PREFIX)\lib
|
||||||
|
|
||||||
|
clean:
|
||||||
|
del *.obj *.lib *.exe *.pdb *.dll *.exp
|
||||||
|
|
||||||
|
$(SQLITE3_STATIC_BASE).lib: sqlite3.c sqlite3.h
|
||||||
|
$(CC) $(CFLAGS) /Fd$(SQLITE3_STATIC_BASE).pdb /c sqlite3.c
|
||||||
|
$(AR) sqlite3.obj /OUT:$(SQLITE3_STATIC_BASE).lib
|
||||||
|
|
||||||
|
$(SQLITE3_EXE_BASE).exe: shell.c sqlite3.c sqlite3.h
|
||||||
|
$(CC) $(CFLAGS) shell.c sqlite3.c /Fd$(SQLITE3_EXE_BASE).pdb /Fe$(SQLITE3_EXE_BASE).exe
|
||||||
|
|
||||||
|
$(SQLITE3_DLL_BASE).dll: sqlite3.c sqlite3.h
|
||||||
|
$(CC) $(CFLAGS) /DSQLITE_API=__declspec(dllexport) /Fd$(SQLITE3_DLL_BASE).pdb /c sqlite3.c
|
||||||
|
$(LINK) /DLL /OUT:$(SQLITE3_DLL_BASE).dll sqlite3.obj
|
||||||
@@ -47,6 +47,13 @@ function arch2gnu(string $arch): string
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function match_pattern(string $pattern, string $subject): bool
|
||||||
|
{
|
||||||
|
$pattern = str_replace(['\*', '\\\\.*'], ['.*', '\*'], preg_quote($pattern, '/'));
|
||||||
|
$pattern = '/^' . $pattern . '$/i';
|
||||||
|
return preg_match($pattern, $subject) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
function quote(string $str, string $quote = '"'): string
|
function quote(string $str, string $quote = '"'): string
|
||||||
{
|
{
|
||||||
return $quote . $str . $quote;
|
return $quote . $str . $quote;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||||
$extensions = match (PHP_OS_FAMILY) {
|
$extensions = match (PHP_OS_FAMILY) {
|
||||||
'Linux', 'Darwin' => 'calendar,ctype,curl,dom,fileinfo,filter,gd,iconv,imagick,mbregex,mbstring,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,rar,redis,session,simplexml,soap,sockets,sqlite3,swoole,swoole-hook-mysql,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib',
|
'Linux', 'Darwin' => 'zlib,openssl,curl,pcntl,posix,mbstring,tokenizer,phar',
|
||||||
'Windows' => 'mbstring,openssl',
|
'Windows' => 'mbstring,pdo_sqlite,mbregex,ffi',
|
||||||
};
|
};
|
||||||
|
|
||||||
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
||||||
@@ -62,6 +62,7 @@ $final_libs = trim($with_libs, $trim_value);
|
|||||||
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
$final_extensions_cmd = '"' . $final_extensions . '"';
|
$final_extensions_cmd = '"' . $final_extensions . '"';
|
||||||
|
$final_libs = $final_libs === '' ? '' : ('"' . $final_libs . '"');
|
||||||
} else {
|
} else {
|
||||||
$final_extensions_cmd = $final_extensions;
|
$final_extensions_cmd = $final_extensions;
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ if (PHP_OS_FAMILY === 'Windows') {
|
|||||||
echo match ($argv[1]) {
|
echo match ($argv[1]) {
|
||||||
'extensions' => $final_extensions,
|
'extensions' => $final_extensions,
|
||||||
'libs' => $final_libs,
|
'libs' => $final_libs,
|
||||||
'libs_cmd' => ($final_libs === '' ? '' : (' --with-libs="' . $final_libs . '"')),
|
'libs_cmd' => ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)),
|
||||||
'cmd' => $final_extensions_cmd . ($final_libs === '' ? '' : (' --with-libs="' . $final_libs . '"')),
|
'cmd' => $final_extensions_cmd . ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)),
|
||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
|
|||||||
25
src/globals/tests/gettext.php
Normal file
25
src/globals/tests/gettext.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
assert(function_exists('gettext'));
|
||||||
|
assert(function_exists('bindtextdomain'));
|
||||||
|
assert(function_exists('textdomain'));
|
||||||
|
assert(function_exists('bind_textdomain_codeset'));
|
||||||
|
|
||||||
|
if (!is_dir('locale/en_US/LC_MESSAGES/')) {
|
||||||
|
mkdir('locale/en_US/LC_MESSAGES/', 0755, true);
|
||||||
|
}
|
||||||
|
if (!file_exists('locale/en_US/LC_MESSAGES/test.mo')) {
|
||||||
|
$mo = '3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABgAAAFEAAAAXAQAAWAAAAAcAAABwAQAAAQAAAAAAAAAAAAAAAgAAAAAAAAAA56S65L6LAFByb2plY3QtSWQtVmVyc2lvbjogUEFDS0FHRSBWRVJTSU9OClJlcG9ydC1Nc2dpZC1CdWdzLVRvOiAKUE8tUmV2aXNpb24tRGF0ZTogWUVBUi1NTy1EQSBITzpNSStaT05FCkxhc3QtVHJhbnNsYXRvcjogRlVMTCBOQU1FIDxFTUFJTEBBRERSRVNTPgpMYW5ndWFnZS1UZWFtOiBMQU5HVUFHRSA8TExAbGkub3JnPgpMYW5ndWFnZTogCk1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA4Yml0CgBFeGFtcGxlAA==';
|
||||||
|
file_put_contents('locale/en_US/LC_MESSAGES/test.mo', base64_decode($mo));
|
||||||
|
}
|
||||||
|
putenv('LANG=en_US');
|
||||||
|
setlocale(LC_ALL, 'en_US');
|
||||||
|
|
||||||
|
$domain = 'test';
|
||||||
|
bindtextdomain($domain, 'locale/');
|
||||||
|
bind_textdomain_codeset($domain, 'UTF-8');
|
||||||
|
textdomain($domain);
|
||||||
|
|
||||||
|
assert(gettext(json_decode('"\u793a\u4f8b"', true)) === 'Example');
|
||||||
90
tests/SPC/util/DependencyUtilTest.php
Normal file
90
tests/SPC/util/DependencyUtilTest.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\util;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Config;
|
||||||
|
use SPC\util\DependencyUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class DependencyUtilTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetExtLibsByDeps(): void
|
||||||
|
{
|
||||||
|
// example
|
||||||
|
Config::$source = [
|
||||||
|
'test1' => [
|
||||||
|
'type' => 'url',
|
||||||
|
'url' => 'https://pecl.php.net/get/APCu',
|
||||||
|
'filename' => 'apcu.tgz',
|
||||||
|
'license' => [
|
||||||
|
'type' => 'file',
|
||||||
|
'path' => 'LICENSE',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Config::$lib = [
|
||||||
|
'libaaa' => [
|
||||||
|
'source' => 'test1',
|
||||||
|
'static-libs' => ['libaaa.a'],
|
||||||
|
'lib-depends' => ['libbbb', 'libccc'],
|
||||||
|
'lib-suggests' => ['libeee'],
|
||||||
|
],
|
||||||
|
'libbbb' => [
|
||||||
|
'source' => 'test1',
|
||||||
|
'static-libs' => ['libbbb.a'],
|
||||||
|
'lib-suggests' => ['libccc'],
|
||||||
|
],
|
||||||
|
'libccc' => [
|
||||||
|
'source' => 'test1',
|
||||||
|
'static-libs' => ['libccc.a'],
|
||||||
|
],
|
||||||
|
'libeee' => [
|
||||||
|
'source' => 'test1',
|
||||||
|
'static-libs' => ['libeee.a'],
|
||||||
|
'lib-suggests' => ['libfff'],
|
||||||
|
],
|
||||||
|
'libfff' => [
|
||||||
|
'source' => 'test1',
|
||||||
|
'static-libs' => ['libfff.a'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
Config::$ext = [
|
||||||
|
'ext-a' => [
|
||||||
|
'type' => 'builtin',
|
||||||
|
'lib-depends' => ['libaaa'],
|
||||||
|
'ext-suggests' => ['ext-b'],
|
||||||
|
],
|
||||||
|
'ext-b' => [
|
||||||
|
'type' => 'builtin',
|
||||||
|
'lib-depends' => ['libeee'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
// test getExtLibsByDeps (notmal test with ext-depends and lib-depends)
|
||||||
|
|
||||||
|
[$exts, $libs, $not_included] = DependencyUtil::getExtsAndLibs(['ext-a'], include_suggested_exts: true);
|
||||||
|
$this->assertContains('libbbb', $libs);
|
||||||
|
$this->assertContains('libccc', $libs);
|
||||||
|
$this->assertContains('ext-b', $exts);
|
||||||
|
$this->assertContains('ext-b', $not_included);
|
||||||
|
// test dep order
|
||||||
|
$this->assertIsInt($b = array_search('libbbb', $libs));
|
||||||
|
$this->assertIsInt($c = array_search('libccc', $libs));
|
||||||
|
$this->assertIsInt($a = array_search('libaaa', $libs));
|
||||||
|
// libbbb, libaaa
|
||||||
|
$this->assertTrue($b < $a);
|
||||||
|
$this->assertTrue($c < $a);
|
||||||
|
$this->assertTrue($c < $b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNotExistExtException(): void
|
||||||
|
{
|
||||||
|
$this->expectException(WrongUsageException::class);
|
||||||
|
DependencyUtil::getExtsAndLibs(['sdsd']);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user