mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-03 23:05:41 +08:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7adec1341 | ||
|
|
a236ee3ac3 | ||
|
|
d7b9e5a7d4 | ||
|
|
3d1738b14b | ||
|
|
f0e634a4fa | ||
|
|
0f5f60e477 | ||
|
|
9fe09f57f6 | ||
|
|
cf24b88bc8 | ||
|
|
d34fa0ba4e | ||
|
|
f40170ee6f | ||
|
|
2da750d5f9 | ||
|
|
720e700701 | ||
|
|
b452f7f32a | ||
|
|
7bfb8d6f53 | ||
|
|
b06db1f920 | ||
|
|
61eafa48ff | ||
|
|
8b07b15f6c | ||
|
|
5e67133495 | ||
|
|
30b740b7f0 | ||
|
|
7501ae4b4d | ||
|
|
4391c30299 | ||
|
|
536641eadd | ||
|
|
21594cd4c0 | ||
|
|
d4b263bc9f | ||
|
|
4e4eaed123 | ||
|
|
610843398e | ||
|
|
615e680b9b | ||
|
|
4e67c63808 | ||
|
|
f556f375ee | ||
|
|
f21f833aed | ||
|
|
0c6dd7a577 | ||
|
|
fc4872c5d6 | ||
|
|
3fe50e9ca3 | ||
|
|
a5e4d6a5ec | ||
|
|
0524129b64 | ||
|
|
7ce13751a0 | ||
|
|
e149ee0d70 | ||
|
|
2f3c71e55a | ||
|
|
5c04638cb4 | ||
|
|
6dd6d807b6 | ||
|
|
237d39f09c | ||
|
|
7a2f77193f | ||
|
|
d21980170e | ||
|
|
7dec34bdfe | ||
|
|
62d619b6cd | ||
|
|
67afffeb96 | ||
|
|
c58ea0c3bd | ||
|
|
acb8cea437 | ||
|
|
11f0957963 | ||
|
|
2d7c052fd9 | ||
|
|
23bd216cc7 | ||
|
|
50cfc5899b | ||
|
|
01d3cb4b11 | ||
|
|
a940200164 | ||
|
|
4e5c0f0a48 | ||
|
|
8e5657eff0 | ||
|
|
631a1b5864 | ||
|
|
67d2ad5511 | ||
|
|
ab4d7fae7d | ||
|
|
0e4a3f5e2b | ||
|
|
87c0535624 | ||
|
|
5648681ecc | ||
|
|
2c0bb1f7ba | ||
|
|
16d82212dd | ||
|
|
6ea1d06460 | ||
|
|
936413a6d9 | ||
|
|
88ce2eafab | ||
|
|
3915c8410b | ||
|
|
4115e42dc6 | ||
|
|
48f257f85a | ||
|
|
acdec64144 | ||
|
|
0beb97648a | ||
|
|
5564559192 | ||
|
|
8cb93bc1fe | ||
|
|
ae23b721b3 | ||
|
|
df06a4bb2c | ||
|
|
f37110605e | ||
|
|
8459754692 | ||
|
|
fc08e5cf23 | ||
|
|
6dec44bdc3 | ||
|
|
8cd69b2b70 | ||
|
|
625a03e799 | ||
|
|
aa4d4db11f | ||
|
|
76c353e790 | ||
|
|
8909b62dc4 | ||
|
|
371a588396 | ||
|
|
ee54b6d347 | ||
|
|
3ba215c35c | ||
|
|
161a3924d2 | ||
|
|
7b6fae6d92 | ||
|
|
71b52e58b2 | ||
|
|
d0a66ab16b | ||
|
|
9d75265e25 | ||
|
|
744e066d5f | ||
|
|
1791b443bc | ||
|
|
e850df505c | ||
|
|
918223e7da | ||
|
|
1552d992df | ||
|
|
f0a895691b | ||
|
|
1f7c805da4 | ||
|
|
1ad33556e9 | ||
|
|
6b5e83b98e | ||
|
|
6fb9c2df3b | ||
|
|
1b29803ed2 | ||
|
|
3477857584 | ||
|
|
0ce2c894e9 | ||
|
|
92470a35da | ||
|
|
6447fec028 | ||
|
|
0bc143cac3 |
20
.github/workflows/build-unix.yml
vendored
20
.github/workflows/build-unix.yml
vendored
@@ -6,10 +6,13 @@ on:
|
|||||||
os:
|
os:
|
||||||
required: true
|
required: true
|
||||||
description: Build target OS
|
description: Build target OS
|
||||||
|
default: 'linux-x86_64'
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- 'linux-x86_64'
|
- 'linux-x86_64'
|
||||||
- 'linux-aarch64'
|
- 'linux-aarch64'
|
||||||
|
- 'linux-x86_64-glibc'
|
||||||
|
- 'linux-aarch64-glibc'
|
||||||
- 'macos-x86_64'
|
- 'macos-x86_64'
|
||||||
- 'macos-aarch64'
|
- 'macos-aarch64'
|
||||||
php-version:
|
php-version:
|
||||||
@@ -22,7 +25,6 @@ on:
|
|||||||
- '8.3'
|
- '8.3'
|
||||||
- '8.2'
|
- '8.2'
|
||||||
- '8.1'
|
- '8.1'
|
||||||
- '8.0'
|
|
||||||
extensions:
|
extensions:
|
||||||
description: Extensions to build (comma separated)
|
description: Extensions to build (comma separated)
|
||||||
required: true
|
required: true
|
||||||
@@ -77,9 +79,19 @@ jobs:
|
|||||||
RUNS_ON="ubuntu-latest"
|
RUNS_ON="ubuntu-latest"
|
||||||
;;
|
;;
|
||||||
linux-aarch64)
|
linux-aarch64)
|
||||||
DOWN_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker download"
|
DOWN_CMD="./bin/spc-alpine-docker download"
|
||||||
BUILD_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker build"
|
BUILD_CMD="./bin/spc-alpine-docker build"
|
||||||
RUNS_ON="ubuntu-latest"
|
RUNS_ON="ubuntu-24.04-arm"
|
||||||
|
;;
|
||||||
|
linux-x86_64-glibc)
|
||||||
|
DOWN_CMD="./bin/spc-gnu-docker download"
|
||||||
|
BUILD_CMD="./bin/spc-gnu-docker build"
|
||||||
|
RUNS_ON="ubuntu-22.04"
|
||||||
|
;;
|
||||||
|
linux-aarch64-glibc)
|
||||||
|
DOWN_CMD="./bin/spc-gnu-docker download"
|
||||||
|
BUILD_CMD="./bin/spc-gnu-docker build"
|
||||||
|
RUNS_ON="ubuntu-22.04-arm"
|
||||||
;;
|
;;
|
||||||
macos-x86_64)
|
macos-x86_64)
|
||||||
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"
|
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"
|
||||||
|
|||||||
12
.github/workflows/tests.yml
vendored
12
.github/workflows/tests.yml
vendored
@@ -176,18 +176,18 @@ jobs:
|
|||||||
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
|
||||||
|
|
||||||
- name: "Run Build Tests (doctor)"
|
- name: "Run Build Tests (doctor)"
|
||||||
run: bin/spc doctor --auto-fix --debug
|
run: php src/globals/test-extensions.php doctor_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
|
|
||||||
- name: "Prepare UPX for Windows"
|
- name: "Prepare UPX for Windows"
|
||||||
if: matrix.os == 'windows-latest'
|
if: ${{ startsWith(matrix.os, 'windows-') }}
|
||||||
run: |
|
run: |
|
||||||
bin/spc install-pkg upx
|
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
|
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
- name: "Prepare UPX for Linux"
|
- name: "Prepare UPX for Linux"
|
||||||
if: matrix.os == 'ubunut-latest'
|
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
|
||||||
run: |
|
run: |
|
||||||
bin/spc install-pkg upx
|
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV
|
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: "Run Build Tests (download)"
|
- name: "Run Build Tests (download)"
|
||||||
@@ -197,5 +197,5 @@ jobs:
|
|||||||
run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }}
|
run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
|
|
||||||
- name: "Run Build Tests (build - embed for non-windows)"
|
- name: "Run Build Tests (build - embed for non-windows)"
|
||||||
if: matrix.os != 'windows-latest'
|
if: ${{ !startsWith(matrix.os, 'windows-') }}
|
||||||
run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }}
|
run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ WORKDIR /app
|
|||||||
ADD ./src /app/src
|
ADD ./src /app/src
|
||||||
COPY ./composer.* /app/
|
COPY ./composer.* /app/
|
||||||
ADD ./bin /app/bin
|
ADD ./bin /app/bin
|
||||||
RUN composer install --no-dev --classmap-authoritative
|
RUN composer install --no-dev
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -122,6 +122,20 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
# shellcheck disable=SC2090
|
# shellcheck disable=SC2090
|
||||||
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
||||||
|
echo "* Debug mode enabled, run docker in interactive mode."
|
||||||
|
echo "* You can use 'exit' to exit the docker container."
|
||||||
|
echo "* You can use 'bin/spc' like normal builds."
|
||||||
|
echo "*"
|
||||||
|
echo "* Mounted directories:"
|
||||||
|
echo "* ./config: $(pwd)/config"
|
||||||
|
echo "* ./src: $(pwd)/src"
|
||||||
|
echo "* ./buildroot: $(pwd)/buildroot"
|
||||||
|
echo "* ./source: $(pwd)/source"
|
||||||
|
echo "* ./dist: $(pwd)/dist"
|
||||||
|
echo "* ./downloads: $(pwd)/downloads"
|
||||||
|
echo "* ./pkgroot: $(pwd)/pkgroot"
|
||||||
|
echo "*"
|
||||||
|
|
||||||
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2
|
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2
|
||||||
else
|
else
|
||||||
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@
|
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ DOCKER_EXECUTABLE="docker"
|
|||||||
# shellcheck disable=SC2046
|
# shellcheck disable=SC2046
|
||||||
if [ $(id -u) -ne 0 ]; then
|
if [ $(id -u) -ne 0 ]; then
|
||||||
if ! docker info > /dev/null 2>&1; then
|
if ! docker info > /dev/null 2>&1; then
|
||||||
if [ "$SPC_USE_SUDO" != "yes" ]; then
|
if [ "$SPC_USE_SUDO" != "yes" ] && [ "$SPC_DOCKER_DEBUG" != "yes" ]; then
|
||||||
echo "Docker command requires sudo"
|
echo "Docker command requires sudo"
|
||||||
# shellcheck disable=SC2039
|
# shellcheck disable=SC2039
|
||||||
echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again'
|
echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again'
|
||||||
@@ -86,7 +86,7 @@ COPY ./composer.* /app/
|
|||||||
ADD ./bin/setup-runtime /app/bin/setup-runtime
|
ADD ./bin/setup-runtime /app/bin/setup-runtime
|
||||||
ADD ./bin/spc /app/bin/spc
|
ADD ./bin/spc /app/bin/spc
|
||||||
RUN /app/bin/setup-runtime
|
RUN /app/bin/setup-runtime
|
||||||
RUN /app/bin/php /app/bin/composer install --no-dev --classmap-authoritative
|
RUN /app/bin/php /app/bin/composer install --no-dev
|
||||||
ENV PATH="/app/bin:/cmake/bin:$PATH"
|
ENV PATH="/app/bin:/cmake/bin:$PATH"
|
||||||
ENV SPC_LIBC=glibc
|
ENV SPC_LIBC=glibc
|
||||||
|
|
||||||
@@ -145,4 +145,22 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"'
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
# shellcheck disable=SC2090
|
# shellcheck disable=SC2090
|
||||||
|
|
||||||
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
|
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
||||||
|
echo "* Debug mode enabled, run docker in interactive mode."
|
||||||
|
echo "* You can use 'exit' to exit the docker container."
|
||||||
|
echo "* You can use 'bin/spc' like normal builds."
|
||||||
|
echo "*"
|
||||||
|
echo "* Mounted directories:"
|
||||||
|
echo "* ./config: $(pwd)/config"
|
||||||
|
echo "* ./src: $(pwd)/src"
|
||||||
|
echo "* ./buildroot: $(pwd)/buildroot"
|
||||||
|
echo "* ./source: $(pwd)/source"
|
||||||
|
echo "* ./dist: $(pwd)/dist"
|
||||||
|
echo "* ./downloads: $(pwd)/downloads"
|
||||||
|
echo "* ./pkgroot: $(pwd)/pkgroot"
|
||||||
|
echo "*"
|
||||||
|
|
||||||
|
$DOCKER_EXECUTABLE run --rm -it --privileged $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH
|
||||||
|
else
|
||||||
|
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
|
||||||
|
fi
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
; PATH: static-php-cli will add `$BUILD_BIN_PATH` to PATH.
|
; PATH: static-php-cli will add `$BUILD_BIN_PATH` to PATH.
|
||||||
; PKG_CONFIG: static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG.
|
; PKG_CONFIG: static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG.
|
||||||
; PKG_CONFIG_PATH: static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH.
|
; PKG_CONFIG_PATH: static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH.
|
||||||
; SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS: the default optimization CFLAGS for compiling php. (if --no-strip option is set: `-g -O0`, else: `-g -Os`)
|
|
||||||
;
|
;
|
||||||
; * These vars are only be defined in LinuxBuilder and cannot be changed anywhere:
|
; * These vars are only be defined in LinuxBuilder and cannot be changed anywhere:
|
||||||
; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`)
|
; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`)
|
||||||
@@ -50,7 +49,7 @@ SPC_SKIP_DOCTOR_CHECK_ITEMS=""
|
|||||||
; RHEL: /usr/lib64/php/modules
|
; RHEL: /usr/lib64/php/modules
|
||||||
; Alpine: /usr/lib/php{PHP_VERSION}/modules
|
; Alpine: /usr/lib/php{PHP_VERSION}/modules
|
||||||
; where {PHP_VERSION} is 84 for php 8.4
|
; where {PHP_VERSION} is 84 for php 8.4
|
||||||
EXTENSION_DIR=
|
; EXTENSION_DIR=
|
||||||
|
|
||||||
[windows]
|
[windows]
|
||||||
; php-sdk-binary-tools path
|
; php-sdk-binary-tools path
|
||||||
@@ -98,9 +97,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
|
|||||||
; LIBS for configuring php
|
; LIBS for configuring php
|
||||||
SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm"
|
SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm"
|
||||||
; EXTRA_CFLAGS for `make` php
|
; EXTRA_CFLAGS for `make` php
|
||||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE -fPIC"
|
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-ident -fPIE -fPIC"
|
||||||
; EXTRA_LIBS for `make` php
|
; EXTRA_LIBS for `make` php
|
||||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS=""
|
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm"
|
||||||
; EXTRA_LDFLAGS_PROGRAM for `make` php
|
; EXTRA_LDFLAGS_PROGRAM for `make` php
|
||||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
|
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
|
||||||
|
|
||||||
@@ -132,7 +131,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}"
|
|||||||
; LDFLAGS for configuring php
|
; LDFLAGS for configuring php
|
||||||
SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
|
SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
|
||||||
; EXTRA_CFLAGS for `make` php
|
; EXTRA_CFLAGS for `make` php
|
||||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS}"
|
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
|
||||||
; EXTRA_LIBS for `make` php
|
; EXTRA_LIBS for `make` php
|
||||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv"
|
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv"
|
||||||
; embed type for php, static (libphp.a) or shared (libphp.dylib)
|
; embed type for php, static (libphp.a) or shared (libphp.dylib)
|
||||||
|
|||||||
@@ -92,6 +92,11 @@
|
|||||||
},
|
},
|
||||||
"type": "wip"
|
"type": "wip"
|
||||||
},
|
},
|
||||||
|
"ev": {
|
||||||
|
"type": "external",
|
||||||
|
"source": "ev",
|
||||||
|
"arg-type-windows": "with"
|
||||||
|
},
|
||||||
"event": {
|
"event": {
|
||||||
"support": {
|
"support": {
|
||||||
"Windows": "wip",
|
"Windows": "wip",
|
||||||
@@ -119,6 +124,10 @@
|
|||||||
"Linux": "partial",
|
"Linux": "partial",
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
|
"target": [
|
||||||
|
"static",
|
||||||
|
"shared"
|
||||||
|
],
|
||||||
"notes": true,
|
"notes": true,
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
@@ -253,6 +262,7 @@
|
|||||||
"Windows": "wip",
|
"Windows": "wip",
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
|
"notes": true,
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "ext-imagick",
|
"source": "ext-imagick",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
@@ -426,6 +436,17 @@
|
|||||||
},
|
},
|
||||||
"notes": true
|
"notes": true
|
||||||
},
|
},
|
||||||
|
"odbc": {
|
||||||
|
"support": {
|
||||||
|
"BSD": "wip",
|
||||||
|
"Windows": "wip"
|
||||||
|
},
|
||||||
|
"type": "builtin",
|
||||||
|
"arg-type-unix": "custom",
|
||||||
|
"lib-depends-unix": [
|
||||||
|
"unixodbc"
|
||||||
|
]
|
||||||
|
},
|
||||||
"opcache": {
|
"opcache": {
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type-unix": "custom"
|
"arg-type-unix": "custom"
|
||||||
@@ -492,19 +513,36 @@
|
|||||||
"mysqlnd"
|
"mysqlnd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pdo_odbc": {
|
||||||
|
"support": {
|
||||||
|
"BSD": "wip"
|
||||||
|
},
|
||||||
|
"type": "builtin",
|
||||||
|
"arg-type": "custom",
|
||||||
|
"lib-depends-unix": [
|
||||||
|
"unixodbc"
|
||||||
|
],
|
||||||
|
"ext-depends": [
|
||||||
|
"pdo",
|
||||||
|
"odbc"
|
||||||
|
]
|
||||||
|
},
|
||||||
"pdo_pgsql": {
|
"pdo_pgsql": {
|
||||||
"support": {
|
"support": {
|
||||||
"Windows": "wip",
|
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with-prefix",
|
"arg-type": "with-prefix",
|
||||||
|
"arg-type-windows": "custom",
|
||||||
"ext-depends": [
|
"ext-depends": [
|
||||||
"pdo",
|
"pdo",
|
||||||
"pgsql"
|
"pgsql"
|
||||||
],
|
],
|
||||||
"lib-depends": [
|
"lib-depends-unix": [
|
||||||
"postgresql"
|
"postgresql"
|
||||||
|
],
|
||||||
|
"lib-depends-windows": [
|
||||||
|
"postgresql-win"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"pdo_sqlite": {
|
"pdo_sqlite": {
|
||||||
@@ -535,14 +573,16 @@
|
|||||||
},
|
},
|
||||||
"pgsql": {
|
"pgsql": {
|
||||||
"support": {
|
"support": {
|
||||||
"Windows": "wip",
|
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
"notes": true,
|
"notes": true,
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "custom",
|
"arg-type": "custom",
|
||||||
"lib-depends": [
|
"lib-depends-unix": [
|
||||||
"postgresql"
|
"postgresql"
|
||||||
|
],
|
||||||
|
"lib-depends-windows": [
|
||||||
|
"postgresql-win"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"phar": {
|
"phar": {
|
||||||
@@ -741,6 +781,9 @@
|
|||||||
"Windows": "no",
|
"Windows": "no",
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
|
"target": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
"notes": true,
|
"notes": true,
|
||||||
"type": "external",
|
"type": "external",
|
||||||
"source": "swoole",
|
"source": "swoole",
|
||||||
@@ -888,12 +931,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"xdebug": {
|
"xdebug": {
|
||||||
"type": "builtin",
|
"type": "external",
|
||||||
|
"source": "xdebug",
|
||||||
|
"target": [
|
||||||
|
"shared"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"Windows": "wip",
|
"Windows": "wip",
|
||||||
"BSD": "no",
|
"BSD": "no",
|
||||||
"Darwin": "no",
|
"Darwin": "partial",
|
||||||
"Linux": "no"
|
"Linux": "partial"
|
||||||
},
|
},
|
||||||
"notes": true
|
"notes": true
|
||||||
},
|
},
|
||||||
@@ -1009,6 +1056,9 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"BSD": "wip"
|
"BSD": "wip"
|
||||||
},
|
},
|
||||||
|
"target": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
"type": "builtin",
|
"type": "builtin",
|
||||||
"arg-type": "with-prefix",
|
"arg-type": "with-prefix",
|
||||||
"arg-type-windows": "enable",
|
"arg-type-windows": "enable",
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
"libcurl.a"
|
"libcurl.a"
|
||||||
],
|
],
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
"libcurl.lib"
|
"libcurl_a.lib"
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
"curl"
|
"curl"
|
||||||
@@ -78,7 +78,6 @@
|
|||||||
"zlib"
|
"zlib"
|
||||||
],
|
],
|
||||||
"lib-depends-windows": [
|
"lib-depends-windows": [
|
||||||
"openssl",
|
|
||||||
"zlib",
|
"zlib",
|
||||||
"libssh2",
|
"libssh2",
|
||||||
"nghttp2"
|
"nghttp2"
|
||||||
@@ -211,12 +210,12 @@
|
|||||||
"libwebp",
|
"libwebp",
|
||||||
"freetype",
|
"freetype",
|
||||||
"libtiff",
|
"libtiff",
|
||||||
"libheif"
|
"libheif",
|
||||||
|
"bzip2"
|
||||||
],
|
],
|
||||||
"lib-suggests": [
|
"lib-suggests": [
|
||||||
"zstd",
|
"zstd",
|
||||||
"xz",
|
"xz",
|
||||||
"bzip2",
|
|
||||||
"libzip",
|
"libzip",
|
||||||
"libxml2"
|
"libxml2"
|
||||||
]
|
]
|
||||||
@@ -282,8 +281,7 @@
|
|||||||
"headers-unix": [
|
"headers-unix": [
|
||||||
"ares.h",
|
"ares.h",
|
||||||
"ares_dns.h",
|
"ares_dns.h",
|
||||||
"ares_nameser.h",
|
"ares_nameser.h"
|
||||||
"ares_rules.h"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"libde265": {
|
"libde265": {
|
||||||
@@ -589,6 +587,12 @@
|
|||||||
"openssl"
|
"openssl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"mimalloc": {
|
||||||
|
"source": "mimalloc",
|
||||||
|
"static-libs-unix": [
|
||||||
|
"mimalloc.o"
|
||||||
|
]
|
||||||
|
},
|
||||||
"ncurses": {
|
"ncurses": {
|
||||||
"source": "ncurses",
|
"source": "ncurses",
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
@@ -666,6 +670,14 @@
|
|||||||
"zstd"
|
"zstd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"postgresql-win": {
|
||||||
|
"source": "postgresql-win",
|
||||||
|
"static-libs": [
|
||||||
|
"libpq.lib",
|
||||||
|
"libpgport.lib",
|
||||||
|
"libpgcommon.lib"
|
||||||
|
]
|
||||||
|
},
|
||||||
"pthreads4w": {
|
"pthreads4w": {
|
||||||
"source": "pthreads4w",
|
"source": "pthreads4w",
|
||||||
"static-libs-windows": [
|
"static-libs-windows": [
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"nasm-x86_64-win": {
|
"nasm-x86_64-win": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
|
"url": "https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip",
|
||||||
"extract-files": {
|
"extract-files": {
|
||||||
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
|
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
|
||||||
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
|
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"repo": "static-php/static-php-cli-hosted",
|
"repo": "static-php/static-php-cli-hosted",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"match-pattern": "{name}-{arch}-{os}.txz",
|
"match-pattern-linux": "{name}-{arch}-{os}-{libc}-{libcver}.txz",
|
||||||
"suffix": "txz"
|
"match-pattern": "{name}-{arch}-{os}.txz"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attr": {
|
"attr": {
|
||||||
"type": "git",
|
"alt": {
|
||||||
"rev": "v2.5.2",
|
"type": "url",
|
||||||
"url": "https://git.savannah.nongnu.org/git/attr.git",
|
"url": "https://mirror.souseiseki.middlendian.com/nongnu/attr/attr-2.5.2.tar.gz"
|
||||||
|
},
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://download.savannah.nongnu.org/releases/attr/attr-2.5.2.tar.gz",
|
||||||
"provide-pre-built": true,
|
"provide-pre-built": true,
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@@ -89,6 +92,16 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ev": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/ev",
|
||||||
|
"path": "php-src/ext/ev",
|
||||||
|
"filename": "ev.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ext-ds": {
|
"ext-ds": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/ds",
|
"url": "https://pecl.php.net/get/ds",
|
||||||
@@ -335,9 +348,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libacl": {
|
"libacl": {
|
||||||
"type": "git",
|
"alt": {
|
||||||
"rev": "v2.3.2",
|
"type": "url",
|
||||||
"url": "https://git.savannah.nongnu.org/git/acl.git",
|
"url": "https://mirror.souseiseki.middlendian.com/nongnu/acl/acl-2.3.2.tar.gz"
|
||||||
|
},
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://download.savannah.nongnu.org/releases/acl/acl-2.3.2.tar.gz",
|
||||||
"provide-pre-built": true,
|
"provide-pre-built": true,
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
@@ -636,6 +652,16 @@
|
|||||||
"path": "LICENSE"
|
"path": "LICENSE"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mimalloc": {
|
||||||
|
"type": "ghtagtar",
|
||||||
|
"repo": "microsoft/mimalloc",
|
||||||
|
"match": "v2\\.\\d\\.[^3].*",
|
||||||
|
"provide-pre-built": false,
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
"type": "ghrel",
|
"type": "ghrel",
|
||||||
"repo": "mongodb/mongo-php-driver",
|
"repo": "mongodb/mongo-php-driver",
|
||||||
@@ -751,6 +777,14 @@
|
|||||||
"path": "COPYRIGHT"
|
"path": "COPYRIGHT"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"postgresql-win": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://get.enterprisedb.com/postgresql/postgresql-16.8-1-windows-x64-binaries.zip",
|
||||||
|
"license": {
|
||||||
|
"type": "text",
|
||||||
|
"text": "PostgreSQL Database Management System\n(also known as Postgres, formerly as Postgres95)\n\nPortions Copyright (c) 1996-2025, The PostgreSQL Global Development Group\n\nPortions Copyright (c) 1994, The Regents of the University of California\n\nPermission to use, copy, modify, and distribute this software and its\ndocumentation for any purpose, without fee, and without a written\nagreement is hereby granted, provided that the above copyright notice\nand this paragraph and the following two paragraphs appear in all\ncopies.\n\nIN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY\nFOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,\nINCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS\nDOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGE.\n\nTHE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS\nON AN \"AS IS\" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS\nTO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
|
||||||
|
}
|
||||||
|
},
|
||||||
"protobuf": {
|
"protobuf": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/protobuf",
|
"url": "https://pecl.php.net/get/protobuf",
|
||||||
@@ -895,6 +929,15 @@
|
|||||||
"path": "COPYING"
|
"path": "COPYING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"xdebug": {
|
||||||
|
"type": "url",
|
||||||
|
"url": "https://pecl.php.net/get/xdebug",
|
||||||
|
"filename": "xdebug.tgz",
|
||||||
|
"license": {
|
||||||
|
"type": "file",
|
||||||
|
"path": "LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
"xhprof": {
|
"xhprof": {
|
||||||
"type": "url",
|
"type": "url",
|
||||||
"url": "https://pecl.php.net/get/xhprof",
|
"url": "https://pecl.php.net/get/xhprof",
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ This extension contains an implementation of the coroutine environment for `pdo_
|
|||||||
|
|
||||||
1. Only PHP 8.0 ~ 8.4 is supported.
|
1. Only PHP 8.0 ~ 8.4 is supported.
|
||||||
|
|
||||||
|
## imagick
|
||||||
|
|
||||||
|
1. The imagick extension currently only has openmp support on musl libc. This means that multithreading is disabled on glibc or other operating systems. The extension is still fully functional.
|
||||||
|
|
||||||
## imap
|
## imap
|
||||||
|
|
||||||
1. Kerberos is not supported
|
1. Kerberos is not supported
|
||||||
@@ -76,11 +80,9 @@ and this extension cannot be compiled into php by static linking, so it cannot b
|
|||||||
|
|
||||||
## xdebug
|
## xdebug
|
||||||
|
|
||||||
1. Xdebug is a Zend extension. The functions of Xdebug depend on PHP's Zend engine and underlying code.
|
1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc.
|
||||||
If you want to statically compile it into PHP, you may need a huge amount of patch code, which is not feasible.
|
2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug".
|
||||||
2. The macOS platform can compile an xdebug extension under PHP compiled on the same platform,
|
The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`.
|
||||||
extract the `xdebug.so` file, and then use the `--no-strip` parameter in static-php-cli to retain the debug symbol table and add the `ffi` extension.
|
|
||||||
The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`.
|
|
||||||
|
|
||||||
## xml
|
## xml
|
||||||
|
|
||||||
@@ -123,8 +125,8 @@ For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use
|
|||||||
|
|
||||||
## ffi
|
## ffi
|
||||||
|
|
||||||
1. Due to the limitation of Linux system, you cannot use it to load other `so` extensions in the purely static compiled state (spc defaults to pure static compilation).
|
1. Due to the limitation of musl libc's static linkage, you cannot use ffi because dynamic libraries cannot be loaded.
|
||||||
Linux supports loading so extensions only if they are non-statically compiled. If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc).
|
If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc).
|
||||||
2. macOS supports the ffi extension, but errors will occur when some kernels do not contain debugging symbols.
|
2. macOS supports the ffi extension, but errors will occur when some kernels do not contain debugging symbols.
|
||||||
3. Windows x64 supports the ffi extension.
|
3. Windows x64 supports the ffi extension.
|
||||||
|
|
||||||
@@ -149,3 +151,9 @@ Parallel is only supported on PHP 8.0 ZTS and above.
|
|||||||
|
|
||||||
1. The [SPX extension](https://github.com/NoiseByNorthwest/php-spx) only supports NTS mode.
|
1. The [SPX extension](https://github.com/NoiseByNorthwest/php-spx) only supports NTS mode.
|
||||||
2. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx).
|
2. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx).
|
||||||
|
|
||||||
|
## mimalloc
|
||||||
|
|
||||||
|
1. This is not technically an extension, but a library.
|
||||||
|
2. Building with `--with-libs="mimalloc"` on Linux or macOS will override the default allocator.
|
||||||
|
3. This is experimental for now, but is recommended in threaded environments.
|
||||||
@@ -314,6 +314,7 @@ You can try to use the following commands:
|
|||||||
- `--with-suggested-exts`: Add `ext-suggests` as dependencies when compiling
|
- `--with-suggested-exts`: Add `ext-suggests` as dependencies when compiling
|
||||||
- `--with-suggested-libs`: Add `lib-suggests` as dependencies when compiling
|
- `--with-suggested-libs`: Add `lib-suggests` as dependencies when compiling
|
||||||
- `--with-upx-pack`: Use UPX to reduce the size of the binary file after compilation (you need to use `bin/spc install-pkg upx` to install upx first)
|
- `--with-upx-pack`: Use UPX to reduce the size of the binary file after compilation (you need to use `bin/spc install-pkg upx` to install upx first)
|
||||||
|
- `--build-shared=XXX,YYY`: compile the specified extension into a shared library (the default is to compile into a static library)
|
||||||
|
|
||||||
For hardcoding INI options, it works for cli, micro, embed sapi. Here is a simple example where we preset a larger `memory_limit` and disable the `system` function:
|
For hardcoding INI options, it works for cli, micro, embed sapi. Here is a simple example where we preset a larger `memory_limit` and disable the `system` function:
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ swoole-hook-sqlite 与 `pdo_sqlite` 扩展冲突。如需使用 Swoole 和 `pdo_
|
|||||||
|
|
||||||
1. swow 仅支持 PHP 8.0 ~ 8.4 版本。
|
1. swow 仅支持 PHP 8.0 ~ 8.4 版本。
|
||||||
|
|
||||||
|
## imagick
|
||||||
|
|
||||||
|
imagick 扩展目前仅在 musl libc 上支持 OpenMP(libgomp)。使用 glibc 方式构建的 imagick 扩展无法支持多线程特性。
|
||||||
|
|
||||||
## imap
|
## imap
|
||||||
|
|
||||||
1. 该扩展目前不支持 Kerberos。
|
1. 该扩展目前不支持 Kerberos。
|
||||||
@@ -70,9 +74,9 @@ bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
|
|||||||
|
|
||||||
## xdebug
|
## xdebug
|
||||||
|
|
||||||
1. Xdebug 是一个 Zend 扩展,Xdebug 的功能依赖于 PHP 的 Zend 引擎和底层代码,如果要将其静态编译到 PHP 中,可能需要巨量的 patch 代码,这是不可行的。
|
1. Xdebug 只能作为共享扩展进行构建。在 Linux 上,您需要使用 static-php-cli 并设置 SPC_LIBC=glibc。
|
||||||
2. macOS 平台可以通过在相同平台编译的 PHP 下编译一个 xdebug 扩展,并提取其中的 `xdebug.so` 文件,再在 static-php-cli 中使用 `--no-strip` 参数保留调试符号表,同时加入 `ffi` 扩展。
|
2. 使用 Linux/glibc 或 macOS 时,您可以使用 `--build-shared=xdebug` 将 Xdebug 编译为共享扩展。
|
||||||
编译的 `./php` 二进制可以通过指定 INI 配置并运行,例如`./php -d 'zend_extension=xdebug.so' your-code.php`。
|
编译后的 `./php` 二进制文件可以通过指定 INI 文件进行配置和运行,例如 `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`。
|
||||||
|
|
||||||
## xml
|
## xml
|
||||||
|
|
||||||
@@ -113,9 +117,10 @@ pgsql 16.2 修复了这个 Bug,现在正常工作了。
|
|||||||
|
|
||||||
## ffi
|
## ffi
|
||||||
|
|
||||||
1. 因为 Linux 系统的限制,纯静态编译的状态下(spc 默认编译结果为纯静态)无法使用它加载其他 `so` 扩展。Linux 支持加载 so 扩展的前提是非静态编译。如果你需要使用 ffi 扩展,请参见 [编译 GNU libc 的 PHP](./build-with-glibc)。
|
1. 由于 musl libc 静态链接的限制,无法加载动态库,因此无法使用 ffi。
|
||||||
2. macOS 支持 ffi 扩展,但是部分内核下不包含调试符号时会出现错误。
|
如果您需要使用 ffi 扩展,请参阅 [使用 GNU libc 编译 PHP](./build-with-glibc)。
|
||||||
3. Windows 支持 ffi 扩展。
|
2. macOS 支持 ffi 扩展,但某些内核不包含调试符号时会出现错误。
|
||||||
|
3. Windows x64 支持 ffi 扩展。
|
||||||
|
|
||||||
## xhprof
|
## xhprof
|
||||||
|
|
||||||
@@ -136,3 +141,9 @@ parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`--
|
|||||||
|
|
||||||
1. [SPX 扩展](https://github.com/NoiseByNorthwest/php-spx) 只支持非线程模式。
|
1. [SPX 扩展](https://github.com/NoiseByNorthwest/php-spx) 只支持非线程模式。
|
||||||
2. SPX 目前不支持 Windows,且官方仓库也不支持静态编译,static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)。
|
2. SPX 目前不支持 Windows,且官方仓库也不支持静态编译,static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)。
|
||||||
|
|
||||||
|
## mimalloc
|
||||||
|
|
||||||
|
1. 从技术上讲,这不是扩展,而是一个库。
|
||||||
|
2. 在 Linux 或 macOS 上使用 `--with-libs="mimalloc"` 进行构建将覆盖默认分配器。
|
||||||
|
3. 目前,这还处于实验阶段,但建议在线程环境中使用。
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ bin/spc build mysqlnd,pdo_mysql --build-all --debug
|
|||||||
- `--with-suggested-exts`: 编译时将 `ext-suggests` 也作为编译依赖加入
|
- `--with-suggested-exts`: 编译时将 `ext-suggests` 也作为编译依赖加入
|
||||||
- `--with-suggested-libs`: 编译时将 `lib-suggests` 也作为编译依赖加入
|
- `--with-suggested-libs`: 编译时将 `lib-suggests` 也作为编译依赖加入
|
||||||
- `--with-upx-pack`: 编译后使用 UPX 减小二进制文件体积(需先使用 `bin/spc install-pkg upx` 安装 upx)
|
- `--with-upx-pack`: 编译后使用 UPX 减小二进制文件体积(需先使用 `bin/spc install-pkg upx` 安装 upx)
|
||||||
|
- `--build-shared=XXX,YYY`: 编译时将指定的扩展编译为共享库(默认编译为静态库)
|
||||||
|
|
||||||
硬编码 INI 选项适用于 cli、micro、embed。有关硬编码 INI 选项,下面是一个简单的例子,我们预设一个更大的 `memory_limit`,并且禁用 `system` 函数:
|
硬编码 INI 选项适用于 cli、micro、embed。有关硬编码 INI 选项,下面是一个简单的例子,我们预设一个更大的 `memory_limit`,并且禁用 `system` 函数:
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use Symfony\Component\Console\Application;
|
|||||||
*/
|
*/
|
||||||
final class ConsoleApplication extends Application
|
final class ConsoleApplication extends Application
|
||||||
{
|
{
|
||||||
public const VERSION = '2.5.0';
|
public const VERSION = '2.5.2';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -122,9 +122,12 @@ abstract class BuilderBase
|
|||||||
*
|
*
|
||||||
* @return Extension[]
|
* @return Extension[]
|
||||||
*/
|
*/
|
||||||
public function getExts(): array
|
public function getExts(bool $including_shared = true): array
|
||||||
{
|
{
|
||||||
return $this->exts;
|
if ($including_shared) {
|
||||||
|
return $this->exts;
|
||||||
|
}
|
||||||
|
return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +139,7 @@ abstract class BuilderBase
|
|||||||
public function hasCpp(): bool
|
public function hasCpp(): bool
|
||||||
{
|
{
|
||||||
// judge cpp-extension
|
// judge cpp-extension
|
||||||
$exts = array_keys($this->getExts());
|
$exts = array_keys($this->getExts(false));
|
||||||
foreach ($exts as $ext) {
|
foreach ($exts as $ext) {
|
||||||
if (Config::getExt($ext, 'cpp-extension', false) === true) {
|
if (Config::getExt($ext, 'cpp-extension', false) === true) {
|
||||||
return true;
|
return true;
|
||||||
@@ -170,23 +173,46 @@ abstract class BuilderBase
|
|||||||
* @throws \Throwable|WrongUsageException
|
* @throws \Throwable|WrongUsageException
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
public function proveExts(array $extensions, bool $skip_check_deps = false): void
|
public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false, bool $skip_extract = false): void
|
||||||
{
|
{
|
||||||
CustomExt::loadCustomExt();
|
CustomExt::loadCustomExt();
|
||||||
$this->emitPatchPoint('before-php-extract');
|
// judge ext
|
||||||
SourceManager::initSource(sources: ['php-src']);
|
foreach ($static_extensions as $ext) {
|
||||||
$this->emitPatchPoint('after-php-extract');
|
// if extension does not support static build, throw exception
|
||||||
if ($this->getPHPVersionID() >= 80000) {
|
if (!in_array('static', Config::getExtTarget($ext))) {
|
||||||
$this->emitPatchPoint('before-micro-extract');
|
throw new WrongUsageException('Extension [' . $ext . '] does not support static build!');
|
||||||
SourceManager::initSource(sources: ['micro']);
|
}
|
||||||
$this->emitPatchPoint('after-micro-extract');
|
|
||||||
}
|
}
|
||||||
$this->emitPatchPoint('before-exts-extract');
|
foreach ($shared_extensions as $ext) {
|
||||||
SourceManager::initSource(exts: $extensions);
|
// if extension does not support shared build, throw exception
|
||||||
$this->emitPatchPoint('after-exts-extract');
|
if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_extensions)) {
|
||||||
foreach ($extensions as $extension) {
|
throw new WrongUsageException('Extension [' . $ext . '] does not support shared build!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$skip_extract) {
|
||||||
|
$this->emitPatchPoint('before-php-extract');
|
||||||
|
SourceManager::initSource(sources: ['php-src'], source_only: true);
|
||||||
|
$this->emitPatchPoint('after-php-extract');
|
||||||
|
if ($this->getPHPVersionID() >= 80000) {
|
||||||
|
$this->emitPatchPoint('before-micro-extract');
|
||||||
|
SourceManager::initSource(sources: ['micro'], source_only: true);
|
||||||
|
$this->emitPatchPoint('after-micro-extract');
|
||||||
|
}
|
||||||
|
$this->emitPatchPoint('before-exts-extract');
|
||||||
|
SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]);
|
||||||
|
$this->emitPatchPoint('after-exts-extract');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([...$static_extensions, ...$shared_extensions] as $extension) {
|
||||||
$class = CustomExt::getExtClass($extension);
|
$class = CustomExt::getExtClass($extension);
|
||||||
|
/** @var Extension $ext */
|
||||||
$ext = new $class($extension, $this);
|
$ext = new $class($extension, $this);
|
||||||
|
if (in_array($extension, $static_extensions)) {
|
||||||
|
$ext->setBuildStatic();
|
||||||
|
}
|
||||||
|
if (in_array($extension, $shared_extensions)) {
|
||||||
|
$ext->setBuildShared();
|
||||||
|
}
|
||||||
$this->addExt($ext);
|
$this->addExt($ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,10 +220,10 @@ abstract class BuilderBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->getExts() as $ext) {
|
||||||
$ext->checkDependency();
|
$ext->checkDependency();
|
||||||
}
|
}
|
||||||
$this->ext_list = $extensions;
|
$this->ext_list = [...$static_extensions, ...$shared_extensions];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,6 +233,17 @@ abstract class BuilderBase
|
|||||||
*/
|
*/
|
||||||
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
|
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
|
||||||
|
|
||||||
|
public function buildSharedExts(): void
|
||||||
|
{
|
||||||
|
foreach ($this->getExts() as $ext) {
|
||||||
|
if (!$ext->isBuildShared()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger()->info('Building extension [' . $ext->getName() . '] as shared extension (' . $ext->getName() . '.so)');
|
||||||
|
$ext->buildShared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate extension enable arguments for configure.
|
* Generate extension enable arguments for configure.
|
||||||
* e.g. --enable-mbstring
|
* e.g. --enable-mbstring
|
||||||
@@ -214,10 +251,10 @@ abstract class BuilderBase
|
|||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public function makeExtensionArgs(): string
|
public function makeStaticExtensionArgs(): string
|
||||||
{
|
{
|
||||||
$ret = [];
|
$ret = [];
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->getExts(false) as $ext) {
|
||||||
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
|
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
|
||||||
$ret[] = trim($ext->getConfigureArg());
|
$ret[] = trim($ext->getConfigureArg());
|
||||||
}
|
}
|
||||||
@@ -396,7 +433,7 @@ abstract class BuilderBase
|
|||||||
foreach ($this->libs as $lib) {
|
foreach ($this->libs as $lib) {
|
||||||
$lib->validate();
|
$lib->validate();
|
||||||
}
|
}
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->getExts() as $ext) {
|
||||||
$ext->validate();
|
$ext->validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,7 +478,7 @@ abstract class BuilderBase
|
|||||||
{
|
{
|
||||||
$php = "<?php\n\necho '[micro-test-start]' . PHP_EOL;\n";
|
$php = "<?php\n\necho '[micro-test-start]' . PHP_EOL;\n";
|
||||||
|
|
||||||
foreach ($this->getExts() as $ext) {
|
foreach ($this->getExts(false) as $ext) {
|
||||||
$ext_name = $ext->getDistName();
|
$ext_name = $ext->getDistName();
|
||||||
if (!empty($ext_name)) {
|
if (!empty($ext_name)) {
|
||||||
$php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n";
|
$php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n";
|
||||||
|
|||||||
@@ -9,11 +9,18 @@ use SPC\exception\RuntimeException;
|
|||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\SPCConfigUtil;
|
||||||
|
|
||||||
class Extension
|
class Extension
|
||||||
{
|
{
|
||||||
protected array $dependencies = [];
|
protected array $dependencies = [];
|
||||||
|
|
||||||
|
protected bool $build_shared = false;
|
||||||
|
|
||||||
|
protected bool $build_static = false;
|
||||||
|
|
||||||
|
protected string $source_dir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
@@ -30,6 +37,18 @@ class Extension
|
|||||||
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
|
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
|
||||||
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
|
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
|
||||||
}
|
}
|
||||||
|
// set source_dir for builtin
|
||||||
|
if ($ext_type === 'builtin') {
|
||||||
|
$this->source_dir = SOURCE_PATH . '/php-src/ext/' . $this->name;
|
||||||
|
} else {
|
||||||
|
$source = Config::getExt($this->name, 'source');
|
||||||
|
if ($source === null) {
|
||||||
|
throw new RuntimeException("{$ext_type} extension {$name} source not found");
|
||||||
|
}
|
||||||
|
$source_path = Config::getSource($source)['path'] ?? null;
|
||||||
|
$source_path = $source_path === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $source_path;
|
||||||
|
$this->source_dir = $source_path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +151,7 @@ class Extension
|
|||||||
// Windows is not supported yet
|
// Windows is not supported yet
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -167,6 +186,21 @@ class Extension
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run shared extension check when cli is enabled
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function runSharedExtensionCheckUnix(): void
|
||||||
|
{
|
||||||
|
[$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "extension=' . BUILD_LIB_PATH . '/' . $this->getName() . '.so" --ri ' . $this->getName());
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException($this->getName() . '.so failed to load');
|
||||||
|
}
|
||||||
|
if ($this->isBuildStatic()) {
|
||||||
|
logger()->warning($this->getName() . '.so test succeeded, but has little significance since it is also compiled in statically.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
@@ -231,6 +265,53 @@ class Extension
|
|||||||
// do nothing, just throw wrong usage exception if not valid
|
// do nothing, just throw wrong usage exception if not valid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build shared extension
|
||||||
|
*
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function buildShared(): void
|
||||||
|
{
|
||||||
|
match (PHP_OS_FAMILY) {
|
||||||
|
'Darwin', 'Linux' => $this->buildUnixShared(),
|
||||||
|
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build shared extension for Unix
|
||||||
|
*
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws \ReflectionException
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function buildUnixShared(): void
|
||||||
|
{
|
||||||
|
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()]);
|
||||||
|
$env = [
|
||||||
|
'CFLAGS' => $config['cflags'],
|
||||||
|
'LDFLAGS' => $config['ldflags'],
|
||||||
|
'LIBS' => $config['libs'],
|
||||||
|
];
|
||||||
|
// prepare configure args
|
||||||
|
shell()->cd($this->source_dir)
|
||||||
|
->setEnv($env)
|
||||||
|
->execWithEnv(BUILD_BIN_PATH . '/phpize')
|
||||||
|
->execWithEnv('./configure ' . $this->getUnixConfigureArg(true) . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static')
|
||||||
|
->execWithEnv('make clean')
|
||||||
|
->execWithEnv('make -j' . $this->builder->concurrency);
|
||||||
|
|
||||||
|
// copy shared library
|
||||||
|
copy($this->source_dir . '/modules/' . $this->getDistName() . '.so', BUILD_LIB_PATH . '/' . $this->getDistName() . '.so');
|
||||||
|
// check shared extension with php-cli
|
||||||
|
if (file_exists(BUILD_BIN_PATH . '/php')) {
|
||||||
|
$this->runSharedExtensionCheckUnix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current extension version
|
* Get current extension version
|
||||||
*
|
*
|
||||||
@@ -241,6 +322,32 @@ class Extension
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setBuildStatic(): void
|
||||||
|
{
|
||||||
|
if (!in_array('static', Config::getExtTarget($this->name))) {
|
||||||
|
throw new WrongUsageException("Extension [{$this->name}] does not support static build!");
|
||||||
|
}
|
||||||
|
$this->build_static = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBuildShared(): void
|
||||||
|
{
|
||||||
|
if (!in_array('shared', Config::getExtTarget($this->name))) {
|
||||||
|
throw new WrongUsageException("Extension [{$this->name}] does not support shared build!");
|
||||||
|
}
|
||||||
|
$this->build_shared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBuildShared(): bool
|
||||||
|
{
|
||||||
|
return $this->build_shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBuildStatic(): bool
|
||||||
|
{
|
||||||
|
return $this->build_static;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourceManager;
|
use SPC\store\SourceManager;
|
||||||
|
|
||||||
@@ -45,8 +46,9 @@ abstract class LibraryBase
|
|||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
$source = Config::getLib(static::NAME, 'source');
|
$source = Config::getLib(static::NAME, 'source');
|
||||||
// if source is locked as pre-built, we just tryInstall it
|
// if source is locked as pre-built, we just tryInstall it
|
||||||
if (isset($lock[$source]) && ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
|
$pre_built_name = Downloader::getPreBuiltLockName($source);
|
||||||
return $this->tryInstall($lock[$source]['filename'], $force);
|
if (isset($lock[$pre_built_name]) && ($lock[$pre_built_name]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
|
return $this->tryInstall($lock[$pre_built_name]['filename'], $force);
|
||||||
}
|
}
|
||||||
return $this->tryBuild($force);
|
return $this->tryBuild($force);
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ abstract class LibraryBase
|
|||||||
// extract first if not exists
|
// extract first if not exists
|
||||||
if (!is_dir($this->source_dir)) {
|
if (!is_dir($this->source_dir)) {
|
||||||
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract');
|
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract');
|
||||||
SourceManager::initSource(libs: [static::NAME]);
|
SourceManager::initSource(libs: [static::NAME], source_only: true);
|
||||||
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract');
|
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class amqp extends Extension
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
|
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('dba')]
|
#[CustomExt('dba')]
|
||||||
class dba extends Extension
|
class dba extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
|
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
|
||||||
return '--enable-dba' . $qdbm;
|
return '--enable-dba' . $qdbm;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('enchant')]
|
#[CustomExt('enchant')]
|
||||||
class enchant extends Extension
|
class enchant extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$glibs = [
|
$glibs = [
|
||||||
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a',
|
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a',
|
||||||
|
|||||||
31
src/SPC/builder/extension/ev.php
Normal file
31
src/SPC/builder/extension/ev.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('ev')]
|
||||||
|
class ev extends Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public function patchBeforeBuildconf(): bool
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* replace EXTENSION('ev', php_ev_sources, true, ' /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
|
||||||
|
* to EXTENSION('ev', php_ev_sources, PHP_EV_SHARED, ' /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
|
||||||
|
*/
|
||||||
|
FileSystem::replaceFileLineContainsString(
|
||||||
|
$this->source_dir . '/config.w32',
|
||||||
|
'EXTENSION(\'ev\'',
|
||||||
|
" EXTENSION('ev', php_ev_sources, PHP_EV_SHARED, ' /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');"
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('event')]
|
#[CustomExt('event')]
|
||||||
class event extends Extension
|
class event extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH;
|
$arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH;
|
||||||
if ($this->builder->getLib('openssl')) {
|
if ($this->builder->getLib('openssl')) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('ffi')]
|
#[CustomExt('ffi')]
|
||||||
class ffi extends Extension
|
class ffi extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--with-ffi --enable-zend-signals';
|
return '--with-ffi --enable-zend-signals';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('gd')]
|
#[CustomExt('gd')]
|
||||||
class gd extends Extension
|
class gd extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--enable-gd';
|
$arg = '--enable-gd';
|
||||||
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';
|
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class glfw extends Extension
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
|
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class grpc extends Extension
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH;
|
return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace SPC\builder\extension;
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
use SPC\builder\Extension;
|
use SPC\builder\Extension;
|
||||||
use SPC\builder\linux\LinuxBuilder;
|
|
||||||
use SPC\util\CustomExt;
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
#[CustomExt('imagick')]
|
#[CustomExt('imagick')]
|
||||||
@@ -13,17 +12,18 @@ class imagick extends Extension
|
|||||||
{
|
{
|
||||||
public function patchBeforeMake(): bool
|
public function patchBeforeMake(): bool
|
||||||
{
|
{
|
||||||
// imagick may call omp_pause_all which requires -lgomp
|
if (getenv('SPC_LIBC') !== 'musl') {
|
||||||
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
|
return false;
|
||||||
if ($this->builder instanceof LinuxBuilder) {
|
|
||||||
$extra_libs .= (empty($extra_libs) ? '' : ' ') . '-lgomp ';
|
|
||||||
}
|
}
|
||||||
|
// imagick with calls omp_pause_all which requires -lgomp, on non-musl we build imagick without openmp
|
||||||
|
$extra_libs = trim(getenv('SPC_EXTRA_LIBS') . ' -lgomp');
|
||||||
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
|
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--with-imagick=' . BUILD_ROOT_PATH;
|
$disable_omp = getenv('SPC_LIBC') === 'musl' ? '' : ' ac_cv_func_omp_pause_resource_all=no';
|
||||||
|
return '--with-imagick=' . BUILD_ROOT_PATH . $disable_omp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class imap extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--with-imap=' . BUILD_ROOT_PATH;
|
$arg = '--with-imap=' . BUILD_ROOT_PATH;
|
||||||
if ($this->builder->getLib('openssl') !== null) {
|
if ($this->builder->getLib('openssl') !== null) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('memcache')]
|
#[CustomExt('memcache')]
|
||||||
class memcache extends Extension
|
class memcache extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
|
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('memcached')]
|
#[CustomExt('memcached')]
|
||||||
class memcached extends Extension
|
class memcached extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$rootdir = BUILD_ROOT_PATH;
|
$rootdir = BUILD_ROOT_PATH;
|
||||||
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";
|
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('mongodb')]
|
#[CustomExt('mongodb')]
|
||||||
class mongodb extends Extension
|
class mongodb extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = ' --enable-mongodb ';
|
$arg = ' --enable-mongodb ';
|
||||||
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';
|
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';
|
||||||
|
|||||||
17
src/SPC/builder/extension/odbc.php
Normal file
17
src/SPC/builder/extension/odbc.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('odbc')]
|
||||||
|
class odbc extends Extension
|
||||||
|
{
|
||||||
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
|
{
|
||||||
|
return '--with-unixODBC=' . BUILD_ROOT_PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ class opcache extends Extension
|
|||||||
return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false;
|
return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-opcache';
|
return '--enable-opcache';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class openssl extends Extension
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --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;
|
return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir;
|
||||||
|
|||||||
29
src/SPC/builder/extension/pdo_odbc.php
Normal file
29
src/SPC/builder/extension/pdo_odbc.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('pdo_odbc')]
|
||||||
|
class pdo_odbc extends Extension
|
||||||
|
{
|
||||||
|
public function patchBeforeBuildconf(): bool
|
||||||
|
{
|
||||||
|
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/pdo_odbc/config.m4', 'PDO_ODBC_LDFLAGS="$pdo_odbc_def_ldflags', 'PDO_ODBC_LDFLAGS="-liconv $pdo_odbc_def_ldflags');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
|
{
|
||||||
|
return '--with-pdo-odbc=unixODBC,' . BUILD_ROOT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--with-pdo-odbc';
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/SPC/builder/extension/pdo_pgsql.php
Normal file
17
src/SPC/builder/extension/pdo_pgsql.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('pdo_pgsql')]
|
||||||
|
class pdo_pgsql extends Extension
|
||||||
|
{
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
return '--with-pdo-pgsql=yes';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,11 +33,23 @@ class pgsql extends Extension
|
|||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
if ($this->builder->getPHPVersionID() >= 80400) {
|
if ($this->builder->getPHPVersionID() >= 80400) {
|
||||||
return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
|
return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
|
||||||
}
|
}
|
||||||
return '--with-pgsql=' . BUILD_ROOT_PATH;
|
return '--with-pgsql=' . BUILD_ROOT_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public function getWindowsConfigureArg(): string
|
||||||
|
{
|
||||||
|
if ($this->builder->getPHPVersionID() >= 80400) {
|
||||||
|
return '--with-pgsql';
|
||||||
|
}
|
||||||
|
return '--with-pgsql=' . BUILD_ROOT_PATH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('redis')]
|
#[CustomExt('redis')]
|
||||||
class redis extends Extension
|
class redis extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--enable-redis';
|
$arg = '--enable-redis';
|
||||||
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';
|
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class snappy extends Extension
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
|
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class spx extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--enable-spx';
|
$arg = '--enable-spx';
|
||||||
if ($this->builder->getExt('zlib') === null) {
|
if ($this->builder->getExt('zlib') === null) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class swoole extends Extension
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
// enable swoole
|
// enable swoole
|
||||||
$arg = '--enable-swoole';
|
$arg = '--enable-swoole';
|
||||||
@@ -49,7 +49,9 @@ class swoole extends Extension
|
|||||||
|
|
||||||
// additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature)
|
// 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('libcares') ? ' --enable-cares' : '';
|
||||||
$arg .= $this->builder->getLib('brotli') ? (' --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
|
if (!$shared) {
|
||||||
|
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
|
||||||
|
}
|
||||||
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-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.
|
// additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class swoole_hook_mysql extends Extension
|
|||||||
return 'swoole';
|
return 'swoole';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
// pdo_mysql doesn't need to be disabled
|
// 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
|
// enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class swoole_hook_pgsql extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
// enable swoole pgsql hook
|
// enable swoole pgsql hook
|
||||||
return '--enable-swoole-pgsql';
|
return '--enable-swoole-pgsql';
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class swoole_hook_sqlite extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
// enable swoole pgsql hook
|
// enable swoole pgsql hook
|
||||||
return '--enable-swoole-sqlite';
|
return '--enable-swoole-sqlite';
|
||||||
|
|||||||
21
src/SPC/builder/extension/xdebug.php
Normal file
21
src/SPC/builder/extension/xdebug.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\extension;
|
||||||
|
|
||||||
|
use SPC\builder\Extension;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\util\CustomExt;
|
||||||
|
|
||||||
|
#[CustomExt('xdebug')]
|
||||||
|
class xdebug extends Extension
|
||||||
|
{
|
||||||
|
public function runSharedExtensionCheckUnix(): void
|
||||||
|
{
|
||||||
|
[$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "zend_extension=' . BUILD_LIB_PATH . '/xdebug.so" --ri xdebug');
|
||||||
|
if ($ret !== 0) {
|
||||||
|
throw new RuntimeException('xdebug.so failed to load.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('xlswriter')]
|
#[CustomExt('xlswriter')]
|
||||||
class xlswriter extends Extension
|
class xlswriter extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = '--with-xlswriter --enable-reader';
|
$arg = '--with-xlswriter --enable-reader';
|
||||||
if ($this->builder->getLib('openssl')) {
|
if ($this->builder->getLib('openssl')) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class xml extends Extension
|
|||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$arg = match ($this->name) {
|
$arg = match ($this->name) {
|
||||||
'xml' => '--enable-xml',
|
'xml' => '--enable-xml',
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class yac extends Extension
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-yac --enable-igbinary --enable-json';
|
return '--enable-yac --enable-igbinary --enable-json';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('zlib')]
|
#[CustomExt('zlib')]
|
||||||
class zlib extends Extension
|
class zlib extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH;
|
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH;
|
||||||
return '--with-zlib' . $zlib_dir;
|
return '--with-zlib' . $zlib_dir;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
|
|||||||
#[CustomExt('zstd')]
|
#[CustomExt('zstd')]
|
||||||
class zstd extends Extension
|
class zstd extends Extension
|
||||||
{
|
{
|
||||||
public function getUnixConfigureArg(): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
return '--enable-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
|
return '--enable-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class BSDBuilder extends UnixBuilderBase
|
|||||||
$config_file_scan_dir .
|
$config_file_scan_dir .
|
||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$this->makeExtensionArgs()
|
$this->makeStaticExtensionArgs()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->emitPatchPoint('before-php-make');
|
$this->emitPatchPoint('before-php-make');
|
||||||
|
|||||||
@@ -150,12 +150,13 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
$enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
$enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
|
||||||
$enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
$enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
|
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
|
||||||
// prepare build php envs
|
// prepare build php envs
|
||||||
$envs_build_php = SystemUtil::makeEnvVarString([
|
$envs_build_php = SystemUtil::makeEnvVarString([
|
||||||
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
|
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
|
||||||
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
|
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
|
||||||
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
|
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
|
||||||
'LIBS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
|
'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// process micro upx patch if micro sapi enabled
|
// process micro upx patch if micro sapi enabled
|
||||||
@@ -181,7 +182,7 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$maxExecutionTimers .
|
$maxExecutionTimers .
|
||||||
$this->makeExtensionArgs() .
|
$this->makeStaticExtensionArgs() .
|
||||||
' ' . $envs_build_php . ' '
|
' ' . $envs_build_php . ' '
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -310,7 +311,7 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
shell()->cd(SOURCE_PATH . '/php-src')
|
||||||
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
->exec('sed -i "s|//lib|/lib|g" Makefile')
|
||||||
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
|
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
|
||||||
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/php-config', 'prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"');
|
$this->patchPhpScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMakeExtraVars(): array
|
private function getMakeExtraVars(): array
|
||||||
|
|||||||
@@ -182,4 +182,39 @@ class SystemUtil
|
|||||||
'arch', 'manjaro',
|
'arch', 'manjaro',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get libc version string from ldd
|
||||||
|
*/
|
||||||
|
public static function getLibcVersionIfExists(): ?string
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'glibc') {
|
||||||
|
$result = shell()->execWithResult('ldd --version', false);
|
||||||
|
if ($result[0] !== 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// get first line
|
||||||
|
$first_line = $result[1][0];
|
||||||
|
// match ldd version: "ldd (some useless text) 2.17" match 2.17
|
||||||
|
$pattern = '/ldd\s+\(.*?\)\s+(\d+\.\d+)/';
|
||||||
|
if (preg_match($pattern, $first_line, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
|
||||||
|
if (self::isMuslDist()) {
|
||||||
|
$result = shell()->execWithResult('ldd 2>&1', false);
|
||||||
|
} else {
|
||||||
|
$result = shell()->execWithResult('/usr/local/musl/lib/libc.so 2>&1', false);
|
||||||
|
}
|
||||||
|
// Match Version * line
|
||||||
|
// match ldd version: "Version 1.2.3" match 1.2.3
|
||||||
|
$pattern = '/Version\s+(\d+\.\d+\.\d+)/';
|
||||||
|
if (preg_match($pattern, $result[1][1] ?? '', $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/SPC/builder/linux/library/mimalloc.php
Normal file
12
src/SPC/builder/linux/library/mimalloc.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\linux\library;
|
||||||
|
|
||||||
|
class mimalloc extends LinuxLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\mimalloc;
|
||||||
|
|
||||||
|
public const NAME = 'mimalloc';
|
||||||
|
}
|
||||||
@@ -148,10 +148,12 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
|
||||||
|
|
||||||
// prepare build php envs
|
// prepare build php envs
|
||||||
|
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
|
||||||
$envs_build_php = SystemUtil::makeEnvVarString([
|
$envs_build_php = SystemUtil::makeEnvVarString([
|
||||||
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
|
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
|
||||||
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
|
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
|
||||||
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
|
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
|
||||||
|
'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->getLib('postgresql')) {
|
if ($this->getLib('postgresql')) {
|
||||||
@@ -174,7 +176,7 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
$config_file_scan_dir .
|
$config_file_scan_dir .
|
||||||
$json_74 .
|
$json_74 .
|
||||||
$zts .
|
$zts .
|
||||||
$this->makeExtensionArgs() . ' ' .
|
$this->makeStaticExtensionArgs() . ' ' .
|
||||||
$envs_build_php
|
$envs_build_php
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -298,6 +300,7 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
|
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
|
||||||
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
|
->exec('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');
|
||||||
|
$this->patchPhpScripts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMakeExtraVars(): array
|
private function getMakeExtraVars(): array
|
||||||
|
|||||||
12
src/SPC/builder/macos/library/mimalloc.php
Normal file
12
src/SPC/builder/macos/library/mimalloc.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\macos\library;
|
||||||
|
|
||||||
|
class mimalloc extends MacOSLibraryBase
|
||||||
|
{
|
||||||
|
use \SPC\builder\unix\library\mimalloc;
|
||||||
|
|
||||||
|
public const NAME = 'mimalloc';
|
||||||
|
}
|
||||||
@@ -146,7 +146,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
|
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->getExts(false) as $ext) {
|
||||||
logger()->debug('testing ext: ' . $ext->getName());
|
logger()->debug('testing ext: ' . $ext->getName());
|
||||||
$ext->runCliCheckUnix();
|
$ext->runCliCheckUnix();
|
||||||
}
|
}
|
||||||
@@ -238,4 +238,29 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
logger()->info('cleaning up');
|
logger()->info('cleaning up');
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch phpize and php-config if needed
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
protected function patchPhpScripts(): void
|
||||||
|
{
|
||||||
|
// patch phpize
|
||||||
|
if (file_exists(BUILD_BIN_PATH . '/phpize')) {
|
||||||
|
logger()->debug('Patching phpize prefix');
|
||||||
|
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
|
||||||
|
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
|
||||||
|
}
|
||||||
|
// patch php-config
|
||||||
|
if (file_exists(BUILD_BIN_PATH . '/php-config')) {
|
||||||
|
logger()->debug('Patching php-config prefix and libs order');
|
||||||
|
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
|
||||||
|
$php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
|
||||||
|
// move mimalloc to the beginning of libs
|
||||||
|
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
|
||||||
|
// move lstdc++ to the end of libs
|
||||||
|
$php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
|
||||||
|
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,17 @@ trait gettext
|
|||||||
$ldflags = $this->builder->getOption('enable-zts') ? '-lpthread' : '';
|
$ldflags = $this->builder->getOption('enable-zts') ? '-lpthread' : '';
|
||||||
|
|
||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
->setEnv(['CFLAGS' => "{$this->getLibExtraCFlags()} {$cflags}", 'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags, 'LIBS' => $this->getLibExtraLibs()])
|
->setEnv([
|
||||||
|
'CFLAGS' => "{$this->getLibExtraCFlags()} {$cflags}",
|
||||||
|
'LDFLAGS' => $this->getLibExtraLdFlags() ?: $ldflags,
|
||||||
|
'LIBS' => $this->getLibExtraLibs(),
|
||||||
|
])
|
||||||
->execWithEnv(
|
->execWithEnv(
|
||||||
'./configure ' .
|
'./configure ' .
|
||||||
'--enable-static ' .
|
'--enable-static ' .
|
||||||
'--disable-shared ' .
|
'--disable-shared ' .
|
||||||
'--disable-java ' .
|
'--disable-java ' .
|
||||||
'--disable-c+ ' .
|
'--disable-c++ ' .
|
||||||
$zts .
|
$zts .
|
||||||
$extra .
|
$extra .
|
||||||
'--with-included-gettext ' .
|
'--with-included-gettext ' .
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ trait imagemagick
|
|||||||
*/
|
*/
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
// TODO: imagemagick build with bzip2 failed with bugs, we need to fix it in the future
|
// TODO: glibc rh 10 toolset's libgomp.a was built without -fPIC -fPIE so we can't use openmp without depending on libgomp.so
|
||||||
$extra = '--without-jxl --without-x --enable-openmp --without-bzlib ';
|
$openmp = getenv('SPC_LIBC') === 'musl' ? '--enable-openmp' : '--disable-openmp';
|
||||||
|
$extra = "--without-jxl --without-x {$openmp} ";
|
||||||
$required_libs = '';
|
$required_libs = '';
|
||||||
$optional_libs = [
|
$optional_libs = [
|
||||||
'libzip' => 'zip',
|
'libzip' => 'zip',
|
||||||
@@ -27,10 +28,12 @@ trait imagemagick
|
|||||||
'libpng' => 'png',
|
'libpng' => 'png',
|
||||||
'libwebp' => 'webp',
|
'libwebp' => 'webp',
|
||||||
'libxml2' => 'xml',
|
'libxml2' => 'xml',
|
||||||
|
'libheif' => 'heic',
|
||||||
'zlib' => 'zlib',
|
'zlib' => 'zlib',
|
||||||
'xz' => 'lzma',
|
'xz' => 'lzma',
|
||||||
'zstd' => 'zstd',
|
'zstd' => 'zstd',
|
||||||
'freetype' => 'freetype',
|
'freetype' => 'freetype',
|
||||||
|
'bzip2' => 'bzlib',
|
||||||
];
|
];
|
||||||
foreach ($optional_libs as $lib => $option) {
|
foreach ($optional_libs as $lib => $option) {
|
||||||
$extra .= $this->builder->getLib($lib) ? "--with-{$option} " : "--without-{$option} ";
|
$extra .= $this->builder->getLib($lib) ? "--with-{$option} " : "--without-{$option} ";
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ trait libcares
|
|||||||
{
|
{
|
||||||
shell()->cd($this->source_dir)
|
shell()->cd($this->source_dir)
|
||||||
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
|
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
|
||||||
->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests')
|
->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests --with-pic')
|
||||||
->execWithEnv("make -j {$this->builder->concurrency}")
|
->execWithEnv("make -j {$this->builder->concurrency}")
|
||||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||||
|
|
||||||
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
|
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/SPC/builder/unix/library/mimalloc.php
Normal file
38
src/SPC/builder/unix/library/mimalloc.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\unix\library;
|
||||||
|
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
|
||||||
|
trait mimalloc
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
$args = '';
|
||||||
|
if (getenv('SPC_LIBC') === 'musl') {
|
||||||
|
$args .= '-DMI_LIBC_MUSL=ON ';
|
||||||
|
}
|
||||||
|
$args .= '-DMI_BUILD_SHARED=OFF ';
|
||||||
|
$args .= '-DMI_INSTALL_TOPLEVEL=ON ';
|
||||||
|
FileSystem::resetDir($this->source_dir . '/build');
|
||||||
|
shell()->cd($this->source_dir . '/build')
|
||||||
|
->execWithEnv(
|
||||||
|
'cmake ' .
|
||||||
|
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||||
|
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||||
|
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||||
|
$args .
|
||||||
|
'..'
|
||||||
|
)
|
||||||
|
->execWithEnv("make -j{$this->builder->concurrency}")
|
||||||
|
->execWithEnv('make install');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -95,8 +95,9 @@ class WindowsBuilder extends BuilderBase
|
|||||||
|
|
||||||
if (($logo = $this->getOption('with-micro-logo')) !== null) {
|
if (($logo = $this->getOption('with-micro-logo')) !== null) {
|
||||||
// realpath
|
// realpath
|
||||||
$logo = realpath($logo);
|
// $logo = realpath($logo);
|
||||||
$micro_logo = '--enable-micro-logo=' . $logo . ' ';
|
$micro_logo = '--enable-micro-logo=' . $logo . ' ';
|
||||||
|
copy($logo, SOURCE_PATH . '\php-src\\' . $logo);
|
||||||
} else {
|
} else {
|
||||||
$micro_logo = '';
|
$micro_logo = '';
|
||||||
}
|
}
|
||||||
@@ -118,7 +119,7 @@ class WindowsBuilder extends BuilderBase
|
|||||||
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
|
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
|
||||||
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
|
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
|
||||||
$config_file_scan_dir .
|
$config_file_scan_dir .
|
||||||
"{$this->makeExtensionArgs()} " .
|
"{$this->makeStaticExtensionArgs()} " .
|
||||||
$zts .
|
$zts .
|
||||||
'"'
|
'"'
|
||||||
);
|
);
|
||||||
@@ -285,7 +286,7 @@ class WindowsBuilder extends BuilderBase
|
|||||||
throw new RuntimeException('cli failed sanity check');
|
throw new RuntimeException('cli failed sanity check');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->exts as $ext) {
|
foreach ($this->getExts(false) as $ext) {
|
||||||
logger()->debug('testing ext: ' . $ext->getName());
|
logger()->debug('testing ext: ' . $ext->getName());
|
||||||
$ext->runCliCheckWindows();
|
$ext->runCliCheckWindows();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ class curl extends WindowsLibraryBase
|
|||||||
'-DBUILD_EXAMPLES=OFF ' . // disable examples
|
'-DBUILD_EXAMPLES=OFF ' . // disable examples
|
||||||
'-DUSE_LIBIDN2=OFF ' . // disable libidn2
|
'-DUSE_LIBIDN2=OFF ' . // disable libidn2
|
||||||
'-DCURL_USE_LIBPSL=OFF ' . // disable libpsl
|
'-DCURL_USE_LIBPSL=OFF ' . // disable libpsl
|
||||||
|
'-DCURL_USE_SCHANNEL=ON ' . // use Schannel instead of OpenSSL
|
||||||
|
'-DCURL_USE_OPENSSL=OFF ' . // disable openssl due to certificate issue
|
||||||
'-DCURL_ENABLE_SSL=ON ' .
|
'-DCURL_ENABLE_SSL=ON ' .
|
||||||
'-DUSE_NGHTTP2=ON ' . // enable nghttp2
|
'-DUSE_NGHTTP2=ON ' . // enable nghttp2
|
||||||
'-DCURL_USE_LIBSSH2=ON ' . // enable libssh2
|
'-DCURL_USE_LIBSSH2=ON ' . // enable libssh2
|
||||||
@@ -48,5 +50,7 @@ class curl extends WindowsLibraryBase
|
|||||||
$this->builder->makeSimpleWrapper('cmake'),
|
$this->builder->makeSimpleWrapper('cmake'),
|
||||||
"--build cmakebuild --config Release --target install -j{$this->builder->concurrency}"
|
"--build cmakebuild --config Release --target install -j{$this->builder->concurrency}"
|
||||||
);
|
);
|
||||||
|
// move libcurl.lib to libcurl_a.lib
|
||||||
|
rename(BUILD_LIB_PATH . '\libcurl.lib', BUILD_LIB_PATH . '\libcurl_a.lib');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/SPC/builder/windows/library/postgresql_win.php
Normal file
27
src/SPC/builder/windows/library/postgresql_win.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\builder\windows\library;
|
||||||
|
|
||||||
|
class postgresql_win extends WindowsLibraryBase
|
||||||
|
{
|
||||||
|
public const NAME = 'postgresql-win';
|
||||||
|
|
||||||
|
protected function build(): void
|
||||||
|
{
|
||||||
|
copy($this->source_dir . '\pgsql\lib\libpq.lib', BUILD_LIB_PATH . '\libpq.lib');
|
||||||
|
copy($this->source_dir . '\pgsql\lib\libpgport.lib', BUILD_LIB_PATH . '\libpgport.lib');
|
||||||
|
copy($this->source_dir . '\pgsql\lib\libpgcommon.lib', BUILD_LIB_PATH . '\libpgcommon.lib');
|
||||||
|
|
||||||
|
// create libpq folder in buildroot/includes/libpq
|
||||||
|
if (!file_exists(BUILD_INCLUDE_PATH . '\libpq')) {
|
||||||
|
mkdir(BUILD_INCLUDE_PATH . '\libpq');
|
||||||
|
}
|
||||||
|
|
||||||
|
$headerFiles = ['libpq-fe.h', 'postgres_ext.h', 'pg_config_ext.h', 'libpq\libpq-fs.h'];
|
||||||
|
foreach ($headerFiles as $header) {
|
||||||
|
copy($this->source_dir . '\pgsql\include\\' . $header, BUILD_INCLUDE_PATH . '\\' . $header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -165,7 +165,7 @@ abstract class BaseCommand extends Command
|
|||||||
return SPC_EXTENSION_ALIAS[$lower];
|
return SPC_EXTENSION_ALIAS[$lower];
|
||||||
}
|
}
|
||||||
return $lower;
|
return $lower;
|
||||||
}, is_array($ext_list) ? $ext_list : explode(',', $ext_list));
|
}, is_array($ext_list) ? $ext_list : array_filter(explode(',', $ext_list)));
|
||||||
|
|
||||||
// filter internals
|
// filter internals
|
||||||
return array_values(array_filter($ls, function ($x) {
|
return array_values(array_filter($ls, function ($x) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
|
|
||||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
|
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
|
||||||
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
|
||||||
|
$this->addOption('build-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', '');
|
||||||
$this->addOption('build-micro', null, null, 'Build micro SAPI');
|
$this->addOption('build-micro', null, null, 'Build micro SAPI');
|
||||||
$this->addOption('build-cli', null, null, 'Build cli SAPI');
|
$this->addOption('build-cli', null, null, 'Build cli SAPI');
|
||||||
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
|
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
|
||||||
@@ -52,13 +53,31 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
// transform string to array
|
// transform string to array
|
||||||
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
|
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
|
||||||
// transform string to array
|
// transform string to array
|
||||||
$extensions = $this->parseExtensionList($this->getArgument('extensions'));
|
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
|
||||||
|
// transform string to array
|
||||||
|
$static_extensions = $this->parseExtensionList($this->getArgument('extensions'));
|
||||||
|
|
||||||
// parse rule with options
|
// parse rule with options
|
||||||
$rule = $this->parseRules();
|
$rule = $this->parseRules($shared_extensions);
|
||||||
|
|
||||||
|
// check dynamic extension build env
|
||||||
|
// macOS must use --no-strip option
|
||||||
|
if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Darwin' && !$this->getOption('no-strip')) {
|
||||||
|
$this->output->writeln('MacOS does not support dynamic extension loading with stripped binary, please use --no-strip option!');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
// linux must build with glibc
|
||||||
|
if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') {
|
||||||
|
$this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!');
|
||||||
|
return static::FAILURE;
|
||||||
|
}
|
||||||
|
$static_and_shared = array_intersect($static_extensions, $shared_extensions);
|
||||||
|
if (!empty($static_and_shared)) {
|
||||||
|
$this->output->writeln('<comment>Building extensions [' . implode(',', $static_and_shared) . '] as both static and shared\, tests may not be accurate or fail.</comment>');
|
||||||
|
}
|
||||||
|
|
||||||
if ($rule === BUILD_TARGET_NONE) {
|
if ($rule === BUILD_TARGET_NONE) {
|
||||||
$this->output->writeln('<error>Please add at least one build target!</error>');
|
$this->output->writeln('<error>Please add at least one build SAPI!</error>');
|
||||||
$this->output->writeln("<comment>\t--build-cli\tBuild php-cli SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-cli\tBuild php-cli SAPI</comment>");
|
||||||
$this->output->writeln("<comment>\t--build-micro\tBuild phpmicro SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-micro\tBuild phpmicro SAPI</comment>");
|
||||||
$this->output->writeln("<comment>\t--build-fpm\tBuild php-fpm SAPI</comment>");
|
$this->output->writeln("<comment>\t--build-fpm\tBuild php-fpm SAPI</comment>");
|
||||||
@@ -107,18 +126,26 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||||
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
||||||
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $shared_extensions), $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||||
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
|
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
|
||||||
|
$display_extensions = array_map(fn ($ext) => in_array($ext, $shared_extensions) ? "*{$ext}" : $ext, $extensions);
|
||||||
|
|
||||||
|
// separate static and shared extensions from $extensions
|
||||||
|
// filter rule: including shared extensions if they are in $static_extensions or $shared_extensions
|
||||||
|
$static_extensions = array_filter($extensions, fn ($ext) => !in_array($ext, $shared_extensions) || in_array($ext, $static_extensions));
|
||||||
|
|
||||||
// print info
|
// print info
|
||||||
$indent_texts = [
|
$indent_texts = [
|
||||||
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
||||||
'Build SAPI' => $builder->getBuildTypeName($rule),
|
'Build SAPI' => $builder->getBuildTypeName($rule),
|
||||||
'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
|
'Extensions (' . count($extensions) . ')' => implode(',', $display_extensions),
|
||||||
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
|
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
|
||||||
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
|
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
|
||||||
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
|
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
|
||||||
];
|
];
|
||||||
|
if (!empty($shared_extensions) || ($rule & BUILD_TARGET_EMBED)) {
|
||||||
|
$indent_texts['Build Dev'] = 'yes';
|
||||||
|
}
|
||||||
if (!empty($this->input->getOption('with-config-file-path'))) {
|
if (!empty($this->input->getOption('with-config-file-path'))) {
|
||||||
$indent_texts['Config File Path'] = $this->input->getOption('with-config-file-path');
|
$indent_texts['Config File Path'] = $this->input->getOption('with-config-file-path');
|
||||||
}
|
}
|
||||||
@@ -152,8 +179,8 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
// compile libraries
|
// compile libraries
|
||||||
$builder->proveLibs($libraries);
|
$builder->proveLibs($libraries);
|
||||||
// check extensions
|
// check extensions
|
||||||
$builder->proveExts($extensions);
|
$builder->proveExts($static_extensions, $shared_extensions);
|
||||||
// validate libs and exts
|
// validate libs and extensions
|
||||||
$builder->validateLibsAndExts();
|
$builder->validateLibsAndExts();
|
||||||
|
|
||||||
// clean builds and sources
|
// clean builds and sources
|
||||||
@@ -183,6 +210,12 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
// start to build
|
// start to build
|
||||||
$builder->buildPHP($rule);
|
$builder->buildPHP($rule);
|
||||||
|
|
||||||
|
// build dynamic extensions if needed
|
||||||
|
if (!empty($shared_extensions)) {
|
||||||
|
logger()->info('Building shared extensions ...');
|
||||||
|
$builder->buildSharedExts();
|
||||||
|
}
|
||||||
|
|
||||||
// compile stopwatch :P
|
// compile stopwatch :P
|
||||||
$time = round(microtime(true) - START_TIME, 3);
|
$time = round(microtime(true) - START_TIME, 3);
|
||||||
logger()->info('');
|
logger()->info('');
|
||||||
@@ -211,6 +244,12 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
$path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm");
|
$path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm");
|
||||||
logger()->info("Static php-fpm binary path{$fixed}: {$path}");
|
logger()->info("Static php-fpm binary path{$fixed}: {$path}");
|
||||||
}
|
}
|
||||||
|
if (!empty($shared_extensions)) {
|
||||||
|
foreach ($shared_extensions as $ext) {
|
||||||
|
$path = FileSystem::convertPath("{$build_root_path}/lib/{$ext}.so");
|
||||||
|
logger()->info("Shared extension [{$ext}] path{$fixed}: {$path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// export metadata
|
// export metadata
|
||||||
file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||||
@@ -239,13 +278,13 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
/**
|
/**
|
||||||
* Parse build options to rule int.
|
* Parse build options to rule int.
|
||||||
*/
|
*/
|
||||||
private function parseRules(): int
|
private function parseRules(array $shared_extensions = []): int
|
||||||
{
|
{
|
||||||
$rule = BUILD_TARGET_NONE;
|
$rule = BUILD_TARGET_NONE;
|
||||||
$rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
|
||||||
$rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
|
||||||
$rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
|
||||||
$rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-embed') || !empty($shared_extensions) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
|
||||||
$rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
|
$rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
|
||||||
return $rule;
|
return $rule;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace SPC\command;
|
|||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@@ -47,30 +48,35 @@ class DeleteDownloadCommand extends BaseCommand
|
|||||||
$chosen_sources = $sources;
|
$chosen_sources = $sources;
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
|
||||||
|
$deleted_sources = [];
|
||||||
foreach ($chosen_sources as $source) {
|
foreach ($chosen_sources as $source) {
|
||||||
$source = trim($source);
|
$source = trim($source);
|
||||||
if (!isset($lock[$source])) {
|
foreach ([$source, Downloader::getPreBuiltLockName($source)] as $name) {
|
||||||
logger()->warning("Source/Package [{$source}] not locked or not downloaded, skipped.");
|
if (isset($lock[$name])) {
|
||||||
continue;
|
$deleted_sources[] = $name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($deleted_sources as $lock_name) {
|
||||||
// remove download file/dir if exists
|
// remove download file/dir if exists
|
||||||
if ($lock[$source]['source_type'] === 'archive') {
|
if ($lock[$lock_name]['source_type'] === 'archive') {
|
||||||
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['filename']))) {
|
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']))) {
|
||||||
logger()->info('Deleting file ' . $path);
|
logger()->info('Deleting file ' . $path);
|
||||||
unlink($path);
|
unlink($path);
|
||||||
} else {
|
} else {
|
||||||
logger()->warning("Source/Package [{$source}] file not found, skip deleting file.");
|
logger()->warning("Source/Package [{$lock_name}] file not found, skip deleting file.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['dirname']))) {
|
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname']))) {
|
||||||
logger()->info('Deleting dir ' . $path);
|
logger()->info('Deleting dir ' . $path);
|
||||||
FileSystem::removeDir($path);
|
FileSystem::removeDir($path);
|
||||||
} else {
|
} else {
|
||||||
logger()->warning("Source/Package [{$source}] directory not found, skip deleting dir.");
|
logger()->warning("Source/Package [{$lock_name}] directory not found, skip deleting dir.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove locked sources
|
// remove locked sources
|
||||||
unset($lock[$source]);
|
unset($lock[$lock_name]);
|
||||||
}
|
}
|
||||||
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||||
logger()->info('Delete success!');
|
logger()->info('Delete success!');
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
@@ -212,7 +213,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
if (isset($config['filename'])) {
|
if (isset($config['filename'])) {
|
||||||
$new_config['filename'] = $config['filename'];
|
$new_config['filename'] = $config['filename'];
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom url: {$new_config['url']}");
|
||||||
Downloader::downloadSource($source, $new_config, true);
|
Downloader::downloadSource($source, $new_config, true);
|
||||||
} elseif (isset($custom_gits[$source])) {
|
} elseif (isset($custom_gits[$source])) {
|
||||||
$config = Config::getSource($source);
|
$config = Config::getSource($source);
|
||||||
@@ -224,23 +225,30 @@ class DownloadCommand extends BaseCommand
|
|||||||
if (isset($config['path'])) {
|
if (isset($config['path'])) {
|
||||||
$new_config['path'] = $config['path'];
|
$new_config['path'] = $config['path'];
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} from custom git [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom git: {$new_config['url']}");
|
||||||
Downloader::downloadSource($source, $new_config, true);
|
Downloader::downloadSource($source, $new_config, true);
|
||||||
} else {
|
} else {
|
||||||
$config = Config::getSource($source);
|
$config = Config::getSource($source);
|
||||||
// Prefer pre-built, we need to search pre-built library
|
// Prefer pre-built, we need to search pre-built library
|
||||||
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
|
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
|
||||||
// We need to replace pattern
|
// We need to replace pattern
|
||||||
$find = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
|
$replace = [
|
||||||
|
'{name}' => $source,
|
||||||
|
'{arch}' => arch2gnu(php_uname('m')),
|
||||||
|
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||||
|
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||||
|
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||||
|
];
|
||||||
|
$find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern'));
|
||||||
// find filename in asset list
|
// find filename in asset list
|
||||||
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
|
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
|
||||||
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading pre-built content {$source}");
|
||||||
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
|
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_DOWNLOAD_PRE_BUILT);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
|
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
|
||||||
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,6 +360,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
*/
|
*/
|
||||||
private function findPreBuilt(array $assets, string $filename): ?string
|
private function findPreBuilt(array $assets, string $filename): ?string
|
||||||
{
|
{
|
||||||
|
logger()->debug("Finding pre-built asset {$filename}");
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
if ($asset['name'] === $filename) {
|
if ($asset['name'] === $filename) {
|
||||||
return $asset['browser_download_url'];
|
return $asset['browser_download_url'];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class ExtractCommand extends BaseCommand
|
|||||||
public function configure(): void
|
public function configure(): void
|
||||||
{
|
{
|
||||||
$this->addArgument('sources', InputArgument::REQUIRED, 'The sources will be compiled, comma separated');
|
$this->addArgument('sources', InputArgument::REQUIRED, 'The sources will be compiled, comma separated');
|
||||||
|
$this->addOption('source-only', null, null, 'Only check the source exist, do not check the lib and ext');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +35,7 @@ class ExtractCommand extends BaseCommand
|
|||||||
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
|
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
SourceManager::initSource(sources: $sources);
|
SourceManager::initSource(sources: $sources, source_only: $this->getOption('source-only'));
|
||||||
logger()->info('Extract done !');
|
logger()->info('Extract done !');
|
||||||
return static::SUCCESS;
|
return static::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class SPCConfigCommand extends BuildCommand
|
|||||||
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
$include_suggest_ext = $this->getOption('with-suggested-exts');
|
||||||
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
$include_suggest_lib = $this->getOption('with-suggested-libs');
|
||||||
|
|
||||||
$util = new SPCConfigUtil(null, $this->input);
|
$util = new SPCConfigUtil();
|
||||||
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||||
|
|
||||||
if ($this->getOption('includes')) {
|
if ($this->getOption('includes')) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace SPC\command\dev;
|
|||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\command\BaseCommand;
|
use SPC\command\BaseCommand;
|
||||||
use SPC\store\Config;
|
|
||||||
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;
|
||||||
@@ -31,8 +30,7 @@ class ExtVerCommand extends BaseCommand
|
|||||||
// Get lib object
|
// Get lib object
|
||||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||||
|
|
||||||
$ext_conf = Config::getExt($this->getArgument('extension'));
|
$builder->proveExts([$this->getArgument('extension')], [], true);
|
||||||
$builder->proveExts([$this->getArgument('extension')], true);
|
|
||||||
|
|
||||||
// Check whether lib is extracted
|
// Check whether lib is extracted
|
||||||
// if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
|
// if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace SPC\command\dev;
|
|||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\builder\LibraryBase;
|
use SPC\builder\LibraryBase;
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\command\BuildCommand;
|
use SPC\command\BuildCommand;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
@@ -23,6 +24,7 @@ class PackLibCommand extends BuildCommand
|
|||||||
public function configure(): void
|
public function configure(): void
|
||||||
{
|
{
|
||||||
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
|
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
|
||||||
|
$this->addOption('show-libc-ver', null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
@@ -47,7 +49,7 @@ class PackLibCommand extends BuildCommand
|
|||||||
// Get lock info
|
// Get lock info
|
||||||
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
$source = Config::getLib($lib->getName(), 'source');
|
$source = Config::getLib($lib->getName(), 'source');
|
||||||
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
|
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
|
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,16 @@ class PackLibCommand extends BuildCommand
|
|||||||
// write list to packlib_files.txt
|
// write list to packlib_files.txt
|
||||||
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
|
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
|
||||||
// pack
|
// pack
|
||||||
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
|
$filename = Config::getPreBuilt('match-pattern');
|
||||||
|
$replace = [
|
||||||
|
'{name}' => $lib->getName(),
|
||||||
|
'{arch}' => arch2gnu(php_uname('m')),
|
||||||
|
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||||
|
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||||
|
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||||
|
];
|
||||||
|
$filename = str_replace(array_keys($replace), array_values($replace), $filename);
|
||||||
|
$filename = WORKING_DIR . '/dist/' . $filename;
|
||||||
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
|
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
|
||||||
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
|
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,30 @@ class Config
|
|||||||
|
|
||||||
public static ?array $pre_built = null;
|
public static ?array $pre_built = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
public static function getPreBuilt(string $name): mixed
|
public static function getPreBuilt(string $name): mixed
|
||||||
{
|
{
|
||||||
if (self::$pre_built === null) {
|
if (self::$pre_built === null) {
|
||||||
self::$pre_built = FileSystem::loadConfigArray('pre-built');
|
self::$pre_built = FileSystem::loadConfigArray('pre-built');
|
||||||
}
|
}
|
||||||
|
$supported_sys_based = ['match-pattern', 'prefer-stable', 'repo'];
|
||||||
|
if (in_array($name, $supported_sys_based)) {
|
||||||
|
$m_key = match (PHP_OS_FAMILY) {
|
||||||
|
'Windows' => ['-windows', '-win', ''],
|
||||||
|
'Darwin' => ['-macos', '-unix', ''],
|
||||||
|
'Linux' => ['-linux', '-unix', ''],
|
||||||
|
'BSD' => ['-freebsd', '-bsd', '-unix', ''],
|
||||||
|
default => throw new WrongUsageException('OS ' . PHP_OS_FAMILY . ' is not supported'),
|
||||||
|
};
|
||||||
|
foreach ($m_key as $v) {
|
||||||
|
if (isset(self::$pre_built["{$name}{$v}"])) {
|
||||||
|
return self::$pre_built["{$name}{$v}"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return self::$pre_built[$name] ?? null;
|
return self::$pre_built[$name] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +125,21 @@ class Config
|
|||||||
return self::$lib;
|
return self::$lib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function getExtTarget(string $name): ?array
|
||||||
|
{
|
||||||
|
if (self::$ext === null) {
|
||||||
|
self::$ext = FileSystem::loadConfigArray('ext');
|
||||||
|
}
|
||||||
|
if (!isset(self::$ext[$name])) {
|
||||||
|
throw new WrongUsageException('ext [' . $name . '] is not supported yet');
|
||||||
|
}
|
||||||
|
return self::$ext[$name]['target'] ?? ['static', 'shared'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\store;
|
namespace SPC\store;
|
||||||
|
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
@@ -69,14 +70,19 @@ class Downloader
|
|||||||
retry: self::getRetryTime()
|
retry: self::getRetryTime()
|
||||||
), true);
|
), true);
|
||||||
|
|
||||||
if (($source['prefer-stable'] ?? false) === false) {
|
$url = null;
|
||||||
$url = $data[0]['tarball_url'];
|
for ($i = 0; $i < count($data); ++$i) {
|
||||||
} else {
|
if (($data[$i]['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
|
||||||
$id = 0;
|
continue;
|
||||||
while ($data[$id]['prerelease'] === true) {
|
}
|
||||||
++$id;
|
if (!($source['match'] ?? null)) {
|
||||||
|
$url = $data[$i]['tarball_url'] ?? null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (preg_match('|' . $source['match'] . '|', $data[$i]['tarball_url'])) {
|
||||||
|
$url = $data[$i]['tarball_url'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
$url = $data[$id]['tarball_url'] ?? null;
|
|
||||||
}
|
}
|
||||||
if (!$url) {
|
if (!$url) {
|
||||||
throw new DownloaderException("failed to find {$name} source");
|
throw new DownloaderException("failed to find {$name} source");
|
||||||
@@ -119,6 +125,7 @@ class Downloader
|
|||||||
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
|
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
logger()->debug("Found {$release['name']} releases assets");
|
||||||
if (!$match_result) {
|
if (!$match_result) {
|
||||||
return $release['assets'];
|
return $release['assets'];
|
||||||
}
|
}
|
||||||
@@ -184,7 +191,7 @@ class Downloader
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $download_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
logger()->debug("Downloading {$url}");
|
logger()->debug("Downloading {$url}");
|
||||||
$cancel_func = function () use ($filename) {
|
$cancel_func = function () use ($filename) {
|
||||||
@@ -197,12 +204,23 @@ class Downloader
|
|||||||
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
|
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
|
||||||
self::unregisterCancelEvent();
|
self::unregisterCancelEvent();
|
||||||
logger()->debug("Locking {$filename}");
|
logger()->debug("Locking {$filename}");
|
||||||
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
|
if ($download_as === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
|
$name = self::getPreBuiltLockName($name);
|
||||||
|
}
|
||||||
|
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $download_as]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to lock source.
|
* Try to lock source.
|
||||||
*
|
*
|
||||||
|
* @param string $name Source name
|
||||||
|
* @param array{
|
||||||
|
* source_type: string,
|
||||||
|
* dirname: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* move_path: ?string,
|
||||||
|
* lock_as: int
|
||||||
|
* } $data Source data
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public static function lockSource(string $name, array $data): void
|
public static function lockSource(string $name, array $data): void
|
||||||
@@ -223,7 +241,7 @@ class Downloader
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
|
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
|
||||||
if (file_exists($download_path)) {
|
if (file_exists($download_path)) {
|
||||||
@@ -241,6 +259,7 @@ class Downloader
|
|||||||
self::registerCancelEvent($cancel_func);
|
self::registerCancelEvent($cancel_func);
|
||||||
f_passthru(
|
f_passthru(
|
||||||
SPC_GIT_EXEC . ' clone' . $check .
|
SPC_GIT_EXEC . ' clone' . $check .
|
||||||
|
(defined('DEBUG_MODE') ? '' : ' --quiet') .
|
||||||
' --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}\""
|
||||||
);
|
);
|
||||||
@@ -278,8 +297,22 @@ class Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param string $name Package name
|
||||||
|
* @param null|array{
|
||||||
|
* type: string,
|
||||||
|
* repo: ?string,
|
||||||
|
* url: ?string,
|
||||||
|
* rev: ?string,
|
||||||
|
* path: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* match: ?string,
|
||||||
|
* prefer-stable: ?bool,
|
||||||
|
* extract-files: ?array<string, string>
|
||||||
|
* } $pkg Package config
|
||||||
|
* @param bool $force Download all the time even if it exists
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
|
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
|
||||||
{
|
{
|
||||||
@@ -296,50 +329,36 @@ class Downloader
|
|||||||
FileSystem::createDir(DOWNLOAD_PATH);
|
FileSystem::createDir(DOWNLOAD_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load lock file
|
if (self::isAlreadyDownloaded($name, $force, SPC_DOWNLOAD_PACKAGE)) {
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
return;
|
||||||
$lock = [];
|
|
||||||
} else {
|
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
|
||||||
}
|
|
||||||
// If lock file exists, skip downloading
|
|
||||||
if (isset($lock[$name]) && !$force) {
|
|
||||||
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
|
|
||||||
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['filename']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
|
|
||||||
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['dirname']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($pkg['type']) {
|
switch ($pkg['type']) {
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghtar': // GitHub Release (tar)
|
case 'ghtar': // GitHub Release (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
[$url, $filename] = self::getFromFileList($name, $pkg);
|
[$url, $filename] = self::getFromFileList($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'url': // Direct download URL
|
case 'url': // Direct download URL
|
||||||
$url = $pkg['url'];
|
$url = $pkg['url'];
|
||||||
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'git': // Git repo
|
case 'git': // Git repo
|
||||||
self::downloadGit(
|
self::downloadGit(
|
||||||
@@ -348,7 +367,7 @@ class Downloader
|
|||||||
$pkg['rev'],
|
$pkg['rev'],
|
||||||
$pkg['extract'] ?? null,
|
$pkg['extract'] ?? null,
|
||||||
self::getRetryTime(),
|
self::getRetryTime(),
|
||||||
SPC_LOCK_PRE_BUILT
|
SPC_DOWNLOAD_PRE_BUILT
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
@@ -377,15 +396,30 @@ class Downloader
|
|||||||
/**
|
/**
|
||||||
* Download source by name and meta.
|
* Download source by name and meta.
|
||||||
*
|
*
|
||||||
* @param string $name source name
|
* @param string $name source name
|
||||||
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
|
* @param null|array{
|
||||||
* @param bool $force Whether to force download (default: false)
|
* type: string,
|
||||||
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
|
* repo: ?string,
|
||||||
|
* url: ?string,
|
||||||
|
* rev: ?string,
|
||||||
|
* path: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* match: ?string,
|
||||||
|
* prefer-stable: ?bool,
|
||||||
|
* provide-pre-built: ?bool,
|
||||||
|
* license: array{
|
||||||
|
* type: string,
|
||||||
|
* path: ?string,
|
||||||
|
* text: ?string
|
||||||
|
* }
|
||||||
|
* } $source source meta info: [type, path, rev, url, filename, regex, license]
|
||||||
|
* @param bool $force Whether to force download (default: false)
|
||||||
|
* @param int $download_as Lock source type (default: SPC_LOCK_SOURCE)
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $download_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
if ($source === null) {
|
if ($source === null) {
|
||||||
$source = Config::getSource($name);
|
$source = Config::getSource($name);
|
||||||
@@ -401,49 +435,36 @@ class Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// load lock file
|
// load lock file
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
if (self::isAlreadyDownloaded($name, $force, $download_as)) {
|
||||||
$lock = [];
|
return;
|
||||||
} else {
|
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
|
||||||
}
|
|
||||||
// If lock file exists, skip downloading
|
|
||||||
if (isset($lock[$name]) && !$force && ($lock[$name]['lock_as'] ?? SPC_LOCK_SOURCE) === $lock_as) {
|
|
||||||
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
|
|
||||||
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['filename']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
|
|
||||||
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['dirname']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($source['type']) {
|
switch ($source['type']) {
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghtar': // GitHub Release (tar)
|
case 'ghtar': // GitHub Release (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
[$url, $filename] = self::getFromFileList($name, $source);
|
[$url, $filename] = self::getFromFileList($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'url': // Direct download URL
|
case 'url': // Direct download URL
|
||||||
$url = $source['url'];
|
$url = $source['url'];
|
||||||
$filename = $source['filename'] ?? basename($source['url']);
|
$filename = $source['filename'] ?? basename($source['url']);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'git': // Git repo
|
case 'git': // Git repo
|
||||||
self::downloadGit(
|
self::downloadGit(
|
||||||
@@ -452,14 +473,14 @@ class Downloader
|
|||||||
$source['rev'],
|
$source['rev'],
|
||||||
$source['path'] ?? null,
|
$source['path'] ?? null,
|
||||||
self::getRetryTime(),
|
self::getRetryTime(),
|
||||||
$lock_as
|
$download_as
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
|
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
||||||
(new $class())->fetch($force, $source, $lock_as);
|
(new $class())->fetch($force, $source, $download_as);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -574,6 +595,11 @@ class Downloader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPreBuiltLockName(string $source): string
|
||||||
|
{
|
||||||
|
return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . (getenv('SPC_LIBC') ?: 'default') . '-' . (SystemUtil::getLibcVersionIfExists() ?? 'default');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register CTRL+C event for different OS.
|
* Register CTRL+C event for different OS.
|
||||||
*
|
*
|
||||||
@@ -606,4 +632,39 @@ class Downloader
|
|||||||
{
|
{
|
||||||
return intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0);
|
return intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
private static function isAlreadyDownloaded(string $name, bool $force, int $download_as = SPC_DOWNLOAD_SOURCE): bool
|
||||||
|
{
|
||||||
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
|
$lock = [];
|
||||||
|
} else {
|
||||||
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
}
|
||||||
|
// If lock file exists, skip downloading for source mode
|
||||||
|
if (!$force && $download_as === SPC_DOWNLOAD_SOURCE && isset($lock[$name])) {
|
||||||
|
if (
|
||||||
|
$lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename']) ||
|
||||||
|
$lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])
|
||||||
|
) {
|
||||||
|
logger()->notice("Source [{$name}] already downloaded: " . ($lock[$name]['filename'] ?? $lock[$name]['dirname']));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If lock file exists for current arch and glibc target, skip downloading
|
||||||
|
|
||||||
|
if (!$force && $download_as === SPC_DOWNLOAD_PRE_BUILT && isset($lock[$lock_name = self::getPreBuiltLockName($name)])) {
|
||||||
|
// lock name with env
|
||||||
|
if (
|
||||||
|
$lock[$lock_name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']) ||
|
||||||
|
$lock[$lock_name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname'])
|
||||||
|
) {
|
||||||
|
logger()->notice("Pre-built content [{$name}] already downloaded: " . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -461,6 +461,23 @@ class FileSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
public static function replaceFileLineContainsString(string $file, string $find, string $line): false|int
|
||||||
|
{
|
||||||
|
$lines = file($file);
|
||||||
|
if ($lines === false) {
|
||||||
|
throw new FileSystemException('Cannot read file: ' . $file);
|
||||||
|
}
|
||||||
|
foreach ($lines as $key => $value) {
|
||||||
|
if (str_contains($value, $find)) {
|
||||||
|
$lines[$key] = $line . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file_put_contents($file, implode('', $lines));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class SourceManager
|
|||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
public static function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null): void
|
public static function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null, bool $source_only = false): void
|
||||||
{
|
{
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
throw new WrongUsageException('Download lock file "downloads/.lock.json" not found, maybe you need to download sources first ?');
|
throw new WrongUsageException('Download lock file "downloads/.lock.json" not found, maybe you need to download sources first ?');
|
||||||
@@ -54,15 +54,22 @@ class SourceManager
|
|||||||
if (Config::getSource($source) === null) {
|
if (Config::getSource($source) === null) {
|
||||||
throw new WrongUsageException("Source [{$source}] does not exist, please check the name and correct it !");
|
throw new WrongUsageException("Source [{$source}] does not exist, please check the name and correct it !");
|
||||||
}
|
}
|
||||||
if (!isset($lock[$source])) {
|
// check source downloaded
|
||||||
throw new WrongUsageException('Source [' . $source . '] not downloaded or not locked, you should download it first !');
|
$pre_built_name = Downloader::getPreBuiltLockName($source);
|
||||||
|
if ($source_only || !isset($lock[$pre_built_name])) {
|
||||||
|
if (!isset($lock[$source])) {
|
||||||
|
throw new WrongUsageException("Source [{$source}] not downloaded or not locked, you should download it first !");
|
||||||
|
}
|
||||||
|
$lock_name = $source;
|
||||||
|
} else {
|
||||||
|
$lock_name = $pre_built_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check source dir exist
|
// check source dir exist
|
||||||
$check = $lock[$source]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$source]['move_path']);
|
$check = $lock[$lock_name]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$lock_name]['move_path']);
|
||||||
if (!is_dir($check)) {
|
if (!is_dir($check)) {
|
||||||
logger()->debug('Extracting source [' . $source . '] to ' . $check . ' ...');
|
logger()->debug('Extracting source [' . $source . '] to ' . $check . ' ...');
|
||||||
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$source]['filename'] ?? $lock[$source]['dirname']), $lock[$source]['move_path']);
|
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']), $lock[$lock_name]['move_path']);
|
||||||
} else {
|
} else {
|
||||||
logger()->debug('Source [' . $source . '] already extracted in ' . $check . ', skip !');
|
logger()->debug('Source [' . $source . '] already extracted in ' . $check . ', skip !');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class SourcePatcher
|
|||||||
*/
|
*/
|
||||||
public static function patchBeforeBuildconf(BuilderBase $builder): void
|
public static function patchBeforeBuildconf(BuilderBase $builder): void
|
||||||
{
|
{
|
||||||
foreach ($builder->getExts() as $ext) {
|
foreach ($builder->getExts(false) as $ext) {
|
||||||
if ($ext->patchBeforeBuildconf() === true) {
|
if ($ext->patchBeforeBuildconf() === true) {
|
||||||
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
|
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ class SourcePatcher
|
|||||||
*/
|
*/
|
||||||
public static function patchBeforeConfigure(BuilderBase $builder): void
|
public static function patchBeforeConfigure(BuilderBase $builder): void
|
||||||
{
|
{
|
||||||
foreach ($builder->getExts() as $ext) {
|
foreach ($builder->getExts(false) as $ext) {
|
||||||
if ($ext->patchBeforeConfigure() === true) {
|
if ($ext->patchBeforeConfigure() === true) {
|
||||||
logger()->info('Extension [' . $ext->getName() . '] patched before configure');
|
logger()->info('Extension [' . $ext->getName() . '] patched before configure');
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ class SourcePatcher
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// call extension patch before make
|
// call extension patch before make
|
||||||
foreach ($builder->getExts() as $ext) {
|
foreach ($builder->getExts(false) as $ext) {
|
||||||
if ($ext->patchBeforeMake() === true) {
|
if ($ext->patchBeforeMake() === true) {
|
||||||
logger()->info('Extension [' . $ext->getName() . '] patched before make');
|
logger()->info('Extension [' . $ext->getName() . '] patched before make');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ abstract class CustomSourceBase
|
|||||||
{
|
{
|
||||||
public const NAME = 'unknown';
|
public const NAME = 'unknown';
|
||||||
|
|
||||||
abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void;
|
abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class PhpSource extends CustomSourceBase
|
|||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.3';
|
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.3';
|
||||||
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
|
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class PostgreSQLSource extends CustomSourceBase
|
|||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
|
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ class GlobalEnvManager
|
|||||||
self::putenv('PATH=' . BUILD_ROOT_PATH . '/bin:' . getenv('PATH'));
|
self::putenv('PATH=' . BUILD_ROOT_PATH . '/bin:' . getenv('PATH'));
|
||||||
self::putenv('PKG_CONFIG=' . BUILD_BIN_PATH . '/pkg-config');
|
self::putenv('PKG_CONFIG=' . BUILD_BIN_PATH . '/pkg-config');
|
||||||
self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig');
|
self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig');
|
||||||
if ($builder instanceof BuilderBase) {
|
|
||||||
self::putenv('SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS=' . ($builder->getOption('no-strip') ? '-g -O0' : '-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define env vars for linux
|
// Define env vars for linux
|
||||||
|
|||||||
@@ -7,26 +7,51 @@ namespace SPC\util;
|
|||||||
use SPC\builder\BuilderBase;
|
use SPC\builder\BuilderBase;
|
||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\builder\macos\MacOSBuilder;
|
use SPC\builder\macos\MacOSBuilder;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\exception\RuntimeException;
|
||||||
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use Symfony\Component\Console\Input\ArgvInput;
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
|
|
||||||
class SPCConfigUtil
|
class SPCConfigUtil
|
||||||
{
|
{
|
||||||
public function __construct(private ?BuilderBase $builder = null, ?InputInterface $input = null)
|
private ?BuilderBase $builder = null;
|
||||||
|
|
||||||
|
public function __construct(?BuilderBase $builder = null)
|
||||||
{
|
{
|
||||||
if ($builder === null) {
|
if ($builder !== null) {
|
||||||
$this->builder = BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
|
$this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate configuration for building PHP extensions.
|
||||||
|
*
|
||||||
|
* @param array $extensions Extension name list
|
||||||
|
* @param array $libraries Additional library name list
|
||||||
|
* @param bool $include_suggest_ext Include suggested extensions
|
||||||
|
* @param bool $include_suggest_lib Include suggested libraries
|
||||||
|
* @return array{
|
||||||
|
* cflags: string,
|
||||||
|
* ldflags: string,
|
||||||
|
* libs: string
|
||||||
|
* }
|
||||||
|
* @throws \ReflectionException
|
||||||
|
* @throws FileSystemException
|
||||||
|
* @throws RuntimeException
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
|
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
|
||||||
{
|
{
|
||||||
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
$this->builder->proveLibs($libraries);
|
if ($this->builder === null) {
|
||||||
$this->builder->proveExts($extensions);
|
$this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput());
|
||||||
|
$this->builder->proveLibs($libraries);
|
||||||
|
$this->builder->proveExts($extensions, skip_extract: true);
|
||||||
|
}
|
||||||
ob_get_clean();
|
ob_get_clean();
|
||||||
$ldflags = $this->getLdflagsString();
|
$ldflags = $this->getLdflagsString();
|
||||||
$libs = $this->getLibsString($libraries);
|
$libs = $this->getLibsString($libraries);
|
||||||
@@ -42,10 +67,14 @@ class SPCConfigUtil
|
|||||||
if ($this->builder->hasCpp()) {
|
if ($this->builder->hasCpp()) {
|
||||||
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
|
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
|
||||||
}
|
}
|
||||||
|
// mimalloc must come first
|
||||||
|
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
|
||||||
|
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
'cflags' => $cflags,
|
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
|
||||||
'ldflags' => $ldflags,
|
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
|
||||||
'libs' => $libs,
|
'libs' => trim(getenv('LIBS') . ' ' . $libs),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +115,8 @@ class SPCConfigUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// patch: imagick (imagemagick wrapper) for linux needs -lgomp
|
// patch: imagick (imagemagick wrapper) for linux needs libgomp
|
||||||
if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux') {
|
if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
|
||||||
$short_name[] = '-lgomp';
|
$short_name[] = '-lgomp';
|
||||||
}
|
}
|
||||||
return implode(' ', $short_name);
|
return implode(' ', $short_name);
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ const SPC_EXTENSION_ALIAS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// spc lock type
|
// spc lock type
|
||||||
const SPC_LOCK_SOURCE = 1; // lock source
|
const SPC_DOWNLOAD_SOURCE = 1; // lock source
|
||||||
const SPC_LOCK_PRE_BUILT = 2; // lock pre-built
|
const SPC_DOWNLOAD_PRE_BUILT = 2; // lock pre-built
|
||||||
|
const SPC_DOWNLOAD_PACKAGE = 3; // lock as package
|
||||||
|
|
||||||
// file replace strategy
|
// file replace strategy
|
||||||
const REPLACE_FILE_STR = 1;
|
const REPLACE_FILE_STR = 1;
|
||||||
|
|||||||
@@ -3,3 +3,16 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
assert(function_exists('curl_init'));
|
assert(function_exists('curl_init'));
|
||||||
|
assert(function_exists('curl_setopt'));
|
||||||
|
assert(function_exists('curl_exec'));
|
||||||
|
assert(function_exists('curl_close'));
|
||||||
|
$curl_version = curl_version();
|
||||||
|
if (stripos($curl_version['ssl_version'], 'schannel') !== false) {
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt($curl, CURLOPT_URL, 'https://example.com/');
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($curl, CURLOPT_HEADER, 0);
|
||||||
|
$data = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
assert($data !== false);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is GitHub Actions automatic test extension args generator.
|
* This is GitHub Actions automatic test extension args generator.
|
||||||
* You can edit $extensions, $with_libs and $base_combination.
|
* You can edit $test_php_version, $test_os, $zts, $no_strip, $upx, $prefer_pre_built, $extensions, $with_libs and $base_combination.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// --------------------------------- edit area ---------------------------------
|
// --------------------------------- edit area ---------------------------------
|
||||||
|
|
||||||
// test php version
|
// test php version (8.1 ~ 8.4 available, multiple for matrix)
|
||||||
$test_php_version = [
|
$test_php_version = [
|
||||||
// '8.1',
|
'8.1',
|
||||||
// '8.2',
|
'8.2',
|
||||||
'8.3',
|
'8.3',
|
||||||
'8.4',
|
'8.4',
|
||||||
];
|
];
|
||||||
@@ -24,11 +24,15 @@ $test_os = [
|
|||||||
'macos-13',
|
'macos-13',
|
||||||
'macos-14',
|
'macos-14',
|
||||||
'ubuntu-latest',
|
'ubuntu-latest',
|
||||||
// 'windows-latest',
|
'ubuntu-22.04',
|
||||||
|
'ubuntu-24.04',
|
||||||
|
'ubuntu-22.04-arm',
|
||||||
|
'ubuntu-24.04-arm',
|
||||||
|
'windows-latest',
|
||||||
];
|
];
|
||||||
|
|
||||||
// whether enable thread safe
|
// whether enable thread safe
|
||||||
$zts = false;
|
$zts = true;
|
||||||
|
|
||||||
$no_strip = false;
|
$no_strip = false;
|
||||||
|
|
||||||
@@ -40,13 +44,19 @@ $prefer_pre_built = false;
|
|||||||
|
|
||||||
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||||
$extensions = match (PHP_OS_FAMILY) {
|
$extensions = match (PHP_OS_FAMILY) {
|
||||||
'Linux', 'Darwin' => 'gd',
|
'Linux', 'Darwin' => 'ev',
|
||||||
'Windows' => 'bcmath',
|
'Windows' => 'ev',
|
||||||
|
};
|
||||||
|
|
||||||
|
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
|
||||||
|
$shared_extensions = match (PHP_OS_FAMILY) {
|
||||||
|
'Linux' => 'xdebug',
|
||||||
|
'Windows', 'Darwin' => '',
|
||||||
};
|
};
|
||||||
|
|
||||||
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
|
||||||
$with_libs = match (PHP_OS_FAMILY) {
|
$with_libs = match (PHP_OS_FAMILY) {
|
||||||
'Linux', 'Darwin' => 'freetype',
|
'Linux', 'Darwin' => '',
|
||||||
'Windows' => '',
|
'Windows' => '',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,6 +95,7 @@ if (!isset($argv[1])) {
|
|||||||
$trim_value = "\r\n \t,";
|
$trim_value = "\r\n \t,";
|
||||||
|
|
||||||
$final_extensions = trim(trim($extensions, $trim_value) . ',' . _getCombination($base_combination), $trim_value);
|
$final_extensions = trim(trim($extensions, $trim_value) . ',' . _getCombination($base_combination), $trim_value);
|
||||||
|
$download_extensions = trim($final_extensions . ',' . $shared_extensions, $trim_value);
|
||||||
$final_libs = trim($with_libs, $trim_value);
|
$final_libs = trim($with_libs, $trim_value);
|
||||||
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
if (PHP_OS_FAMILY === 'Windows') {
|
||||||
@@ -105,7 +116,7 @@ function quote2(string $param): string
|
|||||||
// generate download command
|
// generate download command
|
||||||
if ($argv[1] === 'download_cmd') {
|
if ($argv[1] === 'download_cmd') {
|
||||||
$down_cmd = 'download ';
|
$down_cmd = 'download ';
|
||||||
$down_cmd .= '--for-extensions=' . quote2($final_extensions) . ' ';
|
$down_cmd .= '--for-extensions=' . quote2($download_extensions) . ' ';
|
||||||
$down_cmd .= '--for-libs=' . quote2($final_libs) . ' ';
|
$down_cmd .= '--for-libs=' . quote2($final_libs) . ' ';
|
||||||
$down_cmd .= '--with-php=' . quote2($argv[3]) . ' ';
|
$down_cmd .= '--with-php=' . quote2($argv[3]) . ' ';
|
||||||
$down_cmd .= '--ignore-cache-sources=php-src ';
|
$down_cmd .= '--ignore-cache-sources=php-src ';
|
||||||
@@ -115,10 +126,46 @@ if ($argv[1] === 'download_cmd') {
|
|||||||
$down_cmd .= $prefer_pre_built ? '--prefer-pre-built ' : '';
|
$down_cmd .= $prefer_pre_built ? '--prefer-pre-built ' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($argv[1] === 'doctor_cmd') {
|
||||||
|
$doctor_cmd = 'doctor --auto-fix --debug';
|
||||||
|
}
|
||||||
|
if ($argv[1] === 'install_upx_cmd') {
|
||||||
|
$install_upx_cmd = 'install-pkg upx';
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = match ($argv[2] ?? null) {
|
||||||
|
'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ',
|
||||||
|
'ubuntu-latest' => 'bin/spc-alpine-docker ',
|
||||||
|
'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ',
|
||||||
|
'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ',
|
||||||
|
default => 'bin/spc ',
|
||||||
|
};
|
||||||
|
|
||||||
|
// shared_extension build
|
||||||
|
if ($shared_extensions) {
|
||||||
|
switch ($argv[2] ?? null) {
|
||||||
|
case 'ubuntu-22.04':
|
||||||
|
case 'ubuntu-22.04-arm':
|
||||||
|
$shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' ';
|
||||||
|
break;
|
||||||
|
case 'macos-13':
|
||||||
|
case 'macos-14':
|
||||||
|
$shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' ';
|
||||||
|
$no_strip = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$shared_cmd = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$shared_cmd = '';
|
||||||
|
}
|
||||||
|
|
||||||
// generate build command
|
// generate build command
|
||||||
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
|
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
|
||||||
$build_cmd = 'build ';
|
$build_cmd = 'build ';
|
||||||
$build_cmd .= quote2($final_extensions) . ' ';
|
$build_cmd .= quote2($final_extensions) . ' ';
|
||||||
|
$build_cmd .= $shared_cmd;
|
||||||
$build_cmd .= $zts ? '--enable-zts ' : '';
|
$build_cmd .= $zts ? '--enable-zts ' : '';
|
||||||
$build_cmd .= $no_strip ? '--no-strip ' : '';
|
$build_cmd .= $no_strip ? '--no-strip ' : '';
|
||||||
$build_cmd .= $upx ? '--with-upx-pack ' : '';
|
$build_cmd .= $upx ? '--with-upx-pack ' : '';
|
||||||
@@ -139,32 +186,32 @@ echo match ($argv[1]) {
|
|||||||
'upx' => $upx ? '--with-upx-pack' : '',
|
'upx' => $upx ? '--with-upx-pack' : '',
|
||||||
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
|
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
|
||||||
'download_cmd' => $down_cmd,
|
'download_cmd' => $down_cmd,
|
||||||
|
'install_upx_cmd' => $install_upx_cmd,
|
||||||
|
'doctor_cmd' => $doctor_cmd,
|
||||||
'build_cmd' => $build_cmd,
|
'build_cmd' => $build_cmd,
|
||||||
'build_embed_cmd' => $build_cmd,
|
'build_embed_cmd' => $build_cmd,
|
||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($argv[1] === 'download_cmd') {
|
switch ($argv[1] ?? null) {
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
case 'download_cmd':
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $down_cmd, $retcode);
|
passthru($prefix . $down_cmd, $retcode);
|
||||||
} else {
|
break;
|
||||||
passthru('./bin/spc ' . $down_cmd, $retcode);
|
case 'build_cmd':
|
||||||
}
|
passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode);
|
||||||
} elseif ($argv[1] === 'build_cmd') {
|
break;
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
case 'build_embed_cmd':
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
passthru($prefix . $build_cmd . (str_starts_with($argv[2], 'windows-') ? ' --build-cli' : ' --build-embed'), $retcode);
|
||||||
} else {
|
break;
|
||||||
passthru('./bin/spc ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
case 'doctor_cmd':
|
||||||
}
|
passthru($prefix . $doctor_cmd, $retcode);
|
||||||
} elseif ($argv[1] === 'build_embed_cmd') {
|
break;
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
case 'install_upx_cmd':
|
||||||
// windows does not accept embed SAPI
|
passthru($prefix . $install_upx_cmd, $retcode);
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli', $retcode);
|
break;
|
||||||
} else {
|
default:
|
||||||
passthru('./bin/spc ' . $build_cmd . ' --build-embed', $retcode);
|
$retcode = 0;
|
||||||
}
|
break;
|
||||||
} else {
|
|
||||||
$retcode = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit($retcode);
|
exit($retcode);
|
||||||
|
|||||||
25
tests/SPC/GlobalDefinesTest.php
Normal file
25
tests/SPC/GlobalDefinesTest.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class GlobalDefinesTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGlobalDefines(): void
|
||||||
|
{
|
||||||
|
require __DIR__ . '/../../src/globals/defines.php';
|
||||||
|
$this->assertTrue(defined('WORKING_DIR'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInternalEnv(): void
|
||||||
|
{
|
||||||
|
require __DIR__ . '/../../src/globals/internal-env.php';
|
||||||
|
$this->assertTrue(defined('GNU_ARCH'));
|
||||||
|
}
|
||||||
|
}
|
||||||
33
tests/SPC/GlobalFunctionsTest.php
Normal file
33
tests/SPC/GlobalFunctionsTest.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\exception\InterruptException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class GlobalFunctionsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testMatchPattern(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('abc', match_pattern('a*c', 'abc'));
|
||||||
|
$this->assertFalse(match_pattern('a*c', 'abcd'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFExec(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('abc', f_exec('echo abc', $out, $ret));
|
||||||
|
$this->assertEquals(0, $ret);
|
||||||
|
$this->assertEquals(['abc'], $out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPatchPointInterrupt(): void
|
||||||
|
{
|
||||||
|
$except = patch_point_interrupt(0);
|
||||||
|
$this->assertInstanceOf(InterruptException::class, $except);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ class BuilderTest extends TestCase
|
|||||||
|
|
||||||
public function testMakeExtensionArgs()
|
public function testMakeExtensionArgs()
|
||||||
{
|
{
|
||||||
$this->assertStringContainsString('--enable-mbstring', $this->builder->makeExtensionArgs());
|
$this->assertStringContainsString('--enable-mbstring', $this->builder->makeStaticExtensionArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsLibsOnly()
|
public function testIsLibsOnly()
|
||||||
|
|||||||
@@ -137,6 +137,41 @@ class ConfigValidatorTest extends TestCase
|
|||||||
} catch (ValidationException) {
|
} catch (ValidationException) {
|
||||||
$this->assertTrue(true);
|
$this->assertTrue(true);
|
||||||
}
|
}
|
||||||
|
// lib.json is broken by not assoc array
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1', 'lib2'], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib.json lib is not one of "lib", "package", "root", "target"
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source1', 'type' => 'not one of']], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib.json lib if it is "lib" or "package", it must have "source"
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['type' => 'lib']], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib.json static-libs must be a list
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source1', 'static-libs-windows' => 'not list']], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
// lib.json frameworks must be a list
|
||||||
|
try {
|
||||||
|
ConfigValidator::validateLibs(['lib1' => ['source' => 'source1', 'frameworks' => 'not list']], ['source1' => [], 'source2' => []]);
|
||||||
|
$this->fail('should throw ValidationException');
|
||||||
|
} catch (ValidationException) {
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
// source must be string
|
// source must be string
|
||||||
try {
|
try {
|
||||||
ConfigValidator::validateLibs(['lib1' => ['source' => true]], ['source1' => [], 'source2' => []]);
|
ConfigValidator::validateLibs(['lib1' => ['source' => true]], ['source1' => [], 'source2' => []]);
|
||||||
@@ -169,4 +204,11 @@ class ConfigValidatorTest extends TestCase
|
|||||||
$this->expectException(ValidationException::class);
|
$this->expectException(ValidationException::class);
|
||||||
ConfigValidator::validateExts(null);
|
ConfigValidator::validateExts(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValidatePkgs(): void
|
||||||
|
{
|
||||||
|
ConfigValidator::validatePkgs([]);
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
ConfigValidator::validatePkgs(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ final class DependencyUtilTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testGetExtLibsByDeps(): void
|
public function testGetExtLibsByDeps(): void
|
||||||
{
|
{
|
||||||
|
// setup
|
||||||
|
$bak = [
|
||||||
|
'source' => Config::$source,
|
||||||
|
'lib' => Config::$lib,
|
||||||
|
'ext' => Config::$ext,
|
||||||
|
];
|
||||||
// example
|
// example
|
||||||
Config::$source = [
|
Config::$source = [
|
||||||
'test1' => [
|
'test1' => [
|
||||||
@@ -82,6 +88,10 @@ final class DependencyUtilTest extends TestCase
|
|||||||
$this->assertTrue($b < $a);
|
$this->assertTrue($b < $a);
|
||||||
$this->assertTrue($c < $a);
|
$this->assertTrue($c < $a);
|
||||||
$this->assertTrue($c < $b);
|
$this->assertTrue($c < $b);
|
||||||
|
// restore
|
||||||
|
Config::$source = $bak['source'];
|
||||||
|
Config::$lib = $bak['lib'];
|
||||||
|
Config::$ext = $bak['ext'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNotExistExtException(): void
|
public function testNotExistExtException(): void
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ final class LicenseDumperTest extends TestCase
|
|||||||
|
|
||||||
public function testDumpWithSingleLicense(): void
|
public function testDumpWithSingleLicense(): void
|
||||||
{
|
{
|
||||||
|
$bak = [
|
||||||
|
'source' => Config::$source,
|
||||||
|
'lib' => Config::$lib,
|
||||||
|
];
|
||||||
Config::$lib = [
|
Config::$lib = [
|
||||||
'lib-base' => ['type' => 'root'],
|
'lib-base' => ['type' => 'root'],
|
||||||
'php' => ['type' => 'root'],
|
'php' => ['type' => 'root'],
|
||||||
@@ -54,10 +58,17 @@ final class LicenseDumperTest extends TestCase
|
|||||||
$dumper->dump(self::DIRECTORY);
|
$dumper->dump(self::DIRECTORY);
|
||||||
|
|
||||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
||||||
|
// restore
|
||||||
|
Config::$source = $bak['source'];
|
||||||
|
Config::$lib = $bak['lib'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDumpWithMultipleLicenses(): void
|
public function testDumpWithMultipleLicenses(): void
|
||||||
{
|
{
|
||||||
|
$bak = [
|
||||||
|
'source' => Config::$source,
|
||||||
|
'lib' => Config::$lib,
|
||||||
|
];
|
||||||
Config::$lib = [
|
Config::$lib = [
|
||||||
'lib-base' => ['type' => 'root'],
|
'lib-base' => ['type' => 'root'],
|
||||||
'php' => ['type' => 'root'],
|
'php' => ['type' => 'root'],
|
||||||
@@ -91,5 +102,9 @@ final class LicenseDumperTest extends TestCase
|
|||||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
||||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
|
||||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_2.txt');
|
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_2.txt');
|
||||||
|
|
||||||
|
// restore
|
||||||
|
Config::$source = $bak['source'];
|
||||||
|
Config::$lib = $bak['lib'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
tests/SPC/util/SPCConfigUtilTest.php
Normal file
74
tests/SPC/util/SPCConfigUtilTest.php
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SPC\Tests\util;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SPC\builder\BuilderProvider;
|
||||||
|
use SPC\exception\FileSystemException;
|
||||||
|
use SPC\store\FileSystem;
|
||||||
|
use SPC\util\SPCConfigUtil;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class SPCConfigUtilTest 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');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstruct(): void
|
||||||
|
{
|
||||||
|
$this->assertInstanceOf(SPCConfigUtil::class, new SPCConfigUtil());
|
||||||
|
$this->assertInstanceOf(SPCConfigUtil::class, new SPCConfigUtil(BuilderProvider::makeBuilderByInput(new ArgvInput())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConfig(): void
|
||||||
|
{
|
||||||
|
// normal
|
||||||
|
$result = (new SPCConfigUtil())->config(['bcmath']);
|
||||||
|
$this->assertStringContainsString(BUILD_ROOT_PATH . '/include', $result['cflags']);
|
||||||
|
$this->assertStringContainsString(BUILD_ROOT_PATH . '/lib', $result['ldflags']);
|
||||||
|
$this->assertStringContainsString('-lphp', $result['libs']);
|
||||||
|
|
||||||
|
// has cpp
|
||||||
|
$result = (new SPCConfigUtil())->config(['swoole']);
|
||||||
|
$this->assertStringContainsString(PHP_OS_FAMILY === 'Darwin' ? '-lc++' : '-lstdc++', $result['libs']);
|
||||||
|
|
||||||
|
// has mimalloc.o in lib dir
|
||||||
|
// backup first
|
||||||
|
if (file_exists(BUILD_LIB_PATH . '/mimalloc.o')) {
|
||||||
|
$bak = file_get_contents(BUILD_LIB_PATH . '/mimalloc.o');
|
||||||
|
@unlink(BUILD_LIB_PATH . '/mimalloc.o');
|
||||||
|
}
|
||||||
|
file_put_contents(BUILD_LIB_PATH . '/mimalloc.o', '');
|
||||||
|
$result = (new SPCConfigUtil())->config(['bcmath'], ['mimalloc']);
|
||||||
|
$this->assertStringStartsWith(BUILD_LIB_PATH . '/mimalloc.o', $result['libs']);
|
||||||
|
@unlink(BUILD_LIB_PATH . '/mimalloc.o');
|
||||||
|
if (isset($bak)) {
|
||||||
|
file_put_contents(BUILD_LIB_PATH . '/mimalloc.o', $bak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user