Compare commits

..

2 Commits
2.5.2 ... vcpkg

Author SHA1 Message Date
DubbleClick
3f3767e4a4 fix libheif problem by turning off the option that failed 2025-03-24 17:31:35 +07:00
DubbleClick
fe2bc9e4e1 WIP on vcpkg integration 2025-03-24 14:35:10 +07:00
93 changed files with 401 additions and 1223 deletions

View File

@@ -6,13 +6,10 @@ on:
os:
required: true
description: Build target OS
default: 'linux-x86_64'
type: choice
options:
- 'linux-x86_64'
- 'linux-aarch64'
- 'linux-x86_64-glibc'
- 'linux-aarch64-glibc'
- 'macos-x86_64'
- 'macos-aarch64'
php-version:
@@ -25,6 +22,7 @@ on:
- '8.3'
- '8.2'
- '8.1'
- '8.0'
extensions:
description: Extensions to build (comma separated)
required: true
@@ -79,19 +77,9 @@ jobs:
RUNS_ON="ubuntu-latest"
;;
linux-aarch64)
DOWN_CMD="./bin/spc-alpine-docker download"
BUILD_CMD="./bin/spc-alpine-docker build"
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"
DOWN_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker download"
BUILD_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker build"
RUNS_ON="ubuntu-latest"
;;
macos-x86_64)
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"

View File

@@ -176,18 +176,18 @@ jobs:
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: "Run Build Tests (doctor)"
run: php src/globals/test-extensions.php doctor_cmd ${{ matrix.os }} ${{ matrix.php }}
run: bin/spc doctor --auto-fix --debug
- name: "Prepare UPX for Windows"
if: ${{ startsWith(matrix.os, 'windows-') }}
if: matrix.os == 'windows-latest'
run: |
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
bin/spc install-pkg upx
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
- name: "Prepare UPX for Linux"
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
if: matrix.os == 'ubunut-latest'
run: |
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
bin/spc install-pkg upx
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV
- name: "Run Build Tests (download)"
@@ -197,5 +197,5 @@ jobs:
run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }}
- name: "Run Build Tests (build - embed for non-windows)"
if: ${{ !startsWith(matrix.os, 'windows-') }}
if: matrix.os != 'windows-latest'
run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }}

View File

@@ -95,7 +95,7 @@ WORKDIR /app
ADD ./src /app/src
COPY ./composer.* /app/
ADD ./bin /app/bin
RUN composer install --no-dev
RUN composer install --no-dev --classmap-authoritative
EOF
fi
@@ -122,20 +122,6 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
# shellcheck disable=SC2086
# shellcheck disable=SC2090
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
else
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@

View File

@@ -12,7 +12,7 @@ DOCKER_EXECUTABLE="docker"
# shellcheck disable=SC2046
if [ $(id -u) -ne 0 ]; then
if ! docker info > /dev/null 2>&1; then
if [ "$SPC_USE_SUDO" != "yes" ] && [ "$SPC_DOCKER_DEBUG" != "yes" ]; then
if [ "$SPC_USE_SUDO" != "yes" ]; then
echo "Docker command requires sudo"
# shellcheck disable=SC2039
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/spc /app/bin/spc
RUN /app/bin/setup-runtime
RUN /app/bin/php /app/bin/composer install --no-dev
RUN /app/bin/php /app/bin/composer install --no-dev --classmap-authoritative
ENV PATH="/app/bin:/cmake/bin:$PATH"
ENV SPC_LIBC=glibc
@@ -145,22 +145,4 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"'
# shellcheck disable=SC2086
# shellcheck disable=SC2090
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
$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 $@

View File

