mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-07 16:55:38 +08:00
Compare commits
77 Commits
pmmp-exper
...
2.1.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73035067e3 | ||
|
|
421b3830b6 | ||
|
|
59dcb905fe | ||
|
|
d222190fc7 | ||
|
|
06e9864d19 | ||
|
|
0b1a321615 | ||
|
|
9ee7d7769a | ||
|
|
2440a65d8e | ||
|
|
839931d65f | ||
|
|
2591b48abe | ||
|
|
2549597871 | ||
|
|
2064172bed | ||
|
|
dc19d0c61d | ||
|
|
05c6dc6dab | ||
|
|
4b653bc293 | ||
|
|
1c3476b8e9 | ||
|
|
61ca501c2a | ||
|
|
d916feec62 | ||
|
|
0dcecf6ca4 | ||
|
|
a04deb458f | ||
|
|
34f810571e | ||
|
|
5ab4d140d5 | ||
|
|
104778d17a | ||
|
|
5f8641f417 | ||
|
|
17b69ec1e9 | ||
|
|
8de942c274 | ||
|
|
a7d5a48b48 | ||
|
|
fdc00301c0 | ||
|
|
7620d5900e | ||
|
|
e973fe743e | ||
|
|
149e844d59 | ||
|
|
12ea3218e8 | ||
|
|
f9e7af1c9a | ||
|
|
8d2f6baaa2 | ||
|
|
25a2684e5a | ||
|
|
13e0e12181 | ||
|
|
81df124b42 | ||
|
|
d3d8230a09 | ||
|
|
d4eb199504 | ||
|
|
6562bc200c | ||
|
|
0b322f494b | ||
|
|
ceed1005cc | ||
|
|
6efcb75224 | ||
|
|
a45f2f357d | ||
|
|
0c2de9f936 | ||
|
|
ac005d1e0f | ||
|
|
fce0c2f896 | ||
|
|
a0a0b01cc3 | ||
|
|
450ec21c90 | ||
|
|
7b2c3ac12d | ||
|
|
8d4a375400 | ||
|
|
eda3a9b486 | ||
|
|
5b581a54aa | ||
|
|
5549068275 | ||
|
|
daf0d2eb32 | ||
|
|
bff1a6168f | ||
|
|
54ba41d1b3 | ||
|
|
cb5e13e39a | ||
|
|
269e95e0fe | ||
|
|
dabdb518ce | ||
|
|
eac4763d82 | ||
|
|
fa0ea5443d | ||
|
|
31c71f180b | ||
|
|
5c7552f826 | ||
|
|
fa1bd340f1 | ||
|
|
539aaefd72 | ||
|
|
d54bf42ba8 | ||
|
|
cbfbec41b4 | ||
|
|
db7532cad3 | ||
|
|
6b8df97282 | ||
|
|
584f96484c | ||
|
|
e1e5515694 | ||
|
|
d3ff6fd8c0 | ||
|
|
6bcda6a5a0 | ||
|
|
3828ba7c77 | ||
|
|
a632caed54 | ||
|
|
1e0265e673 |
127
.github/workflows/build-macos-aarch64.yml
vendored
Normal file
127
.github/workflows/build-macos-aarch64.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
name: CI on arm64 macOS
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
description: php version to compile
|
||||||
|
default: '8.2'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- '8.3'
|
||||||
|
- '8.2'
|
||||||
|
- '8.1'
|
||||||
|
- '8.0'
|
||||||
|
- '7.4'
|
||||||
|
build-cli:
|
||||||
|
description: build cli binary
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
build-micro:
|
||||||
|
description: build phpmicro binary
|
||||||
|
type: boolean
|
||||||
|
build-fpm:
|
||||||
|
description: build fpm binary
|
||||||
|
type: boolean
|
||||||
|
extensions:
|
||||||
|
description: extensions to compile (comma separated)
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
debug:
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: build ${{ inputs.version }} on macOS arm64
|
||||||
|
runs-on: macos-14
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Install macOS missing packages and mark os suffix
|
||||||
|
- run: |
|
||||||
|
brew install automake gzip
|
||||||
|
echo "SPC_BUILD_OS=macos" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
|
- name: "Setup PHP"
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: 8.1
|
||||||
|
tools: pecl, composer
|
||||||
|
extensions: curl, openssl, mbstring, tokenizer
|
||||||
|
ini-values: memory_limit=-1
|
||||||
|
|
||||||
|
|
||||||
|
# Cache composer dependencies
|
||||||
|
- id: cache-composer-deps
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: vendor
|
||||||
|
key: composer-dependencies
|
||||||
|
|
||||||
|
# If there's no Composer cache, install dependencies
|
||||||
|
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
||||||
|
run: composer update --no-dev --classmap-authoritative
|
||||||
|
|
||||||
|
# Cache downloaded source
|
||||||
|
- id: cache-download
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: downloads
|
||||||
|
key: php-${{ inputs.version }}-dependencies-${{ inputs.extensions }}
|
||||||
|
|
||||||
|
# With or without debug
|
||||||
|
- if: inputs.debug == true
|
||||||
|
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# With target select: cli, micro or both
|
||||||
|
- if: ${{ inputs.build-cli == true }}
|
||||||
|
run: echo "SPC_BUILD_CLI=--build-cli" >> $GITHUB_ENV
|
||||||
|
- if: ${{ inputs.build-micro == true }}
|
||||||
|
run: echo "SPC_BUILD_MICRO=--build-micro" >> $GITHUB_ENV
|
||||||
|
- if: ${{ inputs.build-fpm == true }}
|
||||||
|
run: echo "SPC_BUILD_FPM=--build-fpm" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# 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 build command
|
||||||
|
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}
|
||||||
|
|
||||||
|
# Upload cli executable
|
||||||
|
- if: ${{ inputs.build-cli == true }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: php-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
|
||||||
|
path: buildroot/bin/php
|
||||||
|
|
||||||
|
# Upload micro self-extracted executable
|
||||||
|
- if: ${{ inputs.build-micro == true }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: micro-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
|
||||||
|
path: buildroot/bin/micro.sfx
|
||||||
|
|
||||||
|
# Upload fpm executable
|
||||||
|
- if: ${{ inputs.build-fpm == true }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: php-fpm-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
|
||||||
|
path: buildroot/bin/php-fpm
|
||||||
|
|
||||||
|
# Upload extensions metadata
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: license-files
|
||||||
|
path: buildroot/license/
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: build-meta
|
||||||
|
path: |
|
||||||
|
buildroot/build-extensions.json
|
||||||
|
buildroot/build-libraries.json
|
||||||
40
.github/workflows/download-cache.yml
vendored
40
.github/workflows/download-cache.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: archive download sources weekly
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: "* 14 * * 5"
|
|
||||||
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
download:
|
|
||||||
name: cache download sources
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
php-version: [ "8.0", "8.1", "8.2", "8.3" ]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Cache composer dependencies
|
|
||||||
- id: cache-composer-deps
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: vendor
|
|
||||||
key: composer-dependencies
|
|
||||||
|
|
||||||
# If there's no Composer cache, install dependencies
|
|
||||||
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
|
||||||
run: composer update --no-dev
|
|
||||||
|
|
||||||
# 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=${{ matrix.php-version }} --all --debug
|
|
||||||
|
|
||||||
# Upload downloaded files
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: download-files-${{ matrix.php-version }}
|
|
||||||
path: downloads/
|
|
||||||
73
.github/workflows/release-build.yml
vendored
73
.github/workflows/release-build.yml
vendored
@@ -1,6 +1,8 @@
|
|||||||
name: Upload SPC Binary (Release)
|
name: Build SPC Binary
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
@@ -8,10 +10,14 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-release-artifacts:
|
build-release-artifacts:
|
||||||
name: "Upload SPC Binary (Release)"
|
name: "Build SPC Binary"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
php-version:
|
||||||
|
- "8.1"
|
||||||
|
micro-version:
|
||||||
|
- "8.1.26"
|
||||||
operating-system:
|
operating-system:
|
||||||
- "linux-x86_64"
|
- "linux-x86_64"
|
||||||
- "macos-x86_64"
|
- "macos-x86_64"
|
||||||
@@ -21,18 +27,57 @@ jobs:
|
|||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v4"
|
uses: "actions/checkout@v4"
|
||||||
|
|
||||||
- name: Reuse static-php-cli-hosted artifacts
|
- if: inputs.debug == true
|
||||||
uses: dawidd6/action-download-artifact@v2
|
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: "Install PHP for official runners"
|
||||||
|
uses: "shivammathur/setup-php@v2"
|
||||||
with:
|
with:
|
||||||
repo: static-php/static-php-cli-hosted
|
coverage: none
|
||||||
branch: master
|
tools: composer:v2
|
||||||
workflow: build-spc-release.yml
|
php-version: "${{ matrix.php-version }}"
|
||||||
name: "spc-${{ matrix.operating-system }}"
|
ini-values: memory_limit=-1
|
||||||
|
|
||||||
|
- name: "Get Composer Cache Directory"
|
||||||
|
id: composer-cache
|
||||||
|
run: |
|
||||||
|
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: "Cache Composer dependencies"
|
||||||
|
uses: "actions/cache@v3"
|
||||||
|
with:
|
||||||
|
path: "${{ steps.composer-cache.outputs.dir }}"
|
||||||
|
key: "php-${{ matrix.php-version }}-locked-composer-${{ hashFiles('**/composer.lock') }}"
|
||||||
|
restore-keys: |
|
||||||
|
php-${{ matrix.php-version }}-locked-composer
|
||||||
|
|
||||||
|
- name: "Install Locked Dependencies"
|
||||||
|
run: "composer install --no-interaction --no-progress"
|
||||||
|
|
||||||
|
- name: "Build PHAR File"
|
||||||
|
run: "composer build:phar"
|
||||||
|
|
||||||
|
- name: "Download minimal combination"
|
||||||
|
run: |
|
||||||
|
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ matrix.micro-version }}-micro-${{ matrix.operating-system }}.tar.gz -o tmp.tgz
|
||||||
|
tar -zxvf tmp.tgz
|
||||||
|
|
||||||
|
- name: "Generate Executable"
|
||||||
|
run: |
|
||||||
|
cat micro.sfx spc.phar > spc
|
||||||
|
chmod +x spc
|
||||||
|
|
||||||
- name: "Archive Executable"
|
- name: "Archive Executable"
|
||||||
run: |
|
run: |
|
||||||
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
|
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
|
||||||
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
|
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
|
||||||
|
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
|
||||||
|
if [ "${{ matrix.operating-system }}" == "linux-x86_64" ]; then
|
||||||
|
./spc dev:extensions
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: "Copy file"
|
||||||
|
run: "mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS"
|
||||||
|
|
||||||
- name: upload binaries to release
|
- name: upload binaries to release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
@@ -40,6 +85,18 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
files: ${{ env.filename }}
|
files: ${{ env.filename }}
|
||||||
|
|
||||||
|
- name: "Deploy to Self-Hosted Server"
|
||||||
|
if: github.repository == 'crazywhalecc/static-php-cli'
|
||||||
|
uses: easingthemes/ssh-deploy@main
|
||||||
|
env:
|
||||||
|
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SERVER_SECRET_KEY }}
|
||||||
|
ARGS: "-rltgoDzvO"
|
||||||
|
SOURCE: "dist/"
|
||||||
|
REMOTE_HOST: ${{ secrets.DEPLOY_SERVER_HOST }}
|
||||||
|
REMOTE_PORT: ${{ secrets.DEPLOY_SERVER_PORT }}
|
||||||
|
REMOTE_USER: ${{ secrets.DEPLOY_SERVER_USER }}
|
||||||
|
TARGET: ${{ secrets.DEPLOY_SERVER_TARGET_SPC_NIGHTLY }}
|
||||||
|
|
||||||
- name: "Upload Artifact"
|
- name: "Upload Artifact"
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
18
.github/workflows/tests.yml
vendored
18
.github/workflows/tests.yml
vendored
@@ -2,7 +2,10 @@ name: Tests
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main" ]
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'src/globals/test-extensions.php'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
@@ -111,6 +114,8 @@ jobs:
|
|||||||
os:
|
os:
|
||||||
- ubuntu-latest
|
- ubuntu-latest
|
||||||
- macos-latest
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
|
- macos-14
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
@@ -133,6 +138,13 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-php-
|
${{ runner.os }}-php-
|
||||||
|
|
||||||
|
# Cache downloaded source
|
||||||
|
- id: cache-download
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: downloads
|
||||||
|
key: php-${{ matrix.php }}-dependencies
|
||||||
|
|
||||||
- name: "Install Dependencies"
|
- name: "Install Dependencies"
|
||||||
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
@@ -140,7 +152,7 @@ jobs:
|
|||||||
run: bin/spc doctor --auto-fix
|
run: bin/spc doctor --auto-fix
|
||||||
|
|
||||||
- name: "Run Build Tests (download)"
|
- name: "Run Build Tests (download)"
|
||||||
run: bin/spc download --for-extensions="$(php src/globals/test-extensions.php)" --with-php=${{ matrix.php }} --debug
|
run: bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --with-php=${{ matrix.php }} --debug
|
||||||
|
|
||||||
- name: "Run Build Tests (build)"
|
- name: "Run Build Tests (build)"
|
||||||
run: bin/spc build "$(php src/globals/test-extensions.php)" --build-cli --build-micro --build-fpm --debug
|
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php libs_cmd) --build-cli --build-micro --build-fpm --debug
|
||||||
|
|||||||
43
.github/workflows/update-docs-config.yml
vendored
Normal file
43
.github/workflows/update-docs-config.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: Update Docs Config
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'config/**.json'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-docs-config:
|
||||||
|
name: "Update Docs Config"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'crazywhalecc/static-php-cli'
|
||||||
|
steps:
|
||||||
|
- name: "Checkout static-php-cli"
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
path: static-php-cli
|
||||||
|
|
||||||
|
- name: "Checkout static-php-cli-docs"
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: static-php/static-php-cli-docs
|
||||||
|
ref: master
|
||||||
|
token: ${{ secrets.DOCS_REPO_TOKEN }}
|
||||||
|
path: static-php-cli-docs
|
||||||
|
|
||||||
|
- name: "Set up Git"
|
||||||
|
run: |
|
||||||
|
git config --global user.email "actions@github.com"
|
||||||
|
git config --global user.name "GitHub Actions"
|
||||||
|
|
||||||
|
- name: "Copy Config Files"
|
||||||
|
run: cp -r static-php-cli/config/* static-php-cli-docs/docs/.vitepress/config/
|
||||||
|
|
||||||
|
- name: "Commit and Push Changes"
|
||||||
|
run: |
|
||||||
|
cd static-php-cli-docs
|
||||||
|
git add -A
|
||||||
|
git commit -m "Sync config files from main"
|
||||||
|
git push origin master
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -22,9 +22,12 @@ docker/source/
|
|||||||
|
|
||||||
# exclude self-runtime
|
# exclude self-runtime
|
||||||
/bin/*
|
/bin/*
|
||||||
!/bin/spc
|
!/bin/spc*
|
||||||
!/bin/setup-runtime
|
!/bin/setup-runtime*
|
||||||
!/bin/spc-alpine-docker
|
!/bin/spc-alpine-docker
|
||||||
|
|
||||||
|
# exclude windows build tools
|
||||||
|
/php-sdk-binary-tools/
|
||||||
|
|
||||||
# default test directory
|
# default test directory
|
||||||
/tests/var/
|
/tests/var/
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ return (new PhpCsFixer\Config())
|
|||||||
'phpdoc_summary' => false,
|
'phpdoc_summary' => false,
|
||||||
'php_unit_test_class_requires_covers' => false,
|
'php_unit_test_class_requires_covers' => false,
|
||||||
'phpdoc_var_without_name' => false,
|
'phpdoc_var_without_name' => false,
|
||||||
|
'fully_qualified_strict_types' => false,
|
||||||
])
|
])
|
||||||
->setFinder(
|
->setFinder(
|
||||||
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
|
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
|
||||||
|
|||||||
178
README-zh.md
178
README-zh.md
@@ -1,32 +1,46 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
Build single static PHP binary, with PHP project together, with popular extensions included.
|
[]()
|
||||||
|
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||||
🌐 **[中文](README-zh.md)** | **[English](README.md)**
|
|
||||||
|
|
||||||
编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携!(cli SAPI)
|
|
||||||
|
|
||||||
<img width="600" alt="截屏2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
|
||||||
|
|
||||||
同时可以使用 micro 二进制文件,将 PHP 源码和 PHP 二进制构建为一个文件分发!(micro SAPI)
|
|
||||||
|
|
||||||
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
|
||||||
|
|
||||||
> 该 SAPI 源自 [dixyes/phpmicro](https://github.com/dixyes/phpmicro) 的 [Fork 仓库](https://github.com/static-php/phpmicro)。
|
|
||||||
|
|
||||||
[]()
|
|
||||||
[]()
|
[]()
|
||||||
[](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-common.yml)
|
[]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html))
|
||||||
[]()
|
[](https://discord.gg/RNpegEYW)
|
||||||
[]()
|
|
||||||
|
|
||||||
> 项目名称是 static-php-cli,但其实支持 cli、fpm、micro 和 embed SAPI 😎
|
**static-php-cli**是一个用于静态编译、构建 PHP 解释器的工具,支持众多流行扩展。
|
||||||
|
|
||||||
|
目前 static-php-cli 支持 `cli`、`fpm`、`embed` 和 `micro` SAPI。
|
||||||
|
|
||||||
|
**static-php-cli**也支持将 PHP 代码和 PHP 运行时打包为一个文件并运行。
|
||||||
|
|
||||||
|
- [README - English](./README.md)
|
||||||
|
- [README - 中文](./README-zh.md)
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
static-php-cli(简称 `spc`)有许多特性:
|
||||||
|
|
||||||
|
- :handbag: 构建独立的单文件 PHP 解释器,无需任何依赖
|
||||||
|
- :hamburger: 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自执行二进制(将 PHP 代码和 PHP 解释器打包为一个文件)
|
||||||
|
- :pill: 提供一键检查和修复编译环境的 Doctor 模块
|
||||||
|
- :zap: 支持多个系统:`Linux`、`macOS`、`FreeBSD`、[`Windows (WIP)`](https://github.com/crazywhalecc/static-php-cli/pull/301)
|
||||||
|
- :wrench: 高度自定义的代码 patch 功能
|
||||||
|
- :books: 自带编译依赖管理
|
||||||
|
- 📦 提供由自身编译的独立 `spc` 二进制(使用 spc 和 [box](https://github.com/box-project/box) 构建)
|
||||||
|
- :fire: 支持大量 [扩展](https://static-php.dev/zh/guide/extensions.html)
|
||||||
|
|
||||||
|
**静态 php-cli:**
|
||||||
|
|
||||||
|
<img width="700" alt="out1" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/01a2e60f-13b0-4242-a645-f7afa4936396">
|
||||||
|
|
||||||
|
**使用 phpmicro 打包 PHP 代码:**
|
||||||
|
|
||||||
|
<img width="700" alt="out2" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/46b7128d-fb72-4169-957e-48564c3ff3e2">
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
目前 README 编写了基本用法。有关 static-php-cli 所有的功能,请点击这里查看文档:<https://static-php.dev>。
|
目前 README 编写了基本用法。有关 static-php-cli 所有的功能,请点击这里查看文档:<https://static-php.dev>。
|
||||||
|
|
||||||
## 自托管直接下载
|
## 直接下载
|
||||||
|
|
||||||
如果你不想自行编译 PHP,可以从本项目现有的示例 Action 下载 Artifact,也可以从自托管的服务器下载。
|
如果你不想自行编译 PHP,可以从本项目现有的示例 Action 下载 Artifact,也可以从自托管的服务器下载。
|
||||||
|
|
||||||
@@ -38,6 +52,10 @@ Build single static PHP binary, with PHP project together, with popular extensio
|
|||||||
|
|
||||||
### 编译环境需求
|
### 编译环境需求
|
||||||
|
|
||||||
|
- PHP >= 8.1(这是 spc 自身需要的版本,不是支持的构建版本)
|
||||||
|
- 扩展:`mbstring,pcntl,posix,tokenizer,phar`
|
||||||
|
- 系统安装了 `curl` 和 `git`
|
||||||
|
|
||||||
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
||||||
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。
|
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。
|
||||||
|
|
||||||
@@ -45,16 +63,14 @@ Build single static PHP binary, with PHP project together, with popular extensio
|
|||||||
|
|
||||||
| | x86_64 | aarch64 |
|
| | x86_64 | aarch64 |
|
||||||
|---------|----------------------|----------------------|
|
|---------|----------------------|----------------------|
|
||||||
| macOS | :octocat: :computer: | :computer: |
|
| macOS | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Linux | :octocat: :computer: | :octocat: :computer: |
|
| Linux | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Windows | | |
|
| Windows | | |
|
||||||
| FreeBSD | :computer: | :computer: |
|
| FreeBSD | :computer: | :computer: |
|
||||||
|
|
||||||
> macOS-arm64 因 GitHub 暂未提供 arm runner,如果要构建 arm 二进制,可以使用手动构建。
|
|
||||||
|
|
||||||
目前支持编译的 PHP 版本为:`7.3`,`7.4`,`8.0`,`8.1`,`8.2`,`8.3`。
|
目前支持编译的 PHP 版本为:`7.3`,`7.4`,`8.0`,`8.1`,`8.2`,`8.3`。
|
||||||
|
|
||||||
### 支持的扩展情况
|
### 支持的扩展
|
||||||
|
|
||||||
请先根据下方扩展列表选择你要编译的扩展。
|
请先根据下方扩展列表选择你要编译的扩展。
|
||||||
|
|
||||||
@@ -63,7 +79,7 @@ Build single static PHP binary, with PHP project together, with popular extensio
|
|||||||
|
|
||||||
> 如果这里没有你需要的扩展,可以提交 Issue。
|
> 如果这里没有你需要的扩展,可以提交 Issue。
|
||||||
|
|
||||||
### 使用 Actions 构建
|
### 在线构建(使用 GitHub Actions)
|
||||||
|
|
||||||
使用 GitHub Action 可以方便地构建一个静态编译的 PHP,同时可以自行定义要编译的扩展。
|
使用 GitHub Action 可以方便地构建一个静态编译的 PHP,同时可以自行定义要编译的扩展。
|
||||||
|
|
||||||
@@ -74,72 +90,77 @@ Build single static PHP binary, with PHP project together, with popular extensio
|
|||||||
|
|
||||||
如果你选择了 `debug`,则会在构建时输出所有日志,包括编译的日志,以供排查错误。
|
如果你选择了 `debug`,则会在构建时输出所有日志,包括编译的日志,以供排查错误。
|
||||||
|
|
||||||
### 手动构建(使用 SPC 二进制)
|
### 本地构建(使用 spc 二进制)
|
||||||
|
|
||||||
本项目提供了一个 static-php-cli 的二进制文件,你可以直接下载对应平台的二进制文件,然后使用它来构建静态的 PHP。目前 `spc` 二进制支持的平台有 Linux 和 macOS。
|
该项目提供了 static-php-cli 的二进制文件:`spc`。
|
||||||
|
您可以使用 `spc` 二进制文件,无需安装任何运行时(用起来就像 golang 程序)。
|
||||||
|
目前,`spc` 二进制文件提供的平台有 Linux 和 macOS。
|
||||||
|
|
||||||
下面是从 GitHub Action 下载的方法:
|
使用以下命令从自托管服务器下载:
|
||||||
|
|
||||||
1. 进入 [GitHub Action](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml)。
|
|
||||||
2. 选择一个最新的构建任务,进入后选择 `Artifacts`,下载对应平台的二进制文件。
|
|
||||||
3. 解压 `.zip` 文件。解压后,为其添加执行权限:`chmod +x ./spc`。
|
|
||||||
|
|
||||||
你也可以从自托管的服务器下载二进制文件:[进入](https://dl.static-php.dev/static-php-cli/spc-bin/nightly/)。
|
|
||||||
|
|
||||||
### 手动构建(使用源码)
|
|
||||||
|
|
||||||
先克隆本项目:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Download from self-hosted nightly builds (sync with main branch)
|
||||||
|
# For Linux x86_64
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
|
||||||
|
# For Linux aarch64
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-aarch64
|
||||||
|
# macOS x86_64 (Intel)
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
||||||
|
# macOS aarch64 (Apple)
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
||||||
|
|
||||||
|
# add x perm
|
||||||
|
chmod +x ./spc
|
||||||
|
./spc --version
|
||||||
|
```
|
||||||
|
|
||||||
|
自托管 `spc` 由 GitHub Actions 构建,你也可以从 Actions 直接下载:[此处](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml)。
|
||||||
|
|
||||||
|
### 本地构建(使用 git 源码)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# clone 仓库即可
|
||||||
git clone https://github.com/crazywhalecc/static-php-cli.git
|
git clone https://github.com/crazywhalecc/static-php-cli.git
|
||||||
```
|
```
|
||||||
|
|
||||||
如果你本机没有安装 PHP,你需要先使用包管理(例如 brew、apt、yum、apk 等)安装 php。
|
如果您的系统上尚未安装 php,我们建议你使用内置的 setup-runtime 自动安装 PHP 和 Composer。
|
||||||
|
|
||||||
你也可以通过 `bin/setup-runtime` 命令下载静态编译好的 php-cli 和 Composer。下载的 php 和 Composer 将保存为 `bin/php` 和 `bin/composer`。
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd static-php-cli
|
cd static-php-cli
|
||||||
chmod +x bin/setup-runtime
|
chmod +x bin/setup-runtime
|
||||||
./bin/setup-runtime
|
# it will download static php (from self-hosted server) and composer (from getcomposer)
|
||||||
|
bin/setup-runtime
|
||||||
# 使用独立的 php 运行 static-php-cli
|
# initialize composer deps
|
||||||
./bin/php bin/spc
|
bin/composer install
|
||||||
|
# chmod
|
||||||
# 使用 composer
|
|
||||||
./bin/php bin/composer
|
|
||||||
|
|
||||||
# 初始化本项目
|
|
||||||
cd static-php-cli
|
|
||||||
composer update
|
|
||||||
chmod +x bin/spc
|
chmod +x bin/spc
|
||||||
|
bin/spc --version
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用 static-php-cli 命令行程序
|
### 开始构建 PHP
|
||||||
|
|
||||||
下面是使用 static-php-cli 编译静态 php 和 micro 的基础用法:
|
下面是使用 static-php-cli 的基础用法:
|
||||||
|
|
||||||
> 如果你使用的是打包好的 `spc` 二进制,你需要将下列命令的 `bin/spc` 替换为 `./spc`。
|
> 如果你使用的是打包好的 `spc` 二进制,你需要将下列命令的 `./bin/spc` 替换为 `./spc`。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 检查环境依赖,并根据提示的命令安装缺失的编译工具
|
# 检查环境依赖,并根据尝试自动安装缺失的编译工具
|
||||||
./bin/spc doctor
|
./bin/spc doctor --auto-fix
|
||||||
|
|
||||||
# 拉取所有依赖库
|
# 拉取所有依赖库
|
||||||
./bin/spc fetch --all
|
./bin/spc download --all
|
||||||
# 只拉取编译指定扩展需要的所有依赖
|
# 只拉取编译指定扩展需要的所有依赖(推荐)
|
||||||
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
||||||
|
# 下载编译不同版本的 PHP (--with-php=x.y,推荐 7.3 ~ 8.3)
|
||||||
|
./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1
|
||||||
|
|
||||||
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
|
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
|
||||||
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
|
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
|
||||||
|
# 编译线程安全版本 (--enable-zts)
|
||||||
|
./bin/spc build curl,phar --enable-zts --build-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
你也可以使用参数 `--with-php=x.y` 来指定下载的 PHP 版本,目前支持 7.3 ~ 8.3:
|
其中,目前支持构建 cli,micro,fpm 和 embed,使用以下参数的一个或多个来指定编译的 SAPI:
|
||||||
|
|
||||||
```bash
|
|
||||||
# 优先考虑使用 >= 8.0 的 PHP 版本,因为 phpmicro 不支持在 PHP7 中构建
|
|
||||||
./bin/spc download --with-php=8.2 --all
|
|
||||||
```
|
|
||||||
|
|
||||||
其中,目前支持构建 cli,micro,fpm 三种静态二进制,使用以下参数的一个或多个来指定编译的 SAPI:
|
|
||||||
|
|
||||||
- `--build-cli`:构建 cli 二进制
|
- `--build-cli`:构建 cli 二进制
|
||||||
- `--build-micro`:构建 phpmicro 自执行二进制
|
- `--build-micro`:构建 phpmicro 自执行二进制
|
||||||
@@ -151,17 +172,9 @@ chmod +x bin/spc
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
||||||
./bin/spc fetch --all --debug
|
./bin/spc download --all --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
此外,默认编译的 PHP 为 NTS 版本。如需编译线程安全版本(ZTS),只需添加参数 `--enable-zts` 即可。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./bin/spc build openssl,pcntl --build-all --enable-zts
|
|
||||||
```
|
|
||||||
|
|
||||||
同时,你也可以使用参数 `--no-strip` 来关闭裁剪,关闭裁剪后可以使用 gdb 等工具调试,但这样会让静态二进制体积变大。
|
|
||||||
|
|
||||||
## 不同 SAPI 的使用
|
## 不同 SAPI 的使用
|
||||||
|
|
||||||
### 使用 cli
|
### 使用 cli
|
||||||
@@ -241,14 +254,13 @@ bin/spc micro:combine my-app.phar -I "memory_limit=4G" -I "disable_functions=sys
|
|||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
本项目依据旧版本惯例采用 MIT License 开源,部分扩展的集成编译命令参考或修改自以下项目:
|
本项目采用 MIT License 许可开源,下面是类似的项目:
|
||||||
|
|
||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)(木兰宽松许可证)
|
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)(Apache 2.0 LICENSE、SWOOLE-CLI LICENSE)
|
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)
|
||||||
|
|
||||||
|
该项目使用了 [dixyes/lwmbs](https://github.com/dixyes/lwmbs) 中的一些代码,例如 Windows 静态构建目标和 libiconv 库支持。
|
||||||
|
lwmbs 使用 [Mulan PSL 2](http://license.coscl.org.cn/MulanPSL2) 许可进行分发。对应文件有关于作者和许可的特殊说明,除此之外,均使用 MIT 授权许可。
|
||||||
|
|
||||||
因本项目的特殊性,使用项目编译过程中会使用很多其他开源项目,例如 curl、protobuf 等,它们都有各自的开源协议。
|
因本项目的特殊性,使用项目编译过程中会使用很多其他开源项目,例如 curl、protobuf 等,它们都有各自的开源协议。
|
||||||
请在编译完成后,使用命令 `bin/spc dump-license` 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
|
请在编译完成后,使用命令 `bin/spc dump-license` 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
|
||||||
|
|
||||||
## 进阶
|
|
||||||
|
|
||||||
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php.dev) 贡献代码或文档。
|
|
||||||
|
|||||||
180
README.md
180
README.md
@@ -1,27 +1,42 @@
|
|||||||
# static-php-cli
|
# static-php-cli
|
||||||
|
|
||||||
Build single static PHP binary, with PHP project together, with popular extensions included.
|
[]()
|
||||||
|
|
||||||
🌐 **[中文](README-zh.md)** | **[English](README.md)**
|
|
||||||
|
|
||||||
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed SAPI 😎
|
|
||||||
|
|
||||||
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI)
|
|
||||||
|
|
||||||
<img width="600" alt="2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
|
||||||
|
|
||||||
You can also use the micro binary file to combine php binary and php source code into one for distribution! (micro SAPI)
|
|
||||||
|
|
||||||
<img width="600" alt="2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
|
||||||
|
|
||||||
> This SAPI feature is from the [Fork](https://github.com/static-php/phpmicro) of [dixyes/phpmicro](https://github.com/dixyes/phpmicro).
|
|
||||||
|
|
||||||
[]()
|
|
||||||
[]()
|
|
||||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||||
|
[]()
|
||||||
|
[]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html))
|
||||||
|
[](https://discord.gg/RNpegEYW)
|
||||||
|
|
||||||
[]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html))
|
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
|
||||||
[]()
|
with popular extensions.
|
||||||
|
|
||||||
|
Static PHP built by **static-php-cli** supports `cli`, `fpm`, `embed` and `micro` SAPI.
|
||||||
|
|
||||||
|
**static-php-cli** also has the ability to package PHP projects
|
||||||
|
along with the PHP interpreter into one single executable file.
|
||||||
|
|
||||||
|
- [README - English](./README.md)
|
||||||
|
- [README - 中文](./README-zh.md)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
static-php-cli (you can call it `spc`) has a lot of features:
|
||||||
|
|
||||||
|
- :handbag: Build single-file php executable, without any dependencies
|
||||||
|
- :hamburger: Build **[phpmicro](https://github.com/dixyes/phpmicro)** self-extracted executable (glue php binary and php source code into one file)
|
||||||
|
- :pill: Automatic build environment checker (Doctor module)
|
||||||
|
- :zap: `Linux`, `macOS`, `FreeBSD`, `Windows` support
|
||||||
|
- :wrench: Configurable source code patches
|
||||||
|
- :books: Build dependency management
|
||||||
|
- 📦 Provide `spc` own standalone executable (built by spc and [box](https://github.com/box-project/box))
|
||||||
|
- :fire: Support many popular [extensions](https://static-php.dev/en/guide/extensions.html)
|
||||||
|
|
||||||
|
**Single-file standalone php-cli:**
|
||||||
|
|
||||||
|
<img width="700" alt="out1" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/01a2e60f-13b0-4242-a645-f7afa4936396">
|
||||||
|
|
||||||
|
**Combine PHP code with PHP interpreter using phpmicro:**
|
||||||
|
|
||||||
|
<img width="700" alt="out2" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/46b7128d-fb72-4169-957e-48564c3ff3e2">
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
@@ -30,7 +45,7 @@ see <https://static-php.dev> .
|
|||||||
|
|
||||||
## Direct Download
|
## Direct Download
|
||||||
|
|
||||||
If you don't want to compile yourself, you can download example pre-compiled artifact from [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-common.yml), or from self-hosted server.
|
If you don't want to build or want to test first, you can download example pre-compiled artifact from [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml), or from self-hosted server.
|
||||||
|
|
||||||
Below are several precompiled static-php binaries with different extension combinations,
|
Below are several precompiled static-php binaries with different extension combinations,
|
||||||
which can be downloaded directly according to your needs.
|
which can be downloaded directly according to your needs.
|
||||||
@@ -39,25 +54,27 @@ which can be downloaded directly according to your needs.
|
|||||||
- [Extension-Combination - bulk](https://dl.static-php.dev/static-php-cli/bulk/): `bulk` contains [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) extensions and is about 70MB in size.
|
- [Extension-Combination - bulk](https://dl.static-php.dev/static-php-cli/bulk/): `bulk` contains [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) extensions and is about 70MB in size.
|
||||||
- [Extension-Combination - minimal](https://dl.static-php.dev/static-php-cli/minimal/): `minimal` contains [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) extensions and is about 6MB in size.
|
- [Extension-Combination - minimal](https://dl.static-php.dev/static-php-cli/minimal/): `minimal` contains [5](https://dl.static-php.dev/static-php-cli/minimal/README.txt) extensions and is about 6MB in size.
|
||||||
|
|
||||||
## Use static-php-cli to build PHP
|
## Build
|
||||||
|
|
||||||
### Compilation Requirements
|
### Compilation Requirements
|
||||||
|
|
||||||
Yes, this project is written in PHP, pretty funny.
|
- PHP >= 8.1 (This is the version required by spc itself, not the build version)
|
||||||
|
- Extension: `mbstring,pcntl,posix,tokenizer,phar`
|
||||||
|
- Supported OS with `curl` and `git` installed
|
||||||
|
|
||||||
|
You can say I made a PHP builder written in PHP, pretty funny.
|
||||||
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension.
|
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension.
|
||||||
|
|
||||||
Here is the architecture support status, where :octocat: represents support for GitHub Action builds,
|
Here is the supported OS and arch, where :octocat: represents support for GitHub Action builds,
|
||||||
:computer: represents support for local manual builds, and blank represents not currently supported.
|
:computer: represents support for local manual builds, and blank represents not currently supported.
|
||||||
|
|
||||||
| | x86_64 | aarch64 |
|
| | x86_64 | aarch64 |
|
||||||
|---------|----------------------|----------------------|
|
|---------|----------------------|----------------------|
|
||||||
| macOS | :octocat: :computer: | :computer: |
|
| macOS | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Linux | :octocat: :computer: | :octocat: :computer: |
|
| Linux | :octocat: :computer: | :octocat: :computer: |
|
||||||
| Windows | | |
|
| Windows | :computer: | |
|
||||||
| FreeBSD | :computer: | :computer: |
|
| FreeBSD | :computer: | :computer: |
|
||||||
|
|
||||||
> macOS-arm64 is not supported for GitHub Actions, if you are going to build on arm, you can build it manually on your own machine.
|
|
||||||
|
|
||||||
Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`.
|
Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`.
|
||||||
|
|
||||||
### Supported Extensions
|
### Supported Extensions
|
||||||
@@ -71,7 +88,7 @@ Please first select the extension you want to compile based on the extension lis
|
|||||||
|
|
||||||
Here is the current planned roadmap for extension support: [#152](https://github.com/crazywhalecc/static-php-cli/issues/152) .
|
Here is the current planned roadmap for extension support: [#152](https://github.com/crazywhalecc/static-php-cli/issues/152) .
|
||||||
|
|
||||||
### GitHub Actions Build
|
### Build Online (using GitHub Actions)
|
||||||
|
|
||||||
Use GitHub Action to easily build a statically compiled PHP,
|
Use GitHub Action to easily build a statically compiled PHP,
|
||||||
and at the same time define the extensions to be compiled by yourself.
|
and at the same time define the extensions to be compiled by yourself.
|
||||||
@@ -83,80 +100,77 @@ 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.
|
If you enable `debug`, all logs will be output at build time, including compiled logs, for troubleshooting.
|
||||||
|
|
||||||
- When using ubuntu-latest, it will build linux-x86_64 binary.
|
### Build Locally (using SPC binary)
|
||||||
- When using macos-latest, it will build macOS-x86_64 binary.
|
|
||||||
|
|
||||||
### Manual build (using SPC binary)
|
This project provides a binary file of static-php-cli: `spc`.
|
||||||
|
You can use `spc` binary instead of installing any runtime like golang app.
|
||||||
This project provides a binary file of static-php-cli.
|
|
||||||
You can directly download the binary file of the corresponding platform and then use it to build static PHP.
|
|
||||||
Currently, the platforms supported by `spc` binary are Linux and macOS.
|
Currently, the platforms supported by `spc` binary are Linux and macOS.
|
||||||
|
|
||||||
Here's how to download from GitHub Actions:
|
Download from self-hosted nightly builds using commands below:
|
||||||
|
|
||||||
1. Enter [GitHub Actions](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml) or [self-hosted nightly builds](https://dl.static-php.dev/static-php-cli/spc-bin/nightly/).
|
|
||||||
2. If you download from GHA, select the latest build task, select `Artifacts`, and download the binary file of the corresponding platform.
|
|
||||||
3. If you download from GHA, unzip the `.zip` file. After decompressing, add execution permissions to it: `chmod +x ./spc`.
|
|
||||||
4. If you download from self-hosted server, download `spc-$os-$arch` file and just use it (don't forget `chmod +x`).
|
|
||||||
|
|
||||||
> SPC single-file binary is built by phpmicro and box, and it doesn't need to install PHP. Just treat `spc` as a standalone executable.
|
|
||||||
|
|
||||||
### Manual build (using source code)
|
|
||||||
|
|
||||||
Clone repo first:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Download from self-hosted nightly builds (sync with main branch)
|
||||||
|
# For Linux x86_64
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
|
||||||
|
# For Linux aarch64
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-aarch64
|
||||||
|
# macOS x86_64 (Intel)
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
|
||||||
|
# macOS aarch64 (Apple)
|
||||||
|
curl -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
|
||||||
|
|
||||||
|
# add x perm
|
||||||
|
chmod +x ./spc
|
||||||
|
./spc --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Self-hosted `spc` is built by GitHub Actions, you can also download from Actions artifacts [here](https://github.com/crazywhalecc/static-php-cli/actions/workflows/release-build.yml).
|
||||||
|
|
||||||
|
### Build Locally (using git source)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# just clone me!
|
||||||
git clone https://github.com/crazywhalecc/static-php-cli.git
|
git clone https://github.com/crazywhalecc/static-php-cli.git
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have not installed php on your system, you can use package management to install PHP (such as brew, apt, yum, apk etc.).
|
If you have not installed php on your system, we recommend that you use the built-in setup-runtime to install PHP and Composer automatically.
|
||||||
|
|
||||||
And you can also download single-file php binary and composer using command `bin/setup-runtime`.
|
|
||||||
The PHP runtime for static-php-cli itself will be downloaded at `bin/php`, and composer is at `bin/composer`.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd static-php-cli
|
cd static-php-cli
|
||||||
chmod +x bin/setup-runtime
|
chmod +x bin/setup-runtime
|
||||||
# It will download php-cli from self-hosted server and composer from getcomposer.org
|
# it will download static php (from self-hosted server) and composer (from getcomposer)
|
||||||
./bin/setup-runtime
|
bin/setup-runtime
|
||||||
|
# initialize composer deps
|
||||||
# Use this php runtime to run static-php-cli compiler
|
bin/composer install
|
||||||
./bin/php bin/spc
|
# chmod
|
||||||
|
|
||||||
# Use composer
|
|
||||||
./bin/php bin/composer
|
|
||||||
|
|
||||||
# Initialize this project
|
|
||||||
cd static-php-cli
|
|
||||||
composer update
|
|
||||||
chmod +x bin/spc
|
chmod +x bin/spc
|
||||||
|
bin/spc --version
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use static-php-cli
|
### Start Building PHP
|
||||||
|
|
||||||
Basic usage for building php and micro with some extensions:
|
Basic usage for building php with some extensions:
|
||||||
|
|
||||||
> If you are using the packaged `spc` binary, you need to replace `bin/spc` with `./spc` in the following commands.
|
> If you are using the packaged `spc` binary, you need to replace `bin/spc` with `./spc` in the following commands.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check system tool dependencies, fix them if possible
|
# Check system tool dependencies, auto-fix them if possible
|
||||||
./bin/spc doctor
|
./bin/spc doctor --auto-fix
|
||||||
|
|
||||||
# fetch all libraries
|
# fetch all libraries
|
||||||
./bin/spc download --all
|
./bin/spc download --all
|
||||||
# only fetch necessary sources by needed extensions
|
# only fetch necessary sources by needed extensions (recommended)
|
||||||
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
./bin/spc download --for-extensions=openssl,pcntl,mbstring,pdo_sqlite
|
||||||
|
# download different PHP version (--with-php=x.y, recommend 7.3 ~ 8.3)
|
||||||
|
./bin/spc download --for-extensions=openssl,curl,mbstring --with-php=8.1
|
||||||
|
|
||||||
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
|
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
|
||||||
./bin/spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-cli --build-micro
|
./bin/spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-cli --build-micro
|
||||||
|
# build thread-safe (ZTS) version (--enable-zts)
|
||||||
|
./bin/spc build curl,phar --enable-zts --build-cli
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the parameter `--with-php=x.y` to specify the downloaded PHP version, currently supports 7.4 ~ 8.3:
|
Now we support `cli`, `micro`, `fpm` and `embed` SAPI. You can use one or more of the following parameters to specify the compiled SAPI:
|
||||||
|
|
||||||
```bash
|
|
||||||
# Using PHP >= 8.0 is recommended, because PHP7 cannot use phpmicro
|
|
||||||
./bin/spc fetch --with-php=8.2 --all
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we support `cli`, `micro`, `fpm`, you can use one or more of the following parameters to specify the compiled SAPI:
|
|
||||||
|
|
||||||
- `--build-cli`: build static cli executable
|
- `--build-cli`: build static cli executable
|
||||||
- `--build-micro`: build static phpmicro self-extracted executable
|
- `--build-micro`: build static phpmicro self-extracted executable
|
||||||
@@ -168,17 +182,9 @@ If anything goes wrong, use `--debug` option to display full terminal output:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
./bin/spc build openssl,pcntl,mbstring --debug --build-all
|
||||||
./bin/spc fetch --all --debug
|
./bin/spc download --all --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
In addition, we build NTS (non-thread-safe) by default. If you are going to build ZTS version, just add `--enable-zts` option.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./bin/spc build openssl,pcntl --build-all --enable-zts
|
|
||||||
```
|
|
||||||
|
|
||||||
Adding option `--no-strip` can produce binaries with debug symbols, in order to debug (using gdb). Disabling strip will increase the size of static binary.
|
|
||||||
|
|
||||||
## Different SAPI Usage
|
## Different SAPI Usage
|
||||||
|
|
||||||
### Use cli
|
### Use cli
|
||||||
@@ -281,10 +287,12 @@ These are similar projects:
|
|||||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)
|
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)
|
||||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)
|
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)
|
||||||
|
|
||||||
|
The project uses some code from [dixyes/lwmbs](https://github.com/dixyes/lwmbs), such as windows static build target and libiconv support.
|
||||||
|
lwmbs is licensed under the [Mulan PSL 2](http://license.coscl.org.cn/MulanPSL2).
|
||||||
|
|
||||||
Due to the special nature of this project,
|
Due to the special nature of this project,
|
||||||
many other open source projects such as curl and protobuf will be used during the project compilation process,
|
many other open source projects such as curl and protobuf will be used during the project compilation process,
|
||||||
and they all have their own open source licenses.
|
and they all have their own open source licenses.
|
||||||
|
|
||||||
Please use the `bin/spc dump-license` command to export the open source licenses used in the project after compilation,
|
Please use the `bin/spc dump-license` command to export the open source licenses used in the project after compilation,
|
||||||
and comply with the corresponding project's LICENSE.
|
and comply with the corresponding project's LICENSE.
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ while [ $# -gt 0 ]; do
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
--mirror)
|
--mirror)
|
||||||
mirror="$2"
|
mirror="$2"
|
||||||
shift
|
|
||||||
;;
|
;;
|
||||||
--*)
|
--*)
|
||||||
echo "Illegal option $1"
|
echo "Illegal option $1"
|
||||||
@@ -47,7 +46,7 @@ done
|
|||||||
case "$mirror" in
|
case "$mirror" in
|
||||||
china)
|
china)
|
||||||
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/bulk/php-8.2.13-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/bulk/php-8.2.13-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
||||||
__COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar"
|
__COMPOSER_URL__="https://mirrors.tencent.com/composer/composer.phar"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|||||||
115
bin/setup-runtime.ps1
Normal file
115
bin/setup-runtime.ps1
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
param (
|
||||||
|
[string] ${action}
|
||||||
|
)
|
||||||
|
|
||||||
|
function AddToPath {
|
||||||
|
param (
|
||||||
|
[string]$pathToAdd
|
||||||
|
)
|
||||||
|
|
||||||
|
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||||
|
|
||||||
|
if ($currentPath -notlike "*$pathToAdd*") {
|
||||||
|
$newPath = $currentPath + ";$pathToAdd"
|
||||||
|
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||||
|
Write-Host "Added '$pathToAdd' to Path."
|
||||||
|
Write-Host "To remove path, use: " -NoNewline
|
||||||
|
Write-Host "bin/setup-runtime remove-path" -ForegroundColor Cyan
|
||||||
|
} else {
|
||||||
|
Write-Host "Path already exists."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RemoveFromPath {
|
||||||
|
param (
|
||||||
|
[string]$pathToRemove
|
||||||
|
)
|
||||||
|
|
||||||
|
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||||
|
|
||||||
|
if ($currentPath -like "*$pathToRemove*") {
|
||||||
|
$newPath = $currentPath -replace [regex]::Escape(';' + $pathToRemove), ''
|
||||||
|
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||||
|
Write-Host "Removed Path '$pathToRemove'"
|
||||||
|
} else {
|
||||||
|
Write-Host "Path '$pathToRemove' not in Path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# working dir
|
||||||
|
$WorkingDir = (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Definition))
|
||||||
|
|
||||||
|
if ($action -eq 'add-path') {
|
||||||
|
AddToPath ($WorkingDir + '\runtime')
|
||||||
|
exit 0
|
||||||
|
} elseif ($action -eq 'remove-path') {
|
||||||
|
RemoveFromPath ($WorkingDir + '\runtime')
|
||||||
|
exit 0
|
||||||
|
} elseif (-not($action -eq '')) {
|
||||||
|
Write-Host ("Invalid action: " + $action) -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# get php 8.1 specific version
|
||||||
|
$API = (Invoke-WebRequest -Uri "https://www.php.net/releases/index.php?json&version=8.1") | ConvertFrom-Json
|
||||||
|
|
||||||
|
# php windows download
|
||||||
|
$PHPRuntimeUrl = "https://windows.php.net/downloads/releases/php-" + $API.version + "-Win32-vs16-x64.zip"
|
||||||
|
$ComposerUrl = "https://getcomposer.org/download/latest-stable/composer.phar"
|
||||||
|
|
||||||
|
# create dir
|
||||||
|
New-Item -Path "downloads" -ItemType Directory -Force | Out-Null
|
||||||
|
|
||||||
|
# download php
|
||||||
|
if (-not(Test-Path "downloads\php.zip"))
|
||||||
|
{
|
||||||
|
Write-Host "Downloading PHP ..."
|
||||||
|
Invoke-WebRequest $PHPRuntimeUrl -OutFile "downloads\php.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
# extract php
|
||||||
|
New-Item -Path "runtime" -ItemType Directory -Force | Out-Null
|
||||||
|
Write-Host "Extracting php.zip ..."
|
||||||
|
Expand-Archive -Path "downloads/php.zip" -DestinationPath "runtime" -Force
|
||||||
|
# make php.ini
|
||||||
|
Move-Item -Path "runtime\php.ini-production" -Destination "runtime\php.ini" -Force
|
||||||
|
$OriginINI = Get-Content -Path "runtime\php.ini" -Raw
|
||||||
|
$OriginINI = $OriginINI -replace ';extension=openssl', 'extension=openssl'
|
||||||
|
$OriginINI = $OriginINI -replace ';extension=curl', 'extension=curl'
|
||||||
|
$OriginINI = $OriginINI -replace ';extension=mbstring', 'extension=mbstring'
|
||||||
|
$OriginINI = $OriginINI -replace ';extension=sodium', 'extension=sodium'
|
||||||
|
$OriginINI = $OriginINI -replace ';extension_dir = "./"', ('extension_dir = "' + (Split-Path -Parent $MyInvocation.MyCommand.Definition) + '\..\runtime\ext"')
|
||||||
|
$OriginINI | Set-Content -Path "runtime\php.ini"
|
||||||
|
|
||||||
|
# download composer
|
||||||
|
if (-not(Test-Path "runtime\composer.phar"))
|
||||||
|
{
|
||||||
|
Write-Host "Downloading composer ..."
|
||||||
|
Invoke-WebRequest $ComposerUrl -OutFile "downloads\composer.phar"
|
||||||
|
Move-Item -Path "downloads\composer.phar" -Destination "runtime\composer.phar" -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
# create runtime\composer.ps1
|
||||||
|
$ComposerContent = '
|
||||||
|
$WorkingDir = (Split-Path -Parent $MyInvocation.MyCommand.Definition)
|
||||||
|
& ($WorkingDir + "\php.exe") (Join-Path $WorkingDir "\composer.phar") @args
|
||||||
|
'
|
||||||
|
$ComposerContent | Set-Content -Path 'runtime\composer.ps1' -Encoding UTF8
|
||||||
|
|
||||||
|
Write-Host "Successfully downloaded PHP and Composer !" -ForegroundColor Green
|
||||||
|
Write-Host "Use static-php-cli: " -NoNewline
|
||||||
|
Write-Host "bin/spc" -ForegroundColor Cyan
|
||||||
|
Write-Host "Use php: " -NoNewline
|
||||||
|
Write-Host "runtime/php" -ForegroundColor Cyan
|
||||||
|
Write-Host "Use composer: " -NoNewline
|
||||||
|
Write-Host "runtime/composer" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Don't forget installing composer dependencies '" -NoNewline
|
||||||
|
Write-Host "runtime/composer install" -ForegroundColor Cyan -NoNewline
|
||||||
|
Write-Host "' before using static-php-cli !"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "If you want to use this PHP for quality tools (like phpstan, php-cs-fixer) or other project,"
|
||||||
|
Write-Host "or use PHP, Composer as system executable,"
|
||||||
|
Write-Host "use '" -NoNewline
|
||||||
|
Write-Host "bin/setup-runtime add-path" -ForegroundColor Cyan -NoNewline
|
||||||
|
Write-Host "' to add runtime dir in Path."
|
||||||
9
bin/spc
9
bin/spc
@@ -4,7 +4,13 @@
|
|||||||
use SPC\ConsoleApplication;
|
use SPC\ConsoleApplication;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
|
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
if (file_exists(dirname(__DIR__) . '/vendor/autoload.php')) {
|
||||||
|
// Current: ./bin (git/project mode)
|
||||||
|
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||||
|
} else {
|
||||||
|
// Current: ./vendor/crazywhalecc/static-php-cli/bin (composer library mode)
|
||||||
|
require_once dirname(__DIR__, 3) . '/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
// 防止 Micro 打包状态下不支持中文的显示(虽然这个项目目前好像没输出过中文?)
|
// 防止 Micro 打包状态下不支持中文的显示(虽然这个项目目前好像没输出过中文?)
|
||||||
if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
|
if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
|
||||||
@@ -15,4 +21,5 @@ try {
|
|||||||
(new ConsoleApplication())->run();
|
(new ConsoleApplication())->run();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ExceptionHandler::getInstance()->handle($e);
|
ExceptionHandler::getInstance()->handle($e);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
11
bin/spc.ps1
Normal file
11
bin/spc.ps1
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
$PHP_Exec = ".\runtime\php.exe"
|
||||||
|
|
||||||
|
if (-not(Test-Path $PHP_Exec)) {
|
||||||
|
$PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition
|
||||||
|
if (-not $PHP_Exec) {
|
||||||
|
Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& "$PHP_Exec" ("bin/spc") @args
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">= 8.1",
|
"php": ">= 8.1",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-pcntl": "*",
|
|
||||||
"laravel/prompts": "^0.1.12",
|
"laravel/prompts": "^0.1.12",
|
||||||
"symfony/console": "^5.4 || ^6 || ^7",
|
"symfony/console": "^5.4 || ^6 || ^7",
|
||||||
"zhamao/logger": "^1.0"
|
"zhamao/logger": "^1.0"
|
||||||
|
|||||||
449
composer.lock
generated
449
composer.lock
generated
File diff suppressed because it is too large
Load Diff
113
config/ext.json
113
config/ext.json
@@ -16,14 +16,6 @@
|
|||||||
"calendar": {
|
"calendar": {
|
||||||
"type": "builtin"
|
"type": "builtin"
|
||||||
},
|
},
|
||||||
"crypto": {
|
|
||||||
"type": "external",
|
|
||||||
"arg-type": "with",
|
|
||||||
"source": "ext-crypto",
|
|
||||||
"lib-depends": [
|
|
||||||
"openssl"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ctype": {
|
"ctype": {
|
||||||
"type": "builtin"
|
"type": "builtin"
|
||||||
},
|
},
|
||||||
@@ -114,7 +106,8 @@
|
|||||||
"source": "ext-glfw",
|
"source": "ext-glfw",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"glfw"
|
"glfw"
|
||||||
]
|
],
|
||||||
|
"lib-depends-windows": []
|
||||||
},
|
},
|
||||||
"gmp": {
|
"gmp": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
@@ -176,14 +169,6 @@
|
|||||||
"openssl"
|
"openssl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"leveldb": {
|
|
||||||
"type": "external",
|
|
||||||
"arg-type": "with-prefix",
|
|
||||||
"source": "pmmp-leveldb",
|
|
||||||
"lib-depends": [
|
|
||||||
"leveldb"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mbregex": {
|
"mbregex": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
@@ -233,10 +218,6 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"morton": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "ext-morton"
|
|
||||||
},
|
|
||||||
"mysqli": {
|
"mysqli": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with",
|
"arg-type": "with",
|
||||||
@@ -258,6 +239,7 @@
|
|||||||
"openssl": {
|
"openssl": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
|
"arg-type-windows": "with",
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"openssl",
|
"openssl",
|
||||||
"zlib"
|
"zlib"
|
||||||
@@ -323,16 +305,6 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"pmmp-chunkutils2": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "pmmp-chunkutils2",
|
|
||||||
"arg-type": "custom",
|
|
||||||
"cpp-extension": true
|
|
||||||
},
|
|
||||||
"pmmpthread": {
|
|
||||||
"type": "external",
|
|
||||||
"source": "pmmpthread"
|
|
||||||
},
|
|
||||||
"posix": {
|
"posix": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"unix-only": true
|
"unix-only": true
|
||||||
@@ -365,7 +337,12 @@
|
|||||||
"source": "redis",
|
"source": "redis",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"ext-suggests": [
|
"ext-suggests": [
|
||||||
"session"
|
"session",
|
||||||
|
"igbinary"
|
||||||
|
],
|
||||||
|
"lib-suggests": [
|
||||||
|
"zstd",
|
||||||
|
"liblz4"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"session": {
|
"session": {
|
||||||
@@ -425,6 +402,17 @@
|
|||||||
"sqlite"
|
"sqlite"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"sqlsrv": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "sqlsrv",
|
||||||
|
"lib-depends": [
|
||||||
|
"unixodbc"
|
||||||
|
],
|
||||||
|
"ext-depends-linux": [
|
||||||
|
"pcntl"
|
||||||
|
],
|
||||||
|
"cpp-extension": true
|
||||||
|
},
|
||||||
"ssh2": {
|
"ssh2": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "ext-ssh2",
|
"source": "ext-ssh2",
|
||||||
@@ -438,17 +426,50 @@
|
|||||||
"source": "swoole",
|
"source": "swoole",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"cpp-extension": true,
|
"cpp-extension": true,
|
||||||
|
"unix-only": true,
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"openssl"
|
"libcares",
|
||||||
|
"brotli",
|
||||||
|
"nghttp2",
|
||||||
|
"zlib"
|
||||||
],
|
],
|
||||||
"ext-depends": [
|
"ext-depends": [
|
||||||
"openssl"
|
"openssl",
|
||||||
|
"curl"
|
||||||
],
|
],
|
||||||
"ext-suggests": [
|
"ext-suggests": [
|
||||||
"curl",
|
"swoole-hook-pgsql",
|
||||||
"pgsql"
|
"swoole-hook-mysql",
|
||||||
|
"swoole-hook-sqlite"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"swoole-hook-mysql": {
|
||||||
|
"type": "addon",
|
||||||
|
"arg-type": "custom",
|
||||||
|
"ext-depends": [
|
||||||
|
"mysqlnd",
|
||||||
|
"pdo",
|
||||||
|
"pdo_mysql"
|
||||||
],
|
],
|
||||||
"unix-only": true
|
"ext-suggests": [
|
||||||
|
"mysqli"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"swoole-hook-pgsql": {
|
||||||
|
"type": "addon",
|
||||||
|
"arg-type": "custom",
|
||||||
|
"ext-depends": [
|
||||||
|
"pgsql",
|
||||||
|
"pdo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"swoole-hook-sqlite": {
|
||||||
|
"type": "addon",
|
||||||
|
"arg-type": "custom",
|
||||||
|
"ext-depends": [
|
||||||
|
"sqlite3",
|
||||||
|
"pdo"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"swow": {
|
"swow": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
@@ -485,6 +506,24 @@
|
|||||||
"tokenizer": {
|
"tokenizer": {
|
||||||
"type": "builtin"
|
"type": "builtin"
|
||||||
},
|
},
|
||||||
|
"uv": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "ext-uv",
|
||||||
|
"arg-type": "with-prefix",
|
||||||
|
"lib-depends": [
|
||||||
|
"libuv"
|
||||||
|
],
|
||||||
|
"ext-depends": [
|
||||||
|
"sockets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"xhprof": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "xhprof",
|
||||||
|
"ext-depends": [
|
||||||
|
"ctype"
|
||||||
|
]
|
||||||
|
},
|
||||||
"xlswriter": {
|
"xlswriter": {
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "xlswriter",
|
"source": "xlswriter",
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
"brotli": {
|
"brotli": {
|
||||||
"source": "brotli",
|
"source": "brotli",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
"libbrotlidec-static.a",
|
"libbrotlidec.a",
|
||||||
"libbrotlienc-static.a",
|
"libbrotlienc.a",
|
||||||
"libbrotlicommon-static.a"
|
"libbrotlicommon.a"
|
||||||
],
|
],
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
"brotlicommon-static.lib",
|
"brotlicommon.lib",
|
||||||
"brotlienc-static.lib",
|
"brotlienc.lib",
|
||||||
"brotlidec-static.lib"
|
"brotlidec.lib"
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
"brotli"
|
"brotli"
|
||||||
@@ -57,9 +57,7 @@
|
|||||||
"brotli",
|
"brotli",
|
||||||
"nghttp2",
|
"nghttp2",
|
||||||
"zstd",
|
"zstd",
|
||||||
"openssl",
|
"openssl"
|
||||||
"idn2",
|
|
||||||
"psl"
|
|
||||||
],
|
],
|
||||||
"frameworks": [
|
"frameworks": [
|
||||||
"CoreFoundation",
|
"CoreFoundation",
|
||||||
@@ -163,13 +161,6 @@
|
|||||||
"libsodium"
|
"libsodium"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"leveldb": {
|
|
||||||
"source": "leveldb",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libleveldb.a"
|
|
||||||
],
|
|
||||||
"cpp-library": true
|
|
||||||
},
|
|
||||||
"libargon2": {
|
"libargon2": {
|
||||||
"source": "libargon2",
|
"source": "libargon2",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -182,6 +173,18 @@
|
|||||||
"libavif.a"
|
"libavif.a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libcares": {
|
||||||
|
"source": "libcares",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libcares.a"
|
||||||
|
],
|
||||||
|
"headers-unix": [
|
||||||
|
"ares.h",
|
||||||
|
"ares_dns.h",
|
||||||
|
"ares_nameser.h",
|
||||||
|
"ares_rules.h"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libevent": {
|
"libevent": {
|
||||||
"source": "libevent",
|
"source": "libevent",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -231,10 +234,10 @@
|
|||||||
"libturbojpeg.a"
|
"libturbojpeg.a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"libmcrypt": {
|
"liblz4": {
|
||||||
"source": "libmcrypt",
|
"source": "liblz4",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
"libmcrypt.a"
|
"liblz4.a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"libmemcached": {
|
"libmemcached": {
|
||||||
@@ -291,6 +294,12 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"libuv": {
|
||||||
|
"source": "libuv",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libuv.a"
|
||||||
|
]
|
||||||
|
},
|
||||||
"libwebp": {
|
"libwebp": {
|
||||||
"source": "libwebp",
|
"source": "libwebp",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -316,16 +325,12 @@
|
|||||||
"libxml2"
|
"libxml2"
|
||||||
],
|
],
|
||||||
"lib-depends": [
|
"lib-depends": [
|
||||||
"libiconv",
|
"libiconv"
|
||||||
"zlib"
|
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests": [
|
||||||
"xz",
|
"xz",
|
||||||
"icu"
|
|
||||||
],
|
|
||||||
"lib-suggests-windows": [
|
|
||||||
"icu",
|
"icu",
|
||||||
"xz"
|
"zlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"libxslt": {
|
"libxslt": {
|
||||||
@@ -375,12 +380,6 @@
|
|||||||
"openssl"
|
"openssl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mcrypt": {
|
|
||||||
"source": "mcrypt",
|
|
||||||
"static-libs-unix": [
|
|
||||||
"libmcrypt.a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ncurses": {
|
"ncurses": {
|
||||||
"source": "ncurses",
|
"source": "ncurses",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -503,6 +502,17 @@
|
|||||||
"libtidy.a"
|
"libtidy.a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"unixodbc": {
|
||||||
|
"source": "unixodbc",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"libodbc.a",
|
||||||
|
"libodbccr.a",
|
||||||
|
"libodbcinst.a"
|
||||||
|
],
|
||||||
|
"lib-depends": [
|
||||||
|
"libiconv"
|
||||||
|
]
|
||||||
|
},
|
||||||
"xz": {
|
"xz": {
|
||||||
"source": "xz",
|
"source": "xz",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
|
|||||||
@@ -42,16 +42,6 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ext-crypto": {
|
|
||||||
"type": "git",
|
|
||||||
"path": "php-src/ext/crypto",
|
|
||||||
"rev": "master",
|
|
||||||
"url": "https://github.com/bukka/php-crypto.git",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ext-event": {
|
"ext-event": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz",
|
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz",
|
||||||
@@ -90,16 +80,6 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ext-morton": {
|
|
||||||
"type": "git",
|
|
||||||
"path": "php-src/ext/morton",
|
|
||||||
"rev": "master",
|
|
||||||
"url": "https://github.com/pmmp/ext-morton.git",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ext-snappy": {
|
"ext-snappy": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"path": "php-src/ext/snappy",
|
"path": "php-src/ext/snappy",
|
||||||
@@ -120,6 +100,16 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ext-uv": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/uv",
|
||||||
|
"path": "php-src/ext/uv",
|
||||||
|
"filename": "uv.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ext-zstd": {
|
"ext-zstd": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"path": "php-src/ext/zstd",
|
"path": "php-src/ext/zstd",
|
||||||
@@ -157,9 +147,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"igbinary": {
|
"igbinary": {
|
||||||
"type": "ghtar",
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/igbinary",
|
||||||
"path": "php-src/ext/igbinary",
|
"path": "php-src/ext/igbinary",
|
||||||
"repo": "igbinary/igbinary",
|
"filename": "igbinary.tgz",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
@@ -201,15 +192,6 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"leveldb": {
|
|
||||||
"type": "git",
|
|
||||||
"rev": "mojang-compatible",
|
|
||||||
"url": "https://github.com/pmmp/leveldb.git",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libargon2": {
|
"libargon2": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"rev": "master",
|
"rev": "master",
|
||||||
@@ -227,6 +209,15 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libcares": {
|
||||||
|
"type": "filelist",
|
||||||
|
"url": "https://c-ares.org/download/",
|
||||||
|
"regex": "/href=\"\\/download\\/(?<file>c-ares-(?<version>[^\"]+)\\.tar\\.gz)\"/",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE.md"
|
||||||
|
}
|
||||||
|
},
|
||||||
"libevent": {
|
"libevent": {
|
||||||
"type": "ghrel",
|
"type": "ghrel",
|
||||||
"repo": "libevent/libevent",
|
"repo": "libevent/libevent",
|
||||||
@@ -262,12 +253,13 @@
|
|||||||
"path": "LICENSE.md"
|
"path": "LICENSE.md"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libmcrypt": {
|
"liblz4": {
|
||||||
"type": "url",
|
"type": "ghrel",
|
||||||
"url": "https://downloads.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz",
|
"repo": "lz4/lz4",
|
||||||
|
"match": "lz4-.+\\.tar\\.gz",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "COPYING"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libmemcached": {
|
"libmemcached": {
|
||||||
@@ -289,8 +281,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libsodium": {
|
"libsodium": {
|
||||||
"type": "url",
|
"type": "ghrel",
|
||||||
"url": "https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz",
|
"repo": "jedisct1/libsodium",
|
||||||
|
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
@@ -305,6 +298,20 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libuv": {
|
||||||
|
"type": "ghtar",
|
||||||
|
"repo": "libuv/libuv",
|
||||||
|
"license": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE-extra"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"libwebp": {
|
"libwebp": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
|
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
|
||||||
@@ -348,14 +355,6 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mcrypt": {
|
|
||||||
"type": "url",
|
|
||||||
"url": "https://downloads.sourceforge.net/project/mcrypt/MCrypt/2.6.8/mcrypt-2.6.8.tar.gz",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "COPYING"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"memcached": {
|
"memcached": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/memcached",
|
"url": "https://pecl.php.net/get/memcached",
|
||||||
@@ -430,34 +429,6 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pmmp-chunkutils2": {
|
|
||||||
"type": "ghtar",
|
|
||||||
"path": "php-src/ext/chunkutils2",
|
|
||||||
"repo": "pmmp/ext-chunkutils2",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pmmp-leveldb": {
|
|
||||||
"type": "git",
|
|
||||||
"path": "php-src/ext/leveldb",
|
|
||||||
"rev": "pmmp-mojang-compatible",
|
|
||||||
"url": "https://github.com/pmmp/php-leveldb.git",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pmmpthread": {
|
|
||||||
"type": "ghtar",
|
|
||||||
"path": "php-src/ext/pmmpthread",
|
|
||||||
"repo": "pmmp/ext-pmmpthread",
|
|
||||||
"license": {
|
|
||||||
"type": "file",
|
|
||||||
"path": "LICENSE"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"postgresql": {
|
"postgresql": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://ftp.postgresql.org/pub/source/v16.1/postgresql-16.1.tar.gz",
|
"url": "https://ftp.postgresql.org/pub/source/v16.1/postgresql-16.1.tar.gz",
|
||||||
@@ -523,6 +494,16 @@
|
|||||||
"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."
|
"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."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sqlsrv": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/sqlsrv",
|
||||||
|
"path": "php-src/ext/sqlsrv",
|
||||||
|
"filename": "sqlsrv.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"swoole": {
|
"swoole": {
|
||||||
"type": "ghtar",
|
"type": "ghtar",
|
||||||
"path": "php-src/ext/swoole",
|
"path": "php-src/ext/swoole",
|
||||||
@@ -552,6 +533,24 @@
|
|||||||
"path": "README/LICENSE.md"
|
"path": "README/LICENSE.md"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"unixodbc": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://www.unixodbc.org/unixODBC-2.3.12.tar.gz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "COPYING"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xhprof": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/xhprof",
|
||||||
|
"path": "php-src/ext/xhprof-src",
|
||||||
|
"filename": "xhprof.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"xlswriter": {
|
"xlswriter": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/xlswriter",
|
"url": "https://pecl.php.net/get/xlswriter",
|
||||||
@@ -563,9 +562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"xz": {
|
"xz": {
|
||||||
"type": "filelist",
|
"type": "ghrel",
|
||||||
"url": "https://tukaani.org/xz/",
|
"repo": "tukaani-project/xz",
|
||||||
"regex": "/href=\"(?<file>xz-(?<version>[^\"]+)\\.tar\\.xz)\"/",
|
"match": "xz-.+\\.tar\\.gz",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
|
|||||||
@@ -8,5 +8,11 @@ parameters:
|
|||||||
- '#Unsafe usage of new static#'
|
- '#Unsafe usage of new static#'
|
||||||
- '#class Fiber#'
|
- '#class Fiber#'
|
||||||
- '#Attribute class JetBrains\\PhpStorm\\ArrayShape does not exist#'
|
- '#Attribute class JetBrains\\PhpStorm\\ArrayShape does not exist#'
|
||||||
|
- '#Function Swoole\\Coroutine\\run not found.#'
|
||||||
dynamicConstantNames:
|
dynamicConstantNames:
|
||||||
- PHP_OS_FAMILY
|
- PHP_OS_FAMILY
|
||||||
|
excludePaths:
|
||||||
|
analyseAndScan:
|
||||||
|
- ./src/globals/tests/swoole.php
|
||||||
|
- ./src/globals/tests/swoole.phpt
|
||||||
|
- ./src/globals/test-extensions.php
|
||||||
@@ -23,7 +23,7 @@ use Symfony\Component\Console\Command\ListCommand;
|
|||||||
*/
|
*/
|
||||||
final class ConsoleApplication extends Application
|
final class ConsoleApplication extends Application
|
||||||
{
|
{
|
||||||
public const VERSION = '2.0.0-rc9';
|
public const VERSION = '2.1.0-beta.2';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder;
|
namespace SPC\builder;
|
||||||
|
|
||||||
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
|
||||||
use SPC\store\SourceExtractor;
|
use SPC\store\SourceExtractor;
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
use SPC\util\DependencyUtil;
|
|
||||||
|
|
||||||
abstract class BuilderBase
|
abstract class BuilderBase
|
||||||
{
|
{
|
||||||
@@ -30,69 +29,19 @@ abstract class BuilderBase
|
|||||||
/** @var array<string, mixed> compile options */
|
/** @var array<string, mixed> compile options */
|
||||||
protected array $options = [];
|
protected array $options = [];
|
||||||
|
|
||||||
|
/** @var string patch point name */
|
||||||
|
protected string $patch_point = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build libraries
|
* Build libraries
|
||||||
*
|
*
|
||||||
* @param array<string> $libraries Libraries to build
|
* @param array<string> $sorted_libraries Libraries to build (if not empty, must sort first)
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
public function buildLibs(array $libraries): void
|
abstract public function buildLibs(array $sorted_libraries);
|
||||||
{
|
|
||||||
// search all supported libs
|
|
||||||
$support_lib_list = [];
|
|
||||||
$classes = FileSystem::getClassesPsr4(
|
|
||||||
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
|
|
||||||
'SPC\\builder\\' . osfamily2dir() . '\\library'
|
|
||||||
);
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
|
|
||||||
$support_lib_list[$class::NAME] = $class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no libs specified, compile all supported libs
|
|
||||||
if ($libraries === [] && $this->isLibsOnly()) {
|
|
||||||
$libraries = array_keys($support_lib_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkg-config must be compiled first, whether it is specified or not
|
|
||||||
if (!in_array('pkg-config', $libraries)) {
|
|
||||||
array_unshift($libraries, 'pkg-config');
|
|
||||||
}
|
|
||||||
|
|
||||||
// append dependencies
|
|
||||||
$libraries = DependencyUtil::getLibsByDeps($libraries);
|
|
||||||
|
|
||||||
// add lib object for builder
|
|
||||||
foreach ($libraries as $library) {
|
|
||||||
// if some libs are not supported (but in config "lib.json", throw exception)
|
|
||||||
if (!isset($support_lib_list[$library])) {
|
|
||||||
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
|
|
||||||
}
|
|
||||||
$lib = new ($support_lib_list[$library])($this);
|
|
||||||
$this->addLib($lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate and check dependencies
|
|
||||||
foreach ($this->libs as $lib) {
|
|
||||||
$lib->calcDependency();
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract sources
|
|
||||||
SourceExtractor::initSource(libs: $libraries);
|
|
||||||
|
|
||||||
// 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'),
|
|
||||||
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add library to build.
|
* Add library to build.
|
||||||
@@ -174,6 +123,8 @@ abstract class BuilderBase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set libs only mode.
|
* Set libs only mode.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
public function setLibsOnly(bool $status = true): void
|
public function setLibsOnly(bool $status = true): void
|
||||||
{
|
{
|
||||||
@@ -187,15 +138,22 @@ abstract class BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
public function proveExts(array $extensions): void
|
public function proveExts(array $extensions): void
|
||||||
{
|
{
|
||||||
CustomExt::loadCustomExt();
|
CustomExt::loadCustomExt();
|
||||||
|
$this->emitPatchPoint('before-php-extract');
|
||||||
SourceExtractor::initSource(sources: ['php-src']);
|
SourceExtractor::initSource(sources: ['php-src']);
|
||||||
|
$this->emitPatchPoint('after-php-extract');
|
||||||
if ($this->getPHPVersionID() >= 80000) {
|
if ($this->getPHPVersionID() >= 80000) {
|
||||||
|
$this->emitPatchPoint('before-micro-extract');
|
||||||
SourceExtractor::initSource(sources: ['micro']);
|
SourceExtractor::initSource(sources: ['micro']);
|
||||||
|
$this->emitPatchPoint('after-micro-extract');
|
||||||
}
|
}
|
||||||
|
$this->emitPatchPoint('before-exts-extract');
|
||||||
SourceExtractor::initSource(exts: $extensions);
|
SourceExtractor::initSource(exts: $extensions);
|
||||||
|
$this->emitPatchPoint('after-exts-extract');
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
$class = CustomExt::getExtClass($extension);
|
$class = CustomExt::getExtClass($extension);
|
||||||
$ext = new $class($extension, $this);
|
$ext = new $class($extension, $this);
|
||||||
@@ -225,9 +183,10 @@ abstract class BuilderBase
|
|||||||
{
|
{
|
||||||
$ret = [];
|
$ret = [];
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->exts as $ext) {
|
||||||
|
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
|
||||||
$ret[] = trim($ext->getConfigureArg());
|
$ret[] = trim($ext->getConfigureArg());
|
||||||
}
|
}
|
||||||
logger()->info('Using configure: ' . implode(' ', $ret));
|
logger()->debug('Using configure: ' . implode(' ', $ret));
|
||||||
return implode(' ', $ret);
|
return implode(' ', $ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,6 +303,39 @@ abstract class BuilderBase
|
|||||||
return implode(' ', $env);
|
return implode(' ', $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get builder patch point name.
|
||||||
|
*/
|
||||||
|
public function getPatchPoint(): string
|
||||||
|
{
|
||||||
|
return $this->patch_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emitPatchPoint(string $point_name): void
|
||||||
|
{
|
||||||
|
$this->patch_point = $point_name;
|
||||||
|
if (($patches = $this->getOption('with-added-patch', [])) === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($patches as $patch) {
|
||||||
|
try {
|
||||||
|
if (!file_exists($patch)) {
|
||||||
|
throw new RuntimeException("Additional patch script file {$patch} not found!");
|
||||||
|
}
|
||||||
|
logger()->debug('Running additional patch script: ' . $patch);
|
||||||
|
require $patch;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
logger()->critical('Patch script ' . $patch . ' failed to run.');
|
||||||
|
if ($this->getOption('debug')) {
|
||||||
|
ExceptionHandler::getInstance()->handle($e);
|
||||||
|
} else {
|
||||||
|
logger()->critical('Please check with --debug option to see more details.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if all libs are downloaded.
|
* Check if all libs are downloaded.
|
||||||
* If not, throw exception.
|
* If not, throw exception.
|
||||||
@@ -367,4 +359,22 @@ abstract class BuilderBase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate micro extension test php code.
|
||||||
|
*/
|
||||||
|
protected function generateMicroExtTests(): string
|
||||||
|
{
|
||||||
|
$php = "<?php\n\necho '[micro-test-start]' . PHP_EOL;\n";
|
||||||
|
|
||||||
|
foreach ($this->getExts() as $ext) {
|
||||||
|
$ext_name = $ext->getDistName();
|
||||||
|
if (!empty($ext_name)) {
|
||||||
|
$php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n";
|
||||||
|
$php .= "assert(extension_loaded('{$ext_name}'));\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$php .= "echo '[micro-test-end]';\n";
|
||||||
|
return $php;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace SPC\builder;
|
|||||||
use SPC\builder\freebsd\BSDBuilder;
|
use SPC\builder\freebsd\BSDBuilder;
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
use SPC\builder\linux\LinuxBuilder;
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
use SPC\builder\macos\MacOSBuilder;
|
||||||
|
use SPC\builder\windows\WindowsBuilder;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
@@ -17,6 +18,8 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||||||
*/
|
*/
|
||||||
class BuilderProvider
|
class BuilderProvider
|
||||||
{
|
{
|
||||||
|
private static ?BuilderBase $builder = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
@@ -24,16 +27,24 @@ class BuilderProvider
|
|||||||
*/
|
*/
|
||||||
public static function makeBuilderByInput(InputInterface $input): BuilderBase
|
public static function makeBuilderByInput(InputInterface $input): BuilderBase
|
||||||
{
|
{
|
||||||
return match (PHP_OS_FAMILY) {
|
self::$builder = match (PHP_OS_FAMILY) {
|
||||||
// 'Windows' => new WindowsBuilder(
|
'Windows' => new WindowsBuilder($input->getOptions()),
|
||||||
// binary_sdk_dir: $input->getOption('with-sdk-binary-dir'),
|
|
||||||
// vs_ver: $input->getOption('vs-ver'),
|
|
||||||
// arch: $input->getOption('arch'),
|
|
||||||
// ),
|
|
||||||
'Darwin' => new MacOSBuilder($input->getOptions()),
|
'Darwin' => new MacOSBuilder($input->getOptions()),
|
||||||
'Linux' => new LinuxBuilder($input->getOptions()),
|
'Linux' => new LinuxBuilder($input->getOptions()),
|
||||||
'BSD' => new BSDBuilder($input->getOptions()),
|
'BSD' => new BSDBuilder($input->getOptions()),
|
||||||
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
|
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
|
||||||
};
|
};
|
||||||
|
return self::$builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
public static function getBuilder(): BuilderBase
|
||||||
|
{
|
||||||
|
if (self::$builder === null) {
|
||||||
|
throw new WrongUsageException('Builder has not been initialized');
|
||||||
|
}
|
||||||
|
return self::$builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use SPC\exception\FileSystemException;
|
|||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
class Extension
|
class Extension
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ class Extension
|
|||||||
$arg = $this->getEnableArg();
|
$arg = $this->getEnableArg();
|
||||||
switch (PHP_OS_FAMILY) {
|
switch (PHP_OS_FAMILY) {
|
||||||
case 'Windows':
|
case 'Windows':
|
||||||
$arg = $this->getWindowsConfigureArg();
|
$arg .= $this->getWindowsConfigureArg();
|
||||||
break;
|
break;
|
||||||
case 'Darwin':
|
case 'Darwin':
|
||||||
case 'Linux':
|
case 'Linux':
|
||||||
@@ -164,14 +165,13 @@ class Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run compile check if build target is cli
|
|
||||||
* If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php
|
|
||||||
* If check failed, throw RuntimeException
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function runCliCheck(): void
|
public function runCliCheckUnix(): void
|
||||||
{
|
{
|
||||||
|
// Run compile check if build target is cli
|
||||||
|
// If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php
|
||||||
|
// If check failed, throw RuntimeException
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $this->getDistName() . '"', false);
|
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $this->getDistName() . '"', false);
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||||
@@ -192,6 +192,34 @@ class Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function runCliCheckWindows(): void
|
||||||
|
{
|
||||||
|
// Run compile check if build target is cli
|
||||||
|
// If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php
|
||||||
|
// If check failed, throw RuntimeException
|
||||||
|
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe --ri "' . $this->getDistName() . '"', false);
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))) {
|
||||||
|
// Trim additional content & escape special characters to allow inline usage
|
||||||
|
$test = str_replace(
|
||||||
|
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
|
||||||
|
['', '', '', '\"', '\$'],
|
||||||
|
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))
|
||||||
|
);
|
||||||
|
|
||||||
|
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -r "' . trim($test) . '"');
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -140,7 +140,9 @@ abstract class LibraryBase
|
|||||||
if (!$this->patched && $this->patchBeforeBuild()) {
|
if (!$this->patched && $this->patchBeforeBuild()) {
|
||||||
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
|
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
|
||||||
}
|
}
|
||||||
|
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
|
||||||
$this->build();
|
$this->build();
|
||||||
|
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
|
||||||
return BUILD_STATUS_OK;
|
return BUILD_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,4 +34,9 @@ class glfw extends Extension
|
|||||||
{
|
{
|
||||||
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
|
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--enable-glfw=static';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/SPC/builder/extension/ldap.php
Normal file
23
src/SPC/builder/extension/ldap.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('ldap')]
|
||||||
|
class ldap extends Extension
|
||||||
|
{
|
||||||
|
public function patchBeforeConfigure(): bool
|
||||||
|
{
|
||||||
|
$output = shell()->execWithResult('$PKG_CONFIG --libs-only-l --static ldap');
|
||||||
|
if (!empty($output[1][0])) {
|
||||||
|
$libs = $output[1][0];
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/configure', '-lldap ', $libs . ' ');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,11 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('mbregex')]
|
#[CustomExt('mbregex')]
|
||||||
class mbregex extends Extension
|
class mbregex extends Extension
|
||||||
{
|
{
|
||||||
|
public function getDistName(): string
|
||||||
|
{
|
||||||
|
return 'mbstring';
|
||||||
|
}
|
||||||
|
|
||||||
public function getConfigureArg(): string
|
public function getConfigureArg(): string
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
@@ -19,7 +24,7 @@ class mbregex extends Extension
|
|||||||
/**
|
/**
|
||||||
* mbregex is not an extension, we need to overwrite the default check.
|
* mbregex is not an extension, we need to overwrite the default check.
|
||||||
*/
|
*/
|
||||||
public function runCliCheck(): void
|
public function runCliCheckUnix(): void
|
||||||
{
|
{
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "mbstring" | grep regex', false);
|
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "mbstring" | grep regex', false);
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('mbstring')]
|
#[CustomExt('mbstring')]
|
||||||
class mbstring extends Extension
|
class mbstring extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getConfigureArg(): string
|
||||||
{
|
{
|
||||||
$arg = '--enable-mbstring';
|
$arg = '--enable-mbstring';
|
||||||
if ($this->builder->getExt('mbregex') === null) {
|
if ($this->builder->getExt('mbregex') === null) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('password-argon2')]
|
#[CustomExt('password-argon2')]
|
||||||
class password_argon2 extends Extension
|
class password_argon2 extends Extension
|
||||||
{
|
{
|
||||||
public function runCliCheck(): void
|
public function runCliCheckUnix(): void
|
||||||
{
|
{
|
||||||
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "assert(defined(\'PASSWORD_ARGON2I\'));"');
|
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "assert(defined(\'PASSWORD_ARGON2I\'));"');
|
||||||
if ($ret !== 0) {
|
if ($ret !== 0) {
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\extension;
|
|
||||||
|
|
||||||
use SPC\builder\Extension;
|
|
||||||
use SPC\util\CustomExt;
|
|
||||||
|
|
||||||
#[CustomExt('pmmp-chunkutils2')]
|
|
||||||
class pmmp_chunkutils2 extends Extension
|
|
||||||
{
|
|
||||||
public function getDistName(): string
|
|
||||||
{
|
|
||||||
return 'chunkutils2';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
|
||||||
{
|
|
||||||
return '--enable-chunkutils2';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,14 +13,14 @@ class redis extends Extension
|
|||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(): string
|
||||||
{
|
{
|
||||||
$arg = '--enable-redis';
|
$arg = '--enable-redis';
|
||||||
if (!$this->builder->getExt('session')) {
|
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';
|
||||||
$arg .= ' --disable-redis-session';
|
$arg .= $this->builder->getExt('igbinary') ? ' --enable-redis-igbinary' : ' --disable-redis-igbinary';
|
||||||
} else {
|
|
||||||
$arg .= ' --enable-redis-session';
|
|
||||||
}
|
|
||||||
if ($this->builder->getLib('zstd')) {
|
if ($this->builder->getLib('zstd')) {
|
||||||
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
|
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
|
||||||
}
|
}
|
||||||
|
if ($this->builder->getLib('liblz4')) {
|
||||||
|
$arg .= ' --enable-redis-lz4 --with-liblz4="' . BUILD_ROOT_PATH . '"';
|
||||||
|
}
|
||||||
return $arg;
|
return $arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,31 @@ class swoole extends Extension
|
|||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(): string
|
||||||
{
|
{
|
||||||
|
// enable swoole
|
||||||
$arg = '--enable-swoole';
|
$arg = '--enable-swoole';
|
||||||
// pgsql hook is buggy for static php
|
|
||||||
$arg .= ' --disable-swoole-pgsql';
|
// commonly-used feature: coroutine-time, thread-context
|
||||||
$arg .= $this->builder->getLib('openssl') ? ' --enable-openssl' : ' --disable-openssl --without-openssl';
|
$arg .= ' --enable-swoole-coro-time --enable-thread-context';
|
||||||
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ' --disable-brotli';
|
|
||||||
// swoole curl hook is buggy for php 8.0
|
// required feature: curl, openssl (but curl hook is buggy for php 8.0)
|
||||||
$arg .= $this->builder->getExt('curl') && $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
|
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
|
||||||
|
$arg .= ' --enable-openssl';
|
||||||
|
|
||||||
|
// additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature)
|
||||||
|
$arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : '';
|
||||||
|
$arg .= $this->builder->getLib('brotli') ? (' --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
|
||||||
|
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : '';
|
||||||
|
|
||||||
|
// additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc.
|
||||||
|
// so this is a tricky way (enable ext [pgsql,pdo] to add postgresql hook and pdo_pgsql support)
|
||||||
|
$arg .= $this->builder->getExt('swoole-hook-pgsql') ? '' : ' --disable-swoole-pgsql';
|
||||||
|
|
||||||
|
// enable this feature , need remove pdo_sqlite
|
||||||
|
// more info : https://wenda.swoole.com/detail/109023
|
||||||
|
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? '' : ' --disable-swoole-sqlite';
|
||||||
|
|
||||||
|
// enable this feature , need stop pdo_*
|
||||||
|
// $arg .= $this->builder->getLib('unixodbc') ? ' --with-swoole-odbc=unixODBC,' : ' ';
|
||||||
return $arg;
|
return $arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/SPC/builder/extension/swoole_hook_mysql.php
Normal file
41
src/SPC/builder/extension/swoole_hook_mysql.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('swoole-hook-mysql')]
|
||||||
|
class swoole_hook_mysql extends Extension
|
||||||
|
{
|
||||||
|
public function getDistName(): string
|
||||||
|
{
|
||||||
|
return 'swoole';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(): string
|
||||||
|
{
|
||||||
|
// pdo_mysql doesn't need to be disabled
|
||||||
|
// enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCliCheckUnix(): void
|
||||||
|
{
|
||||||
|
// skip if not enable swoole
|
||||||
|
if ($this->builder->getExt('swoole') === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||||
|
$out = implode('', $out);
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||||
|
}
|
||||||
|
if (!str_contains($out, 'mysqlnd')) {
|
||||||
|
throw new RuntimeException('swoole mysql hook is not enabled correctly.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/SPC/builder/extension/swoole_hook_pgsql.php
Normal file
45
src/SPC/builder/extension/swoole_hook_pgsql.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('swoole-hook-pgsql')]
|
||||||
|
class swoole_hook_pgsql extends Extension
|
||||||
|
{
|
||||||
|
public function getDistName(): string
|
||||||
|
{
|
||||||
|
return 'swoole';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(): string
|
||||||
|
{
|
||||||
|
// pdo_pgsql need to be disabled
|
||||||
|
if ($this->builder->getExt('pdo_pgsql') !== null) {
|
||||||
|
throw new WrongUsageException('swoole-hook-pgsql provides pdo_pgsql, if you enable pgsql hook for swoole, you must remove pdo_pgsql extension.');
|
||||||
|
}
|
||||||
|
// enable swoole pgsql hook
|
||||||
|
return '--enable-swoole-pgsql';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCliCheckUnix(): void
|
||||||
|
{
|
||||||
|
// skip if not enable swoole
|
||||||
|
if ($this->builder->getExt('swoole') === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||||
|
$out = implode('', $out);
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||||
|
}
|
||||||
|
if (!str_contains($out, 'coroutine_pgsql')) {
|
||||||
|
throw new RuntimeException('swoole pgsql hook is not enabled correctly.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/SPC/builder/extension/swoole_hook_sqlite.php
Normal file
45
src/SPC/builder/extension/swoole_hook_sqlite.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('swoole-hook-sqlite')]
|
||||||
|
class swoole_hook_sqlite extends Extension
|
||||||
|
{
|
||||||
|
public function getDistName(): string
|
||||||
|
{
|
||||||
|
return 'swoole';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(): string
|
||||||
|
{
|
||||||
|
// pdo_pgsql need to be disabled
|
||||||
|
if ($this->builder->getExt('pdo_sqlite') !== null) {
|
||||||
|
throw new WrongUsageException('swoole-hook-sqlite provides pdo_sqlite, if you enable sqlite hook for swoole, you must remove pdo_sqlite extension.');
|
||||||
|
}
|
||||||
|
// enable swoole pgsql hook
|
||||||
|
return '--enable-swoole-sqlite';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCliCheckUnix(): void
|
||||||
|
{
|
||||||
|
// skip if not enable swoole
|
||||||
|
if ($this->builder->getExt('swoole') === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||||
|
$out = implode('', $out);
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||||
|
}
|
||||||
|
if (!str_contains($out, 'coroutine_sqlite')) {
|
||||||
|
throw new RuntimeException('swoole sqlite hook is not enabled correctly.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/SPC/builder/extension/xhprof.php
Normal file
33
src/SPC/builder/extension/xhprof.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('xhprof')]
|
||||||
|
class xhprof extends Extension
|
||||||
|
{
|
||||||
|
public function patchBeforeBuildconf(): bool
|
||||||
|
{
|
||||||
|
if (!is_link(SOURCE_PATH . '/php-src/ext/xhprof')) {
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D xhprof xhprof-src\extension');
|
||||||
|
} else {
|
||||||
|
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s xhprof-src/extension xhprof');
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch config.m4
|
||||||
|
FileSystem::replaceFileStr(
|
||||||
|
SOURCE_PATH . '/php-src/ext/xhprof/config.m4',
|
||||||
|
'if test -f $phpincludedir/ext/pcre/php_pcre.h; then',
|
||||||
|
'if test -f $abs_srcdir/ext/pcre/php_pcre.h; then'
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,19 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\freebsd;
|
namespace SPC\builder\freebsd;
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
use SPC\builder\unix\UnixBuilderBase;
|
||||||
use SPC\builder\traits\UnixBuilderTrait;
|
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
|
|
||||||
class BSDBuilder extends BuilderBase
|
class BSDBuilder extends UnixBuilderBase
|
||||||
{
|
{
|
||||||
/** Unix compatible builder methods */
|
|
||||||
use UnixBuilderTrait;
|
|
||||||
|
|
||||||
/** @var bool Micro patch phar flag */
|
/** @var bool Micro patch phar flag */
|
||||||
private bool $phar_patched = false;
|
private bool $phar_patched = false;
|
||||||
|
|
||||||
@@ -81,10 +77,12 @@ class BSDBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
$this->setOption('extra-libs', $extra_libs);
|
$this->setOption('extra-libs', $extra_libs);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-buildconf');
|
||||||
SourcePatcher::patchBeforeBuildconf($this);
|
SourcePatcher::patchBeforeBuildconf($this);
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-configure');
|
||||||
SourcePatcher::patchBeforeConfigure($this);
|
SourcePatcher::patchBeforeConfigure($this);
|
||||||
|
|
||||||
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
||||||
@@ -115,6 +113,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
$this->makeExtensionArgs()
|
$this->makeExtensionArgs()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-make');
|
||||||
SourcePatcher::patchBeforeMake($this);
|
SourcePatcher::patchBeforeMake($this);
|
||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
@@ -140,6 +139,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (php_uname('m') === $this->getOption('arch')) {
|
if (php_uname('m') === $this->getOption('arch')) {
|
||||||
|
$this->emitPatchPoint('before-sanity-check');
|
||||||
$this->sanityCheck($build_target);
|
$this->sanityCheck($build_target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function buildCli(): void
|
protected function buildCli(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
@@ -173,7 +173,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public function buildMicro(): void
|
protected function buildMicro(): void
|
||||||
{
|
{
|
||||||
if ($this->getPHPVersionID() < 80000) {
|
if ($this->getPHPVersionID() < 80000) {
|
||||||
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
||||||
@@ -211,7 +211,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function buildFpm(): void
|
protected function buildFpm(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
@@ -231,7 +231,7 @@ class BSDBuilder extends BuilderBase
|
|||||||
*
|
*
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function buildEmbed(): void
|
protected function buildEmbed(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString([
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
||||||
|
|||||||
@@ -4,20 +4,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\linux;
|
namespace SPC\builder\linux;
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
use SPC\builder\linux\library\LinuxLibraryBase;
|
||||||
use SPC\builder\traits\UnixBuilderTrait;
|
use SPC\builder\unix\UnixBuilderBase;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
|
|
||||||
class LinuxBuilder extends BuilderBase
|
class LinuxBuilder extends UnixBuilderBase
|
||||||
{
|
{
|
||||||
/** Unix compatible builder methods */
|
|
||||||
use UnixBuilderTrait;
|
|
||||||
|
|
||||||
/** @var array Tune cflags */
|
/** @var array Tune cflags */
|
||||||
public array $tune_c_flags;
|
public array $tune_c_flags;
|
||||||
|
|
||||||
@@ -138,19 +134,22 @@ class LinuxBuilder extends BuilderBase
|
|||||||
// add libstdc++, some extensions or libraries need it
|
// add libstdc++, some extensions or libraries need it
|
||||||
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : '');
|
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : '');
|
||||||
$this->setOption('extra-libs', $extra_libs);
|
$this->setOption('extra-libs', $extra_libs);
|
||||||
|
|
||||||
$cflags = $this->arch_c_flags;
|
$cflags = $this->arch_c_flags;
|
||||||
|
|
||||||
// prepare build php envs
|
// prepare build php envs
|
||||||
$envs_build_php = SystemUtil::makeEnvVarString([
|
$envs_build_php = SystemUtil::makeEnvVarString([
|
||||||
'CFLAGS' => $cflags,
|
'CFLAGS' => $cflags,
|
||||||
|
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH,
|
||||||
|
'LDFLAGS' => '-L' . BUILD_LIB_PATH,
|
||||||
'LIBS' => '-ldl -lpthread',
|
'LIBS' => '-ldl -lpthread',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-buildconf');
|
||||||
SourcePatcher::patchBeforeBuildconf($this);
|
SourcePatcher::patchBeforeBuildconf($this);
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-configure');
|
||||||
SourcePatcher::patchBeforeConfigure($this);
|
SourcePatcher::patchBeforeConfigure($this);
|
||||||
|
|
||||||
$phpVersionID = $this->getPHPVersionID();
|
$phpVersionID = $this->getPHPVersionID();
|
||||||
@@ -189,10 +188,11 @@ class LinuxBuilder extends BuilderBase
|
|||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$maxExecutionTimers .
|
$maxExecutionTimers .
|
||||||
$this->makeExtensionArgs() . ' ' .
|
$this->makeExtensionArgs() .
|
||||||
$envs_build_php
|
' ' . $envs_build_php . ' '
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-make');
|
||||||
SourcePatcher::patchBeforeMake($this);
|
SourcePatcher::patchBeforeMake($this);
|
||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
@@ -218,6 +218,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (php_uname('m') === $this->getOption('arch')) {
|
if (php_uname('m') === $this->getOption('arch')) {
|
||||||
|
$this->emitPatchPoint('before-sanity-check');
|
||||||
$this->sanityCheck($build_target);
|
$this->sanityCheck($build_target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function buildCli(): void
|
protected function buildCli(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
@@ -249,7 +250,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public function buildMicro(): void
|
protected function buildMicro(): void
|
||||||
{
|
{
|
||||||
if ($this->getPHPVersionID() < 80000) {
|
if ($this->getPHPVersionID() < 80000) {
|
||||||
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
||||||
@@ -283,7 +284,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function buildFpm(): void
|
protected function buildFpm(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
@@ -302,7 +303,7 @@ class LinuxBuilder extends BuilderBase
|
|||||||
*
|
*
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function buildEmbed(): void
|
protected function buildEmbed(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
|
|
||||||
@@ -322,10 +323,11 @@ class LinuxBuilder extends BuilderBase
|
|||||||
$cflags = isset($input['EXTRA_CFLAGS']) && $input['EXTRA_CFLAGS'] ? " {$input['EXTRA_CFLAGS']}" : '';
|
$cflags = isset($input['EXTRA_CFLAGS']) && $input['EXTRA_CFLAGS'] ? " {$input['EXTRA_CFLAGS']}" : '';
|
||||||
$libs = isset($input['EXTRA_LIBS']) && $input['EXTRA_LIBS'] ? " {$input['EXTRA_LIBS']}" : '';
|
$libs = isset($input['EXTRA_LIBS']) && $input['EXTRA_LIBS'] ? " {$input['EXTRA_LIBS']}" : '';
|
||||||
$ldflags = isset($input['EXTRA_LDFLAGS_PROGRAM']) && $input['EXTRA_LDFLAGS_PROGRAM'] ? " {$input['EXTRA_LDFLAGS_PROGRAM']}" : '';
|
$ldflags = isset($input['EXTRA_LDFLAGS_PROGRAM']) && $input['EXTRA_LDFLAGS_PROGRAM'] ? " {$input['EXTRA_LDFLAGS_PROGRAM']}" : '';
|
||||||
|
$tune_c_flags = implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags));
|
||||||
return [
|
return [
|
||||||
'EXTRA_CFLAGS' => "{$optimization} -fno-ident -fPIE " . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . $cflags,
|
'EXTRA_CFLAGS' => "{$optimization} -fno-ident -fPIE {$tune_c_flags}{$cflags}",
|
||||||
'EXTRA_LIBS' => $this->getOption('extra-libs', '') . $libs,
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs', '')} {$libs}",
|
||||||
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static" . $ldflags,
|
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static{$ldflags}",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,4 +209,21 @@ class SystemUtil
|
|||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get fully-supported linux distros.
|
||||||
|
*
|
||||||
|
* @return string[] List of supported Linux distro name for doctor
|
||||||
|
*/
|
||||||
|
public static function getSupportedDistros(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// debian-like
|
||||||
|
'debian', 'ubuntu', 'Deepin',
|
||||||
|
// rhel-like
|
||||||
|
'redhat',
|
||||||
|
// alpine
|
||||||
|
'alpine',
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ class imap extends LinuxLibraryBase
|
|||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
->exec('make clean')
|
->exec('make clean')
|
||||||
->exec('touch ip6')
|
->exec('touch ip6')
|
||||||
|
->exec('chmod +x tools/an')
|
||||||
|
->exec('chmod +x tools/ua')
|
||||||
|
->exec('chmod +x src/osdep/unix/drivers')
|
||||||
|
->exec('chmod +x src/osdep/unix/mkauths')
|
||||||
->exec(
|
->exec(
|
||||||
"yes | make slx {$ssl_options}"
|
"yes | make slx {$ssl_options}"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
|
||||||
|
|
||||||
class leveldb extends LinuxLibraryBase
|
|
||||||
{
|
|
||||||
use \SPC\builder\unix\library\leveldb;
|
|
||||||
|
|
||||||
public const NAME = 'leveldb';
|
|
||||||
}
|
|
||||||
12
src/SPC/builder/linux/library/libcares.php
Normal file
12
src/SPC/builder/linux/library/libcares.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class libcares extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libcares;
|
||||||
|
|
||||||
|
public const NAME = 'libcares';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/liblz4.php
Normal file
12
src/SPC/builder/linux/library/liblz4.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class liblz4 extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\liblz4;
|
||||||
|
|
||||||
|
public const NAME = 'liblz4';
|
||||||
|
}
|
||||||
12
src/SPC/builder/linux/library/libuv.php
Normal file
12
src/SPC/builder/linux/library/libuv.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class libuv extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libuv;
|
||||||
|
|
||||||
|
public const NAME = 'libuv';
|
||||||
|
}
|
||||||
@@ -26,7 +26,9 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
->exec(
|
->exec(
|
||||||
'cmake ' .
|
'cmake ' .
|
||||||
"{$this->builder->makeCmakeArgs()} " .
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
'-DIconv_IS_BUILT_IN=OFF ' .
|
'-DIconv_IS_BUILT_IN=OFF ' .
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||||
@@ -39,7 +41,7 @@ class libxml2 extends LinuxLibraryBase
|
|||||||
'..'
|
'..'
|
||||||
)
|
)
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install');
|
||||||
|
|
||||||
FileSystem::replaceFileStr(
|
FileSystem::replaceFileStr(
|
||||||
BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc',
|
BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc',
|
||||||
|
|||||||
@@ -1,72 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
|
||||||
*
|
|
||||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
|
||||||
* software according to the terms and conditions of the
|
|
||||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
*
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace SPC\builder\linux\library;
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
use SPC\exception\WrongUsageException;
|
|
||||||
|
|
||||||
class nghttp2 extends LinuxLibraryBase
|
class nghttp2 extends LinuxLibraryBase
|
||||||
{
|
{
|
||||||
|
use \SPC\builder\unix\library\nghttp2;
|
||||||
|
|
||||||
public const NAME = 'nghttp2';
|
public const NAME = 'nghttp2';
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws WrongUsageException
|
|
||||||
*/
|
|
||||||
public function build(): void
|
|
||||||
{
|
|
||||||
$args = $this->builder->makeAutoconfArgs(static::NAME, [
|
|
||||||
'zlib' => null,
|
|
||||||
'openssl' => null,
|
|
||||||
'libxml2' => null,
|
|
||||||
'libev' => null,
|
|
||||||
'libcares' => null,
|
|
||||||
'libngtcp2' => null,
|
|
||||||
'libnghttp3' => null,
|
|
||||||
'libbpf' => null,
|
|
||||||
'libevent-openssl' => null,
|
|
||||||
'jansson' => null,
|
|
||||||
'jemalloc' => null,
|
|
||||||
'systemd' => null,
|
|
||||||
'cunit' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
'./configure ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->getOption('gnu-arch')}-unknown-linux " .
|
|
||||||
'--enable-lib-only ' .
|
|
||||||
'--with-boost=no ' .
|
|
||||||
$args . ' ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
$this->patchPkgconfPrefix(['libnghttp2.pc']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/linux/library/unixodbc.php
Normal file
12
src/SPC/builder/linux/library/unixodbc.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class unixodbc extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\unixodbc;
|
||||||
|
|
||||||
|
public const NAME = 'unixodbc';
|
||||||
|
}
|
||||||
@@ -4,20 +4,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\macos;
|
namespace SPC\builder\macos;
|
||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
|
||||||
use SPC\builder\macos\library\MacOSLibraryBase;
|
use SPC\builder\macos\library\MacOSLibraryBase;
|
||||||
use SPC\builder\traits\UnixBuilderTrait;
|
use SPC\builder\unix\UnixBuilderBase;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
|
|
||||||
class MacOSBuilder extends BuilderBase
|
class MacOSBuilder extends UnixBuilderBase
|
||||||
{
|
{
|
||||||
/** Unix compatible builder methods */
|
|
||||||
use UnixBuilderTrait;
|
|
||||||
|
|
||||||
/** @var bool Micro patch phar flag */
|
/** @var bool Micro patch phar flag */
|
||||||
private bool $phar_patched = false;
|
private bool $phar_patched = false;
|
||||||
|
|
||||||
@@ -141,10 +137,12 @@ class MacOSBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
$this->setOption('extra-libs', $extra_libs);
|
$this->setOption('extra-libs', $extra_libs);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-buildconf');
|
||||||
SourcePatcher::patchBeforeBuildconf($this);
|
SourcePatcher::patchBeforeBuildconf($this);
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-configure');
|
||||||
SourcePatcher::patchBeforeConfigure($this);
|
SourcePatcher::patchBeforeConfigure($this);
|
||||||
|
|
||||||
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
$json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : '';
|
||||||
@@ -155,6 +153,21 @@ class MacOSBuilder extends BuilderBase
|
|||||||
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
|
// prepare build php envs
|
||||||
|
$envs_build_php = SystemUtil::makeEnvVarString([
|
||||||
|
'CFLAGS' => " {$this->arch_c_flags} -Werror=unknown-warning-option ",
|
||||||
|
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH,
|
||||||
|
'LDFLAGS' => '-L' . BUILD_LIB_PATH,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($this->getLib('postgresql')) {
|
||||||
|
shell()
|
||||||
|
->cd(SOURCE_PATH . '/php-src')
|
||||||
|
->exec(
|
||||||
|
'sed -i.backup "s/ac_cv_func_explicit_bzero\" = xyes/ac_cv_func_explicit_bzero\" = x_fake_yes/" ./configure'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec(
|
->exec(
|
||||||
'./configure ' .
|
'./configure ' .
|
||||||
@@ -162,7 +175,6 @@ class MacOSBuilder extends BuilderBase
|
|||||||
'--with-valgrind=no ' . // Not detect memory leak
|
'--with-valgrind=no ' . // Not detect memory leak
|
||||||
'--enable-shared=no ' .
|
'--enable-shared=no ' .
|
||||||
'--enable-static=yes ' .
|
'--enable-static=yes ' .
|
||||||
"CFLAGS='{$this->arch_c_flags} -Werror=unknown-warning-option' " .
|
|
||||||
'--disable-all ' .
|
'--disable-all ' .
|
||||||
'--disable-cgi ' .
|
'--disable-cgi ' .
|
||||||
'--disable-phpdbg ' .
|
'--disable-phpdbg ' .
|
||||||
@@ -172,9 +184,11 @@ class MacOSBuilder extends BuilderBase
|
|||||||
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
|
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
|
||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$this->makeExtensionArgs()
|
$this->makeExtensionArgs() . ' ' .
|
||||||
|
$envs_build_php
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('before-php-make');
|
||||||
SourcePatcher::patchBeforeMake($this);
|
SourcePatcher::patchBeforeMake($this);
|
||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
@@ -200,6 +214,7 @@ class MacOSBuilder extends BuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (php_uname('m') === $this->getOption('arch')) {
|
if (php_uname('m') === $this->getOption('arch')) {
|
||||||
|
$this->emitPatchPoint('before-sanity-check');
|
||||||
$this->sanityCheck($build_target);
|
$this->sanityCheck($build_target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,12 +225,9 @@ class MacOSBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function buildCli(): void
|
protected function buildCli(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
||||||
$shell->exec("make -j{$this->concurrency} {$vars} cli");
|
$shell->exec("make -j{$this->concurrency} {$vars} cli");
|
||||||
@@ -232,7 +244,7 @@ class MacOSBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public function buildMicro(): void
|
protected function buildMicro(): void
|
||||||
{
|
{
|
||||||
if ($this->getPHPVersionID() < 80000) {
|
if ($this->getPHPVersionID() < 80000) {
|
||||||
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
throw new WrongUsageException('phpmicro only support PHP >= 8.0!');
|
||||||
@@ -246,9 +258,8 @@ class MacOSBuilder extends BuilderBase
|
|||||||
$vars = [
|
$vars = [
|
||||||
// with debug information, optimize for size, remove identifiers, patch fake cli for micro
|
// with debug information, optimize for size, remove identifiers, patch fake cli for micro
|
||||||
'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli,
|
'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli,
|
||||||
// link resolv library (macOS needs it)
|
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv",
|
|
||||||
];
|
];
|
||||||
|
$vars = $this->getBuildVars($vars);
|
||||||
if (!$this->getOption('no-strip', false)) {
|
if (!$this->getOption('no-strip', false)) {
|
||||||
$vars['STRIP'] = 'dsymutil -f ';
|
$vars['STRIP'] = 'dsymutil -f ';
|
||||||
}
|
}
|
||||||
@@ -269,12 +280,9 @@ class MacOSBuilder extends BuilderBase
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function buildFpm(): void
|
protected function buildFpm(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
||||||
$shell->exec("make -j{$this->concurrency} {$vars} fpm");
|
$shell->exec("make -j{$this->concurrency} {$vars} fpm");
|
||||||
@@ -289,12 +297,9 @@ class MacOSBuilder extends BuilderBase
|
|||||||
*
|
*
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function buildEmbed(): void
|
protected function buildEmbed(): void
|
||||||
{
|
{
|
||||||
$vars = SystemUtil::makeEnvVarString([
|
$vars = SystemUtil::makeEnvVarString($this->getBuildVars());
|
||||||
'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size
|
|
||||||
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS needs it)
|
|
||||||
]);
|
|
||||||
|
|
||||||
shell()
|
shell()
|
||||||
->cd(SOURCE_PATH . '/php-src')
|
->cd(SOURCE_PATH . '/php-src')
|
||||||
@@ -308,4 +313,15 @@ class MacOSBuilder extends BuilderBase
|
|||||||
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
|
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
|
||||||
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
|
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getBuildVars($input = []): array
|
||||||
|
{
|
||||||
|
$optimization = $this->getOption('no-strip', false) ? '-g -O0' : '-g0 -Os';
|
||||||
|
$cflags = isset($input['EXTRA_CFLAGS']) && $input['EXTRA_CFLAGS'] ? " {$input['EXTRA_CFLAGS']}" : '';
|
||||||
|
$libs = isset($input['EXTRA_LIBS']) && $input['EXTRA_LIBS'] ? " {$input['EXTRA_LIBS']}" : '';
|
||||||
|
return [
|
||||||
|
'EXTRA_CFLAGS' => "{$optimization} {$cflags} " . $this->getOption('x-extra-cflags'),
|
||||||
|
'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv {$libs} " . $this->getOption('x-extra-libs'),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ class imap extends MacOSLibraryBase
|
|||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
->exec('make clean')
|
->exec('make clean')
|
||||||
->exec('touch ip6')
|
->exec('touch ip6')
|
||||||
|
->exec('chmod +x tools/an')
|
||||||
|
->exec('chmod +x tools/ua')
|
||||||
|
->exec('chmod +x src/osdep/unix/drivers')
|
||||||
|
->exec('chmod +x src/osdep/unix/mkauths')
|
||||||
->exec(
|
->exec(
|
||||||
"yes | EXTRACFLAGS='-Wimplicit-function-declaration -include $(xcrun --show-sdk-path)/usr/include/poll.h -include $(xcrun --show-sdk-path)/usr/include/time.h -include $(xcrun --show-sdk-path)/usr/include/utime.h' make osx {$ssl_options}"
|
"yes | EXTRACFLAGS='-Wimplicit-function-declaration -include $(xcrun --show-sdk-path)/usr/include/poll.h -include $(xcrun --show-sdk-path)/usr/include/time.h -include $(xcrun --show-sdk-path)/usr/include/utime.h' make osx {$ssl_options}"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
|
||||||
|
|
||||||
class leveldb extends MacOSLibraryBase
|
|
||||||
{
|
|
||||||
use \SPC\builder\unix\library\leveldb;
|
|
||||||
|
|
||||||
public const NAME = 'leveldb';
|
|
||||||
}
|
|
||||||
12
src/SPC/builder/macos/library/libcares.php
Normal file
12
src/SPC/builder/macos/library/libcares.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class libcares extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libcares;
|
||||||
|
|
||||||
|
public const NAME = 'libcares';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/liblz4.php
Normal file
12
src/SPC/builder/macos/library/liblz4.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class liblz4 extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\liblz4;
|
||||||
|
|
||||||
|
public const NAME = 'liblz4';
|
||||||
|
}
|
||||||
12
src/SPC/builder/macos/library/libuv.php
Normal file
12
src/SPC/builder/macos/library/libuv.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class libuv extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\libuv;
|
||||||
|
|
||||||
|
public const NAME = 'libuv';
|
||||||
|
}
|
||||||
@@ -27,7 +27,9 @@ class libxml2 extends MacOSLibraryBase
|
|||||||
->exec(
|
->exec(
|
||||||
'cmake ' .
|
'cmake ' .
|
||||||
// '--debug-find ' .
|
// '--debug-find ' .
|
||||||
"{$this->builder->makeCmakeArgs()} " .
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||||
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
||||||
@@ -39,6 +41,6 @@ class libxml2 extends MacOSLibraryBase
|
|||||||
'..'
|
'..'
|
||||||
)
|
)
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,51 +20,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\macos\library;
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
use SPC\exception\FileSystemException;
|
|
||||||
use SPC\exception\RuntimeException;
|
|
||||||
|
|
||||||
class nghttp2 extends MacOSLibraryBase
|
class nghttp2 extends MacOSLibraryBase
|
||||||
{
|
{
|
||||||
|
use \SPC\builder\unix\library\nghttp2;
|
||||||
|
|
||||||
public const NAME = 'nghttp2';
|
public const NAME = 'nghttp2';
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws FileSystemException
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function build(): void
|
|
||||||
{
|
|
||||||
$args = $this->builder->makeAutoconfArgs(static::NAME, [
|
|
||||||
'zlib' => null,
|
|
||||||
'openssl' => null,
|
|
||||||
'libxml2' => null,
|
|
||||||
'libev' => null,
|
|
||||||
'libcares' => null,
|
|
||||||
'libngtcp2' => null,
|
|
||||||
'libnghttp3' => null,
|
|
||||||
'libbpf' => null,
|
|
||||||
'libevent-openssl' => null,
|
|
||||||
'jansson' => null,
|
|
||||||
'jemalloc' => null,
|
|
||||||
'systemd' => null,
|
|
||||||
'cunit' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
[,,$destdir] = SEPARATED_PATH;
|
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
|
||||||
->exec(
|
|
||||||
'./configure ' .
|
|
||||||
'--enable-static ' .
|
|
||||||
'--disable-shared ' .
|
|
||||||
"--host={$this->builder->getOption('gnu-arch')}-apple-darwin " .
|
|
||||||
'--enable-lib-only ' .
|
|
||||||
'--with-boost=no ' .
|
|
||||||
$args . ' ' .
|
|
||||||
'--prefix='
|
|
||||||
)
|
|
||||||
->exec('make clean')
|
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
|
||||||
->exec("make install DESTDIR={$destdir}");
|
|
||||||
$this->patchPkgconfPrefix(['libnghttp2.pc']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/macos/library/unixodbc.php
Normal file
12
src/SPC/builder/macos/library/unixodbc.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class unixodbc extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\unixodbc;
|
||||||
|
|
||||||
|
public const NAME = 'unixodbc';
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
|
||||||
|
|
||||||
trait LibraryTrait {}
|
|
||||||
@@ -12,8 +12,6 @@ use SPC\store\FileSystem;
|
|||||||
|
|
||||||
trait UnixLibraryTrait
|
trait UnixLibraryTrait
|
||||||
{
|
{
|
||||||
use LibraryTrait;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
|||||||
@@ -2,15 +2,19 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace SPC\builder\traits;
|
namespace SPC\builder\unix;
|
||||||
|
|
||||||
|
use SPC\builder\BuilderBase;
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
use SPC\builder\linux\LinuxBuilder;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\store\SourceExtractor;
|
||||||
|
use SPC\util\DependencyUtil;
|
||||||
|
|
||||||
trait UnixBuilderTrait
|
abstract class UnixBuilderBase extends BuilderBase
|
||||||
{
|
{
|
||||||
/** @var string cflags */
|
/** @var string cflags */
|
||||||
public string $arch_c_flags;
|
public string $arch_c_flags;
|
||||||
@@ -49,77 +53,6 @@ trait UnixBuilderTrait
|
|||||||
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
|
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanity check after build complete
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function sanityCheck(int $build_target): void
|
|
||||||
{
|
|
||||||
// sanity check for php-cli
|
|
||||||
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
|
||||||
logger()->info('running cli sanity check');
|
|
||||||
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "echo \"hello\";"');
|
|
||||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
|
||||||
throw new RuntimeException('cli failed sanity check');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
|
||||||
logger()->debug('testing ext: ' . $ext->getName());
|
|
||||||
$ext->runCliCheck();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanity check for phpmicro
|
|
||||||
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
|
||||||
if (file_exists(SOURCE_PATH . '/hello.exe')) {
|
|
||||||
@unlink(SOURCE_PATH . '/hello.exe');
|
|
||||||
}
|
|
||||||
file_put_contents(
|
|
||||||
SOURCE_PATH . '/hello.exe',
|
|
||||||
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
|
|
||||||
'<?php echo "hello";'
|
|
||||||
);
|
|
||||||
chmod(SOURCE_PATH . '/hello.exe', 0755);
|
|
||||||
[$ret, $output2] = shell()->execWithResult(SOURCE_PATH . '/hello.exe');
|
|
||||||
if ($ret !== 0 || trim($out = implode('', $output2)) !== 'hello') {
|
|
||||||
throw new RuntimeException('micro failed sanity check, ret[' . $ret . '], out[' . ($out ?? 'NULL') . ']');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编译好的二进制文件发布到 buildroot
|
|
||||||
*
|
|
||||||
* @param int $type 发布类型
|
|
||||||
* @throws RuntimeException
|
|
||||||
* @throws FileSystemException
|
|
||||||
*/
|
|
||||||
public function deployBinary(int $type): bool
|
|
||||||
{
|
|
||||||
$src = match ($type) {
|
|
||||||
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
|
|
||||||
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
|
|
||||||
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
|
|
||||||
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
|
||||||
};
|
|
||||||
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
|
||||||
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
|
|
||||||
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run php clean
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function cleanMake(): void
|
|
||||||
{
|
|
||||||
logger()->info('cleaning up');
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return generic cmake options when configuring cmake projects
|
* Return generic cmake options when configuring cmake projects
|
||||||
*/
|
*/
|
||||||
@@ -156,4 +89,139 @@ trait UnixBuilderTrait
|
|||||||
}
|
}
|
||||||
return $extra;
|
return $extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildLibs(array $sorted_libraries): void
|
||||||
|
{
|
||||||
|
// search all supported libs
|
||||||
|
$support_lib_list = [];
|
||||||
|
$classes = FileSystem::getClassesPsr4(
|
||||||
|
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
|
||||||
|
'SPC\\builder\\' . osfamily2dir() . '\\library'
|
||||||
|
);
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
|
||||||
|
$support_lib_list[$class::NAME] = $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no libs specified, compile all supported libs
|
||||||
|
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
||||||
|
$libraries = array_keys($support_lib_list);
|
||||||
|
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkg-config must be compiled first, whether it is specified or not
|
||||||
|
if (!in_array('pkg-config', $sorted_libraries)) {
|
||||||
|
array_unshift($sorted_libraries, 'pkg-config');
|
||||||
|
}
|
||||||
|
|
||||||
|
// add lib object for builder
|
||||||
|
foreach ($sorted_libraries as $library) {
|
||||||
|
// if some libs are not supported (but in config "lib.json", throw exception)
|
||||||
|
if (!isset($support_lib_list[$library])) {
|
||||||
|
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
|
||||||
|
}
|
||||||
|
$lib = new ($support_lib_list[$library])($this);
|
||||||
|
$this->addLib($lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate and check dependencies
|
||||||
|
foreach ($this->libs as $lib) {
|
||||||
|
$lib->calcDependency();
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch point
|
||||||
|
$this->emitPatchPoint('before-libs-extract');
|
||||||
|
|
||||||
|
// extract sources
|
||||||
|
SourceExtractor::initSource(libs: $sorted_libraries);
|
||||||
|
|
||||||
|
$this->emitPatchPoint('after-libs-extract');
|
||||||
|
|
||||||
|
// 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'),
|
||||||
|
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanity check after build complete
|
||||||
|
*
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function sanityCheck(int $build_target): void
|
||||||
|
{
|
||||||
|
// sanity check for php-cli
|
||||||
|
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
||||||
|
logger()->info('running cli sanity check');
|
||||||
|
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "echo \"hello\";"');
|
||||||
|
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||||
|
throw new RuntimeException('cli failed sanity check');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->exts as $ext) {
|
||||||
|
logger()->debug('testing ext: ' . $ext->getName());
|
||||||
|
$ext->runCliCheckUnix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check for phpmicro
|
||||||
|
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
||||||
|
if (file_exists(SOURCE_PATH . '/hello.exe')) {
|
||||||
|
@unlink(SOURCE_PATH . '/hello.exe');
|
||||||
|
}
|
||||||
|
file_put_contents(
|
||||||
|
SOURCE_PATH . '/hello.exe',
|
||||||
|
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
|
||||||
|
($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests())
|
||||||
|
);
|
||||||
|
chmod(SOURCE_PATH . '/hello.exe', 0755);
|
||||||
|
[$ret, $output2] = shell()->execWithResult(SOURCE_PATH . '/hello.exe');
|
||||||
|
$raw_out = trim(implode('', $output2));
|
||||||
|
$condition[0] = $ret === 0;
|
||||||
|
$condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
|
||||||
|
foreach ($condition as $k => $v) {
|
||||||
|
if (!$v) {
|
||||||
|
throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将编译好的二进制文件发布到 buildroot
|
||||||
|
*
|
||||||
|
* @param int $type 发布类型
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
protected function deployBinary(int $type): bool
|
||||||
|
{
|
||||||
|
$src = match ($type) {
|
||||||
|
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
|
||||||
|
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
|
||||||
|
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
|
||||||
|
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
||||||
|
};
|
||||||
|
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
||||||
|
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
|
||||||
|
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run php clean
|
||||||
|
*
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function cleanMake(): void
|
||||||
|
{
|
||||||
|
logger()->info('cleaning up');
|
||||||
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,10 +27,7 @@ trait brotli
|
|||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
|
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
|
||||||
shell()->cd(BUILD_ROOT_PATH . '/lib')
|
shell()->cd(BUILD_ROOT_PATH . '/lib')->exec('ln -sf libbrotlicommon.a libbrotli.a');
|
||||||
->exec('ln -s libbrotlicommon.a libbrotlicommon-static.a')
|
|
||||||
->exec('ln -s libbrotlidec.a libbrotlidec-static.a')
|
|
||||||
->exec('ln -s libbrotlienc.a libbrotlienc-static.a');
|
|
||||||
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
|
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
|
||||||
if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
|
if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
|
||||||
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
|
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ trait curl
|
|||||||
// compile!
|
// compile!
|
||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt')
|
->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ../CMakeLists.txt')
|
||||||
->exec("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF {$extra} ..")
|
->exec("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF -DBUILD_LIBCURL_DOCS=OFF {$extra} ..")
|
||||||
->exec("make -j{$this->builder->concurrency}")
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
// patch pkgconf
|
// patch pkgconf
|
||||||
|
|||||||
@@ -4,17 +4,25 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\builder\unix\library;
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
trait ldap
|
trait ldap
|
||||||
{
|
{
|
||||||
|
public function patchBeforeBuild(): bool
|
||||||
|
{
|
||||||
|
FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
$alt = '';
|
$alt = '';
|
||||||
// openssl support
|
// openssl support
|
||||||
$alt .= $this->builder->getLib('openssl') && $this->builder->getExt('zlib') ? '--with-tls=openssl ' : '';
|
$alt .= $this->builder->getLib('openssl') ? '--with-tls=openssl ' : '';
|
||||||
// gmp support
|
// gmp support
|
||||||
$alt .= $this->builder->getLib('gmp') ? '--with-mp=gmp ' : '';
|
$alt .= $this->builder->getLib('gmp') ? '--with-mp=gmp ' : '';
|
||||||
// libsodium support
|
// libsodium support
|
||||||
$alt .= $this->builder->getLib('libsodium') ? '--with-argon2=libsodium ' : '';
|
$alt .= $this->builder->getLib('libsodium') ? '--with-argon2=libsodium ' : '--enable-argon2=no ';
|
||||||
f_putenv('PKG_CONFIG=' . BUILD_ROOT_PATH . '/bin/pkg-config');
|
f_putenv('PKG_CONFIG=' . BUILD_ROOT_PATH . '/bin/pkg-config');
|
||||||
f_putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig');
|
f_putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig');
|
||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
@@ -24,7 +32,6 @@ trait ldap
|
|||||||
'--enable-static ' .
|
'--enable-static ' .
|
||||||
'--disable-shared ' .
|
'--disable-shared ' .
|
||||||
'--disable-slapd ' .
|
'--disable-slapd ' .
|
||||||
'--disable-slurpd ' .
|
|
||||||
'--without-systemd ' .
|
'--without-systemd ' .
|
||||||
'--without-cyrus-sasl ' .
|
'--without-cyrus-sasl ' .
|
||||||
$alt .
|
$alt .
|
||||||
|
|||||||
21
src/SPC/builder/unix/library/libcares.php
Normal file
21
src/SPC/builder/unix/library/libcares.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
|
trait libcares
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec('./configure --prefix=' . BUILD_ROOT_PATH . ' --enable-static --disable-shared --disable-tests')
|
||||||
|
->exec("make -j {$this->builder->concurrency}")
|
||||||
|
->exec('make install');
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/SPC/builder/unix/library/liblz4.php
Normal file
26
src/SPC/builder/unix/library/liblz4.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
trait liblz4
|
||||||
|
{
|
||||||
|
protected function build()
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec("make PREFIX='' clean")
|
||||||
|
->exec("make -j{$this->builder->concurrency} PREFIX=''")
|
||||||
|
->exec("make install PREFIX='' DESTDIR=" . BUILD_ROOT_PATH);
|
||||||
|
|
||||||
|
$this->patchPkgconfPrefix(['liblz4.pc']);
|
||||||
|
|
||||||
|
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
|
||||||
|
if (str_starts_with($filename, 'liblz4') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
|
||||||
|
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use SPC\exception\FileSystemException;
|
|||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
trait leveldb
|
trait libuv
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
@@ -20,14 +20,10 @@ trait leveldb
|
|||||||
FileSystem::resetDir($this->source_dir . '/build');
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
// Start build
|
// Start build
|
||||||
shell()->cd($this->source_dir . '/build')
|
shell()->cd($this->source_dir . '/build')
|
||||||
->exec(
|
->exec("cmake {$this->builder->makeCmakeArgs()} -DLIBUV_BUILD_SHARED=OFF ..")
|
||||||
"cmake {$this->builder->makeCmakeArgs()} " .
|
|
||||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
|
||||||
'-DLEVELDB_BUILD_TESTS=OFF ' .
|
|
||||||
'-DLEVELDB_BUILD_BENCHMARKS=OFF ' .
|
|
||||||
'..'
|
|
||||||
)
|
|
||||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
// patch pkgconfig
|
||||||
|
$this->patchPkgconfPrefix(['libuv-static.pc']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
53
src/SPC/builder/unix/library/nghttp2.php
Normal file
53
src/SPC/builder/unix/library/nghttp2.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
|
||||||
|
trait nghttp2
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$args = $this->builder->makeAutoconfArgs(static::NAME, [
|
||||||
|
'zlib' => null,
|
||||||
|
'openssl' => null,
|
||||||
|
'libxml2' => null,
|
||||||
|
'libev' => null,
|
||||||
|
'libcares' => null,
|
||||||
|
'libngtcp2' => null,
|
||||||
|
'libnghttp3' => null,
|
||||||
|
'libbpf' => null,
|
||||||
|
'libevent-openssl' => null,
|
||||||
|
'jansson' => null,
|
||||||
|
'jemalloc' => null,
|
||||||
|
'systemd' => null,
|
||||||
|
'cunit' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
[,,$destdir] = SEPARATED_PATH;
|
||||||
|
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
'./configure ' .
|
||||||
|
'--enable-static ' .
|
||||||
|
'--disable-shared ' .
|
||||||
|
'--enable-lib-only ' .
|
||||||
|
'--with-boost=no ' .
|
||||||
|
$args . ' ' .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec("make install DESTDIR={$destdir}");
|
||||||
|
$this->patchPkgconfPrefix(['libnghttp2.pc']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,9 +28,6 @@ trait postgresql
|
|||||||
'icu' => 'icu-i18n',
|
'icu' => 'icu-i18n',
|
||||||
];
|
];
|
||||||
|
|
||||||
f_putenv('PKG_CONFIG=' . BUILD_ROOT_PATH . '/bin/pkg-config');
|
|
||||||
f_putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig');
|
|
||||||
|
|
||||||
foreach ($optional_packages as $lib => $pkg) {
|
foreach ($optional_packages as $lib => $pkg) {
|
||||||
if ($this->getBuilder()->getLib($lib)) {
|
if ($this->getBuilder()->getLib($lib)) {
|
||||||
$packages .= ' ' . $pkg;
|
$packages .= ' ' . $pkg;
|
||||||
|
|||||||
35
src/SPC/builder/unix/library/unixodbc.php
Normal file
35
src/SPC/builder/unix/library/unixodbc.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
|
trait unixodbc
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->exec(
|
||||||
|
'./configure ' .
|
||||||
|
'--enable-static --disable-shared ' .
|
||||||
|
'--disable-debug ' .
|
||||||
|
'--disable-dependency-tracking ' .
|
||||||
|
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'--with-included-ltdl ' .
|
||||||
|
'--enable-gui=no ' .
|
||||||
|
'--prefix='
|
||||||
|
)
|
||||||
|
->exec('make clean')
|
||||||
|
->exec("make -j{$this->builder->concurrency}")
|
||||||
|
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
$this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']);
|
||||||
|
$this->cleanLaFiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/SPC/builder/windows/SystemUtil.php
Normal file
104
src/SPC/builder/windows/SystemUtil.php
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class SystemUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Find windows program using executable name.
|
||||||
|
*
|
||||||
|
* @param string $name command name (xxx.exe)
|
||||||
|
* @param array $paths search path (default use env path)
|
||||||
|
* @return null|string null if not found, string is absolute path
|
||||||
|
*/
|
||||||
|
public static function findCommand(string $name, array $paths = [], bool $include_sdk_bin = false): ?string
|
||||||
|
{
|
||||||
|
if (!$paths) {
|
||||||
|
$paths = explode(PATH_SEPARATOR, getenv('Path'));
|
||||||
|
if ($include_sdk_bin) {
|
||||||
|
$paths[] = PHP_SDK_PATH . '\bin';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path . DIRECTORY_SEPARATOR . $name)) {
|
||||||
|
return $path . DIRECTORY_SEPARATOR . $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Visual Studio installation.
|
||||||
|
*
|
||||||
|
* @return array<string, string>|false False if not installed, array contains 'version' and 'dir'
|
||||||
|
*/
|
||||||
|
public static function findVisualStudio(): array|false
|
||||||
|
{
|
||||||
|
$check_path = [
|
||||||
|
'C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe' => 'vs17',
|
||||||
|
'C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe' => 'vs17',
|
||||||
|
'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe' => 'vs17',
|
||||||
|
'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe' => 'vs16',
|
||||||
|
'C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe' => 'vs16',
|
||||||
|
'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe' => 'vs16',
|
||||||
|
];
|
||||||
|
foreach ($check_path as $path => $vs_version) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
$vs_ver = $vs_version;
|
||||||
|
$d_dir = dirname($path, 4);
|
||||||
|
return [
|
||||||
|
'version' => $vs_ver,
|
||||||
|
'dir' => $d_dir,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get CPU count for concurrency.
|
||||||
|
*/
|
||||||
|
public static function getCpuCount(): int
|
||||||
|
{
|
||||||
|
$result = f_exec('echo %NUMBER_OF_PROCESSORS%', $out, $code);
|
||||||
|
if ($code !== 0 || !$result) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return intval($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create CMake toolchain file.
|
||||||
|
*
|
||||||
|
* @param null|string $cflags CFLAGS for cmake, default use '/MT /Os /Ob1 /DNDEBUG /D_ACRTIMP= /D_CRTIMP='
|
||||||
|
* @param null|string $ldflags LDFLAGS for cmake, default use '/nodefaultlib:msvcrt /nodefaultlib:msvcrtd /defaultlib:libcmt'
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function makeCmakeToolchainFile(?string $cflags = null, ?string $ldflags = null): string
|
||||||
|
{
|
||||||
|
if ($cflags === null) {
|
||||||
|
$cflags = '/MT /Os /Ob1 /DNDEBUG /D_ACRTIMP= /D_CRTIMP=';
|
||||||
|
}
|
||||||
|
if ($ldflags === null) {
|
||||||
|
$ldflags = '/nodefaultlib:msvcrt /nodefaultlib:msvcrtd /defaultlib:libcmt';
|
||||||
|
}
|
||||||
|
$buildroot = str_replace('\\', '\\\\', BUILD_ROOT_PATH);
|
||||||
|
$toolchain = <<<CMAKE
|
||||||
|
set(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
SET(CMAKE_C_FLAGS "{$cflags}")
|
||||||
|
SET(CMAKE_C_FLAGS_DEBUG "{$cflags}")
|
||||||
|
SET(CMAKE_CXX_FLAGS "{$cflags}")
|
||||||
|
SET(CMAKE_CXX_FLAGS_DEBUG "{$cflags}")
|
||||||
|
SET(CMAKE_EXE_LINKER_FLAGS "{$ldflags}")
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH "{$buildroot}")
|
||||||
|
SET(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
|
||||||
|
CMAKE;
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\toolchain.cmake', $toolchain);
|
||||||
|
return realpath(SOURCE_PATH . '\toolchain.cmake');
|
||||||
|
}
|
||||||
|
}
|
||||||
343
src/SPC/builder/windows/WindowsBuilder.php
Normal file
343
src/SPC/builder/windows/WindowsBuilder.php
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows;
|
||||||
|
|
||||||
|
use SPC\builder\BuilderBase;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Config;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\store\SourceExtractor;
|
||||||
|
use SPC\store\SourcePatcher;
|
||||||
|
use SPC\util\DependencyUtil;
|
||||||
|
|
||||||
|
class WindowsBuilder extends BuilderBase
|
||||||
|
{
|
||||||
|
/** @var string cmake toolchain file */
|
||||||
|
public string $cmake_toolchain_file;
|
||||||
|
|
||||||
|
public string $sdk_prefix;
|
||||||
|
|
||||||
|
private bool $zts;
|
||||||
|
|
||||||
|
/** @var bool Micro patch phar flag */
|
||||||
|
private bool $phar_patched = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function __construct(array $options = [])
|
||||||
|
{
|
||||||
|
$this->options = $options;
|
||||||
|
|
||||||
|
// ---------- set necessary options ----------
|
||||||
|
// set sdk (require visual studio 16 or 17)
|
||||||
|
$vs = SystemUtil::findVisualStudio()['version'];
|
||||||
|
$this->sdk_prefix = PHP_SDK_PATH . "\\phpsdk-{$vs}-x64.bat -t";
|
||||||
|
|
||||||
|
// set zts
|
||||||
|
$this->zts = $this->getOption('enable-zts', false);
|
||||||
|
|
||||||
|
// set concurrency
|
||||||
|
$this->concurrency = SystemUtil::getCpuCount();
|
||||||
|
|
||||||
|
// make cmake toolchain
|
||||||
|
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
|
||||||
|
{
|
||||||
|
// ---------- Update extra-libs ----------
|
||||||
|
$extra_libs = $this->getOption('extra-libs', '');
|
||||||
|
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
|
||||||
|
$this->setOption('extra-libs', $extra_libs);
|
||||||
|
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
|
||||||
|
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
|
||||||
|
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
|
SourcePatcher::patchBeforeBuildconf($this);
|
||||||
|
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} buildconf.bat");
|
||||||
|
|
||||||
|
SourcePatcher::patchBeforeConfigure($this);
|
||||||
|
|
||||||
|
$zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no ';
|
||||||
|
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')
|
||||||
|
->exec(
|
||||||
|
"{$this->sdk_prefix} configure.bat --task-args \"" .
|
||||||
|
'--disable-all ' .
|
||||||
|
'--disable-cgi ' .
|
||||||
|
'--with-php-build=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
|
||||||
|
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
|
||||||
|
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
|
||||||
|
($enableMicro ? '--enable-micro=yes ' : '--enable-micro=no ') .
|
||||||
|
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
|
||||||
|
"{$this->makeExtensionArgs()} " .
|
||||||
|
$zts .
|
||||||
|
'"'
|
||||||
|
);
|
||||||
|
|
||||||
|
SourcePatcher::patchBeforeMake($this);
|
||||||
|
|
||||||
|
$this->cleanMake();
|
||||||
|
|
||||||
|
if ($enableCli) {
|
||||||
|
logger()->info('building cli');
|
||||||
|
$this->buildCli();
|
||||||
|
}
|
||||||
|
if ($enableFpm) {
|
||||||
|
logger()->warning('Windows does not support fpm SAPI, I will skip it.');
|
||||||
|
}
|
||||||
|
if ($enableMicro) {
|
||||||
|
logger()->info('building micro');
|
||||||
|
$this->buildMicro();
|
||||||
|
}
|
||||||
|
if ($enableEmbed) {
|
||||||
|
logger()->warning('Windows does not currently support embed SAPI.');
|
||||||
|
// logger()->info('building embed');
|
||||||
|
$this->buildEmbed();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sanityCheck($build_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function buildCli(): void
|
||||||
|
{
|
||||||
|
SourcePatcher::patchWindowsCLITarget();
|
||||||
|
|
||||||
|
// add nmake wrapper
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_cli_wrapper.bat', "nmake /nologo LIBS_CLI=\"{$this->getOption('extra-libs')} ws2_32.lib shell32.lib\" EXTRA_LD_FLAGS_PROGRAM= %*");
|
||||||
|
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_cli_wrapper.bat --task-args php.exe");
|
||||||
|
|
||||||
|
$this->deployBinary(BUILD_TARGET_CLI);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildEmbed(): void
|
||||||
|
{
|
||||||
|
// TODO: add embed support for windows
|
||||||
|
/*
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_embed_wrapper.bat', 'nmake /nologo %*');
|
||||||
|
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')
|
||||||
|
->exec("{$this->sdk_prefix} nmake_embed_wrapper.bat --task-args php8embed.lib");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
public function buildMicro(): void
|
||||||
|
{
|
||||||
|
// workaround for fiber (originally from https://github.com/dixyes/lwmbs/blob/master/windows/MicroBuild.php)
|
||||||
|
$makefile = FileSystem::readFile(SOURCE_PATH . '\php-src\Makefile');
|
||||||
|
if ($this->getPHPVersionID() >= 80200 && str_contains($makefile, 'FIBER_ASM_ARCH')) {
|
||||||
|
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ARCH)_ms_pe_masm.obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ARCH)_ms_pe_masm.obj' . "\r\n\r\n";
|
||||||
|
}
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile);
|
||||||
|
|
||||||
|
// add nmake wrapper
|
||||||
|
$fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' /DPHP_MICRO_FAKE_CLI" ' : '';
|
||||||
|
$wrapper = "nmake /nologo LIBS_MICRO=\"{$this->getOption('extra-libs')} ws2_32.lib shell32.lib\" CFLAGS_MICRO=\"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1{$fake_cli}\" %*";
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_micro_wrapper.bat', $wrapper);
|
||||||
|
|
||||||
|
// phar patch for micro
|
||||||
|
if ($this->getExt('phar')) {
|
||||||
|
$this->phar_patched = true;
|
||||||
|
SourcePatcher::patchMicro(['phar']);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_micro_wrapper.bat --task-args micro");
|
||||||
|
|
||||||
|
if ($this->phar_patched) {
|
||||||
|
SourcePatcher::patchMicro(['phar'], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildLibs(array $sorted_libraries): void
|
||||||
|
{
|
||||||
|
// search all supported libs
|
||||||
|
$support_lib_list = [];
|
||||||
|
$classes = FileSystem::getClassesPsr4(
|
||||||
|
ROOT_DIR . '\src\SPC\builder\\' . osfamily2dir() . '\\library',
|
||||||
|
'SPC\\builder\\' . osfamily2dir() . '\\library'
|
||||||
|
);
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
|
||||||
|
$support_lib_list[$class::NAME] = $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no libs specified, compile all supported libs
|
||||||
|
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
||||||
|
$libraries = array_keys($support_lib_list);
|
||||||
|
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add lib object for builder
|
||||||
|
foreach ($sorted_libraries as $library) {
|
||||||
|
// if some libs are not supported (but in config "lib.json", throw exception)
|
||||||
|
if (!isset($support_lib_list[$library])) {
|
||||||
|
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
|
||||||
|
}
|
||||||
|
$lib = new ($support_lib_list[$library])($this);
|
||||||
|
$this->addLib($lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate and check dependencies
|
||||||
|
foreach ($this->libs as $lib) {
|
||||||
|
$lib->calcDependency();
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract sources
|
||||||
|
SourceExtractor::initSource(libs: $sorted_libraries);
|
||||||
|
|
||||||
|
// 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'),
|
||||||
|
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function cleanMake(): void
|
||||||
|
{
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '\php-src\nmake_clean_wrapper.bat', 'nmake /nologo %*');
|
||||||
|
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_clean_wrapper.bat --task-args \"clean\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run extension and PHP cli and micro check
|
||||||
|
*
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function sanityCheck(mixed $build_target): void
|
||||||
|
{
|
||||||
|
// sanity check for php-cli
|
||||||
|
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
||||||
|
logger()->info('running cli sanity check');
|
||||||
|
[$ret, $output] = cmd()->execWithResult(BUILD_ROOT_PATH . '\bin\php.exe -r "echo \"hello\";"');
|
||||||
|
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||||
|
throw new RuntimeException('cli failed sanity check');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->exts as $ext) {
|
||||||
|
logger()->debug('testing ext: ' . $ext->getName());
|
||||||
|
$ext->runCliCheckWindows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check for phpmicro
|
||||||
|
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
||||||
|
if (file_exists(SOURCE_PATH . '\hello.exe')) {
|
||||||
|
@unlink(SOURCE_PATH . '\hello.exe');
|
||||||
|
}
|
||||||
|
file_put_contents(
|
||||||
|
SOURCE_PATH . '\hello.exe',
|
||||||
|
file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') .
|
||||||
|
($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests())
|
||||||
|
);
|
||||||
|
chmod(SOURCE_PATH . '\hello.exe', 0755);
|
||||||
|
[$ret, $output2] = cmd()->execWithResult(SOURCE_PATH . '\hello.exe');
|
||||||
|
$raw_out = trim(implode('', $output2));
|
||||||
|
$condition[0] = $ret === 0;
|
||||||
|
$condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
|
||||||
|
foreach ($condition as $k => $v) {
|
||||||
|
if (!$v) {
|
||||||
|
throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将编译好的二进制文件发布到 buildroot
|
||||||
|
*
|
||||||
|
* @param int $type 发布类型
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function deployBinary(int $type): bool
|
||||||
|
{
|
||||||
|
$ts = $this->zts ? '_TS' : '';
|
||||||
|
$src = match ($type) {
|
||||||
|
BUILD_TARGET_CLI => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\php.exe",
|
||||||
|
BUILD_TARGET_MICRO => SOURCE_PATH . "\\php-src\\x64\\Release{$ts}\\micro.sfx",
|
||||||
|
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
||||||
|
};
|
||||||
|
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
||||||
|
FileSystem::createDir(BUILD_ROOT_PATH . '\bin');
|
||||||
|
|
||||||
|
cmd()->exec('copy ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '\bin\\'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function getAllStaticLibFiles(): array
|
||||||
|
{
|
||||||
|
$libs = [];
|
||||||
|
|
||||||
|
// reorder libs
|
||||||
|
foreach ($this->libs as $lib) {
|
||||||
|
foreach ($lib->getDependencies() as $dep) {
|
||||||
|
$libs[] = $dep;
|
||||||
|
}
|
||||||
|
$libs[] = $lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
$libFiles = [];
|
||||||
|
$libNames = [];
|
||||||
|
// merge libs
|
||||||
|
foreach ($libs as $lib) {
|
||||||
|
if (!in_array($lib::NAME, $libNames, true)) {
|
||||||
|
$libNames[] = $lib::NAME;
|
||||||
|
array_unshift($libFiles, ...$lib->getStaticLibs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $libFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate command wrapper prefix for php-sdk internal commands.
|
||||||
|
*
|
||||||
|
* @param string $internal_cmd command in php-sdk-tools\bin
|
||||||
|
* @return string Example: C:\php-sdk-tools\phpsdk-vs17-x64.bat -t source\cmake_wrapper.bat --task-args
|
||||||
|
*/
|
||||||
|
public function makeSimpleWrapper(string $internal_cmd): string
|
||||||
|
{
|
||||||
|
$wrapper_bat = SOURCE_PATH . '\\' . crc32($internal_cmd) . '_wrapper.bat';
|
||||||
|
if (!file_exists($wrapper_bat)) {
|
||||||
|
file_put_contents($wrapper_bat, $internal_cmd . ' %*');
|
||||||
|
}
|
||||||
|
return "{$this->sdk_prefix} {$wrapper_bat} --task-args";
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/SPC/builder/windows/library/WindowsLibraryBase.php
Normal file
40
src/SPC/builder/windows/library/WindowsLibraryBase.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\builder\BuilderBase;
|
||||||
|
use SPC\builder\LibraryBase;
|
||||||
|
use SPC\builder\windows\WindowsBuilder;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
abstract class WindowsLibraryBase extends LibraryBase
|
||||||
|
{
|
||||||
|
public function __construct(protected WindowsBuilder $builder)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuilder(): BuilderBase
|
||||||
|
{
|
||||||
|
return $this->builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a nmake wrapper file.
|
||||||
|
*
|
||||||
|
* @param string $content nmake wrapper content
|
||||||
|
* @param string $default_filename default nmake wrapper filename
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function makeNmakeWrapper(string $content, string $default_filename = ''): string
|
||||||
|
{
|
||||||
|
if ($default_filename === '') {
|
||||||
|
$default_filename = $this->source_dir . '\nmake_wrapper.bat';
|
||||||
|
}
|
||||||
|
FileSystem::writeFile($default_filename, $content);
|
||||||
|
return 'nmake_wrapper.bat';
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/SPC/builder/windows/library/openssl.php
Normal file
44
src/SPC/builder/windows/library/openssl.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\builder\windows\SystemUtil;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class openssl extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'openssl';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$perl = file_exists(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe') ? (BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe') : SystemUtil::findCommand('perl.exe');
|
||||||
|
if ($perl === null) {
|
||||||
|
throw new RuntimeException('You need to install perl first! (easiest way is using static-php-cli command "doctor")');
|
||||||
|
}
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper($perl),
|
||||||
|
'Configure zlib VC-WIN64A ' .
|
||||||
|
'no-shared ' .
|
||||||
|
'--prefix=' . quote(BUILD_ROOT_PATH) . ' ' .
|
||||||
|
'--with-zlib-lib=' . quote(BUILD_LIB_PATH) . ' ' .
|
||||||
|
'--with-zlib-include=' . quote(BUILD_INCLUDE_PATH) . ' ' .
|
||||||
|
'--release ' .
|
||||||
|
'no-legacy '
|
||||||
|
);
|
||||||
|
|
||||||
|
// patch zlib
|
||||||
|
FileSystem::replaceFileStr($this->source_dir . '\Makefile', 'ZLIB1', 'zlibstatic.lib');
|
||||||
|
// patch debug: https://stackoverflow.com/questions/18486243/how-do-i-build-openssl-statically-linked-against-windows-runtime
|
||||||
|
FileSystem::replaceFileStr($this->source_dir . '\Makefile', '/debug', '/incremental:no /opt:icf /dynamicbase /nxcompat /ltcg /nodefaultlib:msvcrt');
|
||||||
|
cmd()->cd($this->source_dir)->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('nmake'),
|
||||||
|
'install_dev ' .
|
||||||
|
'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');
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/SPC/builder/windows/library/zlib.php
Normal file
38
src/SPC/builder/windows/library/zlib.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class zlib extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'zlib';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
// reset cmake
|
||||||
|
FileSystem::resetDir($this->source_dir . '\build');
|
||||||
|
|
||||||
|
// start build
|
||||||
|
cmd()->cd($this->source_dir)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
'-B build ' .
|
||||||
|
'-A x64 ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||||
|
'-DSKIP_INSTALL_FILES=ON ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
|
||||||
|
)
|
||||||
|
->execWithWrapper(
|
||||||
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
|
"--build build --config Release --target install -j{$this->builder->concurrency}"
|
||||||
|
);
|
||||||
|
copy(BUILD_LIB_PATH . '\zlibstatic.lib', BUILD_LIB_PATH . '\zlib_a.lib');
|
||||||
|
unlink(BUILD_ROOT_PATH . '\bin\zlib.dll');
|
||||||
|
unlink(BUILD_LIB_PATH . '\zlib.lib');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use Laravel\Prompts\ConfirmPrompt;
|
||||||
|
use Laravel\Prompts\Prompt;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
use SPC\ConsoleApplication;
|
use SPC\ConsoleApplication;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||||
use ZM\Logger\ConsoleLogger;
|
use ZM\Logger\ConsoleLogger;
|
||||||
|
|
||||||
abstract class BaseCommand extends Command
|
abstract class BaseCommand extends Command
|
||||||
@@ -78,6 +82,15 @@ abstract class BaseCommand extends Command
|
|||||||
{
|
{
|
||||||
$this->input = $input;
|
$this->input = $input;
|
||||||
$this->output = $output;
|
$this->output = $output;
|
||||||
|
|
||||||
|
// windows fallback
|
||||||
|
Prompt::fallbackWhen(PHP_OS_FAMILY === 'Windows');
|
||||||
|
ConfirmPrompt::fallbackUsing(function (ConfirmPrompt $prompt) use ($input, $output) {
|
||||||
|
$helper = new QuestionHelper();
|
||||||
|
$case = $prompt->default ? ' [Y/n] ' : ' [y/N] ';
|
||||||
|
$question = new ConfirmationQuestion($prompt->label . $case, $prompt->default);
|
||||||
|
return $helper->ask($input, $output, $question);
|
||||||
|
});
|
||||||
if ($this->shouldExecute()) {
|
if ($this->shouldExecute()) {
|
||||||
try {
|
try {
|
||||||
return $this->handle();
|
return $this->handle();
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ class BuildCliCommand extends BuildCommand
|
|||||||
$this->addOption('with-micro-fake-cli', null, null, 'Enable phpmicro fake cli');
|
$this->addOption('with-micro-fake-cli', null, null, 'Enable phpmicro fake cli');
|
||||||
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
|
||||||
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
|
||||||
|
$this->addOption('with-added-patch', 'P', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Inject patch script outside');
|
||||||
|
$this->addOption('without-micro-ext-test', null, null, 'Disable phpmicro with extension test code');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
@@ -102,6 +104,9 @@ class BuildCliCommand extends BuildCommand
|
|||||||
SourcePatcher::patchHardcodedINI($custom_ini);
|
SourcePatcher::patchHardcodedINI($custom_ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add static-php-cli.version to main.c, in order to debug php failure more easily
|
||||||
|
SourcePatcher::patchSPCVersionToPHP($this->getApplication()->getVersion());
|
||||||
|
|
||||||
// start to build
|
// start to build
|
||||||
$builder->buildPHP($rule);
|
$builder->buildPHP($rule);
|
||||||
|
|
||||||
@@ -119,13 +124,17 @@ class BuildCliCommand extends BuildCommand
|
|||||||
$fixed = ' (host system)';
|
$fixed = ' (host system)';
|
||||||
}
|
}
|
||||||
if (($rule & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
if (($rule & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
||||||
logger()->info('Static php binary path' . $fixed . ': ' . $build_root_path . '/bin/php');
|
$win_suffix = PHP_OS_FAMILY === 'Windows' ? '.exe' : '';
|
||||||
|
$path = FileSystem::convertPath("{$build_root_path}/bin/php{$win_suffix}");
|
||||||
|
logger()->info("Static php binary path{$fixed}: {$path}");
|
||||||
}
|
}
|
||||||
if (($rule & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
if (($rule & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
||||||
logger()->info('phpmicro binary path' . $fixed . ': ' . $build_root_path . '/bin/micro.sfx');
|
$path = FileSystem::convertPath("{$build_root_path}/bin/micro.sfx");
|
||||||
|
logger()->info("phpmicro binary path{$fixed}: {$path}");
|
||||||
}
|
}
|
||||||
if (($rule & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
if (($rule & BUILD_TARGET_FPM) === BUILD_TARGET_FPM && PHP_OS_FAMILY !== 'Windows') {
|
||||||
logger()->info('Static php-fpm binary path' . $fixed . ': ' . $build_root_path . '/bin/php-fpm');
|
$path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm");
|
||||||
|
logger()->info("Static php-fpm binary path{$fixed}: {$path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// export metadata
|
// export metadata
|
||||||
@@ -134,7 +143,8 @@ class BuildCliCommand extends BuildCommand
|
|||||||
// export licenses
|
// export licenses
|
||||||
$dumper = new LicenseDumper();
|
$dumper = new LicenseDumper();
|
||||||
$dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
|
$dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
|
||||||
logger()->info('License path' . $fixed . ': ' . $build_root_path . '/license/');
|
$path = FileSystem::convertPath("{$build_root_path}/license/");
|
||||||
|
logger()->info("License path{$fixed}: {$path}");
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
} catch (WrongUsageException $e) {
|
} catch (WrongUsageException $e) {
|
||||||
// WrongUsageException is not an exception, it's a user error, so we just print the error message
|
// WrongUsageException is not an exception, it's a user error, so we just print the error message
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace SPC\command;
|
|||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\util\DependencyUtil;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@@ -59,6 +60,7 @@ class BuildLibsCommand extends BuildCommand
|
|||||||
// 只编译 library 的情况下,标记
|
// 只编译 library 的情况下,标记
|
||||||
$builder->setLibsOnly();
|
$builder->setLibsOnly();
|
||||||
// 编译和检查库完整
|
// 编译和检查库完整
|
||||||
|
$libraries = DependencyUtil::getLibsByDeps($libraries);
|
||||||
$builder->buildLibs($libraries);
|
$builder->buildLibs($libraries);
|
||||||
|
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
|
|||||||
@@ -75,8 +75,9 @@ class DoctorCommand extends BaseCommand
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||||
|
|
||||||
|
if (extension_loaded('pcntl')) {
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
pcntl_signal(SIGINT, SIG_IGN);
|
||||||
|
}
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
// get source list that will be downloaded
|
// get source list that will be downloaded
|
||||||
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||||
if (empty($sources)) {
|
if (empty($sources)) {
|
||||||
|
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
|
||||||
$sources = array_keys(Config::getSources());
|
$sources = array_keys(Config::getSources());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +189,8 @@ class DownloadCommand extends BaseCommand
|
|||||||
// create downloads
|
// create downloads
|
||||||
try {
|
try {
|
||||||
if (PHP_OS_FAMILY !== 'Windows') {
|
if (PHP_OS_FAMILY !== 'Windows') {
|
||||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path));
|
$abs_path = realpath($path);
|
||||||
|
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($abs_path));
|
||||||
}
|
}
|
||||||
// Windows TODO
|
// Windows TODO
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ class MicroCombineCommand extends BaseCommand
|
|||||||
// 8. Combine !
|
// 8. Combine !
|
||||||
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
|
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
|
||||||
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
|
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
|
||||||
|
if (PHP_OS_FAMILY === 'Windows' && !str_ends_with(strtolower($output), '.exe')) {
|
||||||
|
$output .= '.exe';
|
||||||
|
}
|
||||||
|
$output = FileSystem::convertPath($output);
|
||||||
$result = file_put_contents($output, $file_target);
|
$result = file_put_contents($output, $file_target);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
$this->output->writeln('<error>Combine failed.</error>');
|
$this->output->writeln('<error>Combine failed.</error>');
|
||||||
|
|||||||
@@ -34,12 +34,23 @@ final class CheckListHandler
|
|||||||
*/
|
*/
|
||||||
public function emitFix(OutputInterface $output, CheckResult $result): void
|
public function emitFix(OutputInterface $output, CheckResult $result): void
|
||||||
{
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
sapi_windows_set_ctrl_handler(function () use ($output) {
|
||||||
|
$output->writeln('<error>You cancelled fix</error>');
|
||||||
|
});
|
||||||
|
} elseif (extension_loaded('pcntl')) {
|
||||||
pcntl_signal(SIGINT, function () use ($output) {
|
pcntl_signal(SIGINT, function () use ($output) {
|
||||||
$output->writeln('<error>You cancelled fix</error>');
|
$output->writeln('<error>You cancelled fix</error>');
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$fix_result = call_user_func($this->fix_map[$result->getFixItem()], ...$result->getFixParams());
|
$fix_result = call_user_func($this->fix_map[$result->getFixItem()], ...$result->getFixParams());
|
||||||
|
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
sapi_windows_set_ctrl_handler(null);
|
||||||
|
} elseif (extension_loaded('pcntl')) {
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
pcntl_signal(SIGINT, SIG_IGN);
|
||||||
|
}
|
||||||
|
|
||||||
if ($fix_result) {
|
if ($fix_result) {
|
||||||
$output->writeln('<info>Fix done</info>');
|
$output->writeln('<info>Fix done</info>');
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class LinuxToolCheckList
|
|||||||
'ubuntu',
|
'ubuntu',
|
||||||
'alpine',
|
'alpine',
|
||||||
'redhat',
|
'redhat',
|
||||||
|
'Deepin',
|
||||||
'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
|
'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
|
||||||
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
|
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
|
||||||
};
|
};
|
||||||
@@ -70,7 +71,7 @@ class LinuxToolCheckList
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
/** @noinspection PhpUnused */
|
||||||
#[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')]
|
#[AsCheckItem('if necessary linux headers are installed', limit_os: 'Linux')]
|
||||||
public function checkSystemOSPackages(): ?CheckResult
|
public function checkSystemOSPackages(): ?CheckResult
|
||||||
{
|
{
|
||||||
if (SystemUtil::isMuslDist()) {
|
if (SystemUtil::isMuslDist()) {
|
||||||
@@ -90,7 +91,7 @@ class LinuxToolCheckList
|
|||||||
public function fixBuildTools(array $distro, array $missing): bool
|
public function fixBuildTools(array $distro, array $missing): bool
|
||||||
{
|
{
|
||||||
$install_cmd = match ($distro['dist']) {
|
$install_cmd = match ($distro['dist']) {
|
||||||
'ubuntu', 'debian' => 'apt-get install -y',
|
'ubuntu', 'debian', 'Deepin' => 'apt-get install -y',
|
||||||
'alpine' => 'apk add',
|
'alpine' => 'apk add',
|
||||||
'redhat' => 'dnf install -y',
|
'redhat' => 'dnf install -y',
|
||||||
default => throw new RuntimeException('Current linux distro does not have an auto-install script for musl packages yet.'),
|
default => throw new RuntimeException('Current linux distro does not have an auto-install script for musl packages yet.'),
|
||||||
@@ -101,7 +102,7 @@ class LinuxToolCheckList
|
|||||||
logger()->warning('Current user is not root, using sudo for running command');
|
logger()->warning('Current user is not root, using sudo for running command');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$is_debian = in_array($distro['dist'], ['debian', 'ubuntu']);
|
$is_debian = in_array($distro['dist'], ['debian', 'ubuntu', 'Deepin']);
|
||||||
$to_install = $is_debian ? str_replace('xz', 'xz-utils', $missing) : $missing;
|
$to_install = $is_debian ? str_replace('xz', 'xz-utils', $missing) : $missing;
|
||||||
// debian, alpine libtool -> libtoolize
|
// debian, alpine libtool -> libtoolize
|
||||||
$to_install = str_replace('libtoolize', 'libtool', $to_install);
|
$to_install = str_replace('libtoolize', 'libtool', $to_install);
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ class OSCheckList
|
|||||||
{
|
{
|
||||||
use UnixSystemUtilTrait;
|
use UnixSystemUtilTrait;
|
||||||
|
|
||||||
#[AsCheckItem('if current OS are supported', level: 999)]
|
#[AsCheckItem('if current OS are supported', level: 1000)]
|
||||||
public function checkOS(): ?CheckResult
|
public function checkOS(): ?CheckResult
|
||||||
{
|
{
|
||||||
if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
|
if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD', 'Windows'])) {
|
||||||
return CheckResult::fail('Current OS is not supported');
|
return CheckResult::fail('Current OS is not supported: ' . PHP_OS_FAMILY);
|
||||||
}
|
}
|
||||||
$distro = PHP_OS_FAMILY === 'Linux' ? (' ' . SystemUtil::getOSRelease()['dist']) : '';
|
$distro = PHP_OS_FAMILY === 'Linux' ? (' ' . SystemUtil::getOSRelease()['dist']) : '';
|
||||||
return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . $distro . ', supported');
|
$known_distro = PHP_OS_FAMILY === 'Linux' && in_array(SystemUtil::getOSRelease()['dist'], SystemUtil::getSupportedDistros());
|
||||||
|
return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . $distro . ', supported' . ($known_distro ? '' : ' (but not tested on this distro)'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
src/SPC/doctor/item/WindowsToolCheckList.php
Normal file
122
src/SPC/doctor/item/WindowsToolCheckList.php
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\doctor\item;
|
||||||
|
|
||||||
|
use SPC\builder\windows\SystemUtil;
|
||||||
|
use SPC\doctor\AsCheckItem;
|
||||||
|
use SPC\doctor\AsFixItem;
|
||||||
|
use SPC\doctor\CheckResult;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\Downloader;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
class WindowsToolCheckList
|
||||||
|
{
|
||||||
|
#[AsCheckItem('if Visual Studio are installed', limit_os: 'Windows', level: 999)]
|
||||||
|
public function checkVS(): ?CheckResult
|
||||||
|
{
|
||||||
|
$vs_ver = SystemUtil::findVisualStudio();
|
||||||
|
if ($vs_ver === false) {
|
||||||
|
return CheckResult::fail('Visual Studio not installed, please install VS 2022/2019.');
|
||||||
|
}
|
||||||
|
return CheckResult::ok($vs_ver['version'] . ' ' . $vs_ver['dir']);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if git are installed', limit_os: 'Windows', level: 998)]
|
||||||
|
public function checkGit(): ?CheckResult
|
||||||
|
{
|
||||||
|
if (SystemUtil::findCommand('git.exe') === null) {
|
||||||
|
return CheckResult::fail('Git not installed, please install git for windows manually, see: https://git-scm.com/download/win');
|
||||||
|
// return CheckResult::fail('Git not installed, see https://static-php.dev/en/guide/windows-setup.html');
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if php-sdk-binary-tools are downloaded', limit_os: 'Windows', level: 997)]
|
||||||
|
public function checkSDK(): ?CheckResult
|
||||||
|
{
|
||||||
|
if (!file_exists(PHP_SDK_PATH . DIRECTORY_SEPARATOR . 'phpsdk-starter.bat')) {
|
||||||
|
return CheckResult::fail('php-sdk-binary-tools not downloaded', 'install-php-sdk');
|
||||||
|
}
|
||||||
|
return CheckResult::ok(PHP_SDK_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if git associated command exists', limit_os: 'Windows', level: 996)]
|
||||||
|
public function checkGitPatch(): ?CheckResult
|
||||||
|
{
|
||||||
|
if (($path = SystemUtil::findCommand('patch.exe')) === null) {
|
||||||
|
return CheckResult::fail('Git patch (minGW command) not found in path. You need to add "C:\Program Files\Git\usr\bin" in Path.');
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if nasm installed', limit_os: 'Windows', level: 995)]
|
||||||
|
public function checkNasm(): ?CheckResult
|
||||||
|
{
|
||||||
|
if (SystemUtil::findCommand('nasm.exe', include_sdk_bin: true) === null) {
|
||||||
|
return CheckResult::fail('nasm.exe not found in path.', 'install-nasm');
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsCheckItem('if perl(strawberry) installed', limit_os: 'Windows', level: 994)]
|
||||||
|
public function checkPerl(): ?CheckResult
|
||||||
|
{
|
||||||
|
if (file_exists(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe')) {
|
||||||
|
return CheckResult::ok(BUILD_ROOT_PATH . '\perl\perl\bin\perl.exe');
|
||||||
|
}
|
||||||
|
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')) {
|
||||||
|
return CheckResult::fail($path . ' is not built for msvc.', 'install-perl');
|
||||||
|
}
|
||||||
|
return CheckResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsFixItem('install-php-sdk')]
|
||||||
|
public function installPhpSdk(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
FileSystem::removeDir(PHP_SDK_PATH);
|
||||||
|
cmd(true)->exec('git.exe clone --depth 1 https://github.com/php/php-sdk-binary-tools.git ' . PHP_SDK_PATH);
|
||||||
|
} catch (RuntimeException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsFixItem('install-nasm')]
|
||||||
|
public function installNasm(): bool
|
||||||
|
{
|
||||||
|
// The hardcoded version here is to be consistent with the version compiled by `musl-cross-toolchain`.
|
||||||
|
$nasm_ver = '2.16.01';
|
||||||
|
$nasm_dist = "nasm-{$nasm_ver}";
|
||||||
|
$source = [
|
||||||
|
'type' => 'url',
|
||||||
|
'url' => "https://www.nasm.us/pub/nasm/releasebuilds/{$nasm_ver}/win64/{$nasm_dist}-win64.zip",
|
||||||
|
];
|
||||||
|
logger()->info('Downloading ' . $source['url']);
|
||||||
|
Downloader::downloadSource('nasm', $source);
|
||||||
|
FileSystem::extractSource('nasm', DOWNLOAD_PATH . "\\{$nasm_dist}-win64.zip");
|
||||||
|
copy(SOURCE_PATH . "\\nasm\\{$nasm_dist}\\nasm.exe", PHP_SDK_PATH . '\bin\nasm.exe');
|
||||||
|
copy(SOURCE_PATH . "\\nasm\\{$nasm_dist}\\ndisasm.exe", PHP_SDK_PATH . '\bin\ndisasm.exe');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[AsFixItem('install-perl')]
|
||||||
|
public function installPerl(): bool
|
||||||
|
{
|
||||||
|
$url = 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip';
|
||||||
|
$source = [
|
||||||
|
'type' => 'url',
|
||||||
|
'url' => $url,
|
||||||
|
];
|
||||||
|
logger()->info("Downloading {$url}");
|
||||||
|
Downloader::downloadSource('strawberry-perl', $source);
|
||||||
|
FileSystem::extractSource('strawberry-perl', DOWNLOAD_PATH . '\strawberry-perl-5.38.0.1-64bit-portable.zip', '../buildroot/perl');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -168,14 +168,15 @@ class Downloader
|
|||||||
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): void
|
||||||
{
|
{
|
||||||
logger()->debug("Downloading {$url}");
|
logger()->debug("Downloading {$url}");
|
||||||
pcntl_signal(SIGINT, function () use ($filename) {
|
$cancel_func = function () use ($filename) {
|
||||||
if (file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
if (file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/' . $filename))) {
|
||||||
logger()->warning('Deleting download file: ' . $filename);
|
logger()->warning('Deleting download file: ' . $filename);
|
||||||
unlink(DOWNLOAD_PATH . '/' . $filename);
|
unlink(FileSystem::convertPath(DOWNLOAD_PATH . '/' . $filename));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
self::curlDown(url: $url, path: DOWNLOAD_PATH . "/{$filename}");
|
self::registerCancelEvent($cancel_func);
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"));
|
||||||
|
self::unregisterCancelEvent();
|
||||||
logger()->debug("Locking {$filename}");
|
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]);
|
||||||
}
|
}
|
||||||
@@ -187,7 +188,7 @@ class Downloader
|
|||||||
*/
|
*/
|
||||||
public static function lockSource(string $name, array $data): void
|
public static function lockSource(string $name, array $data): void
|
||||||
{
|
{
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
if (!file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/.lock.json'))) {
|
||||||
$lock = [];
|
$lock = [];
|
||||||
} else {
|
} else {
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
@@ -204,24 +205,25 @@ class Downloader
|
|||||||
*/
|
*/
|
||||||
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null): void
|
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null): void
|
||||||
{
|
{
|
||||||
$download_path = DOWNLOAD_PATH . "/{$name}";
|
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
|
||||||
if (file_exists($download_path)) {
|
if (file_exists($download_path)) {
|
||||||
FileSystem::removeDir($download_path);
|
FileSystem::removeDir($download_path);
|
||||||
}
|
}
|
||||||
logger()->debug("cloning {$name} source");
|
logger()->debug("cloning {$name} source");
|
||||||
$check = !defined('DEBUG_MODE') ? ' -q' : '';
|
$check = !defined('DEBUG_MODE') ? ' -q' : '';
|
||||||
pcntl_signal(SIGINT, function () use ($download_path) {
|
$cancel_func = function () use ($download_path) {
|
||||||
if (is_dir($download_path)) {
|
if (is_dir($download_path)) {
|
||||||
logger()->warning('Removing path ' . $download_path);
|
logger()->warning('Removing path ' . $download_path);
|
||||||
FileSystem::removeDir($download_path);
|
FileSystem::removeDir($download_path);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
self::registerCancelEvent($cancel_func);
|
||||||
f_passthru(
|
f_passthru(
|
||||||
'git clone' . $check .
|
SPC_GIT_EXEC . ' clone' . $check .
|
||||||
' --config core.autocrlf=false ' .
|
' --config core.autocrlf=false ' .
|
||||||
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
|
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
|
||||||
);
|
);
|
||||||
pcntl_signal(SIGINT, SIG_IGN);
|
self::unregisterCancelEvent();
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
logger()->debug("Locking git source {$name}");
|
logger()->debug("Locking git source {$name}");
|
||||||
@@ -251,7 +253,6 @@ class Downloader
|
|||||||
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
|
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
*/
|
||||||
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): void
|
||||||
{
|
{
|
||||||
@@ -359,12 +360,12 @@ class Downloader
|
|||||||
};
|
};
|
||||||
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
||||||
|
|
||||||
$cmd = "curl -sfSL {$methodArg} {$headerArg} \"{$url}\"";
|
$cmd = SPC_CURL_EXEC . " -sfSL {$methodArg} {$headerArg} \"{$url}\"";
|
||||||
if (getenv('CACHE_API_EXEC') === 'yes') {
|
if (getenv('CACHE_API_EXEC') === 'yes') {
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.curl_exec_cache')) {
|
if (!file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache'))) {
|
||||||
$cache = [];
|
$cache = [];
|
||||||
} else {
|
} else {
|
||||||
$cache = json_decode(file_get_contents(DOWNLOAD_PATH . '/.curl_exec_cache'), true);
|
$cache = json_decode(file_get_contents(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache')), true);
|
||||||
}
|
}
|
||||||
if (isset($cache[$cmd]) && $cache[$cmd]['expire'] >= time()) {
|
if (isset($cache[$cmd]) && $cache[$cmd]['expire'] >= time()) {
|
||||||
return $cache[$cmd]['cache'];
|
return $cache[$cmd]['cache'];
|
||||||
@@ -375,7 +376,7 @@ class Downloader
|
|||||||
}
|
}
|
||||||
$cache[$cmd]['cache'] = implode("\n", $output);
|
$cache[$cmd]['cache'] = implode("\n", $output);
|
||||||
$cache[$cmd]['expire'] = time() + 3600;
|
$cache[$cmd]['expire'] = time() + 3600;
|
||||||
file_put_contents(DOWNLOAD_PATH . '/.curl_exec_cache', json_encode($cache));
|
file_put_contents(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache'), json_encode($cache));
|
||||||
return $cache[$cmd]['cache'];
|
return $cache[$cmd]['cache'];
|
||||||
}
|
}
|
||||||
f_exec($cmd, $output, $ret);
|
f_exec($cmd, $output, $ret);
|
||||||
@@ -404,7 +405,35 @@ class Downloader
|
|||||||
};
|
};
|
||||||
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
|
||||||
$check = !defined('DEBUG_MODE') ? 's' : '#';
|
$check = !defined('DEBUG_MODE') ? 's' : '#';
|
||||||
$cmd = "curl -{$check}fSL -o \"{$path}\" {$methodArg} {$headerArg} \"{$url}\"";
|
$cmd = SPC_CURL_EXEC . " -{$check}fSL -o \"{$path}\" {$methodArg} {$headerArg} \"{$url}\"";
|
||||||
f_passthru($cmd);
|
f_passthru($cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register CTRL+C event for different OS.
|
||||||
|
*
|
||||||
|
* @param callable $callback callback function
|
||||||
|
*/
|
||||||
|
private static function registerCancelEvent(callable $callback): void
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
sapi_windows_set_ctrl_handler($callback);
|
||||||
|
} elseif (extension_loaded('pcntl')) {
|
||||||
|
pcntl_signal(SIGINT, $callback);
|
||||||
|
} else {
|
||||||
|
logger()->debug('You have not enabled `pcntl` extension, cannot prevent download file corruption when Ctrl+C');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unegister CTRL+C event for different OS.
|
||||||
|
*/
|
||||||
|
private static function unregisterCancelEvent(): void
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
sapi_windows_set_ctrl_handler(null);
|
||||||
|
} elseif (extension_loaded('pcntl')) {
|
||||||
|
pcntl_signal(SIGINT, SIG_IGN);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ class FileSystem
|
|||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public static function loadConfigArray(string $config): array
|
public static function loadConfigArray(string $config, ?string $config_dir = null): array
|
||||||
{
|
{
|
||||||
$whitelist = ['ext', 'lib', 'source'];
|
$whitelist = ['ext', 'lib', 'source'];
|
||||||
if (!in_array($config, $whitelist)) {
|
if (!in_array($config, $whitelist)) {
|
||||||
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
|
throw new FileSystemException('Reading ' . $config . '.json is not allowed');
|
||||||
}
|
}
|
||||||
$tries = [
|
$tries = $config_dir !== null ? [FileSystem::convertPath($config_dir . '/' . $config . '.json')] : [
|
||||||
WORKING_DIR . '/config/' . $config . '.json',
|
WORKING_DIR . '/config/' . $config . '.json',
|
||||||
ROOT_DIR . '/config/' . $config . '.json',
|
ROOT_DIR . '/config/' . $config . '.json',
|
||||||
];
|
];
|
||||||
@@ -160,79 +160,37 @@ class FileSystem
|
|||||||
}
|
}
|
||||||
logger()->info("extracting {$name} source to " . ($move_path ?? SOURCE_PATH . "/{$name}") . ' ...');
|
logger()->info("extracting {$name} source to " . ($move_path ?? SOURCE_PATH . "/{$name}") . ' ...');
|
||||||
try {
|
try {
|
||||||
$target = $move_path ?? (SOURCE_PATH . "/{$name}");
|
$target = self::convertPath($move_path ?? (SOURCE_PATH . "/{$name}"));
|
||||||
// Git source, just move
|
// Git source, just move
|
||||||
if (is_dir($filename)) {
|
if (is_dir(self::convertPath($filename))) {
|
||||||
self::copyDir($filename, $target);
|
self::copyDir(self::convertPath($filename), $target);
|
||||||
self::emitSourceExtractHook($name);
|
self::emitSourceExtractHook($name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
|
|
||||||
if (f_mkdir(directory: $target, recursive: true) !== true) {
|
if (f_mkdir(directory: $target, recursive: true) !== true) {
|
||||||
throw new FileSystemException('create ' . $name . 'source dir failed');
|
throw new FileSystemException('create ' . $name . 'source dir failed');
|
||||||
}
|
}
|
||||||
switch (self::extname($filename)) {
|
|
||||||
case 'xz':
|
if (in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
|
||||||
case 'txz':
|
match (self::extname($filename)) {
|
||||||
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
|
'tar', 'xz', 'txz' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
||||||
// f_passthru("cat {$filename} | xz -d | tar -x -C " . SOURCE_PATH . "/{$name} --strip-components 1");
|
'tgz', 'gz' => f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1"),
|
||||||
break;
|
'bz2' => f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1"),
|
||||||
case 'gz':
|
'zip' => f_passthru("unzip {$filename} -d {$target}"),
|
||||||
case 'tgz':
|
default => throw new FileSystemException('unknown archive format: ' . $filename),
|
||||||
f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1");
|
};
|
||||||
break;
|
|
||||||
case 'bz2':
|
|
||||||
f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
f_passthru("unzip {$filename} -d {$target}");
|
|
||||||
break;
|
|
||||||
// case 'zstd':
|
|
||||||
// case 'zst':
|
|
||||||
// passthru('cat ' . $filename . ' | zstd -d | tar -x -C ".SOURCE_PATH . "/' . $name . ' --strip-components 1', $ret);
|
|
||||||
// break;
|
|
||||||
case 'tar':
|
|
||||||
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FileSystemException('unknown archive format: ' . $filename);
|
|
||||||
}
|
|
||||||
} elseif (PHP_OS_FAMILY === 'Windows') {
|
} elseif (PHP_OS_FAMILY === 'Windows') {
|
||||||
// find 7z
|
// use php-sdk-binary-tools/bin/7za.exe
|
||||||
$_7zExe = self::findCommandPath('7z', [
|
$_7z = self::convertPath(PHP_SDK_PATH . '/bin/7za.exe');
|
||||||
'C:\Program Files\7-Zip-Zstandard',
|
|
||||||
'C:\Program Files (x86)\7-Zip-Zstandard',
|
|
||||||
'C:\Program Files\7-Zip',
|
|
||||||
'C:\Program Files (x86)\7-Zip',
|
|
||||||
]);
|
|
||||||
if (!$_7zExe) {
|
|
||||||
throw new FileSystemException('windows needs 7z to unpack');
|
|
||||||
}
|
|
||||||
f_mkdir(SOURCE_PATH . "/{$name}", recursive: true);
|
f_mkdir(SOURCE_PATH . "/{$name}", recursive: true);
|
||||||
switch (self::extname($filename)) {
|
match (self::extname($filename)) {
|
||||||
case 'zstd':
|
'tar' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
|
||||||
case 'zst':
|
'xz', 'txz', 'gz', 'tgz', 'bz2' => f_passthru("\"{$_7z}\" x -so {$filename} | tar -f - -x -C {$target} --strip-components 1"),
|
||||||
if (!str_contains($_7zExe, 'Zstandard')) {
|
'zip' => f_passthru("\"{$_7z}\" x {$filename} -o{$target} -y"),
|
||||||
throw new FileSystemException("zstd is not supported: {$filename}");
|
default => throw new FileSystemException("unknown archive format: {$filename}"),
|
||||||
}
|
};
|
||||||
// no break
|
|
||||||
case 'xz':
|
|
||||||
case 'txz':
|
|
||||||
case 'gz':
|
|
||||||
case 'tgz':
|
|
||||||
case 'bz2':
|
|
||||||
f_passthru("\"{$_7zExe}\" x -so {$filename} | tar -f - -x -C {$target} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'tar':
|
|
||||||
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
|
|
||||||
break;
|
|
||||||
case 'zip':
|
|
||||||
f_passthru("\"{$_7zExe}\" x {$filename} -o{$target}");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FileSystemException("unknown archive format: {$filename}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self::emitSourceExtractHook($name);
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
f_passthru('rmdir /s /q ' . SOURCE_PATH . "/{$name}");
|
f_passthru('rmdir /s /q ' . SOURCE_PATH . "/{$name}");
|
||||||
@@ -397,7 +355,7 @@ class FileSystem
|
|||||||
public static function createDir(string $path): void
|
public static function createDir(string $path): void
|
||||||
{
|
{
|
||||||
if (!is_dir($path) && !f_mkdir($path, 0755, true) && !is_dir($path)) {
|
if (!is_dir($path) && !f_mkdir($path, 0755, true) && !is_dir($path)) {
|
||||||
throw new FileSystemException(sprintf('无法建立目录:%s', $path));
|
throw new FileSystemException(sprintf('Unable to create dir: %s', $path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +365,7 @@ class FileSystem
|
|||||||
*/
|
*/
|
||||||
public static function writeFile(string $path, mixed $content, ...$args): bool|int|string
|
public static function writeFile(string $path, mixed $content, ...$args): bool|int|string
|
||||||
{
|
{
|
||||||
$dir = pathinfo($path, PATHINFO_DIRNAME);
|
$dir = pathinfo(self::convertPath($path), PATHINFO_DIRNAME);
|
||||||
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
|
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
|
||||||
throw new FileSystemException('Write file failed, cannot create parent directory: ' . $dir);
|
throw new FileSystemException('Write file failed, cannot create parent directory: ' . $dir);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace SPC\store;
|
|||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
use SPC\builder\BuilderBase;
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
use SPC\builder\linux\LinuxBuilder;
|
||||||
|
use SPC\builder\unix\UnixBuilderBase;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ class SourcePatcher
|
|||||||
// FileSystem::addSourceExtractHook('swow', [SourcePatcher::class, 'patchSwow']);
|
// FileSystem::addSourceExtractHook('swow', [SourcePatcher::class, 'patchSwow']);
|
||||||
FileSystem::addSourceExtractHook('micro', [SourcePatcher::class, 'patchMicro']);
|
FileSystem::addSourceExtractHook('micro', [SourcePatcher::class, 'patchMicro']);
|
||||||
FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']);
|
FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']);
|
||||||
|
FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +32,20 @@ class SourcePatcher
|
|||||||
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
|
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// patch windows php 8.1 bug
|
||||||
|
if (PHP_OS_FAMILY === 'Windows' && $builder->getPHPVersionID() >= 80100 && $builder->getPHPVersionID() < 80200) {
|
||||||
|
logger()->info('Patching PHP 8.1 windows Fiber bug');
|
||||||
|
FileSystem::replaceFileStr(
|
||||||
|
SOURCE_PATH . '\php-src\win32\build\config.w32',
|
||||||
|
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
|
||||||
|
"ADD_FLAG('ASM_OBJS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj $(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');"
|
||||||
|
);
|
||||||
|
FileSystem::replaceFileStr(
|
||||||
|
SOURCE_PATH . '\php-src\win32\build\config.w32',
|
||||||
|
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
|
||||||
|
''
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,6 +175,17 @@ class SourcePatcher
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function patchSwoole(): bool
|
||||||
|
{
|
||||||
|
// swoole hook needs pdo/pdo.h
|
||||||
|
FileSystem::replaceFileStr(
|
||||||
|
SOURCE_PATH . '/php-src/ext/swoole/config.m4',
|
||||||
|
'PHP_ADD_INCLUDE([$ext_srcdir])',
|
||||||
|
"PHP_ADD_INCLUDE( [\$ext_srcdir] )\n PHP_ADD_INCLUDE([\$abs_srcdir/ext])"
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
@@ -169,9 +196,10 @@ class SourcePatcher
|
|||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCPY 1$/m', '');
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCPY 1$/m', '');
|
||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
|
||||||
}
|
}
|
||||||
|
if ($builder instanceof UnixBuilderBase) {
|
||||||
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
|
||||||
|
|
||||||
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
|
||||||
|
}
|
||||||
|
|
||||||
// call extension patch before make
|
// call extension patch before make
|
||||||
foreach ($builder->getExts() as $ext) {
|
foreach ($builder->getExts() as $ext) {
|
||||||
@@ -240,4 +268,48 @@ class SourcePatcher
|
|||||||
@unlink($embed_c_bak);
|
@unlink($embed_c_bak);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch cli SAPI Makefile for Windows.
|
||||||
|
*
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public static function patchWindowsCLITarget(): void
|
||||||
|
{
|
||||||
|
// search Makefile code line contains "$(BUILD_DIR)\php.exe:"
|
||||||
|
$content = FileSystem::readFile(SOURCE_PATH . '/php-src/Makefile');
|
||||||
|
$lines = explode("\r\n", $content);
|
||||||
|
$line_num = 0;
|
||||||
|
$found = false;
|
||||||
|
foreach ($lines as $v) {
|
||||||
|
if (strpos($v, '$(BUILD_DIR)\php.exe:') !== false) {
|
||||||
|
$found = $line_num;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++$line_num;
|
||||||
|
}
|
||||||
|
if ($found === false) {
|
||||||
|
throw new RuntimeException('Cannot patch windows CLI Makefile!');
|
||||||
|
}
|
||||||
|
$lines[$line_num] = '$(BUILD_DIR)\php.exe: generated_files $(DEPS_CLI) $(PHP_GLOBAL_OBJS) $(CLI_GLOBAL_OBJS) $(STATIC_EXT_OBJS) $(ASM_OBJS) $(BUILD_DIR)\php.exe.res $(BUILD_DIR)\php.exe.manifest';
|
||||||
|
$lines[$line_num + 1] = "\t" . '"$(LINK)" /nologo $(PHP_GLOBAL_OBJS_RESP) $(CLI_GLOBAL_OBJS_RESP) $(STATIC_EXT_OBJS_RESP) $(STATIC_EXT_LIBS) $(ASM_OBJS) $(LIBS) $(LIBS_CLI) $(BUILD_DIR)\php.exe.res /out:$(BUILD_DIR)\php.exe $(LDFLAGS) $(LDFLAGS_CLI) /ltcg /nodefaultlib:msvcrt /nodefaultlib:msvcrtd /ignore:4286';
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add additional `static-php-cli.version` ini value for PHP source.
|
||||||
|
*
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function patchSPCVersionToPHP(string $version = 'unknown'): void
|
||||||
|
{
|
||||||
|
// detect patch
|
||||||
|
$file = FileSystem::readFile(SOURCE_PATH . '/php-src/main/main.c');
|
||||||
|
if (!str_contains($file, 'static-php-cli.version')) {
|
||||||
|
logger()->debug('Inserting static-php-cli.version to php-src');
|
||||||
|
$file = str_replace('PHP_INI_BEGIN()', "PHP_INI_BEGIN()\n\tPHP_INI_ENTRY(\"static-php-cli.version\",\t\"{$version}\",\tPHP_INI_ALL,\tNULL)", $file);
|
||||||
|
FileSystem::writeFile(SOURCE_PATH . '/php-src/main/main.c', $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ class UnixShell
|
|||||||
|
|
||||||
public function __construct(?bool $debug = null)
|
public function __construct(?bool $debug = null)
|
||||||
{
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
throw new RuntimeException('Windows cannot use UnixShell');
|
||||||
|
}
|
||||||
$this->debug = $debug ?? defined('DEBUG_MODE');
|
$this->debug = $debug ?? defined('DEBUG_MODE');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
95
src/SPC/util/WindowsCmd.php
Normal file
95
src/SPC/util/WindowsCmd.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\util;
|
||||||
|
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use ZM\Logger\ConsoleColor;
|
||||||
|
|
||||||
|
class WindowsCmd
|
||||||
|
{
|
||||||
|
private ?string $cd = null;
|
||||||
|
|
||||||
|
private bool $debug;
|
||||||
|
|
||||||
|
private array $env = [];
|
||||||
|
|
||||||
|
public function __construct(?bool $debug = null)
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY !== 'Windows') {
|
||||||
|
throw new RuntimeException('Only windows can use WindowsCmd');
|
||||||
|
}
|
||||||
|
$this->debug = $debug ?? defined('DEBUG_MODE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cd(string $dir): WindowsCmd
|
||||||
|
{
|
||||||
|
logger()->info('Entering dir: ' . $dir);
|
||||||
|
$c = clone $this;
|
||||||
|
$c->cd = $dir;
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function exec(string $cmd): WindowsCmd
|
||||||
|
{
|
||||||
|
/* @phpstan-ignore-next-line */
|
||||||
|
logger()->info(ConsoleColor::yellow('[EXEC] ') . ConsoleColor::green($cmd));
|
||||||
|
if ($this->cd !== null) {
|
||||||
|
$cmd = 'cd /d ' . escapeshellarg($this->cd) . ' && ' . $cmd;
|
||||||
|
}
|
||||||
|
if (!$this->debug) {
|
||||||
|
$cmd .= ' >nul 2>&1';
|
||||||
|
}
|
||||||
|
echo $cmd . PHP_EOL;
|
||||||
|
|
||||||
|
f_passthru($cmd);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execWithWrapper(string $wrapper, string $args): WindowsCmd
|
||||||
|
{
|
||||||
|
return $this->exec($wrapper . ' "' . str_replace('"', '^"', $args) . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execWithResult(string $cmd, bool $with_log = true): array
|
||||||
|
{
|
||||||
|
if ($with_log) {
|
||||||
|
/* @phpstan-ignore-next-line */
|
||||||
|
logger()->info(ConsoleColor::blue('[EXEC] ') . ConsoleColor::green($cmd));
|
||||||
|
} else {
|
||||||
|
logger()->debug('Running command with result: ' . $cmd);
|
||||||
|
}
|
||||||
|
exec($cmd, $out, $code);
|
||||||
|
return [$code, $out];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEnv(array $env): WindowsCmd
|
||||||
|
{
|
||||||
|
$this->env = array_merge($this->env, $env);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function execWithEnv(string $cmd): WindowsCmd
|
||||||
|
{
|
||||||
|
if ($this->getEnvString() !== '') {
|
||||||
|
return $this->exec($this->getEnvString() . "call {$cmd}");
|
||||||
|
}
|
||||||
|
return $this->exec($cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getEnvString(): string
|
||||||
|
{
|
||||||
|
$str = '';
|
||||||
|
foreach ($this->env as $k => $v) {
|
||||||
|
$str .= 'set ' . $k . '=' . $v . ' && ';
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,26 +2,35 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use SPC\store\FileSystem;
|
||||||
use ZM\Logger\ConsoleLogger;
|
use ZM\Logger\ConsoleLogger;
|
||||||
|
|
||||||
define('WORKING_DIR', getcwd());
|
define('WORKING_DIR', getcwd());
|
||||||
const ROOT_DIR = __DIR__ . '/../..';
|
define('ROOT_DIR', dirname(__DIR__, 2));
|
||||||
|
|
||||||
// CLI start time
|
// CLI start time
|
||||||
define('START_TIME', microtime(true));
|
define('START_TIME', microtime(true));
|
||||||
|
|
||||||
define('BUILD_ROOT_PATH', is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot'));
|
define('BUILD_ROOT_PATH', FileSystem::convertPath(is_string($a = getenv('BUILD_ROOT_PATH')) ? $a : (WORKING_DIR . '/buildroot')));
|
||||||
define('SOURCE_PATH', is_string($a = getenv('SOURCE_PATH')) ? $a : (WORKING_DIR . '/source'));
|
define('SOURCE_PATH', FileSystem::convertPath(is_string($a = getenv('SOURCE_PATH')) ? $a : (WORKING_DIR . '/source')));
|
||||||
define('DOWNLOAD_PATH', is_string($a = getenv('DOWNLOAD_PATH')) ? $a : (WORKING_DIR . '/downloads'));
|
define('DOWNLOAD_PATH', FileSystem::convertPath(is_string($a = getenv('DOWNLOAD_PATH')) ? $a : (WORKING_DIR . '/downloads')));
|
||||||
define('BUILD_BIN_PATH', is_string($a = getenv('INSTALL_BIN_PATH')) ? $a : (BUILD_ROOT_PATH . '/bin'));
|
define('BUILD_BIN_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_BIN_PATH')) ? $a : (BUILD_ROOT_PATH . '/bin')));
|
||||||
define('BUILD_LIB_PATH', is_string($a = getenv('INSTALL_LIB_PATH')) ? $a : (BUILD_ROOT_PATH . '/lib'));
|
define('BUILD_LIB_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_LIB_PATH')) ? $a : (BUILD_ROOT_PATH . '/lib')));
|
||||||
define('BUILD_INCLUDE_PATH', is_string($a = getenv('INSTALL_INCLUDE_PATH')) ? $a : (BUILD_ROOT_PATH . '/include'));
|
define('BUILD_INCLUDE_PATH', FileSystem::convertPath(is_string($a = getenv('INSTALL_INCLUDE_PATH')) ? $a : (BUILD_ROOT_PATH . '/include')));
|
||||||
define('SEPARATED_PATH', [
|
define('SEPARATED_PATH', [
|
||||||
'/' . pathinfo(BUILD_LIB_PATH)['basename'], // lib
|
'/' . pathinfo(BUILD_LIB_PATH)['basename'], // lib
|
||||||
'/' . pathinfo(BUILD_INCLUDE_PATH)['basename'], // include
|
'/' . pathinfo(BUILD_INCLUDE_PATH)['basename'], // include
|
||||||
BUILD_ROOT_PATH,
|
BUILD_ROOT_PATH,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
define('PHP_SDK_PATH', is_string($a = getenv('PHP_SDK_PATH')) ? $a : (WORKING_DIR . DIRECTORY_SEPARATOR . 'php-sdk-binary-tools'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// for windows, prevent calling Invoke-WebRequest and wsl command
|
||||||
|
const SPC_CURL_EXEC = PHP_OS_FAMILY === 'Windows' ? 'curl.exe' : 'curl';
|
||||||
|
const SPC_GIT_EXEC = PHP_OS_FAMILY === 'Windows' ? 'git.exe' : 'git';
|
||||||
|
|
||||||
// dangerous command
|
// dangerous command
|
||||||
const DANGER_CMD = [
|
const DANGER_CMD = [
|
||||||
'rm',
|
'rm',
|
||||||
|
|||||||
@@ -3,8 +3,12 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
use SPC\builder\BuilderBase;
|
||||||
|
use SPC\builder\BuilderProvider;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\util\UnixShell;
|
use SPC\util\UnixShell;
|
||||||
|
use SPC\util\WindowsCmd;
|
||||||
use ZM\Logger\ConsoleLogger;
|
use ZM\Logger\ConsoleLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +72,7 @@ function osfamily2dir(): string
|
|||||||
/**
|
/**
|
||||||
* Execute the shell command, and the output will be directly printed in the terminal. If there is an error, an exception will be thrown
|
* Execute the shell command, and the output will be directly printed in the terminal. If there is an error, an exception will be thrown
|
||||||
*
|
*
|
||||||
* @throws \SPC\exception\RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
function f_passthru(string $cmd): ?bool
|
function f_passthru(string $cmd): ?bool
|
||||||
{
|
{
|
||||||
@@ -86,7 +90,7 @@ function f_passthru(string $cmd): ?bool
|
|||||||
}
|
}
|
||||||
$ret = passthru($cmd, $code);
|
$ret = passthru($cmd, $code);
|
||||||
if ($code !== 0) {
|
if ($code !== 0) {
|
||||||
throw new \SPC\exception\RuntimeException('Command run failed with code[' . $code . ']: ' . $cmd, $code);
|
throw new RuntimeException('Command run failed with code[' . $code . ']: ' . $cmd, $code);
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
@@ -120,3 +124,28 @@ function shell(?bool $debug = null): UnixShell
|
|||||||
{
|
{
|
||||||
return new UnixShell($debug);
|
return new UnixShell($debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cmd(?bool $debug = null): WindowsCmd
|
||||||
|
{
|
||||||
|
return new WindowsCmd($debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current builder.
|
||||||
|
*
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
function builder(): BuilderBase
|
||||||
|
{
|
||||||
|
return BuilderProvider::getBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current patch point.
|
||||||
|
*
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
function patch_point(): string
|
||||||
|
{
|
||||||
|
return BuilderProvider::getBuilder()->getPatchPoint();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,75 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/** @noinspection ALL */
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
# If you want to test new extensions here, just modify it.
|
/**
|
||||||
$extensions = 'password-argon2,apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,event,exif,fileinfo,filter,ftp,gd,gmp,iconv,imagick,imap,intl,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sqlite3,swoole,sysvmsg,sysvsem,sysvshm,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib';
|
* This is GitHub Actions automatic test extension args generator.
|
||||||
|
* You can edit $extensions, $with_libs and $base_combination.
|
||||||
|
*/
|
||||||
|
|
||||||
if (PHP_OS_FAMILY === 'Darwin') {
|
// --------------------------------- edit area ---------------------------------
|
||||||
$extensions .= ',sodium';
|
|
||||||
|
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||||
|
$extensions = match (PHP_OS_FAMILY) {
|
||||||
|
'Linux', 'Darwin' => 'calendar,ctype,curl,dom,fileinfo,filter,gd,iconv,imagick,mbregex,mbstring,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,rar,redis,session,simplexml,soap,sockets,sqlite3,swoole,swoole-hook-mysql,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib',
|
||||||
|
'Windows' => 'mbstring,openssl',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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' => '',
|
||||||
|
'Windows' => '',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Please change your test base combination. We recommend testing with `common`.
|
||||||
|
// 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' => 'none',
|
||||||
|
'Windows' => 'none',
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------- code area, do not modify --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get combination for tests, do not modify it if not necessary.
|
||||||
|
*/
|
||||||
|
function _getCombination(string $type = 'common'): string
|
||||||
|
{
|
||||||
|
return match ($type) {
|
||||||
|
'common' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,' .
|
||||||
|
'mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,' .
|
||||||
|
'sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip',
|
||||||
|
'bulk' => 'apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,event,exif,fileinfo,filter,ftp,gd,gmp,iconv,imagick,imap,' .
|
||||||
|
'intl,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,' .
|
||||||
|
'posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,swoole,sysvmsg,sysvsem,' .
|
||||||
|
'sysvshm,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib',
|
||||||
|
'minimal' => 'pcntl,posix,mbstring,tokenizer,phar',
|
||||||
|
default => '', // none
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
echo $extensions;
|
if (!isset($argv[1])) {
|
||||||
|
exit("Please use 'extensions', 'cmd' or 'libs' as output type");
|
||||||
|
}
|
||||||
|
|
||||||
|
$trim_value = "\r\n \t,";
|
||||||
|
|
||||||
|
$final_extensions = trim(trim($extensions, $trim_value) . ',' . _getCombination($base_combination), $trim_value);
|
||||||
|
$final_libs = trim($with_libs, $trim_value);
|
||||||
|
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
$final_extensions_cmd = '"' . $final_extensions . '"';
|
||||||
|
} else {
|
||||||
|
$final_extensions_cmd = $final_extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo match ($argv[1]) {
|
||||||
|
'extensions' => $final_extensions,
|
||||||
|
'libs' => $final_libs,
|
||||||
|
'libs_cmd' => ($final_libs === '' ? '' : (' --with-libs="' . $final_libs . '"')),
|
||||||
|
'cmd' => $final_extensions_cmd . ($final_libs === '' ? '' : (' --with-libs="' . $final_libs . '"')),
|
||||||
|
default => '',
|
||||||
|
};
|
||||||
|
|||||||
6
src/globals/tests/openssl.php
Normal file
6
src/globals/tests/openssl.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
assert(function_exists('openssl_digest'));
|
||||||
|
assert(openssl_digest('123456', 'md5') === 'e10adc3949ba59abbe56e057f20f883e');
|
||||||
12
src/globals/tests/swoole.php
Normal file
12
src/globals/tests/swoole.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
assert(function_exists('swoole_cpu_num'));
|
||||||
|
assert(function_exists('swoole_string'));
|
||||||
|
assert(class_exists('Swoole\Coroutine'));
|
||||||
|
assert(class_exists('Swoole\Coroutine\Http2\Client'));
|
||||||
|
assert(class_exists('Swoole\Coroutine\Redis'));
|
||||||
|
assert(class_exists('Swoole\Coroutine\WaitGroup'));
|
||||||
|
assert(class_exists('Swoole\Http2\Request'));
|
||||||
|
assert(constant('SWOOLE_VERSION'));
|
||||||
@@ -3,3 +3,4 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
assert(function_exists('gzcompress'));
|
assert(function_exists('gzcompress'));
|
||||||
|
assert(gzdecode(gzencode('aaa')) === 'aaa');
|
||||||
|
|||||||
101
tests/SPC/globals/GlobalFunctionsTest.php
Normal file
101
tests/SPC/globals/GlobalFunctionsTest.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\globals;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Log\LogLevel;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use ZM\Logger\ConsoleLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class GlobalFunctionsTest extends TestCase
|
||||||
|
{
|
||||||
|
private static $logger_cache;
|
||||||
|
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
global $ob_logger;
|
||||||
|
self::$logger_cache = $ob_logger;
|
||||||
|
$ob_logger = new ConsoleLogger(LogLevel::ALERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass(): void
|
||||||
|
{
|
||||||
|
global $ob_logger;
|
||||||
|
$ob_logger = self::$logger_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAssocArray(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(is_assoc_array(['a' => 1, 'b' => 2]));
|
||||||
|
$this->assertFalse(is_assoc_array([1, 2, 3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogger(): void
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf('Psr\Log\LoggerInterface', logger());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
public function testArch2Gnu(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('x86_64', arch2gnu('x86_64'));
|
||||||
|
$this->assertEquals('x86_64', arch2gnu('x64'));
|
||||||
|
$this->assertEquals('x86_64', arch2gnu('amd64'));
|
||||||
|
$this->assertEquals('aarch64', arch2gnu('arm64'));
|
||||||
|
$this->assertEquals('aarch64', arch2gnu('aarch64'));
|
||||||
|
$this->expectException('SPC\exception\WrongUsageException');
|
||||||
|
arch2gnu('armv7');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testQuote(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('"hello"', quote('hello'));
|
||||||
|
$this->assertEquals("'hello'", quote('hello', "'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function testFPassthru(): void
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
$this->markTestSkipped('Windows not support f_passthru');
|
||||||
|
}
|
||||||
|
$this->assertEquals(null, f_passthru('echo ""'));
|
||||||
|
$this->expectException('SPC\exception\RuntimeException');
|
||||||
|
f_passthru('false');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFPutenv(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(f_putenv('SPC_TEST_ENV=1'));
|
||||||
|
$this->assertEquals('1', getenv('SPC_TEST_ENV'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShell(): void
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
$this->markTestSkipped('Windows not support shell');
|
||||||
|
}
|
||||||
|
$shell = shell();
|
||||||
|
$this->assertInstanceOf('SPC\util\UnixShell', $shell);
|
||||||
|
$this->assertInstanceOf('SPC\util\UnixShell', $shell->cd('/'));
|
||||||
|
$this->assertInstanceOf('SPC\util\UnixShell', $shell->exec('echo ""'));
|
||||||
|
$this->assertInstanceOf('SPC\util\UnixShell', $shell->setEnv(['SPC_TEST_ENV' => '1']));
|
||||||
|
|
||||||
|
[$code, $out] = $shell->execWithResult('echo "_"');
|
||||||
|
$this->assertEquals(0, $code);
|
||||||
|
$this->assertEquals('_', implode('', $out));
|
||||||
|
|
||||||
|
$this->expectException('SPC\exception\RuntimeException');
|
||||||
|
$shell->exec('false');
|
||||||
|
}
|
||||||
|
}
|
||||||
96
tests/SPC/store/ConfigTest.php
Normal file
96
tests/SPC/store/ConfigTest.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\store;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Config;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class ConfigTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
$testdir = WORKING_DIR . '/.configtest';
|
||||||
|
FileSystem::createDir($testdir);
|
||||||
|
FileSystem::writeFile($testdir . '/lib.json', file_get_contents(ROOT_DIR . '/config/lib.json'));
|
||||||
|
FileSystem::writeFile($testdir . '/ext.json', file_get_contents(ROOT_DIR . '/config/ext.json'));
|
||||||
|
FileSystem::writeFile($testdir . '/source.json', file_get_contents(ROOT_DIR . '/config/source.json'));
|
||||||
|
FileSystem::loadConfigArray('lib', $testdir);
|
||||||
|
FileSystem::loadConfigArray('ext', $testdir);
|
||||||
|
FileSystem::loadConfigArray('source', $testdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function tearDownAfterClass(): void
|
||||||
|
{
|
||||||
|
FileSystem::removeDir(WORKING_DIR . '/.configtest');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetExts()
|
||||||
|
{
|
||||||
|
$this->assertTrue(is_assoc_array(Config::getExts()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
*/
|
||||||
|
public function testGetLib()
|
||||||
|
{
|
||||||
|
$this->assertIsArray(Config::getLib('zlib'));
|
||||||
|
match (PHP_OS_FAMILY) {
|
||||||
|
'FreeBSD', 'Darwin', 'Linux' => $this->assertStringEndsWith('.a', Config::getLib('zlib', 'static-libs', [])[0]),
|
||||||
|
'Windows' => $this->assertStringEndsWith('.lib', Config::getLib('zlib', 'static-libs', [])[0]),
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetExt()
|
||||||
|
{
|
||||||
|
$this->assertIsArray(Config::getExt('bcmath'));
|
||||||
|
$this->assertEquals('builtin', Config::getExt('bcmath', 'type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetSources()
|
||||||
|
{
|
||||||
|
$this->assertTrue(is_assoc_array(Config::getSources()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetSource()
|
||||||
|
{
|
||||||
|
$this->assertIsArray(Config::getSource('php-src'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetLibs()
|
||||||
|
{
|
||||||
|
$this->assertTrue(is_assoc_array(Config::getLibs()));
|
||||||
|
}
|
||||||
|
}
|
||||||
213
tests/SPC/store/FileSystemTest.php
Normal file
213
tests/SPC/store/FileSystemTest.php
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\store;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class FileSystemTest extends TestCase
|
||||||
|
{
|
||||||
|
private const TEST_FILE_CONTENT = 'Hello! Bye!';
|
||||||
|
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
if (file_put_contents(WORKING_DIR . '/.testfile', self::TEST_FILE_CONTENT) === false) {
|
||||||
|
static::markTestSkipped('Current environment or working dir is not writable!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass(): void
|
||||||
|
{
|
||||||
|
if (file_exists(WORKING_DIR . '/.testfile')) {
|
||||||
|
unlink(WORKING_DIR . '/.testfile');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testReplaceFileRegex()
|
||||||
|
{
|
||||||
|
$file = WORKING_DIR . '/.txt1';
|
||||||
|
file_put_contents($file, 'hello');
|
||||||
|
|
||||||
|
FileSystem::replaceFileRegex($file, '/ll/', '11');
|
||||||
|
$this->assertEquals('he11o', file_get_contents($file));
|
||||||
|
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindCommandPath()
|
||||||
|
{
|
||||||
|
$this->assertNull(FileSystem::findCommandPath('randomtestxxxxx'));
|
||||||
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
|
$this->assertIsString(FileSystem::findCommandPath('explorer'));
|
||||||
|
} elseif (in_array(PHP_OS_FAMILY, ['Linux', 'Darwin', 'FreeBSD'])) {
|
||||||
|
$this->assertIsString(FileSystem::findCommandPath('uname'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testReadFile()
|
||||||
|
{
|
||||||
|
$file = WORKING_DIR . '/.testread';
|
||||||
|
file_put_contents($file, 'haha');
|
||||||
|
$content = FileSystem::readFile($file);
|
||||||
|
$this->assertEquals('haha', $content);
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testReplaceFileUser()
|
||||||
|
{
|
||||||
|
$file = WORKING_DIR . '/.txt1';
|
||||||
|
file_put_contents($file, 'hello');
|
||||||
|
|
||||||
|
FileSystem::replaceFileUser($file, function ($file) {
|
||||||
|
return str_replace('el', '55', $file);
|
||||||
|
});
|
||||||
|
$this->assertEquals('h55lo', file_get_contents($file));
|
||||||
|
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtname()
|
||||||
|
{
|
||||||
|
$this->assertEquals('exe', FileSystem::extname('/tmp/asd.exe'));
|
||||||
|
$this->assertEquals('', FileSystem::extname('/tmp/asd.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \ReflectionException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testGetClassesPsr4()
|
||||||
|
{
|
||||||
|
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\\builder\\extension');
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
$this->assertIsString($class);
|
||||||
|
new \ReflectionClass($class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConvertPath()
|
||||||
|
{
|
||||||
|
$this->assertEquals('phar://C:/pharfile.phar', FileSystem::convertPath('phar://C:/pharfile.phar'));
|
||||||
|
if (DIRECTORY_SEPARATOR === '\\') {
|
||||||
|
$this->assertEquals('C:\Windows\win.ini', FileSystem::convertPath('C:\Windows/win.ini'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testCreateDir()
|
||||||
|
{
|
||||||
|
FileSystem::createDir(WORKING_DIR . '/.testdir');
|
||||||
|
$this->assertDirectoryExists(WORKING_DIR . '/.testdir');
|
||||||
|
rmdir(WORKING_DIR . '/.testdir');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testReplaceFileStr()
|
||||||
|
{
|
||||||
|
$file = WORKING_DIR . '/.txt1';
|
||||||
|
file_put_contents($file, 'hello');
|
||||||
|
|
||||||
|
FileSystem::replaceFileStr($file, 'el', '55');
|
||||||
|
$this->assertEquals('h55lo', file_get_contents($file));
|
||||||
|
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testResetDir()
|
||||||
|
{
|
||||||
|
// prepare fake git dir to test
|
||||||
|
FileSystem::createDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
FileSystem::writeFile(WORKING_DIR . '/.fake_down_test/a.c', 'int main() { return 0; }');
|
||||||
|
FileSystem::resetDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
$this->assertFileDoesNotExist(WORKING_DIR . '/.fake_down_test/a.c');
|
||||||
|
FileSystem::removeDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function testCopyDir()
|
||||||
|
{
|
||||||
|
// prepare fake git dir to test
|
||||||
|
FileSystem::createDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
FileSystem::writeFile(WORKING_DIR . '/.fake_down_test/a.c', 'int main() { return 0; }');
|
||||||
|
FileSystem::copyDir(WORKING_DIR . '/.fake_down_test', WORKING_DIR . '/.fake_down_test2');
|
||||||
|
$this->assertDirectoryExists(WORKING_DIR . '/.fake_down_test2');
|
||||||
|
$this->assertFileExists(WORKING_DIR . '/.fake_down_test2/a.c');
|
||||||
|
FileSystem::removeDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
FileSystem::removeDir(WORKING_DIR . '/.fake_down_test2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testRemoveDir()
|
||||||
|
{
|
||||||
|
FileSystem::createDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
$this->assertDirectoryExists(WORKING_DIR . '/.fake_down_test');
|
||||||
|
FileSystem::removeDir(WORKING_DIR . '/.fake_down_test');
|
||||||
|
$this->assertDirectoryDoesNotExist(WORKING_DIR . '/.fake_down_test');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testLoadConfigArray()
|
||||||
|
{
|
||||||
|
$arr = FileSystem::loadConfigArray('lib');
|
||||||
|
$this->assertArrayHasKey('zlib', $arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsRelativePath()
|
||||||
|
{
|
||||||
|
$this->assertTrue(FileSystem::isRelativePath('.'));
|
||||||
|
$this->assertTrue(FileSystem::isRelativePath('.\\sdf'));
|
||||||
|
if (DIRECTORY_SEPARATOR === '\\') {
|
||||||
|
$this->assertFalse(FileSystem::isRelativePath('C:\\asdasd/fwe\asd'));
|
||||||
|
} else {
|
||||||
|
$this->assertFalse(FileSystem::isRelativePath('/fwefwefewf'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testScanDirFiles()
|
||||||
|
{
|
||||||
|
$this->assertFalse(FileSystem::scanDirFiles('wfwefewfewf'));
|
||||||
|
$files = FileSystem::scanDirFiles(ROOT_DIR . '/config', true, true);
|
||||||
|
$this->assertContains('lib.json', $files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function testWriteFile()
|
||||||
|
{
|
||||||
|
FileSystem::writeFile(WORKING_DIR . '/.txt', 'txt');
|
||||||
|
$this->assertFileExists(WORKING_DIR . '/.txt');
|
||||||
|
$this->assertEquals('txt', FileSystem::readFile(WORKING_DIR . '/.txt'));
|
||||||
|
unlink(WORKING_DIR . '/.txt');
|
||||||
|
}
|
||||||
|
}
|
||||||
172
tests/SPC/util/ConfigValidatorTest.php
Normal file
172
tests/SPC/util/ConfigValidatorTest.php
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\util;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\exception\ValidationException;
|
||||||
|
use SPC\util\ConfigValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class ConfigValidatorTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testValidateSourceGood(): void
|
||||||
|
{
|
||||||
|
$good_source = [
|
||||||
|
'source1' => [
|
||||||
|
'type' => 'filelist',
|
||||||
|
'url' => 'https://example.com',
|
||||||
|
'regex' => '.*',
|
||||||
|
],
|
||||||
|
'source2' => [
|
||||||
|
'type' => 'git',
|
||||||
|
'url' => 'https://example.com',
|
||||||
|
'rev' => 'master',
|
||||||
|
],
|
||||||
|
'source3' => [
|
||||||
|
'type' => 'ghtagtar',
|
||||||
|
'repo' => 'aaaa/bbbb',
|
||||||
|
],
|
||||||
|
'source4' => [
|
||||||
|
'type' => 'ghtar',
|
||||||
|
'repo' => 'aaa/bbb',
|
||||||
|
'path' => 'path/to/dir',
|
||||||
|
],
|
||||||
|
'source5' => [
|
||||||
|
'type' => 'ghrel',
|
||||||
|
'repo' => 'aaa/bbb',
|
||||||
|
'match' => '.*',
|
||||||
|
],
|
||||||
|
'source6' => [
|
||||||
|
'type' => 'url',
|
||||||
|
'url' => 'https://example.com',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateSource($good_source);
|
||||||
|
$this->assertTrue(true);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$this->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateSourceBad(): void
|
||||||
|
{
|
||||||
|
$bad_source = [
|
||||||
|
'source1' => [
|
||||||
|
'type' => 'filelist',
|
||||||
|
'url' => 'https://example.com',
|
||||||
|
// no regex
|
||||||
|
],
|
||||||
|
'source2' => [
|
||||||
|
'type' => 'git',
|
||||||
|
'url' => true, // not string
|
||||||
|
'rev' => 'master',
|
||||||
|
],
|
||||||
|
'source3' => [
|
||||||
|
'type' => 'ghtagtar',
|
||||||
|
'url' => 'aaaa/bbbb', // not repo
|
||||||
|
],
|
||||||
|
'source4' => [
|
||||||
|
'type' => 'ghtar',
|
||||||
|
'repo' => 'aaa/bbb',
|
||||||
|
'path' => true, // not string
|
||||||
|
],
|
||||||
|
'source5' => [
|
||||||
|
'type' => 'ghrel',
|
||||||
|
'repo' => 'aaa/bbb',
|
||||||
|
'match' => 1, // not string
|
||||||
|
],
|
||||||
|
'source6' => [
|
||||||
|
'type' => 'url', // no url
|
||||||
|
],
|
||||||
|
];
|
||||||
|
foreach ($bad_source as $name => $src) {
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateSource([$name => $src]);
|
||||||
|
$this->fail("should throw ValidationException for source {$name}");
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateLibsGood(): void
|
||||||
|
{
|
||||||
|
$good_libs = [
|
||||||
|
'lib1' => [
|
||||||
|
'source' => 'source1',
|
||||||
|
],
|
||||||
|
'lib2' => [
|
||||||
|
'source' => 'source2',
|
||||||
|
'lib-depends' => [
|
||||||
|
'lib1',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'lib3' => [
|
||||||
|
'source' => 'source3',
|
||||||
|
'lib-suggests' => [
|
||||||
|
'lib1',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs($good_libs, ['source1' => [], 'source2' => [], 'source3' => []]);
|
||||||
|
$this->assertTrue(true);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$this->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateLibsBad(): void
|
||||||
|
{
|
||||||
|
// lib.json is broken
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs('not array');
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib source not exists
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source3']], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// source must be string
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => true]], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib-depends must be list
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source1', 'lib-depends' => ['a' => 'not list']]], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib-suggests must be list
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source1', 'lib-suggests' => ['a' => 'not list']]], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public function testValidateExts(): void
|
||||||
|
{
|
||||||
|
ConfigValidator::validateExts([]);
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
ConfigValidator::validateExts(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,13 @@ use SPC\util\LicenseDumper;
|
|||||||
*/
|
*/
|
||||||
final class LicenseDumperTest extends TestCase
|
final class LicenseDumperTest extends TestCase
|
||||||
{
|
{
|
||||||
private const DIRECTORY = '../../var/license-dump';
|
private const DIRECTORY = __DIR__ . '/../../var/license-dump';
|
||||||
|
|
||||||
|
public static function tearDownAfterClass(): void
|
||||||
|
{
|
||||||
|
@rmdir(self::DIRECTORY);
|
||||||
|
@rmdir(dirname(self::DIRECTORY));
|
||||||
|
}
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user