Compare commits

...

53 Commits

Author SHA1 Message Date
crazywhalecc
54f7837f2b Update README.md 2024-07-14 01:23:08 +08:00
crazywhalecc
151c38fa37 Update README.md 2024-07-14 01:22:19 +08:00
crazywhalecc
758b697cee Update docs 2024-07-14 01:20:29 +08:00
crazywhalecc
4dbbf05d5c Tests pre-built feature 2024-07-14 01:20:29 +08:00
crazywhalecc
c0e08a617a Tests 2024-07-14 01:20:29 +08:00
crazywhalecc
de4e219dac Fix opcache for windows not build bug 2024-07-14 01:20:29 +08:00
crazywhalecc
37b48380a5 Disable libyuv for libavif 2024-07-14 01:20:29 +08:00
crazywhalecc
8ca21c42f5 Remove libiconv-win pre-built 2024-07-14 01:20:29 +08:00
crazywhalecc
daa8fad466 Remove redundant license debug msg 2024-07-14 01:20:29 +08:00
crazywhalecc
b1bcf254e4 Fix swoole with event extension <util.h> conflict bug 2024-07-14 01:20:29 +08:00
crazywhalecc
5bd9115a20 Fix pre-built openssl cannot find source in openssl ext patch 2024-07-14 01:20:29 +08:00
crazywhalecc
0839130845 Add pkgroot for spc-alpine-docker 2024-07-14 01:20:29 +08:00
crazywhalecc
6583517dc5 Add pkgroot for spc-alpine-docker 2024-07-14 01:20:29 +08:00
crazywhalecc
7fb8417216 Provide libevent, libiconv-win, libsodium, libwebp, libyaml, ncurses, readline, unixodbc, xz pre-built libs 2024-07-14 01:20:29 +08:00
crazywhalecc
9170d71dc7 Provide libcares pre-built binary 2024-07-14 01:20:29 +08:00
crazywhalecc
2f6987c07b Provide icu pre-built binary 2024-07-14 01:20:29 +08:00
crazywhalecc
dc514eb176 Fix pkgconf patch with space between '=' bug 2024-07-14 01:20:29 +08:00
crazywhalecc
fb85d7c32f Add onig as pre-built library 2024-07-14 01:20:29 +08:00
crazywhalecc
aad260c31e Adjust shell debug log 2024-07-14 01:20:29 +08:00
crazywhalecc
778cd7b2c7 Add timer for build libs 2024-07-14 01:20:29 +08:00
crazywhalecc
ea3cb0218a Add brotli, libargon2, libavif, libiconv, libpng, libtiff pre-built libs 2024-07-14 01:20:29 +08:00
crazywhalecc
d9e9c8c6b7 Remove suffix for LicenseDumper and LicenseDumperTest 2024-07-14 01:20:29 +08:00
crazywhalecc
eec8ee03bf Add license installer for build mode 2024-07-14 01:20:29 +08:00
crazywhalecc
386e9adf44 Add openssl to pre-built 2024-07-14 01:20:29 +08:00
crazywhalecc
1c670f433b Remove perl.exe check log in doctor 2024-07-14 01:20:29 +08:00
crazywhalecc
4432a177a7 Remove initSource for sorted libs in WindowsBuilder 2024-07-14 01:20:29 +08:00
crazywhalecc
73179de5dd Fix windows sqlite portable build 2024-07-14 01:20:29 +08:00
crazywhalecc
67c2421528 Add liblz4, sqlite for pre-built libs 2024-07-14 01:20:29 +08:00
crazywhalecc
893fc97dba Patch sqlite pkgconf file 2024-07-14 01:20:29 +08:00
crazywhalecc
c8355d8381 Remove icu tools 2024-07-14 01:20:29 +08:00
crazywhalecc
cdf3e76528 Fix alpine-docker ssl bug 2024-07-14 01:20:29 +08:00
crazywhalecc
5d39766298 Fix CI quote 2024-07-14 01:20:29 +08:00
crazywhalecc
26d72203c5 Add aarch64-linux to CI 2024-07-14 01:20:29 +08:00
crazywhalecc
fcd2610d79 Fix CI 2024-07-14 01:20:29 +08:00
crazywhalecc
d769b51af2 Fix CI 2024-07-14 01:20:29 +08:00
crazywhalecc
c28a1bccac Fix CI 2024-07-14 01:20:29 +08:00
crazywhalecc
5a869b5c77 Use bash in windows 2024-07-14 01:20:29 +08:00
crazywhalecc
26cff8ebd0 Fix CI 2024-07-14 01:20:29 +08:00
crazywhalecc
bf5bbf24f2 Fix CI 2024-07-14 01:20:29 +08:00
crazywhalecc
bfaf540bb9 Remove windows with pkg-config 2024-07-14 01:20:29 +08:00
crazywhalecc
1d9c008100 Remove windows with pkg-config 2024-07-14 01:20:29 +08:00
crazywhalecc
c842416a9a Add pack-lib tests 2024-07-14 01:20:29 +08:00
crazywhalecc
bdc6b2807a Add pack-lib tests 2024-07-14 01:20:29 +08:00
crazywhalecc
c6a22fbd14 Code style fix and comment addition 2024-07-14 01:20:29 +08:00
crazywhalecc
3c0eb68c70 Add pre-built lib feature 2024-07-14 01:20:29 +08:00
Jerry Ma
522d8b4890 Add spx extension support (#501) 2024-07-06 21:56:42 +08:00
Jerry Ma
29cd50206c Fix prefer-stable negative result in ghtar (#500)
* Fix prefer-stable got opposite result

* Add swoole tests and remove irrelevant tests
2024-07-05 14:35:51 +08:00
Jerry Ma
8d9f7be051 Update release-build.yml 2024-07-05 11:49:56 +08:00
Jerry Ma
96484b0dbd Update release-build.yml 2024-07-05 11:44:46 +08:00
Jerry Ma
72a3c01b31 Fix libyaml patch slashes (#499)
* Fix libyaml patch slashes

* Add tests for libyaml

* Rename due to linux is case-sensitive
2024-07-04 23:59:56 +08:00
Kévin Dunglas
3e077543a7 fix: xz download (#495)
* fix: xz download

* zx -> xz
2024-07-04 16:31:33 +08:00
Jerry Ma
ab948dedaf docs: Add php-src modifications & Release SPC enhancement (#494)
* docs: Add php-src modifications

* Fix release-build.yml
2024-07-01 15:13:08 +08:00
DimitriyB
2cfb672f4e Update xz version to 5.4.7 (#493)
* Update source.json

* Add xz test

---------

Co-authored-by: Jerry Ma <jesse2061@outlook.com>
2024-07-01 14:32:17 +08:00
76 changed files with 2660 additions and 1898 deletions

View File

@@ -34,7 +34,12 @@ on:
description: extensions to compile (comma separated)
required: true
type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug:
description: enable debug logs
type: boolean
env:
@@ -73,6 +78,8 @@ jobs:
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
@@ -84,7 +91,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }}
run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command
- run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated)
required: true
type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug:
description: enable debug logs
type: boolean
env:
@@ -67,6 +72,8 @@ jobs:
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
@@ -78,7 +85,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: CACHE_API_EXEC=yes ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }}
run: CACHE_API_EXEC=yes ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command
- run: ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated)
required: true
type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug:
description: enable debug logs
type: boolean
env:
@@ -82,6 +87,8 @@ jobs:
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
@@ -93,7 +100,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }}
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -28,7 +28,12 @@ on:
description: extensions to compile (comma separated)
required: true
type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug:
description: enable debug logs
type: boolean
env:
@@ -80,6 +85,8 @@ jobs:
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
@@ -91,7 +98,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }}
run: ./bin/spc download --with-php=${{ inputs.version }} --for-extensions=${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -25,7 +25,12 @@ on:
description: extensions to compile (comma separated)
required: true
type: string
prefer-pre-built:
description: prefer pre-built binaries (reduce build time)
type: boolean
default: true
debug:
description: enable debug logs
type: boolean
env:
@@ -65,6 +70,8 @@ jobs:
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $env:GITHUB_ENV
- if: inputs.prefer-pre-built == true
run: echo "SPC_PRE_BUILT=--prefer-pre-built" >> $env:GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
@@ -76,7 +83,7 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php="${{ inputs.version }}" --for-extensions="${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }}
run: ./bin/spc download --with-php="${{ inputs.version }}" --for-extensions="${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_PRE_BUILT }}
# Run build command
- run: ./bin/spc build "${{ inputs.extensions }}" ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}

View File