@@ -28,6 +28,7 @@
; 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_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:
; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`)
@@ -49,7 +50,7 @@ SPC_SKIP_DOCTOR_CHECK_ITEMS=""
; RHEL: /usr/lib64/php/modules
; Alpine: /usr/lib/php{PHP_VERSION}/modules
; where {PHP_VERSION} is 84 for php 8.4
; EXTENSION_DIR=
EXTENSION_DIR=
[windows]
; php-sdk-binary-tools path
@@ -97,9 +98,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
; LIBS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm"
; EXTRA_CFLAGS for `make` php
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"
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE -fPIC"
; EXTRA_LIBS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm"
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS=""
; EXTRA_LDFLAGS_PROGRAM for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
@@ -131,7 +132,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}"
; LDFLAGS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
; EXTRA_CFLAGS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS}"
; EXTRA_LIBS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv"
; embed type for php, static (libphp.a) or shared (libphp.dylib)

View File

@@ -92,11 +92,6 @@
},
"type": "wip"
},
"ev": {
"type": "external",
"source": "ev",
"arg-type-windows": "with"
},
"event": {
"support": {
"Windows": "wip",
@@ -124,10 +119,6 @@
"Linux": "partial",
"BSD": "wip"
},
"target": [
"static",
"shared"
],
"notes": true,
"arg-type": "custom",
"type": "builtin",
@@ -262,7 +253,6 @@
"Windows": "wip",
"BSD": "wip"
},
"notes": true,
"type": "external",
"source": "ext-imagick",
"arg-type": "custom",
@@ -436,17 +426,6 @@
},
"notes": true
},
"odbc": {
"support": {
"BSD": "wip",
"Windows": "wip"
},
"type": "builtin",
"arg-type-unix": "custom",
"lib-depends-unix": [
"unixodbc"
]
},
"opcache": {
"type": "builtin",
"arg-type-unix": "custom"
@@ -513,36 +492,19 @@
"mysqlnd"
]
},
"pdo_odbc": {
"support": {
"BSD": "wip"
},
"type": "builtin",
"arg-type": "custom",
"lib-depends-unix": [
"unixodbc"
],
"ext-depends": [
"pdo",
"odbc"
]
},
"pdo_pgsql": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "builtin",
"arg-type": "with-prefix",
"arg-type-windows": "custom",
"ext-depends": [
"pdo",
"pgsql"
],
"lib-depends-unix": [
"lib-depends": [
"postgresql"
],
"lib-depends-windows": [
"postgresql-win"
]
},
"pdo_sqlite": {
@@ -573,16 +535,14 @@
},
"pgsql": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"notes": true,
"type": "builtin",
"arg-type": "custom",
"lib-depends-unix": [
"lib-depends": [
"postgresql"
],
"lib-depends-windows": [
"postgresql-win"
]
},
"phar": {
@@ -781,9 +741,6 @@
"Windows": "no",
"BSD": "wip"
},
"target": [
"static"
],
"notes": true,
"type": "external",
"source": "swoole",
@@ -931,16 +888,12 @@
]
},
"xdebug": {
"type": "external",
"source": "xdebug",
"target": [
"shared"
],
"type": "builtin",
"support": {
"Windows": "wip",
"BSD": "no",
"Darwin": "partial",
"Linux": "partial"
"Darwin": "no",
"Linux": "no"
},
"notes": true
},
@@ -1056,9 +1009,6 @@
"support": {
"BSD": "wip"
},
"target": [
"static"
],
"type": "builtin",
"arg-type": "with-prefix",
"arg-type-windows": "enable",

View File

@@ -210,12 +210,12 @@
"libwebp",
"freetype",
"libtiff",
"libheif",
"bzip2"
"libheif"
],
"lib-suggests": [
"zstd",
"xz",
"bzip2",
"libzip",
"libxml2"
]
@@ -281,7 +281,8 @@
"headers-unix": [
"ares.h",
"ares_dns.h",
"ares_nameser.h"
"ares_nameser.h",
"ares_rules.h"
]
},
"libde265": {
@@ -670,14 +671,6 @@
"zstd"
]
},
"postgresql-win": {
"source": "postgresql-win",
"static-libs": [
"libpq.lib",
"libpgport.lib",
"libpgcommon.lib"
]
},
"pthreads4w": {
"source": "pthreads4w",
"static-libs-windows": [

View File

@@ -9,7 +9,7 @@
},
"nasm-x86_64-win": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip",
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
"extract-files": {
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"

View File

@@ -1,6 +1,6 @@
{
"repo": "static-php/static-php-cli-hosted",
"prefer-stable": true,
"match-pattern-linux": "{name}-{arch}-{os}-{libc}-{libcver}.txz",
"match-pattern": "{name}-{arch}-{os}.txz"
}
"match-pattern": "{name}-{arch}-{os}.txz",
"suffix": "txz"
}

View File

@@ -37,12 +37,9 @@
}
},
"attr": {
"alt": {
"type": "url",
"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",
"type": "git",
"rev": "v2.5.2",
"url": "https://git.savannah.nongnu.org/git/attr.git",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -92,16 +89,6 @@
"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": {
"type": "url",
"url": "https://pecl.php.net/get/ds",
@@ -348,12 +335,9 @@
}
},
"libacl": {
"alt": {
"type": "url",
"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",
"type": "git",
"rev": "v2.3.2",
"url": "https://git.savannah.nongnu.org/git/acl.git",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -655,7 +639,7 @@
"mimalloc": {
"type": "ghtagtar",
"repo": "microsoft/mimalloc",
"match": "v2\\.\\d\\.[^3].*",
"match": "v2.+",
"provide-pre-built": false,
"license": {
"type": "file",
@@ -777,14 +761,6 @@
"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": {
"type": "url",
"url": "https://pecl.php.net/get/protobuf",
@@ -929,15 +905,6 @@
"path": "COPYING"
}
},
"xdebug": {
"type": "url",
"url": "https://pecl.php.net/get/xdebug",
"filename": "xdebug.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"xhprof": {
"type": "url",
"url": "https://pecl.php.net/get/xhprof",

View File

@@ -48,10 +48,6 @@ This extension contains an implementation of the coroutine environment for `pdo_
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
1. Kerberos is not supported
@@ -80,9 +76,10 @@ and this extension cannot be compiled into php by static linking, so it cannot b
## xdebug
1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc.
2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug".
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`.
1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc and then compile php-xdebug from source with the option `--with-php-config=/path/to/buildroot/bin/php-config`.
2. The macOS platform can compile an xdebug extension under PHP compiled on the same platform,
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
@@ -125,8 +122,8 @@ For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use
## ffi
1. Due to the limitation of musl libc's static linkage, you cannot use ffi because dynamic libraries cannot be loaded.
If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc).
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).
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).
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.

View File

@@ -314,7 +314,6 @@ You can try to use the following commands:
- `--with-suggested-exts`: Add `ext-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)
- `--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:

View File

@@ -45,10 +45,6 @@ swoole-hook-sqlite 与 `pdo_sqlite` 扩展冲突。如需使用 Swoole 和 `pdo_
1. swow 仅支持 PHP 8.0 ~ 8.4 版本。
## imagick
imagick 扩展目前仅在 musl libc 上支持 OpenMPlibgomp。使用 glibc 方式构建的 imagick 扩展无法支持多线程特性。
## imap
1. 该扩展目前不支持 Kerberos。
@@ -74,9 +70,9 @@ bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
## xdebug
1. Xdebug 只能作为共享扩展进行构建。在 Linux 上,您需要使用 static-php-cli 并设置 SPC_LIBC=glibc
2. 使用 Linux/glibc 或 macOS 时,您可以使用 `--build-shared=xdebug` 将 Xdebug 编译为共享扩展。
编译`./php` 二进制文件可以通过指定 INI 文件进行配置运行,例如 `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`
1. Xdebug 只能作为共享扩展构建。在 Linux 上,您需要使用带有 `SPC_LIBC=glibc` 的 static-php-cli然后使用选项 `--with-php-config=/path/to/buildroot/bin/php-config` 从源代码编译 php-xdebug
2. macOS 平台可以通过在相同平台编译的 PHP 下编译一个 xdebug 扩展,并提取其中的 `xdebug.so` 文件,再在 static-php-cli 中使用 `--no-strip` 参数保留调试符号表,同时加入 `ffi` 扩展。
编译的 `./php` 二进制可以通过指定 INI 配置运行,例如`./php -d 'zend_extension=xdebug.so' your-code.php`
## xml
@@ -117,10 +113,9 @@ pgsql 16.2 修复了这个 Bug现在正常工作了。
## ffi
1. 由于 musl libc 静态链接的限制,无法加载动态库,因此无法使用 ffi
如果您需要使用 ffi 扩展,请参阅 [使用 GNU libc 编译 PHP](./build-with-glibc)
2. macOS 支持 ffi 扩展,但某些内核不包含调试符号时会出现错误
3. Windows x64 支持 ffi 扩展。
1. 因为 Linux 系统的限制纯静态编译的状态下spc 默认编译结果为纯静态)无法使用它加载其他 `so` 扩展。Linux 支持加载 so 扩展的前提是非静态编译。如果你需要使用 ffi 扩展,请参见 [编译 GNU libc 的 PHP](./build-with-glibc)
2. macOS 支持 ffi 扩展,但是部分内核下不包含调试符号时会出现错误
3. Windows 支持 ffi 扩展。
## xhprof
@@ -146,4 +141,4 @@ parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`--
1. 从技术上讲,这不是扩展,而是一个库。
2. 在 Linux 或 macOS 上使用 `--with-libs="mimalloc"` 进行构建将覆盖默认分配器。
3. 目前,这还处于实验阶段,但建议在线程环境中使用。
3. 目前,这还处于实验阶段,但建议在线程环境中使用。

View File

@@ -272,7 +272,6 @@ bin/spc build mysqlnd,pdo_mysql --build-all --debug
- `--with-suggested-exts`: 编译时将 `ext-suggests` 也作为编译依赖加入
- `--with-suggested-libs`: 编译时将 `lib-suggests` 也作为编译依赖加入
- `--with-upx-pack`: 编译后使用 UPX 减小二进制文件体积(需先使用 `bin/spc install-pkg upx` 安装 upx
- `--build-shared=XXX,YYY`: 编译时将指定的扩展编译为共享库(默认编译为静态库)
硬编码 INI 选项适用于 cli、micro、embed。有关硬编码 INI 选项,下面是一个简单的例子,我们预设一个更大的 `memory_limit`,并且禁用 `system` 函数:

View File

@@ -32,7 +32,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
public const VERSION = '2.5.2';
public const VERSION = '2.5.1';
public function __construct()
{

View File

@@ -122,12 +122,9 @@ abstract class BuilderBase
*
* @return Extension[]
*/
public function getExts(bool $including_shared = true): array
public function getExts(): array
{
if ($including_shared) {
return $this->exts;
}
return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared());
return $this->exts;
}
/**
@@ -139,7 +136,7 @@ abstract class BuilderBase
public function hasCpp(): bool
{
// judge cpp-extension
$exts = array_keys($this->getExts(false));
$exts = array_keys($this->getExts());
foreach ($exts as $ext) {
if (Config::getExt($ext, 'cpp-extension', false) === true) {
return true;
@@ -173,46 +170,23 @@ abstract class BuilderBase
* @throws \Throwable|WrongUsageException
* @internal
*/
public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false, bool $skip_extract = false): void
public function proveExts(array $extensions, bool $skip_check_deps = false): void
{
CustomExt::loadCustomExt();
// judge ext
foreach ($static_extensions as $ext) {
// if extension does not support static build, throw exception
if (!in_array('static', Config::getExtTarget($ext))) {
throw new WrongUsageException('Extension [' . $ext . '] does not support static build!');
}
$this->emitPatchPoint('before-php-extract');
SourceManager::initSource(sources: ['php-src']);
$this->emitPatchPoint('after-php-extract');
if ($this->getPHPVersionID() >= 80000) {
$this->emitPatchPoint('before-micro-extract');
SourceManager::initSource(sources: ['micro']);
$this->emitPatchPoint('after-micro-extract');
}
foreach ($shared_extensions as $ext) {
// if extension does not support shared build, throw exception
if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_extensions)) {
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) {
$this->emitPatchPoint('before-exts-extract');
SourceManager::initSource(exts: $extensions);
$this->emitPatchPoint('after-exts-extract');
foreach ($extensions as $extension) {
$class = CustomExt::getExtClass($extension);
/** @var Extension $ext */
$ext = new $class($extension, $this);
if (in_array($extension, $static_extensions)) {
$ext->setBuildStatic();
}
if (in_array($extension, $shared_extensions)) {
$ext->setBuildShared();
}
$this->addExt($ext);
}
@@ -220,10 +194,10 @@ abstract class BuilderBase
return;
}
foreach ($this->getExts() as $ext) {
foreach ($this->exts as $ext) {
$ext->checkDependency();
}
$this->ext_list = [...$static_extensions, ...$shared_extensions];
$this->ext_list = $extensions;
}
/**
@@ -233,17 +207,6 @@ abstract class BuilderBase
*/
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.
* e.g. --enable-mbstring
@@ -251,10 +214,10 @@ abstract class BuilderBase
* @throws FileSystemException
* @throws WrongUsageException
*/
public function makeStaticExtensionArgs(): string
public function makeExtensionArgs(): string
{
$ret = [];
foreach ($this->getExts(false) as $ext) {
foreach ($this->exts as $ext) {
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
$ret[] = trim($ext->getConfigureArg());
}
@@ -433,7 +396,7 @@ abstract class BuilderBase
foreach ($this->libs as $lib) {
$lib->validate();
}
foreach ($this->getExts() as $ext) {
foreach ($this->exts as $ext) {
$ext->validate();
}
}
@@ -478,7 +441,7 @@ abstract class BuilderBase
{
$php = "<?php\n\necho '[micro-test-start]' . PHP_EOL;\n";
foreach ($this->getExts(false) as $ext) {
foreach ($this->getExts() as $ext) {
$ext_name = $ext->getDistName();
if (!empty($ext_name)) {
$php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n";

View File

@@ -9,18 +9,11 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\util\SPCConfigUtil;
class Extension
{
protected array $dependencies = [];
protected bool $build_shared = false;
protected bool $build_static = false;
protected string $source_dir;
/**
* @throws FileSystemException
* @throws RuntimeException
@@ -37,18 +30,6 @@ class Extension
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
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;
}
}
/**
@@ -151,7 +132,7 @@ class Extension
// Windows is not supported yet
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '';
}
@@ -186,21 +167,6 @@ class Extension
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
*/
@@ -265,53 +231,6 @@ class Extension
// 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
*
@@ -322,32 +241,6 @@ class Extension
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
*/

View File

@@ -8,7 +8,6 @@ use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use SPC\store\SourceManager;
@@ -46,9 +45,8 @@ abstract class LibraryBase
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib(static::NAME, 'source');
// if source is locked as pre-built, we just tryInstall it
$pre_built_name = Downloader::getPreBuiltLockName($source);
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);
if (isset($lock[$source]) && ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
return $this->tryInstall($lock[$source]['filename'], $force);
}
return $this->tryBuild($force);
}
@@ -222,7 +220,7 @@ abstract class LibraryBase
// extract first if not exists
if (!is_dir($this->source_dir)) {
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract');
SourceManager::initSource(libs: [static::NAME], source_only: true);
SourceManager::initSource(libs: [static::NAME]);
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract');
}

View File

@@ -23,7 +23,7 @@ class amqp extends Extension
return false;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('dba')]
class dba extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
return '--enable-dba' . $qdbm;

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('enchant')]
class enchant extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$glibs = [
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a',

View File

@@ -1,31 +0,0 @@
<?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;
}
}

View File

@@ -13,7 +13,7 @@ use SPC\util\CustomExt;
#[CustomExt('event')]
class event extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH;
if ($this->builder->getLib('openssl')) {

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('ffi')]
class ffi extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--with-ffi --enable-zend-signals';
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('gd')]
class gd extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--enable-gd';
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';

View File

@@ -30,7 +30,7 @@ class glfw extends Extension
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
}

View File

@@ -44,7 +44,7 @@ class grpc extends Extension
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH;
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\linux\LinuxBuilder;
use SPC\util\CustomExt;
#[CustomExt('imagick')]
@@ -12,18 +13,17 @@ class imagick extends Extension
{
public function patchBeforeMake(): bool
{
if (getenv('SPC_LIBC') !== 'musl') {
return false;
// imagick may call omp_pause_all which requires -lgomp
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
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);
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$disable_omp = getenv('SPC_LIBC') === 'musl' ? '' : ' ac_cv_func_omp_pause_resource_all=no';
return '--with-imagick=' . BUILD_ROOT_PATH . $disable_omp;
return '--with-imagick=' . BUILD_ROOT_PATH;
}
}

View File

@@ -33,7 +33,7 @@ class imap extends Extension
}
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--with-imap=' . BUILD_ROOT_PATH;
if ($this->builder->getLib('openssl') !== null) {

View File

@@ -12,7 +12,7 @@ use SPC\util\CustomExt;
#[CustomExt('memcache')]
class memcache extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('memcached')]
class memcached extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$rootdir = BUILD_ROOT_PATH;
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('mongodb')]
class mongodb extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = ' --enable-mongodb ';
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';

View File

@@ -1,17 +0,0 @@
<?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;
}
}

View File

@@ -42,7 +42,7 @@ class opcache extends Extension
return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-opcache';
}

View File

@@ -23,7 +23,7 @@ class openssl extends Extension
return false;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH;
return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir;

View File

@@ -1,29 +0,0 @@
<?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';
}
}

View File

@@ -1,17 +0,0 @@
<?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';
}
}

View File

@@ -33,23 +33,11 @@ class pgsql extends Extension
* @throws WrongUsageException
* @throws RuntimeException
*/
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
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=' . 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;
}
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('redis')]
class redis extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--enable-redis';
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';

View File

@@ -26,7 +26,7 @@ class snappy extends Extension
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
}

View File

@@ -21,7 +21,7 @@ class spx extends Extension
}
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--enable-spx';
if ($this->builder->getExt('zlib') === null) {

View File

@@ -35,7 +35,7 @@ class swoole extends Extension
return null;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
// enable swoole
$arg = '--enable-swoole';
@@ -49,9 +49,7 @@ 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)
$arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : '';
if (!$shared) {
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
}
$arg .= $this->builder->getLib('brotli') ? (' --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : '';
// additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc.

View File

@@ -16,7 +16,7 @@ class swoole_hook_mysql extends Extension
return 'swoole';
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
// pdo_mysql doesn't need to be disabled
// enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options

View File

@@ -25,7 +25,7 @@ class swoole_hook_pgsql extends Extension
}
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
// enable swoole pgsql hook
return '--enable-swoole-pgsql';

View File

@@ -25,7 +25,7 @@ class swoole_hook_sqlite extends Extension
}
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
// enable swoole pgsql hook
return '--enable-swoole-sqlite';

View File

@@ -1,21 +0,0 @@
<?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.');
}
}
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('xlswriter')]
class xlswriter extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = '--with-xlswriter --enable-reader';
if ($this->builder->getLib('openssl')) {

View File

@@ -20,7 +20,7 @@ class xml extends Extension
/**
* @throws RuntimeException
*/
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$arg = match ($this->name) {
'xml' => '--enable-xml',

View File

@@ -19,7 +19,7 @@ class yac extends Extension
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-yac --enable-igbinary --enable-json';
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('zlib')]
class zlib extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH;
return '--with-zlib' . $zlib_dir;

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('zstd')]
class zstd extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
public function getUnixConfigureArg(): string
{
return '--enable-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
}

View File

@@ -118,7 +118,7 @@ class BSDBuilder extends UnixBuilderBase
$config_file_scan_dir .
$json_74 .
$zts .
$this->makeStaticExtensionArgs()
$this->makeExtensionArgs()
);
$this->emitPatchPoint('before-php-make');

View File

@@ -182,7 +182,7 @@ class LinuxBuilder extends UnixBuilderBase
$json_74 .
$zts .
$maxExecutionTimers .
$this->makeStaticExtensionArgs() .
$this->makeExtensionArgs() .
' ' . $envs_build_php . ' '
);
@@ -311,7 +311,15 @@ class LinuxBuilder extends UnixBuilderBase
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
$this->patchPhpScripts();
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
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);
}
private function getMakeExtraVars(): array

View File

@@ -182,39 +182,4 @@ class SystemUtil
'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;
}
}

View File

@@ -176,7 +176,7 @@ class MacOSBuilder extends UnixBuilderBase
$config_file_scan_dir .
$json_74 .
$zts .
$this->makeStaticExtensionArgs() . ' ' .
$this->makeExtensionArgs() . ' ' .
$envs_build_php
);
@@ -300,7 +300,13 @@ class MacOSBuilder extends UnixBuilderBase
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
$this->patchPhpScripts();
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
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);
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
}
private function getMakeExtraVars(): array

View File

@@ -146,7 +146,7 @@ abstract class UnixBuilderBase extends BuilderBase
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
}
foreach ($this->getExts(false) as $ext) {
foreach ($this->exts as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckUnix();
}
@@ -238,29 +238,4 @@ abstract class UnixBuilderBase extends BuilderBase
logger()->info('cleaning up');
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);
}
}
}

View File

@@ -18,9 +18,8 @@ trait imagemagick
*/
protected function build(): void
{
// TODO: glibc rh 10 toolset's libgomp.a was built without -fPIC -fPIE so we can't use openmp without depending on libgomp.so
$openmp = getenv('SPC_LIBC') === 'musl' ? '--enable-openmp' : '--disable-openmp';
$extra = "--without-jxl --without-x {$openmp} ";
// TODO: imagemagick build with bzip2 failed with bugs, we need to fix it in the future
$extra = '--without-jxl --without-x --enable-openmp --without-bzlib ';
$required_libs = '';
$optional_libs = [
'libzip' => 'zip',
@@ -28,12 +27,10 @@ trait imagemagick
'libpng' => 'png',
'libwebp' => 'webp',
'libxml2' => 'xml',
'libheif' => 'heic',
'zlib' => 'zlib',
'xz' => 'lzma',
'zstd' => 'zstd',
'freetype' => 'freetype',
'bzip2' => 'bzlib',
];
foreach ($optional_libs as $lib => $option) {
$extra .= $this->builder->getLib($lib) ? "--with-{$option} " : "--without-{$option} ";

View File

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

View File

@@ -119,7 +119,7 @@ class WindowsBuilder extends BuilderBase
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
$config_file_scan_dir .
"{$this->makeStaticExtensionArgs()} " .
"{$this->makeExtensionArgs()} " .
$zts .
'"'
);
@@ -286,7 +286,7 @@ class WindowsBuilder extends BuilderBase
throw new RuntimeException('cli failed sanity check');
}
foreach ($this->getExts(false) as $ext) {
foreach ($this->exts as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckWindows();
}

View File

@@ -1,27 +0,0 @@
<?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);
}
}
}

View File

@@ -165,7 +165,7 @@ abstract class BaseCommand extends Command
return SPC_EXTENSION_ALIAS[$lower];
}
return $lower;
}, is_array($ext_list) ? $ext_list : array_filter(explode(',', $ext_list)));
}, is_array($ext_list) ? $ext_list : explode(',', $ext_list));
// filter internals
return array_values(array_filter($ls, function ($x) {

View File

@@ -27,7 +27,6 @@ class BuildPHPCommand extends BuildCommand
$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('build-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', '');
$this->addOption('build-micro', null, null, 'Build micro SAPI');
$this->addOption('build-cli', null, null, 'Build cli SAPI');
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
@@ -53,31 +52,13 @@ class BuildPHPCommand extends BuildCommand
// transform string to array
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
// transform string to array
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
// transform string to array
$static_extensions = $this->parseExtensionList($this->getArgument('extensions'));
$extensions = $this->parseExtensionList($this->getArgument('extensions'));
// parse rule with options
$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>');
}
$rule = $this->parseRules();
if ($rule === BUILD_TARGET_NONE) {
$this->output->writeln('<error>Please add at least one build SAPI!</error>');
$this->output->writeln('<error>Please add at least one build target!</error>');
$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-fpm\tBuild php-fpm SAPI</comment>");
@@ -126,26 +107,18 @@ class BuildPHPCommand extends BuildCommand
$builder = BuilderProvider::makeBuilderByInput($this->input);
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $shared_extensions), $libraries, $include_suggest_ext, $include_suggest_lib);
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
$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
$indent_texts = [
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
'Build SAPI' => $builder->getBuildTypeName($rule),
'Extensions (' . count($extensions) . ')' => implode(',', $display_extensions),
'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
'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'))) {
$indent_texts['Config File Path'] = $this->input->getOption('with-config-file-path');
}
@@ -179,8 +152,8 @@ class BuildPHPCommand extends BuildCommand
// compile libraries
$builder->proveLibs($libraries);
// check extensions
$builder->proveExts($static_extensions, $shared_extensions);
// validate libs and extensions
$builder->proveExts($extensions);
// validate libs and exts
$builder->validateLibsAndExts();
// clean builds and sources
@@ -210,12 +183,6 @@ class BuildPHPCommand extends BuildCommand
// start to build
$builder->buildPHP($rule);
// build dynamic extensions if needed
if (!empty($shared_extensions)) {
logger()->info('Building shared extensions ...');
$builder->buildSharedExts();
}
// compile stopwatch :P
$time = round(microtime(true) - START_TIME, 3);
logger()->info('');
@@ -244,12 +211,6 @@ class BuildPHPCommand extends BuildCommand
$path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm");
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
file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
@@ -278,13 +239,13 @@ class BuildPHPCommand extends BuildCommand
/**
* Parse build options to rule int.
*/
private function parseRules(array $shared_extensions = []): int
private function parseRules(): int
{
$rule = 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-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-embed') || !empty($shared_extensions) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
return $rule;
}

View File

@@ -7,7 +7,6 @@ namespace SPC\command;
use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
@@ -48,35 +47,30 @@ class DeleteDownloadCommand extends BaseCommand
$chosen_sources = $sources;
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$deleted_sources = [];
foreach ($chosen_sources as $source) {
$source = trim($source);
foreach ([$source, Downloader::getPreBuiltLockName($source)] as $name) {
if (isset($lock[$name])) {
$deleted_sources[] = $name;
}
if (!isset($lock[$source])) {
logger()->warning("Source/Package [{$source}] not locked or not downloaded, skipped.");
continue;
}
}
foreach ($deleted_sources as $lock_name) {
// remove download file/dir if exists
if ($lock[$lock_name]['source_type'] === 'archive') {
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']))) {
if ($lock[$source]['source_type'] === 'archive') {
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['filename']))) {
logger()->info('Deleting file ' . $path);
unlink($path);
} else {
logger()->warning("Source/Package [{$lock_name}] file not found, skip deleting file.");
logger()->warning("Source/Package [{$source}] file not found, skip deleting file.");
}
} else {
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname']))) {
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['dirname']))) {
logger()->info('Deleting dir ' . $path);
FileSystem::removeDir($path);
} else {
logger()->warning("Source/Package [{$lock_name}] directory not found, skip deleting dir.");
logger()->warning("Source/Package [{$source}] directory not found, skip deleting dir.");
}
}
// remove locked sources
unset($lock[$lock_name]);
unset($lock[$source]);
}
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
logger()->info('Delete success!');

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\command;
use SPC\builder\linux\SystemUtil;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException;
@@ -213,7 +212,7 @@ class DownloadCommand extends BaseCommand
if (isset($config['filename'])) {
$new_config['filename'] = $config['filename'];
}
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom url: {$new_config['url']}");
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
Downloader::downloadSource($source, $new_config, true);
} elseif (isset($custom_gits[$source])) {
$config = Config::getSource($source);
@@ -225,30 +224,23 @@ class DownloadCommand extends BaseCommand
if (isset($config['path'])) {
$new_config['path'] = $config['path'];
}
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom git: {$new_config['url']}");
logger()->info("Fetching source {$source} from custom git [{$ni}/{$cnt}]");
Downloader::downloadSource($source, $new_config, true);
} else {
$config = Config::getSource($source);
// Prefer pre-built, we need to search pre-built library
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
// We need to replace pattern
$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 = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
// find filename in asset list
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
logger()->info("[{$ni}/{$cnt}] Downloading pre-built content {$source}");
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_DOWNLOAD_PRE_BUILT);
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
continue;
}
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
}
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
}
}
@@ -360,7 +352,6 @@ class DownloadCommand extends BaseCommand
*/
private function findPreBuilt(array $assets, string $filename): ?string
{
logger()->debug("Finding pre-built asset {$filename}");
foreach ($assets as $asset) {
if ($asset['name'] === $filename) {
return $asset['browser_download_url'];

View File

@@ -20,7 +20,6 @@ class ExtractCommand extends BaseCommand
public function configure(): void
{
$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');
}
/**
@@ -35,7 +34,7 @@ class ExtractCommand extends BaseCommand
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
return static::FAILURE;
}
SourceManager::initSource(sources: $sources, source_only: $this->getOption('source-only'));
SourceManager::initSource(sources: $sources);
logger()->info('Extract done !');
return static::SUCCESS;
}

View File

@@ -37,7 +37,7 @@ class SPCConfigCommand extends BuildCommand
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
$util = new SPCConfigUtil();
$util = new SPCConfigUtil(null, $this->input);
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
if ($this->getOption('includes')) {

View File

@@ -6,6 +6,7 @@ namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\command\BaseCommand;
use SPC\store\Config;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -30,7 +31,8 @@ class ExtVerCommand extends BaseCommand
// Get lib object
$builder = BuilderProvider::makeBuilderByInput($this->input);
$builder->proveExts([$this->getArgument('extension')], [], true);
$ext_conf = Config::getExt($this->getArgument('extension'));
$builder->proveExts([$this->getArgument('extension')], true);
// Check whether lib is extracted
// if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {

View File

@@ -6,7 +6,6 @@ namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\builder\LibraryBase;
use SPC\builder\linux\SystemUtil;
use SPC\command\BuildCommand;
use SPC\exception\ExceptionHandler;
use SPC\exception\FileSystemException;
@@ -24,7 +23,6 @@ class PackLibCommand extends BuildCommand
public function configure(): void
{
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
$this->addOption('show-libc-ver', null, null);
}
public function handle(): int
@@ -49,7 +47,7 @@ class PackLibCommand extends BuildCommand
// Get lock info
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib($lib->getName(), 'source');
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
return static::FAILURE;
}
@@ -71,16 +69,7 @@ class PackLibCommand extends BuildCommand
// write list to packlib_files.txt
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
// pack
$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;
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
}

View File

@@ -22,30 +22,11 @@ class Config
public static ?array $pre_built = null;
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public static function getPreBuilt(string $name): mixed
{
if (self::$pre_built === null) {
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;
}
@@ -125,21 +106,6 @@ class Config
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 WrongUsageException

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\store;
use SPC\builder\linux\SystemUtil;
use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
@@ -125,7 +124,6 @@ class Downloader
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
continue;
}
logger()->debug("Found {$release['name']} releases assets");
if (!$match_result) {
return $release['assets'];
}
@@ -191,7 +189,7 @@ class Downloader
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $download_as = SPC_DOWNLOAD_SOURCE): void
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
{
logger()->debug("Downloading {$url}");
$cancel_func = function () use ($filename) {
@@ -204,23 +202,12 @@ class Downloader
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
self::unregisterCancelEvent();
logger()->debug("Locking {$filename}");
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]);
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
}
/**
* 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
*/
public static function lockSource(string $name, array $data): void
@@ -241,7 +228,7 @@ class Downloader
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_DOWNLOAD_SOURCE): void
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
{
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
if (file_exists($download_path)) {
@@ -259,7 +246,6 @@ class Downloader
self::registerCancelEvent($cancel_func);
f_passthru(
SPC_GIT_EXEC . ' clone' . $check .
(defined('DEBUG_MODE') ? '' : ' --quiet') .
' --config core.autocrlf=false ' .
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
);
@@ -297,22 +283,8 @@ 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 FileSystemException
* @throws WrongUsageException
*/
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
{
@@ -329,36 +301,50 @@ class Downloader
FileSystem::createDir(DOWNLOAD_PATH);
}
if (self::isAlreadyDownloaded($name, $force, SPC_DOWNLOAD_PACKAGE)) {
return;
// load lock file
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading
if (isset($lock[$name]) && !$force) {
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['filename']);
return;
}
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['dirname']);
return;
}
}
try {
switch ($pkg['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'url': // Direct download URL
$url = $pkg['url'];
$filename = $pkg['filename'] ?? basename($pkg['url']);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
break;
case 'git': // Git repo
self::downloadGit(
@@ -367,7 +353,7 @@ class Downloader
$pkg['rev'],
$pkg['extract'] ?? null,
self::getRetryTime(),
SPC_DOWNLOAD_PRE_BUILT
SPC_LOCK_PRE_BUILT
);
break;
case 'custom': // Custom download method, like API-based download or other
@@ -396,30 +382,15 @@ class Downloader
/**
* Download source by name and meta.
*
* @param string $name source name
* @param null|array{
* type: string,
* 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)
* @param string $name source name
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
* @param bool $force Whether to force download (default: false)
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
* @throws DownloaderException
* @throws FileSystemException
* @throws WrongUsageException
*/
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $download_as = SPC_DOWNLOAD_SOURCE): void
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
{
if ($source === null) {
$source = Config::getSource($name);
@@ -435,36 +406,49 @@ class Downloader
}
// load lock file
if (self::isAlreadyDownloaded($name, $force, $download_as)) {
return;
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading
if (isset($lock[$name]) && !$force && ($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 {
switch ($source['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'url': // Direct download URL
$url = $source['url'];
$filename = $source['filename'] ?? basename($source['url']);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
break;
case 'git': // Git repo
self::downloadGit(
@@ -473,14 +457,14 @@ class Downloader
$source['rev'],
$source['path'] ?? null,
self::getRetryTime(),
$download_as
$lock_as
);
break;
case 'custom': // Custom download method, like API-based download or other
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force, $source, $download_as);
(new $class())->fetch($force, $source, $lock_as);
break;
}
}
@@ -595,11 +579,6 @@ 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.
*
@@ -632,39 +611,4 @@ class Downloader
{
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;
}
}

View File

@@ -461,23 +461,6 @@ 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 FileSystemException

View File

@@ -15,7 +15,7 @@ class SourceManager
* @throws FileSystemException
* @throws RuntimeException
*/
public static function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null, bool $source_only = false): void
public static function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null): void
{
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 ?');
@@ -54,22 +54,15 @@ class SourceManager
if (Config::getSource($source) === null) {
throw new WrongUsageException("Source [{$source}] does not exist, please check the name and correct it !");
}
// check source downloaded
$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;
if (!isset($lock[$source])) {
throw new WrongUsageException('Source [' . $source . '] not downloaded or not locked, you should download it first !');
}
// check source dir exist
$check = $lock[$lock_name]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$lock_name]['move_path']);
$check = $lock[$source]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$source]['move_path']);
if (!is_dir($check)) {
logger()->debug('Extracting source [' . $source . '] to ' . $check . ' ...');
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']), $lock[$lock_name]['move_path']);
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$source]['filename'] ?? $lock[$source]['dirname']), $lock[$source]['move_path']);
} else {
logger()->debug('Source [' . $source . '] already extracted in ' . $check . ', skip !');
}

View File

@@ -43,7 +43,7 @@ class SourcePatcher
*/
public static function patchBeforeBuildconf(BuilderBase $builder): void
{
foreach ($builder->getExts(false) as $ext) {
foreach ($builder->getExts() as $ext) {
if ($ext->patchBeforeBuildconf() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
}
@@ -86,7 +86,7 @@ class SourcePatcher
*/
public static function patchBeforeConfigure(BuilderBase $builder): void
{
foreach ($builder->getExts(false) as $ext) {
foreach ($builder->getExts() as $ext) {
if ($ext->patchBeforeConfigure() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before configure');
}
@@ -253,7 +253,7 @@ class SourcePatcher
// }
// call extension patch before make
foreach ($builder->getExts(false) as $ext) {
foreach ($builder->getExts() as $ext) {
if ($ext->patchBeforeMake() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before make');
}

View File

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

View File

@@ -17,7 +17,7 @@ class PhpSource extends CustomSourceBase
* @throws DownloaderException
* @throws FileSystemException
*/
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
{
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.3';
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);

View File

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

View File

@@ -40,6 +40,9 @@ class GlobalEnvManager
self::putenv('PATH=' . BUILD_ROOT_PATH . '/bin:' . getenv('PATH'));
self::putenv('PKG_CONFIG=' . BUILD_BIN_PATH . '/pkg-config');
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

View File

@@ -7,51 +7,26 @@ namespace SPC\util;
use SPC\builder\BuilderBase;
use SPC\builder\BuilderProvider;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
class SPCConfigUtil
{
private ?BuilderBase $builder = null;
public function __construct(?BuilderBase $builder = null)
public function __construct(private ?BuilderBase $builder = null, ?InputInterface $input = null)
{
if ($builder !== null) {
$this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
if ($builder === null) {
$this->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
{
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
ob_start();
if ($this->builder === null) {
$this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput());
$this->builder->proveLibs($libraries);
$this->builder->proveExts($extensions, skip_extract: true);
}
$this->builder->proveLibs($libraries);
$this->builder->proveExts($extensions);
ob_get_clean();
$ldflags = $this->getLdflagsString();
$libs = $this->getLibsString($libraries);
@@ -72,9 +47,9 @@ class SPCConfigUtil
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
}
return [
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
'libs' => trim(getenv('LIBS') . ' ' . $libs),
'cflags' => $cflags,
'ldflags' => $ldflags,
'libs' => $libs,
];
}
@@ -115,8 +90,8 @@ class SPCConfigUtil
}
}
}
// patch: imagick (imagemagick wrapper) for linux needs libgomp
if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
// patch: imagick (imagemagick wrapper) for linux needs -lgomp
if (in_array('imagemagick', $libraries) && PHP_OS_FAMILY === 'Linux') {
$short_name[] = '-lgomp';
}
return implode(' ', $short_name);

View File

@@ -41,9 +41,8 @@ const SPC_EXTENSION_ALIAS = [
];
// spc lock type
const SPC_DOWNLOAD_SOURCE = 1; // lock source
const SPC_DOWNLOAD_PRE_BUILT = 2; // lock pre-built
const SPC_DOWNLOAD_PACKAGE = 3; // lock as package
const SPC_LOCK_SOURCE = 1; // lock source
const SPC_LOCK_PRE_BUILT = 2; // lock pre-built
// file replace strategy
const REPLACE_FILE_STR = 1;

View File

@@ -21,18 +21,14 @@ $test_php_version = [
// test os (macos-13, macos-14, ubuntu-latest, windows-latest are available)
$test_os = [
'macos-13',
'macos-14',
// 'macos-13',
// 'macos-14',
'ubuntu-latest',
'ubuntu-22.04',
'ubuntu-24.04',
'ubuntu-22.04-arm',
'ubuntu-24.04-arm',
'windows-latest',
];
// whether enable thread safe
$zts = true;
$zts = false;
$no_strip = false;
@@ -44,14 +40,8 @@ $prefer_pre_built = false;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'ev',
'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' => '',
'Linux', 'Darwin' => '',
'Windows' => 'mbstring,tokenizer,phar,curl,openssl',
};
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
@@ -95,7 +85,6 @@ if (!isset($argv[1])) {
$trim_value = "\r\n \t,";
$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);
if (PHP_OS_FAMILY === 'Windows') {
@@ -116,7 +105,7 @@ function quote2(string $param): string
// generate download command
if ($argv[1] === 'download_cmd') {
$down_cmd = 'download ';
$down_cmd .= '--for-extensions=' . quote2($download_extensions) . ' ';
$down_cmd .= '--for-extensions=' . quote2($final_extensions) . ' ';
$down_cmd .= '--for-libs=' . quote2($final_libs) . ' ';
$down_cmd .= '--with-php=' . quote2($argv[3]) . ' ';
$down_cmd .= '--ignore-cache-sources=php-src ';
@@ -126,46 +115,10 @@ if ($argv[1] === 'download_cmd') {
$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
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
$build_cmd = 'build ';
$build_cmd .= quote2($final_extensions) . ' ';
$build_cmd .= $shared_cmd;
$build_cmd .= $zts ? '--enable-zts ' : '';
$build_cmd .= $no_strip ? '--no-strip ' : '';
$build_cmd .= $upx ? '--with-upx-pack ' : '';
@@ -186,32 +139,32 @@ echo match ($argv[1]) {
'upx' => $upx ? '--with-upx-pack' : '',
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
'download_cmd' => $down_cmd,
'install_upx_cmd' => $install_upx_cmd,
'doctor_cmd' => $doctor_cmd,
'build_cmd' => $build_cmd,
'build_embed_cmd' => $build_cmd,
default => '',
};
switch ($argv[1] ?? null) {
case 'download_cmd':
passthru($prefix . $down_cmd, $retcode);
break;
case 'build_cmd':
passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode);
break;
case 'build_embed_cmd':
passthru($prefix . $build_cmd . (str_starts_with($argv[2], 'windows-') ? ' --build-cli' : ' --build-embed'), $retcode);
break;
case 'doctor_cmd':
passthru($prefix . $doctor_cmd, $retcode);
break;
case 'install_upx_cmd':
passthru($prefix . $install_upx_cmd, $retcode);
break;
default:
$retcode = 0;
break;
if ($argv[1] === 'download_cmd') {
if (str_starts_with($argv[2], 'windows-')) {
passthru('powershell.exe -file .\bin\spc.ps1 ' . $down_cmd, $retcode);
} else {
passthru('./bin/spc ' . $down_cmd, $retcode);
}
} elseif ($argv[1] === 'build_cmd') {
if (str_starts_with($argv[2], 'windows-')) {
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli --build-micro', $retcode);
} else {
passthru('./bin/spc ' . $build_cmd . ' --build-cli --build-micro', $retcode);
}
} elseif ($argv[1] === 'build_embed_cmd') {
if (str_starts_with($argv[2], 'windows-')) {
// windows does not accept embed SAPI
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli', $retcode);
} else {
passthru('./bin/spc ' . $build_cmd . ' --build-embed', $retcode);
}
} else {
$retcode = 0;
}
exit($retcode);

View File

@@ -1,25 +0,0 @@
<?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'));
}
}

View File

@@ -1,33 +0,0 @@
<?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);
}
}

View File

@@ -72,7 +72,7 @@ class BuilderTest extends TestCase
public function testMakeExtensionArgs()
{
$this->assertStringContainsString('--enable-mbstring', $this->builder->makeStaticExtensionArgs());
$this->assertStringContainsString('--enable-mbstring', $this->builder->makeExtensionArgs());
}
public function testIsLibsOnly()

View File

@@ -137,41 +137,6 @@ class ConfigValidatorTest extends TestCase
} catch (ValidationException) {
$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
try {
ConfigValidator::validateLibs(['lib1' => ['source' => true]], ['source1' => [], 'source2' => []]);
@@ -204,11 +169,4 @@ class ConfigValidatorTest extends TestCase
$this->expectException(ValidationException::class);
ConfigValidator::validateExts(null);
}
public function testValidatePkgs(): void
{
ConfigValidator::validatePkgs([]);
$this->expectException(ValidationException::class);
ConfigValidator::validatePkgs(null);
}
}

View File

@@ -16,12 +16,6 @@ final class DependencyUtilTest extends TestCase
{
public function testGetExtLibsByDeps(): void
{
// setup
$bak = [
'source' => Config::$source,
'lib' => Config::$lib,
'ext' => Config::$ext,
];
// example
Config::$source = [
'test1' => [
@@ -88,10 +82,6 @@ final class DependencyUtilTest extends TestCase
$this->assertTrue($b < $a);
$this->assertTrue($c < $a);
$this->assertTrue($c < $b);
// restore
Config::$source = $bak['source'];
Config::$lib = $bak['lib'];
Config::$ext = $bak['ext'];
}
public function testNotExistExtException(): void

View File

@@ -33,10 +33,6 @@ final class LicenseDumperTest extends TestCase
public function testDumpWithSingleLicense(): void
{
$bak = [
'source' => Config::$source,
'lib' => Config::$lib,
];
Config::$lib = [
'lib-base' => ['type' => 'root'],
'php' => ['type' => 'root'],
@@ -58,17 +54,10 @@ final class LicenseDumperTest extends TestCase
$dumper->dump(self::DIRECTORY);
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
// restore
Config::$source = $bak['source'];
Config::$lib = $bak['lib'];
}
public function testDumpWithMultipleLicenses(): void
{
$bak = [
'source' => Config::$source,
'lib' => Config::$lib,
];
Config::$lib = [
'lib-base' => ['type' => 'root'],
'php' => ['type' => 'root'],
@@ -102,9 +91,5 @@ final class LicenseDumperTest extends TestCase
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_2.txt');
// restore
Config::$source = $bak['source'];
Config::$lib = $bak['lib'];
}
}

View File

@@ -1,74 +0,0 @@
<?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);
}
}
}

14
vcpkg-configuration.json Normal file
View File

@@ -0,0 +1,14 @@
{
"default-registry": {
"kind": "git",
"baseline": "a76b33254af4092ff45f08ec5adcd9fd06468b43",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}

View File

@@ -0,0 +1,7 @@
set(CMAKE_C_COMPILER /usr/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/bin/g++)
set(CMAKE_AR /usr/bin/ar)
set(CMAKE_LINKER /usr/bin/ld.gold)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(ENV{CFLAGS} "-fPIC -fPIE")
set(ENV{CXXFLAGS} "-fPIC -fPIE")

View File

@@ -0,0 +1,17 @@
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Linux)
set(VCPKG_BUILD_TYPE release)
set(VCPKG_C_FLAGS "-fPIC -fPIE")
set(VCPKG_CXX_FLAGS "-fPIC -fPIE")
set(VCPKG_CMAKE_CONFIGURE_OPTIONS
-DBUILD_SHARED_LIBS=OFF
-DWITH_EXAMPLES=OFF
-DWITH_GDK_PIXBUF=OFF
-DBUILD_TESTING=OFF
)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/x64-linux-glibc-toolchain.cmake")

View File

@@ -0,0 +1,5 @@
set(CMAKE_C_COMPILER /usr/local/musl/bin/x86_64-linux-musl-gcc)
set(CMAKE_CXX_COMPILER /usr/local/musl/bin/x86_64-linux-musl-g++)
set(CMAKE_AR /usr/local/musl/bin/x86_64-linux-musl-ar)
set(CMAKE_LINKER /usr/local/musl/bin/x86_64-linux-musl-ld.gold)
set(CMAKE_CROSSCOMPILING TRUE)

View File

@@ -0,0 +1,10 @@
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Linux)
set(VCPKG_BUILD_TYPE release)
set(VCPKG_C_FLAGS "-fPIC -fPIE -static")
set(VCPKG_CXX_FLAGS "-fPIC -fPIE -static")
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/x64-linux-musl-toolchain.cmake")

66
vcpkg.json Normal file
View File

@@ -0,0 +1,66 @@
{
"dependencies": [
"acl",
"aom",
"argon2",
"brotli",
"bzip2",
"c-ares",
"curl",
"freetype",
"gettext",
"gmp",
"grpc",
"icu",
"libavif",
"libde265",
"libevent",
"libffi",
{
"name": "libgd",
"features": [
"fontconfig",
"freetype",
"jpeg",
"png",
"tiff",
"webp"
]
},
{
"name": "libheif",
"features": [
"aom",
"jpeg",
"hevc"
]
},
"libiconv",
"libpng",
"librabbitmq",
"librdkafka",
"libsodium",
"libssh2",
"libuuid",
"libuv",
"libwebp",
"libxml2",
"libxslt",
"libyaml",
"libzip",
"lz4",
"mimalloc",
"ncurses",
"nghttp2",
"nghttp3",
"openldap",
"pkgconf",
"readline",
"snappy",
"sqlite3",
"tidy-html5",
"tiff",
"zlib",
"zstd"
]
}