mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
Merge branch 'main' into feat/gnu-static
# Conflicts: # src/SPC/builder/linux/LinuxBuilder.php
This commit is contained in:
commit
23bfad6f87
8
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
8
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Build PHP or library failed, download failed, doesn't seem to work...
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: crazywhalecc
|
||||
|
||||
---
|
||||
8
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
8
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: new feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
10
.github/ISSUE_TEMPLATE/something-want-to-know.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/something-want-to-know.md
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Something want to know
|
||||
about: Describe your question about static-php, we will reply ASAP
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@ -7,6 +7,7 @@
|
||||
> If your PR involves the changes mentioned below and completed the action, please tick the corresponding option.
|
||||
> If a modification is not involved, please skip it directly.
|
||||
|
||||
- [ ] If you modified `*.php`, run `composer cs-fix` at local machine.
|
||||
- [ ] If it's an extension or dependency update, make sure adding related extensions in `src/global/test-extensions.php`.
|
||||
- [ ] If you changed the behavior of static-php-cli, update docs in `./docs/`.
|
||||
- [ ] If you updated `config/xxx.json` content, run `bin/spc dev:sort-config xxx`.
|
||||
|
||||
2
.github/workflows/build-unix.yml
vendored
2
.github/workflows/build-unix.yml
vendored
@ -129,7 +129,7 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ inputs.php-version }}
|
||||
php-version: 8.4
|
||||
tools: pecl, composer
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
|
||||
2
.github/workflows/build-windows-x86_64.yml
vendored
2
.github/workflows/build-windows-x86_64.yml
vendored
@ -6,7 +6,7 @@ on:
|
||||
version:
|
||||
required: true
|
||||
description: php version to compile
|
||||
default: '8.2'
|
||||
default: '8.4'
|
||||
type: choice
|
||||
options:
|
||||
- '8.4'
|
||||
|
||||
2
.github/workflows/ext-matrix-tests.yml
vendored
2
.github/workflows/ext-matrix-tests.yml
vendored
@ -113,7 +113,7 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.2
|
||||
php-version: 8.4
|
||||
tools: pecl, composer
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
|
||||
4
.github/workflows/release-build.yml
vendored
4
.github/workflows/release-build.yml
vendored
@ -9,8 +9,8 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
PHP_VERSION: 8.2
|
||||
MICRO_VERSION: 8.2.18
|
||||
PHP_VERSION: 8.4
|
||||
MICRO_VERSION: 8.4.4
|
||||
|
||||
jobs:
|
||||
build-release-artifacts:
|
||||
|
||||
13
.github/workflows/tests.yml
vendored
13
.github/workflows/tests.yml
vendored
@ -34,13 +34,13 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.4'
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
tools: pecl, composer, php-cs-fixer
|
||||
|
||||
- name: Run PHP-CS-Fixer fix
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
run: PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
||||
phpstan:
|
||||
runs-on: ubuntu-latest
|
||||
@ -52,7 +52,7 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.4'
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
tools: composer
|
||||
@ -79,9 +79,6 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- php: '8.1'
|
||||
- php: '8.2'
|
||||
- php: '8.3'
|
||||
- php: '8.4'
|
||||
|
||||
steps:
|
||||
@ -125,7 +122,7 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.2
|
||||
php-version: 8.4
|
||||
|
||||
- name: Define
|
||||
id: gendef
|
||||
@ -153,7 +150,7 @@ jobs:
|
||||
- name: "Setup PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.2
|
||||
php-version: 8.4
|
||||
tools: pecl, composer
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
|
||||
2
.github/workflows/vitepress-deploy.yml
vendored
2
.github/workflows/vitepress-deploy.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
with:
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
php-version: 8.2
|
||||
php-version: 8.4
|
||||
ini-values: memory_limit=-1
|
||||
|
||||
- name: "Get Composer Cache Directory"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,6 +32,7 @@ packlib_files.txt
|
||||
!/bin/spc*
|
||||
!/bin/setup-runtime*
|
||||
!/bin/spc-alpine-docker
|
||||
!/bin/php-cs-fixer-wrapper
|
||||
|
||||
# exclude windows build tools
|
||||
/php-sdk-binary-tools/
|
||||
|
||||
@ -64,6 +64,8 @@ return (new PhpCsFixer\Config())
|
||||
'php_unit_test_class_requires_covers' => false,
|
||||
'phpdoc_var_without_name' => false,
|
||||
'fully_qualified_strict_types' => false,
|
||||
'operator_linebreak' => false,
|
||||
'php_unit_data_provider_method_order' => false,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
|
||||
|
||||
@ -58,7 +58,7 @@ static-php-cli(简称 `spc`)有许多特性:
|
||||
|
||||
### 编译环境需求
|
||||
|
||||
- PHP >= 8.1(这是 spc 自身需要的版本,不是支持的构建版本)
|
||||
- PHP >= 8.4(这是 spc 自身需要的版本,不是支持的构建版本)
|
||||
- 扩展:`mbstring,tokenizer,phar`
|
||||
- 系统安装了 `curl` 和 `git`
|
||||
|
||||
@ -180,6 +180,9 @@ bin/spc --version
|
||||
# 检查环境依赖,并根据尝试自动安装缺失的编译工具
|
||||
./bin/spc doctor --auto-fix
|
||||
|
||||
# 输出目标项目依赖的扩展列表
|
||||
./bin/spc dump-extensions /path/to/your/project --format=text
|
||||
|
||||
# 拉取所有依赖库
|
||||
./bin/spc download --all
|
||||
# 只拉取编译指定扩展需要的所有依赖(推荐)
|
||||
|
||||
@ -67,7 +67,7 @@ which can be downloaded directly according to your needs.
|
||||
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 extensions mentioned below.
|
||||
|
||||
- PHP >= 8.1 (This is the version required by spc itself, not the build version)
|
||||
- PHP >= 8.4 (This is the version required by spc itself, not the build version)
|
||||
- Extension: `mbstring,tokenizer,phar`
|
||||
- Supported OS with `curl` and `git` installed
|
||||
|
||||
@ -194,6 +194,8 @@ Basic usage for building php with some extensions:
|
||||
|
||||
# fetch all libraries
|
||||
./bin/spc download --all
|
||||
# dump a list of extensions required by your project
|
||||
./bin/spc dump-extensions /path/to/your/project --format=text
|
||||
# only fetch necessary sources by needed extensions (recommended)
|
||||
./bin/spc download --for-extensions="openssl,pcntl,mbstring,pdo_sqlite"
|
||||
# download pre-built libraries first (save time for compiling dependencies)
|
||||
|
||||
4
bin/php-cs-fixer-wrapper
Executable file
4
bin/php-cs-fixer-wrapper
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# get parent dir, and run the php-cs-fixer
|
||||
PHP_CS_FIXER_IGNORE_ENV=1 "$(dirname "$0")/../vendor/bin/php-cs-fixer" "$@"
|
||||
@ -25,7 +25,7 @@ __DIR__=$(cd "$(dirname "$0")" && pwd)
|
||||
__PROJECT__=$(cd "${__DIR__}"/../ && pwd)
|
||||
|
||||
# set download dir
|
||||
__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.4.4-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
||||
__COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar"
|
||||
|
||||
# use china mirror
|
||||
@ -45,7 +45,7 @@ done
|
||||
|
||||
case "$mirror" in
|
||||
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.4.4-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
|
||||
__COMPOSER_URL__="https://mirrors.tencent.com/composer/composer.phar"
|
||||
;;
|
||||
|
||||
@ -61,7 +61,7 @@ test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_
|
||||
test -f "${__DIR__}"/php || { tar -xf "${__PROJECT__}"/downloads/runtime.tar.gz -C "${__DIR__}"/ ; }
|
||||
chmod +x "${__DIR__}"/php
|
||||
# download composer
|
||||
test -f "${__DIR__}"/composer || curl -#fSL -o "${__DIR__}"/composer "$__COMPOSER_URL__"
|
||||
test -f "${__DIR__}"/composer || { echo "Downloading Composer from $__COMPOSER_URL__" && curl -#fSL -o "${__DIR__}"/composer "$__COMPOSER_URL__" ; }
|
||||
chmod +x "${__DIR__}"/composer
|
||||
# sanity check for php and composer
|
||||
"${__DIR__}"/php -v >/dev/null || { echo "Failed to run php" && exit 1; }
|
||||
|
||||
@ -51,7 +51,7 @@ if ($action -eq 'add-path') {
|
||||
}
|
||||
|
||||
# get php 8.1 specific version
|
||||
$API = (Invoke-WebRequest -Uri "https://www.php.net/releases/index.php?json&version=8.3") | ConvertFrom-Json
|
||||
$API = (Invoke-WebRequest -Uri "https://www.php.net/releases/index.php?json&version=8.4") | ConvertFrom-Json
|
||||
|
||||
# php windows download
|
||||
$PHPRuntimeUrl = "https://windows.php.net/downloads/releases/php-" + $API.version + "-nts-Win32-vs16-x64.zip"
|
||||
|
||||
5
bin/spc
5
bin/spc
@ -17,6 +17,11 @@ if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
|
||||
exec('CHCP 65001');
|
||||
}
|
||||
|
||||
// Print deprecation notice on PHP < 8.4, use red and highlight background
|
||||
if (PHP_VERSION_ID < 80400) {
|
||||
echo "\e[43mDeprecation Notice: PHP < 8.4 is deprecated, please upgrade your PHP version.\e[0m\n";
|
||||
}
|
||||
|
||||
try {
|
||||
(new ConsoleApplication())->run();
|
||||
} catch (Exception $e) {
|
||||
|
||||
@ -50,9 +50,9 @@ else
|
||||
fi
|
||||
|
||||
# Detect docker env is setup
|
||||
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
|
||||
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH-v2; then
|
||||
echo "Docker container does not exist. Building docker image ..."
|
||||
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH -f- . <<EOF
|
||||
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH-v2 -f- . <<EOF
|
||||
FROM $ALPINE_FROM
|
||||
$SPC_USE_MIRROR
|
||||
RUN apk update; \
|
||||
@ -79,21 +79,16 @@ RUN apk update; \
|
||||
linux-headers \
|
||||
m4 \
|
||||
make \
|
||||
php82 \
|
||||
php82-common \
|
||||
php82-pcntl \
|
||||
php82-phar \
|
||||
php82-posix \
|
||||
php82-sodium \
|
||||
php82-tokenizer \
|
||||
php82-dom \
|
||||
php82-xml \
|
||||
php82-xmlwriter \
|
||||
composer \
|
||||
pkgconfig \
|
||||
wget \
|
||||
xz
|
||||
|
||||
RUN curl -#fSL https://dl.static-php.dev/static-php-cli/bulk/php-8.4.4-cli-linux-\$(uname -m).tar.gz | tar -xz -C /usr/local/bin && \
|
||||
chmod +x /usr/local/bin/php
|
||||
|
||||
RUN curl -#fSL https://getcomposer.org/download/latest-stable/composer.phar -o /usr/local/bin/composer && \
|
||||
chmod +x /usr/local/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
ADD ./src /app/src
|
||||
COPY ./composer.* /app/
|
||||
@ -124,4 +119,4 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
|
||||
# shellcheck disable=SC2068
|
||||
# shellcheck disable=SC2086
|
||||
# shellcheck disable=SC2090
|
||||
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH bin/spc $@
|
||||
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">= 8.1",
|
||||
"php": ">= 8.3",
|
||||
"ext-mbstring": "*",
|
||||
"ext-zlib": "*",
|
||||
"laravel/prompts": "^0.1.12",
|
||||
@ -19,7 +19,7 @@
|
||||
"require-dev": {
|
||||
"captainhook/captainhook-phar": "^5.23",
|
||||
"captainhook/hook-installer": "^1.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.25",
|
||||
"friendsofphp/php-cs-fixer": "^3.60",
|
||||
"humbug/box": "^4.5.0 || ^4.6.0",
|
||||
"nunomaduro/collision": "^7.8",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
@ -44,7 +44,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"analyse": "phpstan analyse --memory-limit 300M",
|
||||
"cs-fix": "php-cs-fixer fix",
|
||||
"cs-fix": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix",
|
||||
"test": "vendor/bin/phpunit tests/ --no-coverage",
|
||||
"build:phar": "vendor/bin/box compile"
|
||||
},
|
||||
|
||||
2702
composer.lock
generated
2702
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -355,10 +355,8 @@
|
||||
"type": "external",
|
||||
"source": "ext-memcache",
|
||||
"arg-type": "custom",
|
||||
"lib-depends": [
|
||||
"zlib"
|
||||
],
|
||||
"ext-depends": [
|
||||
"zlib",
|
||||
"session"
|
||||
]
|
||||
},
|
||||
@ -445,6 +443,13 @@
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"opentelemetry": {
|
||||
"support": {
|
||||
"BSD": "wip"
|
||||
},
|
||||
"type": "external",
|
||||
"source": "opentelemetry"
|
||||
},
|
||||
"parallel": {
|
||||
"support": {
|
||||
"BSD": "wip"
|
||||
|
||||
@ -1,4 +1,29 @@
|
||||
{
|
||||
"lib-base": {
|
||||
"type": "root",
|
||||
"lib-depends-unix": [
|
||||
"pkg-config"
|
||||
]
|
||||
},
|
||||
"php": {
|
||||
"type": "root",
|
||||
"source": "php-src",
|
||||
"lib-depends": [
|
||||
"micro",
|
||||
"lib-base"
|
||||
]
|
||||
},
|
||||
"micro": {
|
||||
"type": "target",
|
||||
"source": "micro"
|
||||
},
|
||||
"pkg-config": {
|
||||
"type": "package",
|
||||
"source": "pkg-config",
|
||||
"bin-unix": [
|
||||
"pkg-config"
|
||||
]
|
||||
},
|
||||
"brotli": {
|
||||
"source": "brotli",
|
||||
"static-libs-unix": [
|
||||
@ -34,7 +59,7 @@
|
||||
"libcurl.a"
|
||||
],
|
||||
"static-libs-windows": [
|
||||
"libcurl_a.lib"
|
||||
"libcurl.lib"
|
||||
],
|
||||
"headers": [
|
||||
"curl"
|
||||
@ -599,9 +624,6 @@
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"pkg-config": {
|
||||
"source": "pkg-config"
|
||||
},
|
||||
"postgresql": {
|
||||
"source": "postgresql",
|
||||
"static-libs-unix": [
|
||||
|
||||
@ -683,6 +683,16 @@
|
||||
"path": "LICENSE.txt"
|
||||
}
|
||||
},
|
||||
"opentelemetry": {
|
||||
"type": "url",
|
||||
"url": "https://pecl.php.net/get/opentelemetry",
|
||||
"path": "php-src/ext/opentelemetry",
|
||||
"filename": "opentelemetry.tgz",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"parallel": {
|
||||
"type": "url",
|
||||
"url": "https://pecl.php.net/get/parallel",
|
||||
|
||||
@ -57,56 +57,6 @@ cd static-php-cli
|
||||
composer update
|
||||
```
|
||||
|
||||
### Use System PHP
|
||||
|
||||
Below are some example commands for installing PHP and Composer in the system.
|
||||
It is recommended to search for the specific installation method yourself or ask the AI search engine to obtain the answer,
|
||||
which will not be elaborated here.
|
||||
|
||||
```bash
|
||||
# [macOS], need install Homebrew first. See https://brew.sh/
|
||||
# Remember change your composer executable path. For M1/M2 Chip mac, "/opt/homebrew/bin/", for Intel mac, "/usr/local/bin/". Or add it to your own path.
|
||||
brew install php wget
|
||||
wget https://getcomposer.org/download/latest-stable/composer.phar -O /path/to/your/bin/composer && chmod +x /path/to/your/bin/composer
|
||||
|
||||
# [Debian], you need to make sure your php version >= 8.1 and composer >= 2.0
|
||||
sudo apt install php-cli composer php-tokenizer
|
||||
|
||||
# [Alpine]
|
||||
apk add bash file wget xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
|
||||
```
|
||||
|
||||
::: tip
|
||||
Currently, some versions of Ubuntu install older PHP versions,
|
||||
so no installation commands are provided. If necessary, it is recommended to add software sources such as ppa first,
|
||||
and then install the latest version of PHP and tokenizer, XML, and phar extensions.
|
||||
|
||||
Older versions of Debian may have an older (<= 7.4) version of PHP installed by default, it is recommended to upgrade Debian first.
|
||||
:::
|
||||
|
||||
### Use Docker
|
||||
|
||||
If you don't want to install PHP and Composer runtime environment on your system, you can use the built-in Docker environment build script.
|
||||
|
||||
```bash
|
||||
# To use directly, replace `bin/spc` with `bin/spc-alpine-docker` in all used commands
|
||||
bin/spc-alpine-docker
|
||||
```
|
||||
|
||||
The first time the command is executed, `docker build` will be used to build a Docker image.
|
||||
The default built Docker image is the `x86_64` architecture, and the image name is `cwcc-spc-x86_64`.
|
||||
|
||||
If you want to build `aarch64` static-php-cli in `x86_64` environment,
|
||||
you can use qemu to emulate the arm image to run Docker, but the speed will be very slow.
|
||||
Use command: `SPC_USE_ARCH=aarch64 bin/spc-alpine-docker`.
|
||||
|
||||
If it prompts that sudo is required to run after running,
|
||||
execute the following command once to grant static-php-cli permission to execute sudo:
|
||||
|
||||
```bash
|
||||
export SPC_USE_SUDO=yes
|
||||
```
|
||||
|
||||
### Use Precompiled Static PHP Binaries
|
||||
|
||||
If you don't want to use Docker and install PHP in the system,
|
||||
@ -133,6 +83,56 @@ This script will download two files in total: `bin/php` and `bin/composer`. Afte
|
||||
it is equivalent to installing PHP in the system, you can directly Use commands such as `composer`, `php -v`, or directly use `bin/spc`.
|
||||
2. Direct call, such as executing static-php-cli command: `bin/php bin/spc --help`, executing Composer: `bin/php bin/composer update`.
|
||||
|
||||
### Use Docker
|
||||
|
||||
If you don't want to install PHP and Composer runtime environment on your system, you can use the built-in Docker environment build script.
|
||||
|
||||
```bash
|
||||
# To use directly, replace `bin/spc` with `bin/spc-alpine-docker` in all used commands
|
||||
bin/spc-alpine-docker
|
||||
```
|
||||
|
||||
The first time the command is executed, `docker build` will be used to build a Docker image.
|
||||
The default built Docker image is the `x86_64` architecture, and the image name is `cwcc-spc-x86_64`.
|
||||
|
||||
If you want to build `aarch64` static-php-cli in `x86_64` environment,
|
||||
you can use qemu to emulate the arm image to run Docker, but the speed will be very slow.
|
||||
Use command: `SPC_USE_ARCH=aarch64 bin/spc-alpine-docker`.
|
||||
|
||||
If it prompts that sudo is required to run after running,
|
||||
execute the following command once to grant static-php-cli permission to execute sudo:
|
||||
|
||||
```bash
|
||||
export SPC_USE_SUDO=yes
|
||||
```
|
||||
|
||||
### Use System PHP
|
||||
|
||||
Below are some example commands for installing PHP and Composer in the system.
|
||||
It is recommended to search for the specific installation method yourself or ask the AI search engine to obtain the answer,
|
||||
which will not be elaborated here.
|
||||
|
||||
```bash
|
||||
# [macOS], need install Homebrew first. See https://brew.sh/
|
||||
# Remember change your composer executable path. For M1/M2 Chip mac, "/opt/homebrew/bin/", for Intel mac, "/usr/local/bin/". Or add it to your own path.
|
||||
brew install php wget
|
||||
wget https://getcomposer.org/download/latest-stable/composer.phar -O /path/to/your/bin/composer && chmod +x /path/to/your/bin/composer
|
||||
|
||||
# [Debian], you need to make sure your php version >= 8.1 and composer >= 2.0
|
||||
sudo apt install php-cli composer php-tokenizer
|
||||
|
||||
# [Alpine]
|
||||
apk add bash file wget xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
|
||||
```
|
||||
|
||||
::: tip
|
||||
Currently, some versions of Ubuntu install older PHP versions,
|
||||
so no installation commands are provided. If necessary, it is recommended to add software sources such as ppa first,
|
||||
and then install the latest version of PHP and tokenizer, XML, and phar extensions.
|
||||
|
||||
Older versions of Debian may have an older (<= 7.4) version of PHP installed by default, it is recommended to upgrade Debian first.
|
||||
:::
|
||||
|
||||
## Command - download
|
||||
|
||||
Use the command `bin/spc download` to download the source code required for compilation,
|
||||
@ -397,6 +397,31 @@ manually unpack and copy the package to a specified location, and we can use com
|
||||
bin/spc extract php-src,libxml2
|
||||
```
|
||||
|
||||
## Command - dump-extensions
|
||||
|
||||
Use the command `bin/spc dump-extensions` to export required extensions of the current project.
|
||||
|
||||
```bash
|
||||
# Print the extension list of the project, pass in the root directory of the project containing composer.json
|
||||
bin/spc dump-extensions /path/to/your/project/
|
||||
|
||||
# Print the extension list of the project, excluding development dependencies
|
||||
bin/spc dump-extensions /path-to/tour/project/ --no-dev
|
||||
|
||||
# Output in the extension list format acceptable to the spc command (comma separated)
|
||||
bin/spc dump-extensions /path-to/tour/project/ --format=text
|
||||
|
||||
# Output as a JSON list
|
||||
bin/spc dump-extensions /path-to/tour/project/ --format=json
|
||||
|
||||
# When the project does not have any extensions, output the specified extension combination instead of returning failure
|
||||
bin/spc dump-extensions /path-to/your/project/ --no-ext-output=mbstring,posix,pcntl,phar
|
||||
|
||||
# Do not exclude extensions not supported by spc when outputting
|
||||
bin/spc dump-extensions /path/to/your/project/ --no-spc-filter
|
||||
```
|
||||
It should be noted that the project directory must contain the `vendor/installed.json` and `composer.lock` files, otherwise they cannot be found normally.
|
||||
|
||||
## Dev Command - dev
|
||||
|
||||
Debug commands refer to a collection of commands that can assist in outputting some information
|
||||
|
||||
@ -8,8 +8,15 @@ here will describe how to check the errors by yourself and report Issue.
|
||||
Problems with downloading resources are one of the most common problems with spc.
|
||||
The main reason is that the addresses used for SPC download resources are generally the official website of the corresponding project or GitHub, etc.,
|
||||
and these websites may occasionally go down and block IP addresses.
|
||||
Currently, version 2.0.0 has not added an automatic retry mechanism, so after encountering a download failure,
|
||||
you can try to call the download command multiple times. If you confirm that the address is indeed inaccessible,
|
||||
After encountering a download failure,
|
||||
you can try to call the download command multiple times.
|
||||
|
||||
When downloading extensions, you may eventually see errors like `curl: (56) The requested URL returned error: 403` which are often caused by github rate limiting.
|
||||
You can verify this by adding `--debug` to the command and will see something like `[DEBU] Running command (no output) : curl -sfSL "https://api.github.com/repos/openssl/openssl/releases"`.
|
||||
|
||||
To fix this, [create](https://github.com/settings/tokens) a personal access token on GitHub and set it as an environment variable `GITHUB_TOKEN=<XXX>`.
|
||||
|
||||
If you confirm that the address is indeed inaccessible,
|
||||
you can submit an Issue or PR to update the url or download type.
|
||||
|
||||
## Doctor Can't Fix Something
|
||||
|
||||
@ -50,29 +50,29 @@ cd static-php-cli
|
||||
composer update
|
||||
```
|
||||
|
||||
### 使用系统 PHP 环境
|
||||
### 使用预编译静态 PHP 二进制运行 static-php-cli
|
||||
|
||||
下面是系统安装 PHP、Composer 的一些示例命令。具体安装方式建议自行搜索或询问 AI 搜索引擎获取答案,这里不多赘述。
|
||||
如果你不想使用 Docker、在系统内安装 PHP,可以直接下载本项目自身编译好的 php 二进制 cli 程序。使用流程如下:
|
||||
|
||||
```bash
|
||||
# [macOS], 需要先安装 Homebrew. See https://brew.sh/
|
||||
# Remember change your composer executable path. For M1/M2 Chip mac, "/opt/homebrew/bin/", for Intel mac, "/usr/local/bin/". Or add it to your own path.
|
||||
brew install php wget
|
||||
wget https://getcomposer.org/download/latest-stable/composer.phar -O /path/to/your/bin/composer && chmod +x /path/to/your/bin/composer
|
||||
|
||||
# [Debian], you need to make sure your php version >= 8.1 and composer >= 2.0
|
||||
sudo apt install php-cli composer php-tokenizer
|
||||
|
||||
# [Alpine]
|
||||
apk add bash file wget xz php81 php81-common php81-pcntl php81-tokenizer php81-phar php81-posix php81-xml composer
|
||||
```
|
||||
使用命令部署环境,此脚本会从 [自托管的服务器](https://dl.static-php.dev/static-php-cli/) 下载一个当前操作系统的 php-cli 包,
|
||||
并从 [getcomposer](https://getcomposer.org/download/latest-stable/composer.phar) 或 [Aliyun(镜像)](https://mirrors.aliyun.com/composer/composer.phar) 下载 Composer。
|
||||
|
||||
::: tip
|
||||
目前 Ubuntu 部分版本的 apt 安装的 php 版本较旧,故不提供安装命令。如有需要,建议先添加 ppa 等软件源后,安装最新版的 PHP 以及 tokenizer、xml、phar 扩展。
|
||||
|
||||
较老版本的 Debian 默认安装的可能为旧版本(<= 7.4)版本的 PHP,建议先升级 Debian。
|
||||
使用预编译静态 PHP 二进制目前仅支持 Linux 和 macOS。FreeBSD 环境因为缺少自动化构建环境,所以暂不支持。
|
||||
:::
|
||||
|
||||
```bash
|
||||
bin/setup-runtime
|
||||
|
||||
# 对于中国大陆地区等网络环境特殊的用户,可使用镜像站加快下载速度
|
||||
bin/setup-runtime --mirror china
|
||||
```
|
||||
|
||||
此脚本总共会下载两个文件:`bin/php` 和 `bin/composer`,下载完成后,有两种使用方式:
|
||||
|
||||
1. 将 `bin/` 目录添加到 PATH 路径中:`export PATH="/path/to/your/static-php-cli/bin:$PATH"`,添加路径后,相当于系统安装了 PHP,可直接使用 `composer`、`php -v` 等命令,也可以直接使用 `bin/spc`。
|
||||
2. 直接调用,比如执行 static-php-cli 命令:`bin/php bin/spc --help`,执行 Composer:`bin/php bin/composer update`。
|
||||
|
||||
### 使用 Docker 环境
|
||||
|
||||
如果你不愿意在系统安装 PHP 和 Composer 运行环境,可以使用内置的 Docker 环境构建脚本。
|
||||
@ -92,28 +92,25 @@ bin/spc-alpine-docker
|
||||
export SPC_USE_SUDO=yes
|
||||
```
|
||||
|
||||
### 使用预编译静态 PHP 二进制
|
||||
### 使用系统 PHP 环境
|
||||
|
||||
如果你不想使用 Docker、在系统内安装 PHP,可以直接下载本项目自身编译好的 php 二进制 cli 程序。使用流程如下:
|
||||
|
||||
使用命令部署环境,此脚本会从 [自托管的服务器](https://dl.static-php.dev/static-php-cli/) 下载一个当前操作系统的 php-cli 包,
|
||||
并从 [getcomposer](https://getcomposer.org/download/latest-stable/composer.phar) 或 [Aliyun(镜像)](https://mirrors.aliyun.com/composer/composer.phar) 下载 Composer。
|
||||
|
||||
::: tip
|
||||
使用预编译静态 PHP 二进制目前仅支持 Linux 和 macOS。FreeBSD 环境因为缺少自动化构建环境,所以暂不支持。
|
||||
:::
|
||||
下面是系统安装 PHP、Composer 的一些示例命令。具体安装方式建议自行搜索或询问 AI 搜索引擎获取答案,这里不多赘述。
|
||||
|
||||
```bash
|
||||
bin/setup-runtime
|
||||
# [macOS], 需要先安装 Homebrew. See https://brew.sh/
|
||||
# Remember change your composer executable path. For M1/M2 Chip mac, "/opt/homebrew/bin/", for Intel mac, "/usr/local/bin/". Or add it to your own path.
|
||||
brew install php wget
|
||||
wget https://getcomposer.org/download/latest-stable/composer.phar -O /path/to/your/bin/composer && chmod +x /path/to/your/bin/composer
|
||||
|
||||
# 对于中国大陆地区等网络环境特殊的用户,可使用镜像站加快下载速度
|
||||
bin/setup-runtime --mirror china
|
||||
# [Debian], you need to make sure your php version >= 8.4 and composer >= 2.0
|
||||
sudo apt install php-cli composer php-tokenizer
|
||||
```
|
||||
|
||||
此脚本总共会下载两个文件:`bin/php` 和 `bin/composer`,下载完成后,有两种使用方式:
|
||||
::: tip
|
||||
目前 Ubuntu 部分版本的 apt 安装的 php 版本较旧,故不提供安装命令。如有需要,建议先添加 ppa 等软件源后,安装最新版的 PHP 以及 tokenizer、xml、phar 扩展。
|
||||
|
||||
1. 将 `bin/` 目录添加到 PATH 路径中:`export PATH="/path/to/your/static-php-cli/bin:$PATH"`,添加路径后,相当于系统安装了 PHP,可直接使用 `composer`、`php -v` 等命令,也可以直接使用 `bin/spc`。
|
||||
2. 直接调用,比如执行 static-php-cli 命令:`bin/php bin/spc --help`,执行 Composer:`bin/php bin/composer update`。
|
||||
较老版本的 Debian 默认安装的可能为旧版本(<= 8.3)版本的 PHP,建议先升级 Debian 或使用 Docker 或自带的静态二进制环境。
|
||||
:::
|
||||
|
||||
## 命令 download - 下载依赖包
|
||||
|
||||
@ -353,6 +350,32 @@ memory_limit=1G
|
||||
bin/spc extract php-src,libxml2
|
||||
```
|
||||
|
||||
## 命令 dump-extensions - 导出项目扩展依赖
|
||||
|
||||
使用命令 `bin/spc dump-extensions` 可以导出当前项目的扩展依赖。
|
||||
|
||||
```bash
|
||||
# 打印项目的扩展列表,传入项目包含composer.json的根目录
|
||||
bin/spc dump-extensions /path/to/your/project/
|
||||
|
||||
# 打印项目的扩展列表,不包含开发依赖
|
||||
bin/spc dump-extensions /path-to/tour/project/ --no-dev
|
||||
|
||||
# 输出为 spc 命令可接受的扩展列表格式(逗号分割)
|
||||
bin/spc dump-extensions /path-to/tour/project/ --format=text
|
||||
|
||||
# 输出为 JSON 列表
|
||||
bin/spc dump-extensions /path-to/tour/project/ --format=json
|
||||
|
||||
# 当项目没有任何扩展时,输出指定扩展组合,而不是返回失败
|
||||
bin/spc dump-extensions /path-to/your/project/ --no-ext-output=mbstring,posix,pcntl,phar
|
||||
|
||||
# 输出时不排除 spc 不支持的扩展
|
||||
bin/spc dump-extensions /path/to/your/project/ --no-spc-filter
|
||||
```
|
||||
|
||||
需要注意的是,项目的目录下必须包含 `vendor/installed.json` 和 `composer.lock` 文件,否则无法正常获取。
|
||||
|
||||
## 调试命令 dev - 调试命令集合
|
||||
|
||||
调试命令指的是你在使用 static-php-cli 构建 PHP 或改造、增强 static-php-cli 项目本身的时候,可以辅助输出一些信息的命令集合。
|
||||
|
||||
@ -5,7 +5,14 @@
|
||||
## 下载失败问题
|
||||
|
||||
下载资源问题是 spc 最常见的问题之一。主要是由于 spc 下载资源使用的地址一般均为对应项目的官方网站或 GitHub 等,而这些网站可能偶尔会宕机、屏蔽 IP 地址。
|
||||
目前 2.0.0 版本还没有加入自动重试机制,所以在遇到下载失败后,可以多次尝试调用下载命令。如果确认地址确实无法正常访问,可以提交 Issue 或 PR 更新地址。
|
||||
在遇到下载失败后,可以多次尝试调用下载命令。
|
||||
|
||||
当下载资源时,你可能最终会看到类似 `curl: (56) The requested URL returned error: 403` 的错误,这通常是由于 GitHub 限制导致的。
|
||||
你可以通过在命令中添加 `--debug` 来验证,会看到类似 `[DEBU] Running command (no output) : curl -sfSL "https://api.github.com/repos/openssl/openssl/releases"` 的输出。
|
||||
|
||||
要解决这个问题,可以在 GitHub 上 [创建](https://github.com/settings/token) 一个个人访问令牌,并将其设置为环境变量 `GITHUB_TOKEN=<XXX>`。
|
||||
|
||||
如果确认地址确实无法正常访问,可以提交 Issue 或 PR 更新地址。
|
||||
|
||||
## doctor 无法修复
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ use SPC\command\dev\PhpVerCommand;
|
||||
use SPC\command\dev\SortConfigCommand;
|
||||
use SPC\command\DoctorCommand;
|
||||
use SPC\command\DownloadCommand;
|
||||
use SPC\command\DumpExtensionsCommand;
|
||||
use SPC\command\DumpLicenseCommand;
|
||||
use SPC\command\ExtractCommand;
|
||||
use SPC\command\InstallPkgCommand;
|
||||
@ -31,7 +32,7 @@ use Symfony\Component\Console\Application;
|
||||
*/
|
||||
final class ConsoleApplication extends Application
|
||||
{
|
||||
public const VERSION = '2.4.4';
|
||||
public const VERSION = '2.5.0';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@ -54,6 +55,7 @@ final class ConsoleApplication extends Application
|
||||
new MicroCombineCommand(),
|
||||
new SwitchPhpVersionCommand(),
|
||||
new SPCConfigCommand(),
|
||||
new DumpExtensionsCommand(),
|
||||
|
||||
// Dev commands
|
||||
new AllExtCommand(),
|
||||
|
||||
@ -172,7 +172,7 @@ 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/ext-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 -n --ri "' . $this->getDistName() . '"', false);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||
}
|
||||
@ -185,7 +185,7 @@ class Extension
|
||||
file_get_contents(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')
|
||||
);
|
||||
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"');
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "' . trim($test) . '"');
|
||||
if ($ret !== 0) {
|
||||
if ($this->builder->getOption('debug')) {
|
||||
var_dump($out);
|
||||
@ -203,7 +203,7 @@ 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/ext-tests/{extension_name}.php
|
||||
// If check failed, throw RuntimeException
|
||||
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe --ri "' . $this->getDistName() . '"', false);
|
||||
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -n --ri "' . $this->getDistName() . '"', false);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||
}
|
||||
@ -216,7 +216,7 @@ class Extension
|
||||
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php'))
|
||||
);
|
||||
|
||||
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -r "' . trim($test) . '"');
|
||||
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -n -r "' . trim($test) . '"');
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
|
||||
}
|
||||
|
||||
@ -146,6 +146,17 @@ abstract class LibraryBase
|
||||
return Config::getLib(static::NAME, 'headers', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get binary files.
|
||||
*
|
||||
* @throws FileSystemException
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
public function getBinaryFiles(): array
|
||||
{
|
||||
return Config::getLib(static::NAME, 'bin', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
* @throws FileSystemException
|
||||
@ -203,7 +214,8 @@ abstract class LibraryBase
|
||||
}
|
||||
// force means just build
|
||||
if ($force_build) {
|
||||
logger()->info('Building required library [' . static::NAME . ']');
|
||||
$type = Config::getLib(static::NAME, 'type', 'lib');
|
||||
logger()->info('Building required ' . $type . ' [' . static::NAME . ']');
|
||||
|
||||
// extract first if not exists
|
||||
if (!is_dir($this->source_dir)) {
|
||||
@ -236,10 +248,14 @@ abstract class LibraryBase
|
||||
return LIB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
|
||||
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
|
||||
$this->tryBuild(true);
|
||||
return LIB_STATUS_OK;
|
||||
// current library is package and binary file is not exists
|
||||
if (Config::getLib(static::NAME, 'type', 'lib') === 'package') {
|
||||
foreach ($this->getBinaryFiles() as $name) {
|
||||
if (!file_exists(BUILD_BIN_PATH . "/{$name}")) {
|
||||
$this->tryBuild(true);
|
||||
return LIB_STATUS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if all the files exist at this point, skip the compilation process
|
||||
return LIB_STATUS_ALREADY;
|
||||
|
||||
@ -26,7 +26,7 @@ class mbregex extends Extension
|
||||
*/
|
||||
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 -n --ri "mbstring" | grep regex', false);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
|
||||
}
|
||||
@ -34,7 +34,7 @@ class mbregex extends Extension
|
||||
|
||||
public function runCliCheckWindows(): void
|
||||
{
|
||||
[$ret, $out] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "mbstring"', false);
|
||||
[$ret, $out] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "mbstring"', false);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli does not contain mbstring !');
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ class memcached extends Extension
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
$rootdir = BUILD_ROOT_PATH;
|
||||
return "--enable-memcached --with-zlib-dir={$rootdir} --with-libmemcached-dir={$rootdir} --disable-memcached-sasl --enable-memcached-json";
|
||||
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";
|
||||
return "--enable-memcached {$zlib_dir} --with-libmemcached-dir={$rootdir} --disable-memcached-sasl --enable-memcached-json";
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ class openssl extends Extension
|
||||
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
return '--with-openssl=' . BUILD_ROOT_PATH . ' --with-openssl-dir=' . BUILD_ROOT_PATH;
|
||||
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH;
|
||||
return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir;
|
||||
}
|
||||
}
|
||||
|
||||
41
src/SPC/builder/extension/opentelemetry.php
Normal file
41
src/SPC/builder/extension/opentelemetry.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\extension;
|
||||
|
||||
use SPC\builder\Extension;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\CustomExt;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
#[CustomExt('opentelemetry')]
|
||||
class opentelemetry extends Extension
|
||||
{
|
||||
public function validate(): void
|
||||
{
|
||||
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
|
||||
throw new \RuntimeException('The opentelemetry extension requires PHP 8.0 or later');
|
||||
}
|
||||
}
|
||||
|
||||
public function patchBeforeBuildconf(): bool
|
||||
{
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/ext/opentelemetry/config.w32',
|
||||
"EXTENSION('opentelemetry', 'opentelemetry.c otel_observer.c', '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');",
|
||||
"EXTENSION('opentelemetry', 'opentelemetry.c otel_observer.c', PHP_OPENTELEMETRY_SHARED, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');"
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function patchBeforeMake(): bool
|
||||
{
|
||||
// add -Wno-strict-prototypes
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,7 @@ class password_argon2 extends Extension
|
||||
|
||||
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 -n -r "assert(defined(\'PASSWORD_ARGON2I\'));"');
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed sanity check');
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ class swoole_hook_mysql extends Extension
|
||||
if ($this->builder->getExt('swoole') === null) {
|
||||
return;
|
||||
}
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
|
||||
$out = implode('', $out);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||
|
||||
@ -37,7 +37,7 @@ class swoole_hook_pgsql extends Extension
|
||||
if ($this->builder->getExt('swoole') === null) {
|
||||
return;
|
||||
}
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
|
||||
$out = implode('', $out);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||
|
||||
@ -37,7 +37,7 @@ class swoole_hook_sqlite extends Extension
|
||||
if ($this->builder->getExt('swoole') === null) {
|
||||
return;
|
||||
}
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "swoole"', false);
|
||||
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
|
||||
$out = implode('', $out);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
|
||||
|
||||
@ -12,9 +12,7 @@ class zlib extends Extension
|
||||
{
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
if ($this->builder->getPHPVersionID() >= 80400) {
|
||||
return '--with-zlib';
|
||||
}
|
||||
return '--with-zlib --with-zlib-dir="' . BUILD_ROOT_PATH . '"';
|
||||
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH;
|
||||
return '--with-zlib' . $zlib_dir;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,14 +34,14 @@ class LinuxBuilder extends UnixBuilderBase
|
||||
// check musl-cross make installed if we use musl-cross-make
|
||||
$arch = arch2gnu(php_uname('m'));
|
||||
|
||||
if ($this->libc !== LIBC_GLIBC) {
|
||||
// set library path, some libraries need it. (We cannot use `putenv` here, because cmake will be confused)
|
||||
$this->setOptionIfNotExist('library_path', "LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
$this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
}
|
||||
|
||||
GlobalEnvManager::init($this);
|
||||
|
||||
// set library path, some libraries need it. (We cannot use `putenv` here, because cmake will be confused)
|
||||
if (!filter_var(getenv('SPC_NO_MUSL_PATH'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
$this->setOptionIfNotExist('library_path', "LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
|
||||
$this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
|
||||
}
|
||||
|
||||
if (str_ends_with(getenv('CC'), 'linux-musl-gcc') && !file_exists("/usr/local/musl/bin/{$arch}-linux-musl-gcc") && (getenv('SPC_NO_MUSL_PATH') !== 'yes')) {
|
||||
throw new WrongUsageException('musl-cross-make not installed, please install it first. (You can use `doctor` command to install it)');
|
||||
}
|
||||
|
||||
@ -110,13 +110,11 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
$sorted_libraries = DependencyUtil::getLibs($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 (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
|
||||
continue;
|
||||
}
|
||||
// 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!');
|
||||
@ -142,9 +140,10 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
// 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');
|
||||
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "echo \"hello\";"');
|
||||
$raw_output = implode('', $output);
|
||||
if ($ret !== 0 || trim($raw_output) !== 'hello') {
|
||||
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
|
||||
}
|
||||
|
||||
foreach ($this->exts as $ext) {
|
||||
|
||||
@ -10,14 +10,21 @@ trait gettext
|
||||
{
|
||||
$extra = $this->builder->getLib('ncurses') ? ('--with-libncurses-prefix=' . BUILD_ROOT_PATH . ' ') : '';
|
||||
$extra .= $this->builder->getLib('libxml2') ? ('--with-libxml2-prefix=' . BUILD_ROOT_PATH . ' ') : '';
|
||||
|
||||
$zts = $this->builder->getOption('enable-zts') ? '--enable-threads=isoc+posix ' : '--disable-threads ';
|
||||
|
||||
$cflags = $this->builder->getOption('enable-zts') ? '-lpthread -D_REENTRANT' : '';
|
||||
$ldflags = $this->builder->getOption('enable-zts') ? '-lpthread' : '';
|
||||
|
||||
shell()->cd($this->source_dir)
|
||||
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
|
||||
->setEnv(['CFLAGS' => $this->getLibExtraCFlags() ?: $cflags, 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()])
|
||||
->execWithEnv(
|
||||
'./configure ' .
|
||||
'--enable-static ' .
|
||||
'--disable-shared ' .
|
||||
'--disable-java ' .
|
||||
'--disable-c+ ' .
|
||||
$zts .
|
||||
$extra .
|
||||
'--with-included-gettext ' .
|
||||
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
|
||||
|
||||
@ -236,6 +236,9 @@ class WindowsBuilder extends BuilderBase
|
||||
|
||||
// add lib object for builder
|
||||
foreach ($sorted_libraries as $library) {
|
||||
if (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
|
||||
continue;
|
||||
}
|
||||
// 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!');
|
||||
@ -277,7 +280,7 @@ class WindowsBuilder extends BuilderBase
|
||||
// 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\";"');
|
||||
[$ret, $output] = cmd()->execWithResult(BUILD_ROOT_PATH . '\bin\php.exe -n -r "echo \"hello\";"');
|
||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||
throw new RuntimeException('cli failed sanity check');
|
||||
}
|
||||
|
||||
@ -12,14 +12,41 @@ class curl extends WindowsLibraryBase
|
||||
|
||||
protected function build(): void
|
||||
{
|
||||
FileSystem::createDir(BUILD_BIN_PATH);
|
||||
cmd()->cd($this->source_dir . '\winbuild')
|
||||
// reset cmake
|
||||
FileSystem::resetDir($this->source_dir . '\cmakebuild');
|
||||
|
||||
// lib:zstd
|
||||
$alt = $this->builder->getLib('zstd') ? '' : '-DCURL_ZSTD=OFF';
|
||||
// lib:brotli
|
||||
$alt .= $this->builder->getLib('brotli') ? '' : ' -DCURL_BROTLI=OFF';
|
||||
|
||||
// start build
|
||||
cmd()->cd($this->source_dir)
|
||||
->execWithWrapper(
|
||||
$this->builder->makeSimpleWrapper('nmake'),
|
||||
'/f Makefile.vc WITH_DEVEL=' . BUILD_ROOT_PATH . ' ' .
|
||||
'WITH_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||
'mode=static RTLIBCFG=static WITH_SSL=static WITH_NGHTTP2=static WITH_SSH2=static ENABLE_IPV6=yes WITH_ZLIB=static MACHINE=x64 DEBUG=no'
|
||||
$this->builder->makeSimpleWrapper('cmake'),
|
||||
'-B cmakebuild ' .
|
||||
'-A x64 ' .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||
'-DBUILD_STATIC_LIBS=ON ' .
|
||||
'-DCURL_STATICLIB=ON ' .
|
||||
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||
'-DBUILD_CURL_EXE=OFF ' . // disable curl.exe
|
||||
'-DBUILD_TESTING=OFF ' . // disable tests
|
||||
'-DBUILD_EXAMPLES=OFF ' . // disable examples
|
||||
'-DUSE_LIBIDN2=OFF ' . // disable libidn2
|
||||
'-DCURL_USE_LIBPSL=OFF ' . // disable libpsl
|
||||
'-DCURL_ENABLE_SSL=ON ' .
|
||||
'-DUSE_NGHTTP2=ON ' . // enable nghttp2
|
||||
'-DCURL_USE_LIBSSH2=ON ' . // enable libssh2
|
||||
'-DENABLE_IPV6=ON ' . // enable ipv6
|
||||
'-DNGHTTP2_CFLAGS="/DNGHTTP2_STATICLIB" ' .
|
||||
$alt
|
||||
)
|
||||
->execWithWrapper(
|
||||
$this->builder->makeSimpleWrapper('cmake'),
|
||||
"--build cmakebuild --config Release --target install -j{$this->builder->concurrency}"
|
||||
);
|
||||
FileSystem::copyDir($this->source_dir . '\include\curl', BUILD_INCLUDE_PATH . '\curl');
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,6 @@ abstract class BaseCommand extends Command
|
||||
E_USER_ERROR => ['PHP Error: ', 'error'],
|
||||
E_USER_WARNING => ['PHP Warning: ', 'warning'],
|
||||
E_USER_NOTICE => ['PHP Notice: ', 'notice'],
|
||||
E_STRICT => ['PHP Strict: ', 'notice'],
|
||||
E_RECOVERABLE_ERROR => ['PHP Recoverable Error: ', 'error'],
|
||||
E_DEPRECATED => ['PHP Deprecated: ', 'notice'],
|
||||
E_USER_DEPRECATED => ['PHP User Deprecated: ', 'notice'],
|
||||
@ -56,7 +55,7 @@ abstract class BaseCommand extends Command
|
||||
logger()->{$level_tip[1]}($error);
|
||||
// 如果 return false 则错误会继续递交给 PHP 标准错误处理
|
||||
return true;
|
||||
}, E_ALL | E_STRICT);
|
||||
});
|
||||
$version = ConsoleApplication::VERSION;
|
||||
if (!$this->no_motd) {
|
||||
echo " _ _ _ _
|
||||
@ -154,24 +153,24 @@ abstract class BaseCommand extends Command
|
||||
/**
|
||||
* Parse extension list from string, replace alias and filter internal extensions.
|
||||
*
|
||||
* @param string $ext_list Extension string list, e.g. "mbstring,posix,sockets"
|
||||
* @param array|string $ext_list Extension string list, e.g. "mbstring,posix,sockets" or array
|
||||
*/
|
||||
protected function parseExtensionList(string $ext_list): array
|
||||
protected function parseExtensionList(array|string $ext_list): array
|
||||
{
|
||||
// replace alias
|
||||
$ls = array_map(function ($x) {
|
||||
$lower = strtolower(trim($x));
|
||||
if (isset(SPC_EXTENSION_ALIAS[$lower])) {
|
||||
logger()->notice("Extension [{$lower}] is an alias of [" . SPC_EXTENSION_ALIAS[$lower] . '], it will be replaced.');
|
||||
logger()->debug("Extension [{$lower}] is an alias of [" . SPC_EXTENSION_ALIAS[$lower] . '], it will be replaced.');
|
||||
return SPC_EXTENSION_ALIAS[$lower];
|
||||
}
|
||||
return $lower;
|
||||
}, explode(',', $ext_list));
|
||||
}, is_array($ext_list) ? $ext_list : explode(',', $ext_list));
|
||||
|
||||
// filter internals
|
||||
return array_values(array_filter($ls, function ($x) {
|
||||
if (in_array($x, SPC_INTERNAL_EXTENSIONS)) {
|
||||
logger()->warning("Extension [{$x}] is an builtin extension, it will be ignored.");
|
||||
logger()->debug("Extension [{$x}] is an builtin extension, it will be ignored.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -7,6 +7,7 @@ namespace SPC\command;
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\store\SourcePatcher;
|
||||
use SPC\util\DependencyUtil;
|
||||
@ -32,7 +33,6 @@ class BuildCliCommand extends BuildCommand
|
||||
$this->addOption('build-embed', null, null, 'Build embed SAPI');
|
||||
$this->addOption('build-all', null, null, 'Build all SAPI');
|
||||
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
|
||||
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
||||
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
|
||||
$this->addOption('with-config-file-path', null, InputOption::VALUE_REQUIRED, 'Set the path in which to look for php.ini', $isWindows ? null : '/usr/local/etc/php');
|
||||
$this->addOption('with-config-file-scan-dir', null, InputOption::VALUE_REQUIRED, 'Set the directory to scan for .ini files after reading php.ini', $isWindows ? null : '/usr/local/etc/php/conf.d');
|
||||
@ -108,13 +108,14 @@ class BuildCliCommand extends BuildCommand
|
||||
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
||||
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
|
||||
|
||||
// print info
|
||||
$indent_texts = [
|
||||
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
||||
'Build SAPI' => $builder->getBuildTypeName($rule),
|
||||
'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
|
||||
'Libraries (' . count($libraries) . ')' => implode(',', $libraries),
|
||||
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
|
||||
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
|
||||
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
|
||||
];
|
||||
|
||||
@ -33,5 +33,6 @@ abstract class BuildCommand extends BaseCommand
|
||||
$this->addOption('with-clean', null, null, 'fresh build, remove `source` dir before `make`');
|
||||
$this->addOption('bloat', null, null, 'add all libraries into binary');
|
||||
$this->addOption('rebuild', 'r', null, 'Delete old build and rebuild');
|
||||
$this->addOption('enable-zts', null, null, 'enable ZTS support');
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ namespace SPC\command;
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\Config;
|
||||
use SPC\util\DependencyUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@ -61,7 +62,9 @@ class BuildLibsCommand extends BuildCommand
|
||||
$builder->setLibsOnly();
|
||||
// 编译和检查库完整
|
||||
$libraries = DependencyUtil::getLibs($libraries);
|
||||
logger()->info('Building libraries: ' . implode(',', $libraries));
|
||||
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
|
||||
|
||||
logger()->info('Building libraries: ' . implode(',', $display_libs));
|
||||
sleep(2);
|
||||
$builder->proveLibs($libraries);
|
||||
$builder->validateLibsAndExts();
|
||||
|
||||
@ -72,10 +72,6 @@ class DownloadCommand extends BaseCommand
|
||||
if ($for_ext = $input->getOption('for-extensions')) {
|
||||
$ext = $this->parseExtensionList($for_ext);
|
||||
$sources = $this->calculateSourcesByExt($ext, !$input->getOption('without-suggestions'));
|
||||
if (PHP_OS_FAMILY !== 'Windows') {
|
||||
array_unshift($sources, 'pkg-config');
|
||||
}
|
||||
array_unshift($sources, 'php-src', 'micro');
|
||||
$final_sources = array_merge($final_sources, array_diff($sources, $final_sources));
|
||||
}
|
||||
// mode: --for-libs
|
||||
@ -323,7 +319,10 @@ class DownloadCommand extends BaseCommand
|
||||
}
|
||||
}
|
||||
foreach ($libraries as $library) {
|
||||
$sources[] = Config::getLib($library, 'source');
|
||||
$source = Config::getLib($library, 'source');
|
||||
if ($source !== null) {
|
||||
$sources[] = $source;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($sources));
|
||||
}
|
||||
|
||||
160
src/SPC/command/DumpExtensionsCommand.php
Normal file
160
src/SPC/command/DumpExtensionsCommand.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand(name: 'dump-extensions', description: 'Determines the required php extensions')]
|
||||
class DumpExtensionsCommand extends BaseCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
public function configure(): void
|
||||
{
|
||||
// path to project files or specific composer file
|
||||
$this->addArgument('path', InputArgument::OPTIONAL, 'Path to project root', '.');
|
||||
$this->addOption('format', 'F', InputOption::VALUE_REQUIRED, 'Parsed output format', 'default');
|
||||
// output zero extension replacement rather than exit as failure
|
||||
$this->addOption('no-ext-output', 'N', InputOption::VALUE_REQUIRED, 'When no extensions found, output default combination (comma separated)');
|
||||
// no dev
|
||||
$this->addOption('no-dev', null, null, 'Do not include dev dependencies');
|
||||
// no spc filter
|
||||
$this->addOption('no-spc-filter', 'S', null, 'Do not use SPC filter to determine the required extensions');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$path = FileSystem::convertPath($this->getArgument('path'));
|
||||
|
||||
$path_installed = FileSystem::convertPath(rtrim($path, '/\\') . '/vendor/composer/installed.json');
|
||||
$path_lock = FileSystem::convertPath(rtrim($path, '/\\') . '/composer.lock');
|
||||
|
||||
$ext_installed = $this->extractFromInstalledJson($path_installed, !$this->getOption('no-dev'));
|
||||
if ($ext_installed === null) {
|
||||
if ($this->getOption('format') === 'default') {
|
||||
$this->output->writeln('<comment>vendor/composer/installed.json load failed, skipped</comment>');
|
||||
}
|
||||
$ext_installed = [];
|
||||
}
|
||||
|
||||
$ext_lock = $this->extractFromComposerLock($path_lock, !$this->getOption('no-dev'));
|
||||
if ($ext_lock === null) {
|
||||
$this->output->writeln('<error>composer.lock load failed</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
$extensions = array_unique(array_merge($ext_installed, $ext_lock));
|
||||
sort($extensions);
|
||||
|
||||
if (empty($extensions)) {
|
||||
if ($this->getOption('no-ext-output')) {
|
||||
$this->outputExtensions(explode(',', $this->getOption('no-ext-output')));
|
||||
return static::SUCCESS;
|
||||
}
|
||||
$this->output->writeln('<error>No extensions found</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
$this->outputExtensions($extensions);
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function filterExtensions(array $requirements): array
|
||||
{
|
||||
return array_map(
|
||||
fn ($key) => substr($key, 4),
|
||||
array_keys(
|
||||
array_filter($requirements, function ($key) {
|
||||
return str_starts_with($key, 'ext-');
|
||||
}, ARRAY_FILTER_USE_KEY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function loadJson(string $file): array|bool
|
||||
{
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents($file), true);
|
||||
if (!$data) {
|
||||
return false;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function extractFromInstalledJson(string $file, bool $include_dev = true): ?array
|
||||
{
|
||||
if (!($data = $this->loadJson($file))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$packages = $data['packages'] ?? [];
|
||||
|
||||
if (!$include_dev) {
|
||||
$packages = array_filter($packages, fn ($package) => !in_array($package['name'], $data['dev-package-names'] ?? []));
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
...array_map(fn ($x) => isset($x['require']) ? $this->filterExtensions($x['require']) : [], $packages)
|
||||
);
|
||||
}
|
||||
|
||||
private function extractFromComposerLock(string $file, bool $include_dev = true): ?array
|
||||
{
|
||||
if (!($data = $this->loadJson($file))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get packages ext
|
||||
$packages = $data['packages'] ?? [];
|
||||
$exts = array_merge(
|
||||
...array_map(fn ($package) => $this->filterExtensions($package['require'] ?? []), $packages)
|
||||
);
|
||||
|
||||
// get dev packages ext
|
||||
if ($include_dev) {
|
||||
$packages = $data['packages-dev'] ?? [];
|
||||
$exts = array_merge(
|
||||
$exts,
|
||||
...array_map(fn ($package) => $this->filterExtensions($package['require'] ?? []), $packages)
|
||||
);
|
||||
}
|
||||
|
||||
// get require ext
|
||||
$platform = $data['platform'] ?? [];
|
||||
$exts = array_merge($exts, $this->filterExtensions($platform));
|
||||
|
||||
// get require-dev ext
|
||||
if ($include_dev) {
|
||||
$platform = $data['platform-dev'] ?? [];
|
||||
$exts = array_merge($exts, $this->filterExtensions($platform));
|
||||
}
|
||||
|
||||
return $exts;
|
||||
}
|
||||
|
||||
private function outputExtensions(array $extensions): void
|
||||
{
|
||||
if (!$this->getOption('no-spc-filter')) {
|
||||
$extensions = $this->parseExtensionList($extensions);
|
||||
}
|
||||
switch ($this->getOption('format')) {
|
||||
case 'json':
|
||||
$this->output->writeln(json_encode($extensions, JSON_PRETTY_PRINT));
|
||||
break;
|
||||
case 'text':
|
||||
$this->output->writeln(implode(',', $extensions));
|
||||
break;
|
||||
default:
|
||||
$this->output->writeln('<info>Required PHP extensions' . ($this->getOption('no-dev') ? ' (without dev)' : '') . ':</info>');
|
||||
$this->output->writeln(implode(',', $extensions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,17 @@ class SortConfigCommand extends BaseCommand
|
||||
case 'lib':
|
||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
|
||||
ConfigValidator::validateLibs($file);
|
||||
ksort($file);
|
||||
uksort($file, function ($a, $b) use ($file) {
|
||||
$type_a = $file[$a]['type'] ?? 'lib';
|
||||
$type_b = $file[$b]['type'] ?? 'lib';
|
||||
$type_order = ['root', 'target', 'package', 'lib'];
|
||||
// compare type first
|
||||
if ($type_a !== $type_b) {
|
||||
return array_search($type_a, $type_order) <=> array_search($type_b, $type_order);
|
||||
}
|
||||
// compare name
|
||||
return $a <=> $b;
|
||||
});
|
||||
if (!file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n")) {
|
||||
$this->output->writeln('<error>Write file lib.json failed!</error>');
|
||||
return static::FAILURE;
|
||||
|
||||
@ -73,7 +73,7 @@ class Config
|
||||
if (!isset(self::$lib[$name])) {
|
||||
throw new WrongUsageException('lib [' . $name . '] is not supported yet');
|
||||
}
|
||||
$supported_sys_based = ['static-libs', 'headers', 'lib-depends', 'lib-suggests', 'frameworks'];
|
||||
$supported_sys_based = ['static-libs', 'headers', 'lib-depends', 'lib-suggests', 'frameworks', 'bin'];
|
||||
if ($key !== null && in_array($key, $supported_sys_based)) {
|
||||
$m_key = match (PHP_OS_FAMILY) {
|
||||
'Windows' => ['-windows', '-win', ''],
|
||||
|
||||
@ -53,13 +53,45 @@ class ConfigValidator
|
||||
*/
|
||||
public static function validateLibs(mixed $data, array $source_data = []): void
|
||||
{
|
||||
is_array($data) || throw new ValidationException('lib.json is broken');
|
||||
// check if it is an array
|
||||
if (!is_array($data)) {
|
||||
throw new ValidationException('lib.json is broken');
|
||||
}
|
||||
// check each lib
|
||||
foreach ($data as $name => $lib) {
|
||||
isset($lib['source']) || throw new ValidationException("lib {$name} does not assign any source");
|
||||
is_string($lib['source']) || throw new ValidationException("lib {$name} source must be string");
|
||||
empty($source_data) || isset($source_data[$lib['source']]) || throw new ValidationException("lib {$name} assigns an invalid source: {$lib['source']}");
|
||||
!isset($lib['lib-depends']) || !is_assoc_array($lib['lib-depends']) || throw new ValidationException("lib {$name} dependencies must be a list");
|
||||
!isset($lib['lib-suggests']) || !is_assoc_array($lib['lib-suggests']) || throw new ValidationException("lib {$name} suggested dependencies must be a list");
|
||||
// check if lib is an assoc array
|
||||
if (!is_assoc_array($lib)) {
|
||||
throw new ValidationException("lib {$name} is not an object");
|
||||
}
|
||||
// check if lib has valid type
|
||||
if (!in_array($lib['type'] ?? 'lib', ['lib', 'package', 'target', 'root'])) {
|
||||
throw new ValidationException("lib {$name} type is invalid");
|
||||
}
|
||||
// check if lib and package has source
|
||||
if (in_array($lib['type'] ?? 'lib', ['lib', 'package']) && !isset($lib['source'])) {
|
||||
throw new ValidationException("lib {$name} does not assign any source");
|
||||
}
|
||||
// check if source is valid
|
||||
if (isset($lib['source']) && !empty($source_data) && !isset($source_data[$lib['source']])) {
|
||||
throw new ValidationException("lib {$name} assigns an invalid source: {$lib['source']}");
|
||||
}
|
||||
// check if [lib-depends|lib-suggests|static-libs][-windows|-unix|-macos|-linux] are valid list array
|
||||
$suffixes = ['', '-windows', '-unix', '-macos', '-linux'];
|
||||
foreach ($suffixes as $suffix) {
|
||||
if (isset($lib['lib-depends' . $suffix]) && !is_list_array($lib['lib-depends' . $suffix])) {
|
||||
throw new ValidationException("lib {$name} lib-depends must be a list");
|
||||
}
|
||||
if (isset($lib['lib-suggests' . $suffix]) && !is_list_array($lib['lib-suggests' . $suffix])) {
|
||||
throw new ValidationException("lib {$name} lib-suggests must be a list");
|
||||
}
|
||||
if (isset($lib['static-libs' . $suffix]) && !is_list_array($lib['static-libs' . $suffix])) {
|
||||
throw new ValidationException("lib {$name} static-libs must be a list");
|
||||
}
|
||||
}
|
||||
// check if frameworks is a list array
|
||||
if (isset($lib['frameworks']) && !is_list_array($lib['frameworks'])) {
|
||||
throw new ValidationException("lib {$name} frameworks must be a list");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ class DependencyUtil
|
||||
$ext_suggests = array_map(fn ($x) => "ext@{$x}", $ext_suggests);
|
||||
// merge ext-depends with lib-depends
|
||||
$lib_depends = Config::getExt($ext_name, 'lib-depends', []);
|
||||
$depends = array_merge($ext_depends, $lib_depends);
|
||||
$depends = array_merge($ext_depends, $lib_depends, ['php']);
|
||||
// merge ext-suggests with lib-suggests
|
||||
$lib_suggests = Config::getExt($ext_name, 'lib-suggests', []);
|
||||
$suggests = array_merge($ext_suggests, $lib_suggests);
|
||||
@ -44,7 +44,7 @@ class DependencyUtil
|
||||
}
|
||||
foreach ($libs as $lib_name => $lib) {
|
||||
$dep_list[$lib_name] = [
|
||||
'depends' => Config::getLib($lib_name, 'lib-depends', []),
|
||||
'depends' => array_merge(Config::getLib($lib_name, 'lib-depends', []), ['lib-base']),
|
||||
'suggests' => Config::getLib($lib_name, 'lib-suggests', []),
|
||||
];
|
||||
}
|
||||
@ -210,6 +210,9 @@ class DependencyUtil
|
||||
}
|
||||
$visited[$lib_name] = true;
|
||||
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
|
||||
if (!isset($dep_list[$lib_name])) {
|
||||
throw new WrongUsageException("{$lib_name} not exist !");
|
||||
}
|
||||
foreach ($dep_list[$lib_name]['depends'] as $dep) {
|
||||
self::visitPlatDeps($dep, $dep_list, $visited, $sorted);
|
||||
}
|
||||
|
||||
@ -57,10 +57,6 @@ class GlobalEnvManager
|
||||
self::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++");
|
||||
self::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar");
|
||||
}
|
||||
self::putenv("SPC_PHP_DEFAULT_LD_LIBRARY_PATH_CMD=LD_LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
if (getenv('SPC_NO_MUSL_PATH') !== 'yes') {
|
||||
self::putenv("PATH=/usr/local/musl/bin:/usr/local/musl/{$arch}-linux-musl/bin:" . getenv('PATH'));
|
||||
}
|
||||
}
|
||||
|
||||
// Init env.ini file, read order:
|
||||
@ -112,6 +108,11 @@ class GlobalEnvManager
|
||||
'BSD' => self::applyConfig($ini['freebsd']),
|
||||
default => null,
|
||||
};
|
||||
|
||||
if (PHP_OS_FAMILY === 'Linux' && !filter_var(getenv('SPC_NO_MUSL_PATH'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
self::putenv("SPC_PHP_DEFAULT_LD_LIBRARY_PATH_CMD=LD_LIBRARY_PATH=/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
self::putenv("PATH=/usr/local/musl/bin:/usr/local/musl/{$arch}-linux-musl/bin:" . getenv('PATH'));
|
||||
}
|
||||
}
|
||||
|
||||
public static function putenv(string $val): void
|
||||
|
||||
@ -70,6 +70,9 @@ class LicenseDumper
|
||||
}
|
||||
|
||||
foreach ($this->libs as $lib) {
|
||||
if (Config::getLib($lib, 'type', 'lib') !== 'lib') {
|
||||
continue;
|
||||
}
|
||||
$source_name = Config::getLib($lib, 'source');
|
||||
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
|
||||
$result = file_put_contents("{$target_dir}/lib_{$lib}_{$index}.txt", $license);
|
||||
|
||||
5
src/globals/ext-tests/opentelemetry.php
Normal file
5
src/globals/ext-tests/opentelemetry.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
assert(function_exists('OpenTelemetry\Instrumentation\hook'));
|
||||
@ -20,6 +20,14 @@ function is_assoc_array(mixed $array): bool
|
||||
return is_array($array) && (!empty($array) && array_keys($array) !== range(0, count($array) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Judge if an array is a list
|
||||
*/
|
||||
function is_list_array(mixed $array): bool
|
||||
{
|
||||
return is_array($array) && (empty($array) || array_keys($array) === range(0, count($array) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a logger instance
|
||||
*/
|
||||
|
||||
@ -13,14 +13,13 @@ declare(strict_types=1);
|
||||
|
||||
// test php version
|
||||
$test_php_version = [
|
||||
// '8.1',
|
||||
// '8.2',
|
||||
// '8.3',
|
||||
'8.3',
|
||||
'8.4',
|
||||
];
|
||||
|
||||
// test os (macos-13, macos-14, ubuntu-latest, windows-latest are available)
|
||||
$test_os = [
|
||||
// 'macos-13',
|
||||
'macos-14',
|
||||
'ubuntu-latest',
|
||||
// 'windows-latest',
|
||||
@ -35,12 +34,12 @@ $no_strip = false;
|
||||
$upx = false;
|
||||
|
||||
// prefer downloading pre-built packages to speed up the build process
|
||||
$prefer_pre_built = true;
|
||||
$prefer_pre_built = false;
|
||||
|
||||
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||
$extensions = match (PHP_OS_FAMILY) {
|
||||
'Linux', 'Darwin' => 'dio',
|
||||
'Windows' => 'dio',
|
||||
'Linux', 'Darwin' => 'imap,openssl,zlib,memcache',
|
||||
'Windows' => 'gettext',
|
||||
};
|
||||
|
||||
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
||||
@ -162,6 +161,8 @@ if ($argv[1] === 'download_cmd') {
|
||||
} else {
|
||||
passthru('./bin/spc ' . $build_cmd . ' --build-embed', $retcode);
|
||||
}
|
||||
} else {
|
||||
$retcode = 0;
|
||||
}
|
||||
|
||||
exit($retcode);
|
||||
|
||||
@ -71,7 +71,7 @@ class ExtensionTest extends TestCase
|
||||
public function testRunCliCheckWindows()
|
||||
{
|
||||
if (is_unix()) {
|
||||
$this->markTestIncomplete('This test is for Windows only');
|
||||
$this->markTestSkipped('This test is for Windows only');
|
||||
} else {
|
||||
$this->extension->runCliCheckWindows();
|
||||
$this->assertTrue(true);
|
||||
|
||||
@ -15,7 +15,7 @@ class SystemUtilTest extends TestCase
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
if (PHP_OS_FAMILY !== 'Linux') {
|
||||
self::markTestIncomplete('This test is only for Linux');
|
||||
self::markTestSkipped('This test is only for Linux');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ class SystemUtilTest extends TestCase
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
if (PHP_OS_FAMILY !== 'Darwin') {
|
||||
self::markTestIncomplete('This test is only for macOS');
|
||||
self::markTestSkipped('This test is only for macOS');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ class UnixSystemUtilTest extends TestCase
|
||||
default => null,
|
||||
};
|
||||
if ($util_class === null) {
|
||||
self::markTestIncomplete('This test is only for Unix');
|
||||
self::markTestSkipped('This test is only for Unix');
|
||||
}
|
||||
$this->util = new $util_class();
|
||||
}
|
||||
|
||||
@ -29,6 +29,8 @@ final class DependencyUtilTest extends TestCase
|
||||
],
|
||||
];
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'libaaa' => [
|
||||
'source' => 'test1',
|
||||
'static-libs' => ['libaaa.a'],
|
||||
|
||||
@ -34,6 +34,8 @@ final class LicenseDumperTest extends TestCase
|
||||
public function testDumpWithSingleLicense(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
@ -57,6 +59,8 @@ final class LicenseDumperTest extends TestCase
|
||||
public function testDumpWithMultipleLicenses(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'lib-base' => ['type' => 'root'],
|
||||
'php' => ['type' => 'root'],
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user