@@ -8,22 +8,32 @@ on:
- published
workflow_dispatch:
env:
PHP_VERSION: 8.2
MICRO_VERSION: 8.2.18
jobs:
build-release-artifacts:
name: "Build SPC Binary"
runs-on: macos-14
name: "Build SPC Binary for ${{ matrix.operating-system.name }}"
runs-on: ${{ matrix.operating-system.os }}
strategy:
matrix:
php-version:
- "8.2"
micro-version:
- "8.2.18"
operating-system:
- "linux-x86_64"
- "macos-x86_64"
- "linux-aarch64"
- "macos-aarch64"
- "windows-x64"
- name: "linux-x86_64"
os: "ubuntu-latest"
filename: "spc-linux-x86_64.tar.gz"
- name: "macos-x86_64"
os: "macos-13"
filename: "spc-macos-x86_64.tar.gz"
- name: "linux-aarch64"
os: "ubuntu-latest"
filename: "spc-linux-aarch64.tar.gz"
- name: "macos-aarch64"
os: "macos-14"
filename: "spc-macos-aarch64.tar.gz"
- name: "windows-x64"
os: "ubuntu-latest"
filename: "spc-windows-x64.exe"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
@@ -36,7 +46,7 @@ jobs:
with:
coverage: none
tools: composer:v2
php-version: "${{ matrix.php-version }}"
php-version: "${{ env.PHP_VERSION }}"
ini-values: memory_limit=-1
- name: "Get Composer Cache Directory"
@@ -48,9 +58,9 @@ jobs:
uses: "actions/cache@v4"
with:
path: "${{ steps.composer-cache.outputs.dir }}"
key: "php-${{ matrix.php-version }}-locked-composer-${{ hashFiles('**/composer.lock') }}"
key: "php-${{ env.PHP_VERSION }}-locked-composer-${{ hashFiles('**/composer.lock') }}"
restore-keys: |
php-${{ matrix.php-version }}-locked-composer
php-${{ env.PHP_VERSION }}-locked-composer
- name: "Install Locked Dependencies"
run: "composer install --no-interaction --no-progress"
@@ -58,56 +68,52 @@ jobs:
- name: "Build PHAR File"
run: "composer build:phar"
- name: "Download minimal combination"
- name: "Download Minimal Combination"
run: |
if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
curl https://dl.static-php.dev/static-php-cli/windows/spc-min/php-${{ matrix.micro-version }}-micro-win.zip -o tmp.zip
if [ "${{ matrix.operating-system.name }}" = "windows-x64" ]; then
curl https://dl.static-php.dev/static-php-cli/windows/spc-min/php-${{ env.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
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ env.MICRO_VERSION }}-micro-${{ matrix.operating-system.name }}.tar.gz -o tmp.tgz
tar -zxvf tmp.tgz
fi
- name: "Generate Executable"
run: |
bin/spc micro:combine spc.phar -M micro.sfx -O spc -I "memory_limit=2G"
if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
if [ "${{ matrix.operating-system.name }}" = "windows-x64" ]; then
mv spc spc.exe
else
chmod +x spc
fi
if [ "${{ matrix.operating-system }}" = "macos-aarch64" ] || [ "${{ matrix.operating-system }}" = "macos-x86_64" ]; then
if [ "${{ matrix.operating-system.name }}" = "macos-aarch64" ] || [ "${{ matrix.operating-system.name }}" = "macos-x86_64" ]; then
sudo xattr -cr ./spc
fi
- name: "Archive Executable"
- name: "Archive Executable and Validate Binary"
run: |
if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
if [ "${{ matrix.operating-system }}" == "macos-aarch64" ]; then
if [ "${{ matrix.operating-system.name }}" != "windows-x64" ]; then
tar -czf ${{ matrix.operating-system.filename }} spc
# validate spc binary
if [ "${{ matrix.operating-system.name }}" == "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
- name: "Copy file"
run: |
if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS
if [ "${{ matrix.operating-system.name }}" != "windows-x64" ]; then
mkdir dist/ && cp ${{ matrix.operating-system.filename }} dist/ && cp spc dist/spc-${{ matrix.operating-system.name }}
else
mkdir dist/ && cp spc.exe dist/${{ env.filename }}
mkdir dist/ && cp spc.exe dist/${{ matrix.operating-system.filename }}
echo "SUFFIX=.exe" >> $GITHUB_ENV
fi
- name: upload binaries to release
- name: "Upload Binaries to Release"
uses: softprops/action-gh-release@v1
if: ${{startsWith(github.ref, 'refs/tags/') }}
with:
files: dist/${{ env.filename }}
files: dist/${{ matrix.operating-system.filename }}
- name: "Deploy to Self-Hosted Server"
if: github.repository == 'crazywhalecc/static-php-cli'
@@ -125,4 +131,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
path: spc${{ env.SUFFIX }}
name: spc-${{ matrix.operating-system }}${{ env.SUFFIX }}
name: spc-${{ matrix.operating-system.name }}${{ env.SUFFIX }}

View File

@@ -8,6 +8,14 @@ on:
- 'src/globals/test-extensions.php'
pull_request:
branches: [ "main" ]
paths:
- 'src/**'
- 'config/**'
- '.github/workflows/tests.yml'
- 'bin/**'
- 'composer.json'
- 'box.json'
- '.php-cs-fixer.php'
permissions:
contents: read
@@ -168,7 +176,13 @@ jobs:
- name: "Run Build Tests (download)"
run: |
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 --retry=5
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 --retry=5 --shallow-clone --prefer-pre-built
- name: "Download pre-built libraries for pkg-config"
if: matrix.os != 'windows-latest'
run: |
bin/spc del-download pkg-config
bin/spc download pkg-config --prefer-pre-built --debug
- name: "Run Build Tests (build, *nix)"
if: matrix.os != 'windows-latest'
@@ -176,4 +190,4 @@ jobs:
- name: "Run Build Tests (build, windows)"
if: matrix.os == 'windows-latest'
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $env:UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --debug --enable-micro-win32
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $env:UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --debug

4
.gitignore vendored
View File

@@ -19,6 +19,10 @@ docker/source/
# default package root directory
/pkgroot/
# default pack:lib and release directory
/dist/
packlib_files.txt
# tools cache files
.php-cs-fixer.cache
.phpunit.result.cache

View File

@@ -43,15 +43,17 @@ static-php-cli简称 `spc`)有许多特性:
如果你不想自行编译 PHP可以从本项目现有的示例 Action 下载 Artifact也可以从自托管的服务器下载。
- [扩展组合 - common](https://dl.static-php.dev/static-php-cli/common/)common 组合包含了约 [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) 个常用扩展,体积为 7.5MB 左右。
- [扩展组合 - bulk](https://dl.static-php.dev/static-php-cli/bulk/)bulk 组合包含了 [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) 个扩展,体积为 25MB 左右。
- [扩展组合 - minimal](https://dl.static-php.dev/static-php-cli/minimal/)minimal 组合包含了 [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) 个扩展,体积为 3MB 左右
| 组合名称 | 组合扩展数 | 系统 | 备注 |
|---------------------------------------------------------------------|----------------------------------------------------------------------------|-------------|--------------|
| [common](https://dl.static-php.dev/static-php-cli/common/) | [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) | Linux/macOS | 体积为 7.5MB 左右 |
| [bulk](https://dl.static-php.dev/static-php-cli/bulk/) | [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) | Linux/macOS | 体积为 25MB 左右 |
| [minimal](https://dl.static-php.dev/static-php-cli/minimal/) | [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) | Linux/macOS | 体积为 3MB 左右 |
| [spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min) | [5](https://dl.static-php.dev/static-php-cli/windows/spc-min/README.txt) | Windows | 体积为 3MB 左右 |
| [spc-max](https://dl.static-php.dev/static-php-cli/windows/spc-max) | [40+](https://dl.static-php.dev/static-php-cli/windows/spc-max/README.txt) | Windows | 体积为 8.5MB 左右 |
> Linux 和 Windows 默认启用了 UPX 压缩,可减小 30~50% 的 PHP 二进制体积。
> macOS 当前不支持 UPX所以上述预编译的 macOS 版本体积可能较大。
对于 Windows 系统,目前支持的扩展较少,故仅提供 SPC 自身运行的最小扩展组合的 `cli``micro`[扩展组合 - spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/)。
## 使用 static-php-cli 构建 PHP
### 编译环境需求
@@ -89,6 +91,7 @@ static-php-cli简称 `spc`)有许多特性:
| 8.1 | :heavy_check_mark: | PHP 官方仅对 8.1 提供安全更新 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :x: | WIP |
### 支持的扩展
@@ -110,7 +113,7 @@ static-php-cli简称 `spc`)有许多特性:
如果你选择了 `debug`,则会在构建时输出所有日志,包括编译的日志,以供排查错误。
### 本地构建(使用 spc 二进制)
### 本地构建(使用 spc 二进制,推荐
该项目提供了 static-php-cli 的二进制文件:`spc`
您可以使用 `spc` 二进制文件,无需安装任何运行时(用起来就像 golang 程序)。
@@ -144,6 +147,8 @@ chmod +x ./spc
### 本地构建(使用 git 源码)
如果你需要修改 static-php-cli 源码,或者使用 spc 二进制构建有问题,你可以使用 git 源码下载 static-php-cli。
```bash
# clone 仓库即可
git clone https://github.com/crazywhalecc/static-php-cli.git
@@ -177,6 +182,8 @@ bin/spc --version
./bin/spc download --all
# 只拉取编译指定扩展需要的所有依赖(推荐)
./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite"
# 下载依赖时,优先下载有预编译的库(节省编译依赖的时间)
./bin/spc download --for-extensions="openssl,curl,mbstring,mbregex" --prefer-pre-built
# 下载编译不同版本的 PHP (--with-php=x.y推荐 7.3 ~ 8.3)
./bin/spc download --for-extensions="openssl,curl,mbstring" --with-php=8.1
@@ -184,7 +191,7 @@ bin/spc --version
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
# 编译线程安全版本 (--enable-zts)
./bin/spc build "curl,phar" --enable-zts --build-cli
# 编译后使用 UPX 减小可执行文件体积 (--with-upx-pack) (至少压缩至原来的 30~50%)
# 编译后使用 UPX 减小可执行文件体积 (仅 Linux、Windows 可用) (至少压缩至原来的 30~50%)
./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack
```

View File

@@ -49,16 +49,17 @@ If you don't want to build or want to test first, you can download example pre-c
Below are several precompiled static-php binaries with different extension combinations,
which can be downloaded directly according to your needs.
- [Extension-Combination - common](https://dl.static-php.dev/static-php-cli/common/): `common` contains about [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) commonly used extensions, and the size is about 7.5MB.
- [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 25MB 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 3MB in size.
| Combination | Extension Count | OS | Comment |
|----------------------------------------------------------------------|----------------------------------------------------------------------------|--------------|--------------------------------|
| [common](https://dl.static-php.dev/static-php-cli/common/) | [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) | Linux, macOS | The binary size is about 7.5MB |
| [bulk](https://dl.static-php.dev/static-php-cli/bulk/) | [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) | Linux, macOS | The binary size is about 25MB |
| [minimal](https://dl.static-php.dev/static-php-cli/minimal/) | [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) | Linux, macOS | The binary size is about 3MB |
| [spc-min](https://dl.static-php.dev/static-php-cli/windows/spc-min/) | [5](https://dl.static-php.dev/static-php-cli/windows/spc-min/README.txt) | Windows | The binary size is about 3MB |
| [spc-max](https://dl.static-php.dev/static-php-cli/windows/spc-max/) | [40+](https://dl.static-php.dev/static-php-cli/windows/spc-max/README.txt) | Windows | The binary size is about 8.5MB |
> Linux and Windows supports UPX compression for binaries, which can reduce the size of the binary by 30% to 50%.
> macOS does not support UPX compression, so the size of the pre-built binaries for mac is larger.
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
### Compilation Requirements
@@ -97,6 +98,7 @@ Currently supported PHP versions for compilation:
| 8.1 | :heavy_check_mark: | PHP official has security fixes only |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :x: | WIP |
### Supported Extensions
@@ -121,7 +123,7 @@ and at the same time define the extensions to be compiled by yourself.
If you enable `debug`, all logs will be output at build time, including compiled logs, for troubleshooting.
### Build Locally (using SPC binary)
### Build Locally (using SPC binary, recommended)
This project provides a binary file of static-php-cli: `spc`.
You can use `spc` binary instead of installing any runtime like golang app.
@@ -155,6 +157,9 @@ Self-hosted `spc` is built by GitHub Actions, you can also download from Actions
### Build Locally (using git source)
If you need to modify the static-php-cli source code, or have problems using the spc binary build,
you can download static-php-cli using the git source code.
```bash
# just clone me!
git clone https://github.com/crazywhalecc/static-php-cli.git
@@ -188,6 +193,8 @@ Basic usage for building php with some extensions:
./bin/spc download --all
# only fetch necessary sources by needed extensions (recommended)
./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite"
# download pre-built libraries first (save time for compiling dependencies)
./bin/spc download --for-extensions="openssl,curl,mbstring,mbregex" --prefer-pre-built
# 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
@@ -195,7 +202,7 @@ Basic usage for building php with some extensions:
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
# build thread-safe (ZTS) version (--enable-zts)
./bin/spc build "curl,phar" --enable-zts --build-cli
# build, pack executable with UPX (--with-upx-pack) (reduce binary size for 30~50%)
# build, pack executable with UPX (linux and windows only) (reduce binary size for 30~50%)
./bin/spc build "curl,phar" --enable-zts --build-cli --with-upx-pack
```

View File

@@ -56,6 +56,7 @@ if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
FROM $ALPINE_FROM
$SPC_USE_MIRROR
RUN apk update; \
apk upgrade -a; \
apk add --no-cache \
autoconf \
automake \
@@ -108,6 +109,19 @@ else
INTERACT=''
fi
# Mounting volumes
MOUNT_LIST=""
# shellcheck disable=SC2089
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/config:/app/config"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/src:/app/src"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/buildroot:/app/buildroot"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/source:/app/source"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
# Run docker
# shellcheck disable=SC2068
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@
# shellcheck disable=SC2086
# shellcheck disable=SC2090
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH bin/spc $@

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
{
"repo": "static-php/static-php-cli-hosted",
"match-pattern": "{name}-{arch}-{os}.tgz",
"pack-config": {}
"prefer-stable": true,
"match-pattern": "{name}-{arch}-{os}.txz",
"suffix": "txz"
}

View File

@@ -29,6 +29,7 @@
"brotli": {
"type": "ghtar",
"repo": "google/brotli",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -38,6 +39,7 @@
"type": "filelist",
"url": "https://sourceware.org/pub/bzip2/",
"regex": "/href=\"(?<file>bzip2-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "text",
"text": "This program, \"bzip2\", the associated library \"libbzip2\", and all documentation, are copyright (C) 1996-2010 Julian R Seward. All rights reserved. \n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nJulian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.6 of 6 September 2010\n\nPATENTS: To the best of my knowledge, bzip2 and libbzip2 do not use any patented algorithms. However, I do not have the resources to carry out a patent search. Therefore I cannot give any guarantee of the above statement."
@@ -182,6 +184,7 @@
"gmp": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz",
"provide-pre-built": true,
"alt": {
"type": "ghtagtar",
"repo": "alisw/GMP"
@@ -196,6 +199,7 @@
"repo": "unicode-org/icu",
"match": "icu4c.+-src\\.tgz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -251,6 +255,7 @@
"type": "git",
"rev": "master",
"url": "https://github.com/static-php/phc-winner-argon2",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -259,6 +264,7 @@
"libavif": {
"type": "ghtar",
"repo": "AOMediaCodec/libavif",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -269,6 +275,7 @@
"repo": "c-ares/c-ares",
"match": "c-ares-.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"alt": {
"type": "filelist",
"url": "https://c-ares.org/download/",
@@ -284,6 +291,7 @@
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -312,6 +320,7 @@
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/libiconv/",
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -339,6 +348,7 @@
"repo": "lz4/lz4",
"match": "lz4-.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -357,6 +367,7 @@
"type": "git",
"url": "https://github.com/glennrp/libpng.git",
"rev": "libpng16",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -376,6 +387,7 @@
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -395,6 +407,7 @@
"type": "filelist",
"url": "https://download.osgeo.org/libtiff/",
"regex": "/href=\"(?<file>tiff-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE.md"
@@ -426,6 +439,7 @@
"libwebp": {
"type": "url",
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -453,6 +467,7 @@
"repo": "yaml/libyaml",
"match": "yaml-.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "License"
@@ -503,6 +518,7 @@
"type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/ncurses/",
"regex": "/href=\"(?<file>ncurses-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -523,6 +539,7 @@
"repo": "kkos/oniguruma",
"match": "onig-.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -532,6 +549,7 @@
"type": "filelist",
"url": "https://www.openssl.org/source/",
"regex": "/href=\"(?<file>openssl-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE.txt"
@@ -560,6 +578,7 @@
"pkg-config": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -615,6 +634,7 @@
"type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/readline/",
"regex": "/href=\"(?<file>readline-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -640,9 +660,20 @@
"path": "COPYING"
}
},
"spx": {
"type": "git",
"rev": "master",
"url": "https://github.com/static-php/php-spx.git",
"path": "php-src/ext/spx",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"sqlite": {
"type": "url",
"url": "https://www.sqlite.org/2023/sqlite-autoconf-3430200.tar.gz",
"provide-pre-built": true,
"license": {
"type": "text",
"text": "The author disclaims copyright to this source code. In place of\na legal notice, here is a blessing:\n\n * May you do good and not evil.\n * May you find forgiveness for yourself and forgive others.\n * May you share freely, never taking more than you give."
@@ -691,6 +722,7 @@
"unixodbc": {
"type": "url",
"url": "https://www.unixodbc.org/unixODBC-2.3.12.tar.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -717,8 +749,11 @@
}
},
"xz": {
"type": "url",
"url": "https://fossies.org/linux/misc/xz-5.4.6.tar.xz",
"type": "ghrel",
"repo": "tukaani-project/xz",
"match": "xz.+\\.tar\\.xz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -749,6 +784,7 @@
"repo": "madler/zlib",
"match": "zlib.+\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
"type": "text",
"text": "(C) 1995-2022 Jean-loup Gailly and Mark Adler\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nJean-loup Gailly Mark Adler\njloup@gzip.org madler@alumni.caltech.edu"

View File

@@ -10,8 +10,11 @@
<h2>{{ I18N[lang].selectExt }}{{ checkedExts.length > 0 ? (' (' + checkedExts.length + ')') : '' }}</h2>
<div class="box">
<div v-for="(item, index) in ext" class="ext-item">
<input type="checkbox" :id="index" :value="index" v-model="checkedExts" :disabled="extDisableList.indexOf(index) !== -1">
<label :for="index">{{ index }}</label>
<span v-if="isSupported(index, selectedSystem)">
<input type="checkbox" :id="index" :value="index" v-model="checkedExts" :disabled="extDisableList.indexOf(index) !== -1">
<label :for="index">{{ index }}</label>
</span>
</div>
</div>
<div class="my-btn" v-if="selectedSystem !== 'windows'" @click="selectCommon">{{ I18N[lang].selectCommon }}</div>
@@ -46,59 +49,80 @@
<p>{{ I18N[lang].windowsSAPIUnavailable }}</p>
</div>
<h2>{{ I18N[lang].buildOptions }}</h2>
<div class="option-line">
<span class="option-title">{{ I18N[lang].buildEnvironment }}</span>
<select v-model="selectedEnv">
<option value="native">{{ I18N[lang].buildEnvNative }}</option>
<option value="spc">{{ I18N[lang].buildEnvSpc }}</option>
<option value="docker" v-if="selectedSystem !== 'windows'">{{ I18N[lang].buildEnvDocker }}</option>
</select>
</div>
<div v-if="selectedEnv === 'spc'" class="option-line">
<span class="option-title">{{ I18N[lang].selectedArch }}</span>
<select v-model="selectedArch">
<option value="x86_64">x86_64 (amd64)</option>
<option value="aarch64" v-if="selectedSystem !== 'windows'">aarch64 (arm64)</option>
</select>
</div>
<div class="option-line">
<span class="option-title">{{ I18N[lang].downloadPhpVersion }}</span>
<select v-model="selectedPhpVersion">
<option v-for="item in availablePhpVersions" :value="item">{{ item }}</option>
</select>
</div>
<div class="option-line">
<span class="option-title">{{ I18N[lang].useDebug }}</span>
<input type="radio" id="debug-yes" :value="1" v-model="debug" />
<label for="debug-yes">{{ I18N[lang].yes }}</label>
<!-- Refactor all build options in table -->
<table>
<!-- buildEnvironment -->
<tr>
<td>{{ I18N[lang].buildEnvironment }}</td>
<td>
<select v-model="selectedEnv">
<option value="native">{{ I18N[lang].buildEnvNative }}</option>
<option value="spc">{{ I18N[lang].buildEnvSpc }}</option>
<option value="docker" v-if="selectedSystem !== 'windows'">{{ I18N[lang].buildEnvDocker }}</option>
</select>
</td>
</tr>
<!-- Download PHP version -->
<tr>
<td>{{ I18N[lang].downloadPhpVersion }}</td>
<td>
<select v-model="selectedPhpVersion">
<option v-for="item in availablePhpVersions" :value="item">{{ item }}</option>
</select>
</td>
</tr>
<!-- Enable debug message -->
<tr>
<td>{{ I18N[lang].useDebug }}</td>
<td>
<input type="radio" id="debug-yes" :value="1" v-model="debug" />
<label for="debug-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="debug-no" :value="0" v-model="debug" />
<label for="debug-no">{{ I18N[lang].no }}</label>
</td>
</tr>
<!-- Enable ZTS -->
<tr>
<td>{{ I18N[lang].useZTS }}</td>
<td>
<input type="radio" id="zts-yes" :value="1" v-model="zts" />
<label for="zts-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="zts-no" :value="0" v-model="zts" />
<label for="zts-no">{{ I18N[lang].no }}</label>
</td>
</tr>
<!-- download corresponding extensions -->
<tr>
<td>{{ I18N[lang].resultShowDownload }}</td>
<td>
<input type="radio" id="show-download-yes" :value="1" v-model="downloadByExt" />
<label for="show-download-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="show-download-no" :value="0" v-model="downloadByExt" />
<label for="show-download-no">{{ I18N[lang].no }}</label>
</td>
</tr>
<!-- Download pre-built -->
<tr>
<td>{{ I18N[lang].usePreBuilt }}</td>
<td>
<input type="radio" id="pre-built-yes" :value="1" v-model="preBuilt" />
<label for="pre-built-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="pre-built-no" :value="0" v-model="preBuilt" />
<label for="pre-built-no">{{ I18N[lang].no }}</label>
</td>
</tr>
<!-- Enable UPX -->
<tr v-if="selectedSystem !== 'macos'">
<td>{{ I18N[lang].useUPX }}</td>
<td>
<input type="radio" id="upx-yes" :value="1" v-model="enableUPX" />
<label for="upx-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="upx-no" :value="0" v-model="enableUPX" />
<label for="upx-no">{{ I18N[lang].no }}</label>
</td>
</tr>
</table>
<input type="radio" id="debug-no" :value="0" v-model="debug" />
<label for="debug-no">{{ I18N[lang].no }}</label>
</div>
<div class="option-line">
<span class="option-title">{{ I18N[lang].useZTS }}</span>
<input type="radio" id="zts-yes" :value="1" v-model="zts" />
<label for="zts-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="zts-no" :value="0" v-model="zts" />
<label for="zts-no">{{ I18N[lang].no }}</label>
</div>
<div class="option-line">
<span class="option-title">{{ I18N[lang].resultShowDownload }}</span>
<input type="radio" id="show-download-yes" :value="1" v-model="downloadByExt" />
<label for="show-download-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="show-download-no" :value="0" v-model="downloadByExt" />
<label for="show-download-no">{{ I18N[lang].no }}</label>
</div>
<div class="option-line" v-if="selectedSystem !== 'macos'">
<span class="option-title">{{ I18N[lang].useUPX }}</span>
<input type="radio" id="upx-yes" :value="1" v-model="enableUPX" />
<label for="upx-yes">{{ I18N[lang].yes }}</label>
<input type="radio" id="upx-no" :value="0" v-model="enableUPX" />
<label for="upx-no">{{ I18N[lang].no }}</label>
</div>
<h2>{{ I18N[lang].hardcodedINI }}</h2>
<textarea class="textarea" :placeholder="I18N[lang].hardcodedINIPlacehoder" v-model="hardcodedINIData" rows="5" />
<h2>{{ I18N[lang].resultShow }}</h2>
@@ -116,11 +140,11 @@
</div>
<div v-if="downloadByExt" class="command-container">
<b>{{ I18N[lang].downloadExtOnlyCommand }}</b>
<div class="command-preview">{{ spcCommand }} download --with-php={{ selectedPhpVersion }} --for-extensions "{{ extList }}"{{ debug ? ' --debug' : '' }}</div>
<div class="command-preview">{{ spcCommand }} download --with-php={{ selectedPhpVersion }} --for-extensions "{{ extList }}"{{ preBuilt ? ' --prefer-pre-built' : '' }}{{ debug ? ' --debug' : '' }}</div>
</div>
<div v-else class="command-container">
<b>{{ I18N[lang].downloadAllCommand }}</b>
<div class="command-preview">{{ spcCommand }} download --all --with-php={{ selectedPhpVersion }}{{ debug ? ' --debug' : '' }}</div>
<div class="command-preview">{{ spcCommand }} download --all --with-php={{ selectedPhpVersion }}{{ preBuilt ? ' --prefer-pre-built' : '' }}{{ debug ? ' --debug' : '' }}</div>
</div>
<div class="command-container" v-if="enableUPX">
<b>{{ I18N[lang].downloadUPXCommand }}</b>
@@ -162,6 +186,14 @@ const osList = [
{ os: 'windows', label: 'Windows', disabled: false },
];
const isSupported = (extName, os) => {
// Convert os to target: linux->Linux, macos->Darwin, windows->Windows (using map)
const a = new Map([['linux', 'Linux'], ['macos', 'Darwin'], ['windows', 'Windows']]);
const osName = a.get(os);
const osSupport = ext.value[extName]?.support?.[osName] ?? 'yes';
return osSupport === 'yes' || osSupport === 'partial';
};
const availablePhpVersions = [
'7.4',
'8.0',
@@ -201,8 +233,9 @@ const I18N = {
depTips: '选择扩展后,不可选中的项目为必需的依赖,编译的依赖库列表中可选的为现有扩展和依赖库的可选依赖。选择可选依赖后,将生成 --with-libs 参数。',
microUnavailable: 'micro 不支持 PHP 7.4 及更早版本!',
windowsSAPIUnavailable: 'Windows 目前不支持 fpm、embed 构建!',
useUPX: '是否开启 UPX 压缩(减小二进制体积,但很少见的情况下 micro SAPI 无法使用',
useUPX: '是否开启 UPX 压缩(减小二进制体积)',
windowsDownSPCWarning: 'Windows 下请手动下载 spc.exe 二进制文件并解压到当前目录!',
usePreBuilt: '如果可能,下载预编译的依赖库(减少编译时间)',
},
en: {
selectExt: 'Select Extensions',
@@ -234,8 +267,9 @@ const I18N = {
depTips: 'After selecting the extensions, the unselectable items are essential dependencies. In the compiled dependencies list, optional dependencies consist of existing extensions and optional dependencies of libraries. Optional dependencies will be added in --with-libs parameter.',
microUnavailable: 'Micro does not support PHP 7.4 and earlier versions!',
windowsSAPIUnavailable: 'Windows does not support fpm and embed build!',
useUPX: 'Enable UPX compression (reduce binary size, but in rare cases micro SAPI doesn\'t work with UPX)',
useUPX: 'Enable UPX compression (reduce binary size)',
windowsDownSPCWarning: 'Please download the spc.exe binary file manually and extract it to the current directory on Windows!',
usePreBuilt: 'Download pre-built dependencies if possible (reduce compile time)',
}
};
@@ -305,6 +339,9 @@ const zts = ref(0);
// chosen download by extensions
const downloadByExt = ref(1);
// use pre-built
const preBuilt = ref(1);
// chosen upx
const enableUPX = ref(0);

View File

@@ -13,7 +13,7 @@ export default {
themeConfig: {
nav: [
{text: 'Guide', link: '/en/guide/',},
{text: 'Developing', link: '/en/develop/'},
{text: 'Advanced', link: '/en/develop/'},
{text: 'Contributing', link: '/en/contributing/'},
{text: 'FAQ', link: '/en/faq/'},
],
@@ -30,7 +30,7 @@ export default {
themeConfig: {
nav: [
{text: '构建指南', link: '/zh/guide/'},
{text: '开发指南', link: '/zh/develop/'},
{text: '进阶', link: '/zh/develop/'},
{text: '贡献', link: '/zh/contributing/'},
{text: 'FAQ', link: '/zh/faq/'},
],

View File

@@ -25,6 +25,7 @@ export default {
items: [
{text: 'Get Started', link: '/en/develop/'},
{text: 'Project Structure', link: '/en/develop/structure'},
{text: 'PHP Source Modification', link: '/en/develop/php-src-changes'},
],
},
{

View File

@@ -25,6 +25,7 @@ export default {
items: [
{ text: '开发简介', link: '/zh/develop/' },
{ text: '项目结构简介', link: '/zh/develop/structure' },
{text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes'},
],
},
{

View File

@@ -0,0 +1,59 @@
# Modifications to PHP source code
During the static compilation process, static-php-cli made some modifications to the PHP source code
in order to achieve good compatibility, performance, and security.
The following is a description of the current modifications to the PHP source code.
## Micro related patches
Based on the patches provided by the phpmicro project,
static-php-cli has made some modifications to the PHP source code to meet the needs of static compilation.
The patches currently used by static-php-cli during compilation in the [patch list](https://github.com/easysoft/phpmicro/tree/master/patches) are:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml patch
Because PHP only provides security updates for 8.1 and stops updating older versions,
static-php-cli applies the libxml compilation patch that has been applied in newer versions of PHP to PHP 8.1 and below.
## gd extension Windows patch
Compiling the gd extension under Windows requires major changes to the `config.w32` file.
static-php-cli has made some changes to the gd extension to make it easier to compile under Windows.
## YAML extension Windows patch
YAML extension needs to modify the `config.w32` file to compile under Windows.
static-php-cli has made some modifications to the YAML extension to make it easier to compile under Windows.
## static-php-cli version information insertion
When compiling, static-php-cli will insert the static-php-cli version information into the PHP version information for easy identification.
## Add option to hardcode INI
When using the `-I` parameter to hardcode INI into static PHP functionality,
static-php-cli will modify the PHP source code to insert the hardcoded content.
## Linux system repair patch
Some compilation environments may lack some system header files or libraries.
static-php-cli will automatically fix these problems during compilation, such as:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Fiber issue fix patch for Windows
When compiling PHP on Windows, there will be some issues with the Fiber extension.
static-php-cli will automatically fix these issues during compilation (modify `config.w32` in php-src).

View File

@@ -24,7 +24,8 @@ The following is the source download configuration corresponding to the `libeven
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"license": {
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
}
@@ -55,6 +56,8 @@ Each source file in source.json has the following params:
- `license`: the open source license of the source code, see **Open Source License** section below
- `type`: must be one of the types mentioned above
- `path` (optional): release the source code to the specified directory instead of `source/{name}`
- `provide-pre-built` (optional): whether to provide precompiled binary files.
If `true`, it will automatically try to download precompiled binary files when running `bin/spc download`
::: tip
The `path` parameter in `source.json` can specify a relative or absolute path. When specified as a relative path, the path is based on `source/`.

View File

@@ -19,7 +19,7 @@ The project is mainly divided into several folders:
- `bin/`: used to store program entry files, including `bin/spc`, `bin/spc-alpine-docker`, `bin/setup-runtime`.
- `config/`: Contains all the extensions and dependent libraries supported by the project,
as well as the download link and download methods of these sources. It is divided into files: `lib.json`, `ext.json`, `source.json`, `pkg.json` .
as well as the download link and download methods of these sources. It is divided into files: `lib.json`, `ext.json`, `source.json`, `pkg.json`, `pre-built.json` .
- `src/`: The core code of the project, including the entire framework and commands for compiling various extensions and libraries.
- `vendor/`: The directory that Composer depends on, you do not need to make any modifications to it.

View File

@@ -144,3 +144,8 @@ If you enable event extension on macOS, the `openpty` will be disabled due to is
## parallel
Parallel is only supported on PHP 8.0 ZTS and above.
## spx
1. The [SPX extension](https://github.com/NoiseByNorthwest/php-spx) only supports NTS mode.
2. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx).

View File

@@ -157,6 +157,9 @@ bin/spc download php-src,micro,zstd,ext-zstd
# Download only extensions and libraries to be compiled (use extensions, including suggested libraries)
bin/spc download --for-extensions=openssl,swoole,zip,pcntl,zstd
# Download resources, prefer to download dependencies with pre-built packages (reduce the time to compile dependencies)
bin/spc download --for-extensions="curl,pcntl,xml,mbstring" --prefer-pre-built
# Download only the extensions and dependent libraries to be compiled (use extensions, excluding suggested libraries)
bin/spc download --for-extensions=openssl,swoole,zip,pcntl --without-suggestions
@@ -388,6 +391,8 @@ when you use static-php-cli to build PHP or modify and enhance the static-php-cl
- `dev:sort-config`: Sort the list of configuration files in the `config/` directory in alphabetical order
- `dev:lib-ver <lib-name>`: Read the version from the source code of the dependency library (only available for specific dependency libraries)
- `dev:ext-ver <ext-name>`: Read the corresponding version from the source code of the extension (only available for specific extensions)
- `dev:pack-lib <lib-name>`: Package the specified library into a tar.gz file (maintainer only)
- `dev:gen-ext-docs`: Generate extension documentation (maintainer only)
```bash
# output all extensions information
@@ -523,3 +528,12 @@ Commonly used objects and functions using the `-P` function are:
static-php-cli has many open methods, which cannot be listed in the docs,
but as long as it is a `public function` and is not marked as `@internal`, it theoretically can be called.
:::
## Multiple builds
If you need to build multiple times locally, the following method can save you time downloading resources and compiling.
- If you only switch the PHP version without changing the dependent libraries, you can use `bin/spc switch-php-version` to quickly switch the PHP version, and then re-run the same `build` command.
- If you want to rebuild once, but do not re-download the source code, you can first `rm -rf buildroot source` to delete the compilation directory and source code directory, and then rebuild.
- If you want to update a version of a dependency, you can use `bin/spc del-download <source-name>` to delete the specified source code, and then use `download <source-name>` to download it again.
- If you want to update all dependent versions, you can use `bin/spc download --clean` to delete all downloaded sources, and then download them again.

View File

@@ -0,0 +1,51 @@
# 对 PHP 源码的修改
由于 static-php-cli 在静态编译过程中为了实现良好的兼容性、性能和安全性,对 PHP 源码进行了一些修改。下面是目前对 PHP 源码修改的说明。
## micro 相关补丁
基于 phpmicro 项目提供的补丁static-php-cli 对 PHP 源码进行了一些修改,以适应静态编译的需求。[补丁列表](https://github.com/easysoft/phpmicro/tree/master/patches) 包含:
目前 static-php-cli 在编译时用到的补丁有:
- static_opcache
- static_extensions_win32
- cli_checks
- disable_huge_page
- vcruntime140
- win32
- zend_stream
- cli_static
- macos_iconv
- phar
## PHP <= 8.1 libxml 补丁
因为 PHP 官方仅对 8.1 进行安全更新,旧版本停止更新,所以 static-php-cli 对 PHP 8.1 及以下版本应用了在新版本 PHP 中已经应用的 libxml 编译补丁。
## gd 扩展 Windows 补丁
在 Windows 下编译 gd 扩展需要大幅改动 `config.w32` 文件static-php-cli 对 gd 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## yaml 扩展 Windows 补丁
yaml 扩展在 Windows 下编译需要修改 `config.w32` 文件static-php-cli 对 yaml 扩展进行了一些修改,使其在 Windows 下编译更加方便。
## static-php-cli 版本信息插入
static-php-cli 在编译时会在 PHP 版本信息中插入 static-php-cli 的版本信息,以便于识别。
## 加入硬编码 INI 的选项
在使用 `-I` 参数硬编码 INI 到静态 PHP 的功能中static-php-cli 会修改 PHP 源码以插入硬编码内容。
## Linux 系统修复补丁
部分编译环境可能缺少一些头文件或库static-php-cli 会在编译时自动修复这些问题,如:
- HAVE_STRLCAT missing problem
- HAVE_STRLCPY missing problem
## Windows 系统下 Fiber 问题修复补丁
在 Windows 下编译 PHP 时Fiber 扩展会出现一些问题static-php-cli 会在编译时自动修复这些问题(修改 php-src 的 `config.w32`)。

View File

@@ -18,6 +18,7 @@ static-php-cli 的下载资源模块是一个主要的功能,它包含了所
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -44,6 +45,7 @@ source.json 中每个源文件拥有以下字段:
- `license`: 源代码的开源许可证,见下方 **开源许可证** 章节
- `type`: 必须为上面提到的类型之一
- `path`(可选): 释放源码到指定目录而非 `source/{name}`
- `provide-pre-built`(可选): 是否提供预编译的二进制文件,如果为 `true`,则会在 `bin/spc download` 时尝试自动下载预编译的二进制文件
::: tip
`source.json` 中的 `path` 参数可指定相对路径或绝对路径。当指定为相对路径时,路径基于 `source/`

View File

@@ -14,7 +14,7 @@ static-php-cli 主要包含三种逻辑组件:资源、依赖库、扩展。
项目主要分为几个文件夹:
- `bin/`: 用于存放程序入口文件,包含 `bin/spc``bin/spc-alpine-docker``bin/setup-runtime`
- `config/`: 包含了所有项目支持的扩展、依赖库以及这些资源下载的地址、下载方式等,分为四个文件`lib.json``ext.json``source.json``pkg.json`
- `config/`: 包含了所有项目支持的扩展、依赖库以及这些资源下载的地址、下载方式等,:`lib.json``ext.json``source.json``pkg.json``pre-built.json`
- `src/SPC/`: 项目的核心代码,包含了整个框架以及编译各种扩展和库的命令。
- `src/globals/`: 项目的全局方法和常量、运行时需要的测试文件(例如:扩展的可用性检查代码)。
- `vendor/`: Composer 依赖的目录,你无需对它做出任何修改。

View File

@@ -131,3 +131,8 @@ event 扩展在 macOS 系统下编译后暂无法使用 `openpty` 特性。相
## parallel
parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`--enable-zts`)。
# spx
1. [SPX 扩展](https://github.com/NoiseByNorthwest/php-spx) 只支持非线程模式。
2. SPX 目前不支持 Windows且官方仓库也不支持静态编译static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)。

View File

@@ -135,6 +135,9 @@ bin/spc download --for-libs=liblz4,libevent --without-suggestions
# 下载资源时,忽略部分资源的缓存,强制下载(如切换 PHP 版本)
bin/spc download --for-extensions=curl,pcntl,xml --ignore-cache-sources=php-src --with-php=8.3
# 下载资源时,优先下载有预编译包的依赖库(减少编译依赖的时间)
bin/spc download --for-extensions="curl,pcntl,xml,mbstring" --prefer-pre-built
# 下载所有依赖包
bin/spc download --all
@@ -346,6 +349,8 @@ bin/spc extract php-src,libxml2
- `dev:sort-config`: 对 `config/` 目录下的配置文件的列表按照字母表排序
- `dev:lib-ver <lib-name>`: 从依赖库的源码中读取版本(仅特定依赖库可用)
- `dev:ext-ver <ext-name>`: 从扩展的源码中读取对应版本(仅特定扩展可用)
- `dev:pack-lib <lib-name>`: 打包指定的依赖库(仅发布者可用)
- `dev:gen-ext-docs`: 生成扩展文档(仅发布者可用)
```bash
# 输出所有扩展
@@ -466,3 +471,12 @@ memory_limit => 8G => 8G
::: tip
static-php-cli 开放的方法非常多,文档中无法一一列举,但只要是 `public function` 并且不被标注为 `@internal`,均可调用。
:::
## 多次构建
如果你在本地要多次构建,以下方法可以为你节省下载资源、编译的时间。
- 仅切换 PHP 版本,不更换依赖库版本时,可以使用 `bin/spc switch-php-version` 快速切换 PHP 版本,然后重新运行同样的 `build` 命令。
- 如果你想重新构建一次,但不重新下载源码,可以先 `rm -rf buildroot source` 删除编译目录和源码目录,然后重新构建。
- 如果你想更新某个依赖的版本,可以使用 `bin/spc del-download <source-name>` 删除指定的源码,然后使用 `download <source-name>` 重新下载。
- 如果你想更新所有依赖的版本,可以使用 `bin/spc download --clean` 删除所有下载的源码,然后重新下载。

View File

@@ -11,6 +11,7 @@ use SPC\command\dev\AllExtCommand;
use SPC\command\dev\ExtVerCommand;
use SPC\command\dev\GenerateExtDocCommand;
use SPC\command\dev\LibVerCommand;
use SPC\command\dev\PackLibCommand;
use SPC\command\dev\PhpVerCommand;
use SPC\command\dev\SortConfigCommand;
use SPC\command\DoctorCommand;
@@ -54,6 +55,7 @@ final class ConsoleApplication extends Application
new ExtVerCommand(),
new SortConfigCommand(),
new GenerateExtDocCommand(),
new PackLibCommand(),
]
);
}

View File

@@ -45,20 +45,22 @@ abstract class BuilderBase
abstract public function proveLibs(array $sorted_libraries);
/**
* Build libraries
* Set-Up libraries
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function buildLibs(): void
public function setupLibs(): void
{
// build all libs
foreach ($this->libs as $lib) {
match ($lib->tryBuild($this->getOption('rebuild', false))) {
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'),
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
$starttime = microtime(true);
match ($lib->setup($this->getOption('rebuild', false))) {
LIB_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] setup success, took ' . round(microtime(true) - $starttime, 2) . ' s'),
LIB_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
LIB_STATUS_BUILD_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
LIB_STATUS_INSTALL_FAILED => logger()->error('lib [' . $lib::NAME . '] install failed'),
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
};
}

View File

@@ -8,6 +8,7 @@ use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceManager;
abstract class LibraryBase
@@ -32,6 +33,32 @@ abstract class LibraryBase
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
}
/**
* Try to install or build this library.
* @param bool $force If true, force install or build
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function setup(bool $force = false): int
{
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib(static::NAME, 'source');
// if source is locked as pre-built, we just tryInstall it
if (isset($lock[$source]) && ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
return $this->tryInstall($lock[$source]['filename'], $force);
}
return $this->tryBuild($force);
}
/**
* Get library name.
*/
public function getName(): string
{
return static::NAME;
}
/**
* Get current lib source root dir.
*/
@@ -119,6 +146,45 @@ abstract class LibraryBase
return Config::getLib(static::NAME, 'headers', []);
}
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public function tryInstall(string $install_file, bool $force_install = false): int
{
if ($force_install) {
logger()->info('Installing required library [' . static::NAME . '] from pre-built binaries');
// Extract files
try {
FileSystem::extractPackage($install_file, DOWNLOAD_PATH . '/' . $install_file, BUILD_ROOT_PATH);
$this->install();
return LIB_STATUS_OK;
} catch (FileSystemException|RuntimeException $e) {
logger()->error('Failed to extract pre-built library [' . static::NAME . ']: ' . $e->getMessage());
return LIB_STATUS_INSTALL_FAILED;
}
}
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryInstall($install_file, true);
return LIB_STATUS_OK;
}
}
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryInstall($install_file, true);
return LIB_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryInstall($install_file, true);
return LIB_STATUS_OK;
}
return LIB_STATUS_ALREADY;
}
/**
* Try to build this library, before build, we check first.
*
@@ -151,31 +217,32 @@ abstract class LibraryBase
}
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
$this->build();
$this->installLicense();
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
return BUILD_STATUS_OK;
return LIB_STATUS_OK;
}
// check if these libraries exist, if not, invoke compilation and return the result status
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
return LIB_STATUS_OK;
}
}
// header files the same
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
return LIB_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
return LIB_STATUS_OK;
}
// if all the files exist at this point, skip the compilation process
return BUILD_STATUS_ALREADY;
return LIB_STATUS_ALREADY;
}
/**
@@ -206,6 +273,11 @@ abstract class LibraryBase
*/
abstract public function getBuilder(): BuilderBase;
public function beforePack(): void
{
// do something before pack, default do nothing. overwrite this method to do something (e.g. modify pkg-config file)
}
/**
* Build this library.
*
@@ -213,6 +285,11 @@ abstract class LibraryBase
*/
abstract protected function build();
protected function install(): void
{
// do something after extracting pre-built files, default do nothing. overwrite this method to do something
}
/**
* Add lib dependency
*
@@ -235,4 +312,26 @@ abstract class LibraryBase
{
return str_replace('-', '_', static::NAME);
}
/**
* Install license files in buildroot directory
*/
protected function installLicense(): void
{
FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName());
$source = Config::getLib($this->getName(), 'source');
$license_files = Config::getSource($source)['license'] ?? [];
if (is_assoc_array($license_files)) {
$license_files = [$license_files];
}
foreach ($license_files as $index => $license) {
if ($license['type'] === 'text') {
FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']);
continue;
}
if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt");
}
}
}
}

View File

@@ -13,7 +13,7 @@ class openssl extends Extension
public function patchBeforeMake(): bool
{
// patch openssl3 with php8.0 bug
if (file_exists(SOURCE_PATH . '/openssl/VERSION.dat') && $this->builder->getPHPVersionID() < 80100) {
if ($this->builder->getPHPVersionID() < 80100) {
$openssl_c = file_get_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c');
$openssl_c = preg_replace('/REGISTER_LONG_CONSTANT\s*\(\s*"OPENSSL_SSLV23_PADDING"\s*.+;/', '', $openssl_c);
file_put_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c', $openssl_c);

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\WrongUsageException;
use SPC\util\CustomExt;
#[CustomExt('spx')]
class spx extends Extension
{
/**
* @throws WrongUsageException
*/
public function validate(): void
{
if ($this->builder->getOption('enable-zts')) {
throw new WrongUsageException('ext-spx is not thread safe, do not build it with ZTS builds');
}
}
public function getUnixConfigureArg(): string
{
$arg = '--enable-spx';
if ($this->builder->getExt('zlib') === null) {
$arg .= ' --with-zlib-dir=' . BUILD_ROOT_PATH;
}
return $arg;
}
}

View File

@@ -5,11 +5,24 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('swoole')]
class swoole extends Extension
{
public function patchBeforeMake(): bool
{
if ($this->builder instanceof MacOSBuilder) {
// Fix swoole with event extension <util.h> conflict bug
$util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h';
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/swoole/thirdparty/php/standard/proc_open.cc', 'include <util.h>', 'include "' . $util_path . '"');
return true;
}
return false;
}
public function getExtVersion(): ?string
{
// Get version from source directory

View File

@@ -6,6 +6,8 @@ namespace SPC\builder\linux\library;
class icu extends LinuxLibraryBase
{
use \SPC\builder\unix\library\icu;
public const NAME = 'icu';
protected function build(): void
@@ -21,10 +23,10 @@ class icu extends LinuxLibraryBase
'--disable-shared ' .
'--with-data-packaging=static ' .
'--enable-release=yes ' .
'--enable-extras=yes ' .
'--enable-extras=no ' .
'--enable-icuio=yes ' .
'--enable-dyload=no ' .
'--enable-tools=yes ' .
'--enable-tools=no ' .
'--enable-tests=no ' .
'--enable-samples=no ' .
'--prefix=' . BUILD_ROOT_PATH
@@ -32,5 +34,7 @@ class icu extends LinuxLibraryBase
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -79,13 +79,15 @@ class openssl extends LinuxLibraryBase
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
}
}

View File

@@ -6,15 +6,19 @@ namespace SPC\builder\macos\library;
class icu extends MacOSLibraryBase
{
use \SPC\builder\unix\library\icu;
public const NAME = 'icu';
protected function build(): void
{
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir . '/source')
->exec("./runConfigureICU MacOSX --enable-static --disable-shared --prefix={$root}")
->exec("./runConfigureICU MacOSX --enable-static --disable-shared --disable-extras --disable-samples --disable-tests --disable-tools --prefix={$root}")
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
$this->patchPkgconfPrefix(['icu-i18n.pc', 'icu-io.pc', 'icu-uc.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -62,13 +62,15 @@ class openssl extends MacOSLibraryBase
$this->patchPkgconfPrefix(['libssl.pc', 'openssl.pc', 'libcrypto.pc']);
// patch for openssl 3.3.0+
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/openssl.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
if (!str_contains($file = FileSystem::readFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc'), 'prefix=')) {
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=' . BUILD_ROOT_PATH . "\n" . $file);
FileSystem::writeFile(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', 'prefix=${pcfiledir}/../..' . "\n" . $file);
}
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/pkgconfig/libcrypto.pc', '/Libs.private:.*/m', 'Libs.private: ${libdir}/libz.a');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
}
}

View File

@@ -75,10 +75,10 @@ trait UnixLibraryTrait
logger()->debug('Patching ' . $realpath);
// replace prefix
$file = FileSystem::readFile($realpath);
$file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix=.*$/m', 'prefix=' . BUILD_ROOT_PATH, $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir=.*$/m', 'includedir=${prefix}/include', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_PREFIX) === PKGCONF_PATCH_PREFIX ? preg_replace('/^prefix\s*=.*$/m', 'prefix=${pcfiledir}/../..', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_EXEC_PREFIX) === PKGCONF_PATCH_EXEC_PREFIX ? preg_replace('/^exec_prefix\s*=.*$/m', 'exec_prefix=${prefix}', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_LIBDIR) === PKGCONF_PATCH_LIBDIR ? preg_replace('/^libdir\s*=.*$/m', 'libdir=${prefix}/lib', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_INCLUDEDIR) === PKGCONF_PATCH_INCLUDEDIR ? preg_replace('/^includedir\s*=.*$/m', 'includedir=${prefix}/include', $file) : $file;
$file = ($patch_option & PKGCONF_PATCH_CUSTOM) === PKGCONF_PATCH_CUSTOM && $custom_replace !== null ? preg_replace($custom_replace[0], $custom_replace[1], $file) : $file;
FileSystem::writeFile($realpath, $file);
}

View File

@@ -11,7 +11,6 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceManager;
use SPC\util\DependencyUtil;
abstract class UnixBuilderBase extends BuilderBase
@@ -129,14 +128,6 @@ abstract class UnixBuilderBase extends BuilderBase
foreach ($this->libs as $lib) {
$lib->calcDependency();
}
// patch point
$this->emitPatchPoint('before-libs-extract');
// extract sources
SourceManager::initSource(libs: $sorted_libraries);
$this->emitPatchPoint('after-libs-extract');
}
/**

View File

@@ -34,5 +34,9 @@ trait brotli
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
}
}
if (file_exists(BUILD_BIN_PATH . '/brotli')) {
unlink(BUILD_BIN_PATH . '/brotli');
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
trait icu
{
public function beforePack(): void
{
// Replace buildroot/bin/icu-config default_prefix=* to placeholder default_prefix={BUILD_ROOT_PATH}
$icu_config = BUILD_ROOT_PATH . '/bin/icu-config';
FileSystem::replaceFileRegex($icu_config, '/default_prefix=.*/m', 'default_prefix="{BUILD_ROOT_PATH}"');
}
protected function install(): void
{
$icu_config = BUILD_ROOT_PATH . '/bin/icu-config';
FileSystem::replaceFileStr($icu_config, '{BUILD_ROOT_PATH}', BUILD_ROOT_PATH);
}
}

View File

@@ -23,5 +23,9 @@ trait libargon2
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
}
}
if (file_exists(BUILD_BIN_PATH . '/argon2')) {
unlink(BUILD_BIN_PATH . '/argon2');
}
}
}

View File

@@ -23,7 +23,7 @@ trait libavif
// Start build
shell()->cd($this->source_dir . '/build')
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..")
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DAVIF_LIBYUV=OFF ..")
->execWithEnv("cmake --build . -j {$this->builder->concurrency}")
->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH);
// patch pkgconfig

View File

@@ -26,8 +26,10 @@ trait libcares
{
shell()->cd($this->source_dir)
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
->execWithEnv('./configure --prefix=' . BUILD_ROOT_PATH . ' --enable-static --disable-shared --disable-tests')
->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests')
->execWithEnv("make -j {$this->builder->concurrency}")
->exec('make install');
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -10,12 +10,36 @@ use SPC\store\FileSystem;
trait libevent
{
public function beforePack(): void
{
if (file_exists(BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake')) {
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/set\(_IMPORT_PREFIX .*\)/m',
'set(_IMPORT_PREFIX "{BUILD_ROOT_PATH}")'
);
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/INTERFACE_INCLUDE_DIRECTORIES ".*"/m',
'INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"'
);
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'/INTERFACE_LINK_LIBRARIES "libevent::core;.*"/m',
'INTERFACE_LINK_LIBRARIES "libevent::core;${_IMPORT_PREFIX}/lib/libssl.a;${_IMPORT_PREFIX}/lib/libcrypto.a"'
);
}
}
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
[$lib, $include, $destdir] = SEPARATED_PATH;
// CMake needs a clean build directory
FileSystem::resetDir($this->source_dir . '/build');
// Start build
@@ -36,5 +60,25 @@ trait libevent
)
->execWithEnv("cmake --build . -j {$this->builder->concurrency}")
->exec('make install');
$this->patchPkgconfPrefix(['libevent.pc', 'libevent_core.pc', 'libevent_extra.pc', 'libevent_openssl.pc']);
$this->patchPkgconfPrefix(
['libevent_openssl.pc'],
PKGCONF_PATCH_CUSTOM,
[
'/Libs.private:.*/m',
'Libs.private: -lssl -lcrypto',
]
);
}
protected function install(): void
{
FileSystem::replaceFileStr(
BUILD_LIB_PATH . '/cmake/libevent/LibeventTargets-static.cmake',
'{BUILD_ROOT_PATH}',
BUILD_ROOT_PATH
);
}
}

View File

@@ -20,5 +20,9 @@ trait libiconv
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . $destdir);
if (file_exists(BUILD_BIN_PATH . '/iconv')) {
unlink(BUILD_BIN_PATH . '/iconv');
}
}
}

View File

@@ -8,7 +8,14 @@ use SPC\store\FileSystem;
trait liblz4
{
protected function build()
public function patchBeforeBuild(): bool
{
// disable executables
FileSystem::replaceFileStr($this->source_dir . '/programs/Makefile', 'install: lz4', "install: lz4\n\ninstallewfwef: lz4");
return true;
}
protected function build(): void
{
shell()->cd($this->source_dir)
->exec("make PREFIX='' clean")

View File

@@ -8,11 +8,12 @@ trait libsodium
{
protected function build(): void
{
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir)
->exec("./configure --enable-static --disable-shared --prefix={$root}")
->exec('./configure --enable-static --disable-shared --prefix=')
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libsodium.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -4,10 +4,13 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
trait ncurses
{
protected function build(): void
{
$filelist = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
shell()->cd($this->source_dir)
->exec(
'./configure ' .
@@ -32,5 +35,22 @@ trait ncurses
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
$final = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
// Remove the new files
$new_files = array_diff($final, $filelist);
foreach ($new_files as $file) {
@unlink(BUILD_BIN_PATH . '/' . $file);
}
shell()->cd(BUILD_ROOT_PATH)->exec('rm -rf share/terminfo');
shell()->cd(BUILD_ROOT_PATH)->exec('rm -rf lib/terminfo');
$pkgconf_list = ['form.pc', 'menu.pc', 'ncurses++.pc', 'ncurses.pc', 'panel.pc', 'tic.pc'];
$this->patchPkgconfPrefix($pkgconf_list);
foreach ($pkgconf_list as $pkgconf) {
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/pkgconfig/' . $pkgconf, '-L' . BUILD_LIB_PATH, '-L${libdir}');
}
}
}

View File

@@ -13,5 +13,6 @@ trait sqlite
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['sqlite3.pc']);
}
}

View File

@@ -10,7 +10,6 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceManager;
use SPC\store\SourcePatcher;
use SPC\util\DependencyUtil;
use SPC\util\GlobalEnvManager;
@@ -245,9 +244,6 @@ class WindowsBuilder extends BuilderBase
foreach ($this->libs as $lib) {
$lib->calcDependency();
}
// extract sources
SourceManager::initSource(libs: $sorted_libraries);
}
/**

View File

@@ -26,6 +26,7 @@ class libavif extends WindowsLibraryBase
'-DBUILD_SHARED_LIBS=OFF ' .
'-DAVIF_BUILD_APPS=OFF ' .
'-DAVIF_BUILD_TESTS=OFF ' .
'-DAVIF_LIBYUV=OFF ' .
'-DAVID_ENABLE_GTEST=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)

View File

@@ -41,5 +41,12 @@ class libwebp extends WindowsLibraryBase
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
// Actually we don't need pkgconf in windows, but for packing, we still need patching prefix.
// for libsharpyuv, libwebp, libwebpdecoder, libwebpdemux
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libsharpyuv.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebp.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebpdecoder.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '\pkgconfig\libwebpdemux.pc', '/^prefix=.*/m', 'prefix=${pcfiledir}/../..');
}
}

View File

@@ -41,5 +41,11 @@ class openssl extends WindowsLibraryBase
'CNF_LDFLAGS="/NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd /DEFAULTLIB:libcmt /LIBPATH:' . BUILD_LIB_PATH . ' zlibstatic.lib"'
);
copy($this->source_dir . '\ms\applink.c', BUILD_INCLUDE_PATH . '\openssl\applink.c');
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '\cmake\OpenSSL\OpenSSLConfig.cmake',
'/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m',
'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}" ws2_32.lib gdi32.lib advapi32.lib crypt32.lib user32.lib)'
);
}
}

View File

@@ -147,8 +147,8 @@ class BuildCliCommand extends BuildCommand
$builder->proveExts($extensions);
// validate libs and exts
$builder->validateLibsAndExts();
// build libraries
$builder->buildLibs();
// build or install libraries
$builder->setupLibs();
if ($this->input->getOption('with-clean')) {
logger()->info('Cleaning source dir...');

View File

@@ -65,7 +65,7 @@ class BuildLibsCommand extends BuildCommand
sleep(2);
$builder->proveLibs($libraries);
$builder->validateLibsAndExts();
$builder->buildLibs();
$builder->setupLibs();
$time = round(microtime(true) - START_TIME, 3);
logger()->info('Build libs complete, used ' . $time . ' s !');

View File

@@ -38,8 +38,9 @@ class DownloadCommand extends BaseCommand
$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('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', '');
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', false);
$this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0');
$this->addOption('prefer-pre-built', 'P', null, 'Download pre-built libraries when available');
}
/**
@@ -147,12 +148,22 @@ class DownloadCommand extends BaseCommand
}
$chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
$force_all = empty($this->getOption('ignore-cache-sources'));
if (!$force_all) {
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
} else {
$sss = $this->getOption('ignore-cache-sources');
if ($sss === false) {
// false is no-any-ignores, that is, default.
$force_all = false;
$force_list = [];
} elseif ($sss === null) {
// null means all sources will be ignored, equals to --force-all (but we don't want to add too many options)
$force_all = true;
$force_list = [];
} else {
// ignore some sources
$force_all = false;
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
}
if ($this->getOption('all')) {
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
}
@@ -164,6 +175,17 @@ class DownloadCommand extends BaseCommand
$custom_urls[$source_name] = $url;
}
// If passing --prefer-pre-built option, we need to load pre-built library list from pre-built.json targeted releases
if ($this->getOption('prefer-pre-built')) {
$repo = Config::getPreBuilt('repo');
$pre_built_libs = Downloader::getLatestGithubRelease($repo, [
'repo' => $repo,
'prefer-stable' => Config::getPreBuilt('prefer-stable'),
], false);
} else {
$pre_built_libs = [];
}
// Download them
f_mkdir(DOWNLOAD_PATH);
$cnt = count($chosen_sources);
@@ -185,8 +207,21 @@ class DownloadCommand extends BaseCommand
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
Downloader::downloadSource($source, $new_config, true);
} else {
$config = Config::getSource($source);
// Prefer pre-built, we need to search pre-built library
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
// We need to replace pattern
$find = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
// find filename in asset list
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
continue;
}
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
}
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, Config::getSource($source), $force_all || in_array($source, $force_list));
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
}
}
$time = round(microtime(true) - START_TIME, 3);
@@ -286,4 +321,19 @@ class DownloadCommand extends BaseCommand
}
return array_values(array_unique($sources));
}
/**
* @param array $assets Asset list from GitHub API
* @param string $filename Match file name, e.g. pkg-config-aarch64-darwin.txz
* @return null|string Return the download URL if found, otherwise null
*/
private function findPreBuilt(array $assets, string $filename): ?string
{
foreach ($assets as $asset) {
if ($asset['name'] === $filename) {
return $asset['browser_download_url'];
}
}
return null;
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\command\BuildCommand;
use SPC\exception\ExceptionHandler;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
#[AsCommand('dev:pack-lib', 'Build and pack library as pre-built release')]
class PackLibCommand extends BuildCommand
{
public function configure(): void
{
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
}
public function handle(): int
{
try {
$lib_name = $this->getArgument('library');
$builder = BuilderProvider::makeBuilderByInput($this->input);
$builder->setLibsOnly();
$libraries = DependencyUtil::getLibs([$lib_name]);
logger()->info('Building libraries: ' . implode(',', $libraries));
sleep(2);
FileSystem::createDir(WORKING_DIR . '/dist');
$builder->proveLibs($libraries);
$builder->validateLibsAndExts();
foreach ($builder->getLibs() as $lib) {
if ($lib->getName() !== $lib_name) {
// other dependencies: install or build, both ok
$lib->setup();
} else {
// Get lock info
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib($lib->getName(), 'source');
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
return static::FAILURE;
}
// Before build: load buildroot/ directory
$before_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
// build
$lib->tryBuild(true);
// do something like patching pkg-conf files.
$lib->beforePack();
// After build: load buildroot/ directory, and calculate increase files
$after_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
$increase_files = array_diff($after_buildroot, $before_buildroot);
// every file mapped with BUILD_ROOT_PATH
// get BUILD_ROOT_PATH last dir part
$buildroot_part = basename(BUILD_ROOT_PATH);
$increase_files = array_map(fn ($file) => $buildroot_part . '/' . $file, $increase_files);
// write list to packlib_files.txt
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
// pack
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
}
}
$time = round(microtime(true) - START_TIME, 3);
logger()->info('Build libs complete, used ' . $time . ' s !');
return static::SUCCESS;
} catch (\Throwable $e) {
if ($this->getOption('debug')) {
ExceptionHandler::getInstance()->handle($e);
} else {
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
logger()->critical('Please check with --debug option to see more details.');
}
return static::FAILURE;
}
}
}

View File

@@ -71,7 +71,7 @@ class WindowsToolCheckList
if (($path = SystemUtil::findCommand('perl.exe')) === null) {
return CheckResult::fail('perl not found in path.', 'install-perl');
}
if (!str_contains(implode('', cmd()->execWithResult(quote($path) . ' -v')[1]), 'MSWin32')) {
if (!str_contains(implode('', cmd()->execWithResult(quote($path) . ' -v', false)[1]), 'MSWin32')) {
return CheckResult::fail($path . ' is not built for msvc.', 'install-perl');
}
return CheckResult::ok();

View File

@@ -20,6 +20,16 @@ class Config
public static ?array $ext = null;
public static ?array $pre_built = null;
public static function getPreBuilt(string $name): mixed
{
if (self::$pre_built === null) {
self::$pre_built = FileSystem::loadConfigArray('pre-built');
}
return self::$pre_built[$name] ?? null;
}
/**
* 从配置文件读取一个资源(source)的元信息
*

View File

@@ -69,7 +69,7 @@ class Downloader
retry: intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0)
), true);
if (($source['prefer-stable'] ?? false) === true) {
if (($source['prefer-stable'] ?? false) === false) {
$url = $data[0]['tarball_url'];
} else {
$id = 0;
@@ -100,14 +100,15 @@ class Downloader
/**
* Get latest version from GitHub release (uploaded archive)
*
* @param string $name source name
* @param array $source source meta info: [repo, match]
* @return array<int, string> [url, filename]
* @param string $name source name
* @param array $source source meta info: [repo, match]
* @param bool $match_result Whether to return matched result by `match` param (default: true)
* @return array<int, string> When $match_result = true, and we matched, [url, filename]. Otherwise, [{asset object}. ...]
* @throws DownloaderException
*/
public static function getLatestGithubRelease(string $name, array $source): array
public static function getLatestGithubRelease(string $name, array $source, bool $match_result = true): array
{
logger()->debug("finding {$name} source from github releases assests");
logger()->debug("finding {$name} from github releases assests");
$data = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/releases",
hooks: [[CurlHook::class, 'setupGithubToken']],
@@ -118,6 +119,9 @@ class Downloader
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
continue;
}
if (!$match_result) {
return $release['assets'];
}
foreach ($release['assets'] as $asset) {
if (preg_match('|' . $source['match'] . '|', $asset['name'])) {
$url = $asset['browser_download_url'];
@@ -127,7 +131,7 @@ class Downloader
}
if (!$url) {
throw new DownloaderException("failed to find {$name} source");
throw new DownloaderException("failed to find {$name} release metadata");
}
$filename = basename($url);
@@ -176,11 +180,10 @@ class Downloader
/**
* Just download file using system curl command, and lock it
*
* @throws DownloaderException
* @throws RuntimeException
* @throws FileSystemException
* @throws RuntimeException
*/
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null): void
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
{
logger()->debug("Downloading {$url}");
$cancel_func = function () use ($filename) {
@@ -193,7 +196,7 @@ class Downloader
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0));
self::unregisterCancelEvent();
logger()->debug("Locking {$filename}");
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path]);
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
}
/**
@@ -218,7 +221,7 @@ class Downloader
* @throws FileSystemException
* @throws RuntimeException
*/
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0): void
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
{
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
if (file_exists($download_path)) {
@@ -253,7 +256,7 @@ class Downloader
}
// Lock
logger()->debug("Locking git source {$name}");
self::lockSource($name, ['source_type' => 'dir', 'dirname' => $name, 'move_path' => $move_path]);
self::lockSource($name, ['source_type' => 'dir', 'dirname' => $name, 'move_path' => $move_path, 'lock_as' => $lock_as]);
/*
// 复制目录过去
@@ -313,28 +316,28 @@ class Downloader
switch ($pkg['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'url': // Direct download URL
$url = $pkg['url'];
$filename = $pkg['filename'] ?? basename($pkg['url']);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'git': // Git repo
self::downloadGit(
@@ -342,7 +345,8 @@ class Downloader
$pkg['url'],
$pkg['rev'],
$pkg['extract'] ?? null,
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0)
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0),
SPC_LOCK_PRE_BUILT
);
break;
case 'custom': // Custom download method, like API-based download or other
@@ -371,12 +375,14 @@ class Downloader
/**
* Download source by name and meta.
*
* @param string $name source name
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
* @param string $name source name
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
* @param bool $force Whether to force download (default: false)
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
* @throws DownloaderException
* @throws FileSystemException
*/
public static function downloadSource(string $name, ?array $source = null, bool $force = false): void
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
{
if ($source === null) {
$source = Config::getSource($name);
@@ -398,7 +404,7 @@ class Downloader
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading
if (isset($lock[$name]) && !$force) {
if (isset($lock[$name]) && !$force && ($lock[$name]['lock_as'] ?? SPC_LOCK_SOURCE) === $lock_as) {
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['filename']);
return;
@@ -413,28 +419,28 @@ class Downloader
switch ($source['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'url': // Direct download URL
$url = $source['url'];
$filename = $source['filename'] ?? basename($source['url']);
self::downloadFile($name, $url, $filename, $source['path'] ?? null);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'git': // Git repo
self::downloadGit(
@@ -442,14 +448,15 @@ class Downloader
$source['url'],
$source['rev'],
$source['path'] ?? null,
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0)
intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0),
$lock_as
);
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);
(new $class())->fetch($force, $source, $lock_as);
break;
}
}
@@ -551,7 +558,6 @@ class Downloader
try {
f_passthru($cmd);
} catch (RuntimeException $e) {
var_dump($e->getCode());
if ($e->getCode() === 2 || $e->getCode() === -1073741510) {
throw new WrongUsageException('Keyboard interrupted, download failed !');
}

View File

@@ -16,7 +16,7 @@ class FileSystem
*/
public static function loadConfigArray(string $config, ?string $config_dir = null): array
{
$whitelist = ['ext', 'lib', 'source', 'pkg'];
$whitelist = ['ext', 'lib', 'source', 'pkg', 'pre-built'];
if (!in_array($config, $whitelist)) {
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
}

View File

@@ -351,12 +351,12 @@ class SourcePatcher
public static function patchLibYaml(string $name, string $target): bool
{
if (!file_exists("{$target}\\cmake\\config.h.in")) {
FileSystem::createDir("{$target}\\cmake");
copy(ROOT_DIR . '\src\globals\extra\libyaml_config.h.in', "{$target}\\cmake\\config.h.in");
if (!file_exists("{$target}/cmake/config.h.in")) {
FileSystem::createDir("{$target}/cmake");
copy(ROOT_DIR . '/src/globals/extra/libyaml_config.h.in', "{$target}/cmake/config.h.in");
}
if (!file_exists("{$target}\\YamlConfig.cmake.in")) {
copy(ROOT_DIR . '\src\globals\extra\libyaml_YamlConfig.cmake.in', "{$target}\\YamlConfig.cmake.in");
if (!file_exists("{$target}/YamlConfig.cmake.in")) {
copy(ROOT_DIR . '/src/globals/extra/libyaml_yamlConfig.cmake.in', "{$target}/yamlConfig.cmake.in");
}
return true;
}

View File

@@ -8,5 +8,5 @@ abstract class CustomSourceBase
{
public const NAME = 'unknown';
abstract public function fetch(bool $force = false);
abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void;
}

View File

@@ -17,7 +17,7 @@ class PhpSource extends CustomSourceBase
* @throws DownloaderException
* @throws FileSystemException
*/
public function fetch(bool $force = false): void
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
{
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1';
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
@@ -45,7 +45,7 @@ class PhpSource extends CustomSourceBase
// 从官网直接下载
return [
'type' => 'url',
'url' => "https://www.php.net/distributions/php-{$version}.tar.gz",
'url' => "https://www.php.net/distributions/php-{$version}.tar.xz",
];
}
}

View File

@@ -16,7 +16,7 @@ class PostgreSQLSource extends CustomSourceBase
* @throws DownloaderException
* @throws FileSystemException
*/
public function fetch(bool $force = false): void
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
{
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
}

View File

@@ -107,9 +107,9 @@ class LicenseDumper
}
foreach ($licenses as $index => $license) {
yield ($license['suffix'] ?? $index) => match ($license['type']) {
yield $index => match ($license['type']) {
'text' => $license['text'],
'file' => $this->loadSourceFile($source_name, $license['path'], Config::getSource($source_name)['path'] ?? null),
'file' => $this->loadSourceFile($source_name, $index, $license['path'], Config::getSource($source_name)['path'] ?? null),
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
};
}
@@ -118,15 +118,20 @@ class LicenseDumper
/**
* @throws RuntimeException
*/
private function loadSourceFile(string $source_name, ?string $in_path, ?string $custom_base_path = null): string
private function loadSourceFile(string $source_name, int $index, ?string $in_path, ?string $custom_base_path = null): string
{
if (is_null($in_path)) {
throw new RuntimeException('source [' . $source_name . '] license file is not set, please check config/source.json');
}
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
if (file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
}
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
if (file_exists(BUILD_ROOT_PATH . '/source-licenses/' . $source_name . '/' . $index . '.txt')) {
return file_get_contents(BUILD_ROOT_PATH . '/source-licenses/' . $source_name . '/' . $index . '.txt');
}
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
}
}

View File

@@ -41,6 +41,7 @@ class UnixShell
{
/* @phpstan-ignore-next-line */
logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd));
logger()->debug('Executed at: ' . debug_backtrace()[0]['file'] . ':' . debug_backtrace()[0]['line']);
if ($this->cd !== null) {
$cmd = 'cd ' . escapeshellarg($this->cd) . ' && ' . $cmd;
}
@@ -57,8 +58,10 @@ class UnixShell
/* @phpstan-ignore-next-line */
logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd));
} else {
logger()->debug('Running command with result: ' . $cmd);
/* @phpstan-ignore-next-line */
logger()->debug(ConsoleColor::blue('[EXEC] ') . ConsoleColor::gray($cmd));
}
logger()->debug('Executed at: ' . debug_backtrace()[0]['file'] . ':' . debug_backtrace()[0]['line']);
exec($cmd, $out, $code);
return [$code, $out];
}

View File

@@ -56,15 +56,20 @@ const SPC_EXTENSION_ALIAS = [
'zendopcache' => 'opcache',
];
// spc lock type
const SPC_LOCK_SOURCE = 1; // lock source
const SPC_LOCK_PRE_BUILT = 2; // lock pre-built
// file replace strategy
const REPLACE_FILE_STR = 1;
const REPLACE_FILE_PREG = 2;
const REPLACE_FILE_USER = 3;
// library build status
const BUILD_STATUS_OK = 0;
const BUILD_STATUS_ALREADY = 1;
const BUILD_STATUS_FAILED = 2;
const LIB_STATUS_OK = 0;
const LIB_STATUS_ALREADY = 1;
const LIB_STATUS_BUILD_FAILED = 2;
const LIB_STATUS_INSTALL_FAILED = 3;
// build target type
const BUILD_TARGET_NONE = 0; // no target

View File

@@ -26,7 +26,7 @@ LDFLAGS=/DEBUG /GUARD:CF /INCREMENTAL:NO
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
CFLAGS=$(COMMON_CFLAGS) /Zi /MT /guard:cf /Zc:inline /Qspectre /Ox /W3 /GF /Gw
LDFLAGS=/GUARD:CF /INCREMENTAL:NO /NXCOMPAT /DYNAMICBASE
!ENDIF

View File

@@ -140,7 +140,7 @@ function f_passthru(string $cmd): ?bool
if ($danger) {
logger()->notice('Running dangerous command: ' . $cmd);
} else {
logger()->debug('Running command with direct output: ' . $cmd);
logger()->debug('[PASSTHRU] ' . $cmd);
}
$ret = passthru($cmd, $code);
if ($code !== 0) {

View File

@@ -19,13 +19,13 @@ $upx = true;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'sockets',
'Windows' => 'mbstring,pdo_sqlite,mbregex,bz2,sqlsrv,pdo_sqlsrv,yaml,zip,rar,apcu,swow',
'Linux', 'Darwin' => 'swoole,bz2,gmp,intl,password-argon2,gd,mbregex,iconv,redis,sodium,yaml,readline,openssl,sqlite3,sqlsrv,zip,zlib',
'Windows' => 'amqp,apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,ds,exif,ffi,fileinfo,filter,ftp,gd,iconv,libxml,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_sqlite,pdo_sqlsrv,phar,rar,session,shmop,simdjson,simplexml,soap,sockets,sqlite3,sqlsrv,ssh2,swow,sysvshm,tokenizer,xml,xmlreader,xmlwriter,yac,yaml,zip,zlib',
};
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
$with_libs = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => '',
'Linux', 'Darwin' => 'brotli,bzip2,gmp,icu,libargon2,libavif,libcares,libevent,libiconv,liblz4,libpng,libsodium,libtiff,libwebp,libyaml,ncurses,onig,openssl,pkg-config,readline,sqlite,unixodbc,xz,zlib',
'Windows' => '',
};
@@ -33,7 +33,7 @@ $with_libs = match (PHP_OS_FAMILY) {
// You can use `common`, `bulk`, `minimal` or `none`.
// note: combination is only available for *nix platform. Windows must use `none` combination
$base_combination = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'minimal',
'Linux', 'Darwin' => 'none',
'Windows' => 'none',
};

View File

@@ -43,7 +43,6 @@ final class LicenseDumperTest extends TestCase
'license' => [
'type' => 'text',
'text' => 'license',
'suffix' => 'zend',
],
],
];
@@ -52,7 +51,7 @@ final class LicenseDumperTest extends TestCase
$dumper->addLibs(['fake_lib']);
$dumper->dump(self::DIRECTORY);
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
}
public function testDumpWithMultipleLicenses(): void
@@ -76,7 +75,6 @@ final class LicenseDumperTest extends TestCase
[
'type' => 'text',
'text' => 'license',
'suffix' => 'zend',
],
],
],
@@ -88,6 +86,6 @@ final class LicenseDumperTest extends TestCase
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_2.txt');
}
}