Compare commits

...

94 Commits

Author SHA1 Message Date
Marc
38ec03fe30 Merge pull request #871 from crazywhalecc/fix/frankenphp-dynamic-exports
build frankenphp and embed after shared extensions
2025-08-31 15:06:11 +02:00
Marc
55836771c9 Merge pull request #869 from crazywhalecc/pkg-config-pkg
turn pkg-config into a package
2025-08-31 15:04:41 +02:00
crazywhalecc
08a68796bf Call export in dynamic symbol getter 2025-08-31 18:05:09 +08:00
crazywhalecc
3b9efcb2d4 Put it into toolchain manager to skip in unit test 2025-08-31 15:24:29 +08:00
crazywhalecc
022ba3dce4 Merge branch 'main' into pkg-config-pkg
# Conflicts:
#	src/globals/test-extensions.php
2025-08-31 15:20:50 +08:00
crazywhalecc
86973e622d sort config 2025-08-31 15:06:59 +08:00
crazywhalecc
0fa38bad6d Use existing pkg-config builds and pre-built contents for packages 2025-08-31 15:04:34 +08:00
crazywhalecc
465bd3ce85 Use separated functions for exporting symbols 2025-08-31 14:24:28 +08:00
Jerry Ma
0c9130ab6c Update node version in vitepress-deploy.yml 2025-08-31 13:44:37 +08:00
crazywhalecc
6c75ecf0c4 Add docs search 2025-08-31 11:47:41 +08:00
DubbleClick
d533a0591b skip line before preg_replacing 2025-08-30 19:31:22 +07:00
DubbleClick
3f74d58503 fix macos, for real this time 2025-08-30 14:12:13 +07:00
DubbleClick
1ba92ccc99 fix patch version stripping (.\d -> .\d+) 2025-08-30 12:02:15 +07:00
DubbleClick
75db184077 fix macos command to print defined symbols? 2025-08-29 17:50:47 +07:00
DubbleClick
66902d74c4 cs fix 2025-08-29 16:38:48 +07:00
DubbleClick
f6cc6af39c macos? 3 2025-08-29 16:36:43 +07:00
DubbleClick
0da8dcf04a macos? 2 2025-08-29 15:14:54 +07:00
DubbleClick
190be6c7b9 macos? 2025-08-29 14:12:00 +07:00
DubbleClick
2972ab31d7 don't add empty dynamic list x) 2025-08-29 12:15:56 +07:00
DubbleClick
4b4ae9b014 write to a --dynamic-list file
see https://sourceware.org/binutils/docs-2.36/ld/Options.html
2025-08-29 10:53:38 +07:00
DubbleClick
20db00afcc no need to test all static targets, nothing changes for them 2025-08-29 10:26:46 +07:00
DubbleClick
56c90ca4a3 use all symbols from libphp.a, so we don't need to build shared extensions 2025-08-29 10:24:51 +07:00
DubbleClick
fad2314539 found ENABLE_SHARED option in liburing! 2025-08-29 09:25:32 +07:00
DubbleClick
460eb02086 build frankenphp and embed after shared extensions, make sure the linker doesn't drop libphp.a symbols that extensions need 2025-08-29 08:52:55 +07:00
Marc
5a30d509e7 Merge pull request #864 from crazywhalecc/swoolehooks
swoole hooks can be compiled if pgsql/sqlite are not compiled in statically
2025-08-29 03:46:30 +02:00
crazywhalecc
0f0050115c Update cli generator, add frankenphp SAPI, add copy-to-clipboard func 2025-08-28 22:35:51 +08:00
crazywhalecc
bf55db959e Add swoole-hook-odbc notes 2025-08-28 22:35:23 +08:00
DubbleClick
39a9840d49 why is phpstan so stupid about this constant? 2025-08-28 12:14:26 +07:00
DubbleClick
866ca264d9 only disable it for x86_64 2025-08-28 11:35:46 +07:00
DubbleClick
f18725083a disable opcache jit automatically on alpine target (only required for php < 8.5) 2025-08-28 11:32:33 +07:00
crazywhalecc
20fbbb1dbe test 2025-08-28 11:01:58 +08:00
crazywhalecc
1a7bf2d070 test 2025-08-28 10:49:02 +08:00
crazywhalecc
fc7e8ebc53 extension test 2025-08-28 10:29:22 +08:00
crazywhalecc
532360886e Merge branch 'main' into swoolehooks 2025-08-28 10:29:07 +08:00
crazywhalecc
117a54d077 extension test 2025-08-28 10:14:47 +08:00
DubbleClick
f2c131a2cc wno-int-conversion 2025-08-27 17:01:07 +07:00
DubbleClick
6f0310e8f7 cs fix 2025-08-27 16:46:58 +07:00
DubbleClick
c7141003db oops 2025-08-27 16:46:09 +07:00
DubbleClick
d32bdb2825 all env vars 2025-08-27 16:45:47 +07:00
DubbleClick
a66abfa583 test all OS 2025-08-27 16:35:24 +07:00
DubbleClick
2551772de4 use system cc 2025-08-27 16:34:29 +07:00
DubbleClick
25fe794acc trim all items 2025-08-27 14:36:05 +07:00
DubbleClick
694fd2f1e0 turn pkg-config into a package instead of a library 2025-08-27 14:33:39 +07:00
DubbleClick
5a4b920ae2 pkg-config patch 2025-08-27 13:04:08 +07:00
DubbleClick
95f1b65bca fix perl installation by checking for FindBin 2025-08-27 13:03:57 +07:00
DubbleClick
25401e5959 cs fix 2025-08-27 12:43:48 +07:00
DubbleClick
3da58d5c24 filter micro patches to not be '' 2025-08-27 11:48:59 +07:00
DubbleClick
08ab3c17d6 fix perl-IPC-Cmd check so it doesn't try installing it every time 2025-08-27 11:40:06 +07:00
DubbleClick
ecdb94b429 suggestions 2025-08-27 08:31:48 +07:00
DubbleClick
00892c20fa fix odbc libs when iconv is built too 2025-08-26 20:44:30 +07:00
DubbleClick
c433aed521 fix macos? 2025-08-26 19:35:10 +07:00
DubbleClick
1243fb9678 don't test macos as it just fails either way, add odbc test 2025-08-26 18:55:22 +07:00
DubbleClick
d9c2247f99 fix alpine realpath -s issue 2025-08-26 18:16:44 +07:00
DubbleClick
0d4d4283d1 only install library for liburing 2025-08-26 18:04:43 +07:00
DubbleClick
effefd4844 string 2025-08-26 14:51:07 +07:00
DubbleClick
2d409db2f9 we don't need a min glibc version, just don't use --use-libc! 2025-08-26 14:42:34 +07:00
DubbleClick
00f262571c cs fix 2025-08-26 14:08:09 +07:00
DubbleClick
4eac953c71 ensure liburing is only pulled in by suggested libs when glibc >= 2.30 (or musl) 2025-08-26 14:07:49 +07:00
DubbleClick
43352ab986 don't print repeated --ri swoole check 2025-08-26 01:01:45 +07:00
DubbleClick
9803bf6c3f prevent warning message from addons 2025-08-26 00:59:54 +07:00
DubbleClick
ba326973e5 prevent infinite recursion if ext suggests addons that depend on the extension 2025-08-26 00:56:57 +07:00
DubbleClick
a1f2126c00 update comments 2025-08-26 00:38:35 +07:00
DubbleClick
b1da64d46b add swoole-hook-odbc to work the same way as the other hooks 2025-08-26 00:24:40 +07:00
DubbleClick
2694dd9e21 add liburing for swoole 2025-08-25 22:57:04 +07:00
Marc
37e0f1d3f3 Update src/SPC/command/BuildPHPCommand.php 2025-08-25 19:50:41 +07:00
DubbleClick
f80aee5133 get rid of $rt 2025-08-25 19:31:15 +07:00
DubbleClick
65ee7479ac suggestion and clean up frankenphp build 2025-08-25 19:29:10 +07:00
DubbleClick
868f6d408b only feed -lgcov to the go driver 2025-08-25 18:44:03 +07:00
DubbleClick
efdfbf437a use format string 2025-08-25 18:23:04 +07:00
DubbleClick
2b57bca55c remove useless import 2025-08-25 15:30:04 +07:00
DubbleClick
99ccbf8a40 @crazywhalecc please look what's wrong with macos 2025-08-25 15:28:53 +07:00
DubbleClick
9fe322375f use 8.4 for tests only 2025-08-25 14:55:30 +07:00
DubbleClick
d13e369994 test swoole 2025-08-25 13:11:40 +07:00
DubbleClick
a46ad7b81e cs fix 2025-08-25 12:58:12 +07:00
DubbleClick
324ba0d3dc use type=addon and arg-type=none 2025-08-25 12:57:49 +07:00
DubbleClick
1c7fa0132d remove space 2025-08-25 12:44:34 +07:00
DubbleClick
93223a9d44 too much pgo, too little pdo 2025-08-25 12:43:21 +07:00
DubbleClick
b6d4af218b zts -> --enable-swoole-thread 2025-08-25 12:42:36 +07:00
DubbleClick
448941f741 don't request configurearg if it's not used (ease debugging) 2025-08-25 12:36:10 +07:00
DubbleClick
7e0e9091be explicitly enable swoole-mysql too 2025-08-25 12:11:56 +07:00
DubbleClick
8104ff7236 update checks for shared swoole-hook extensions 2025-08-25 12:08:53 +07:00
DubbleClick
75f734daa8 cs fix 2025-08-25 11:22:35 +07:00
DubbleClick
779a724875 go's gcc driver is the dumbest shit to ever exist 2025-08-25 11:21:08 +07:00
DubbleClick
e975e151f9 swoole hooks can be compiled if pgsql/sqlite are not compiled in statically 2025-08-25 11:09:02 +07:00
Marc
a5351e1546 Merge pull request #863 from crazywhalecc/brotli-watcher
fix gcc version detection
2025-08-25 05:32:46 +02:00
DubbleClick
af90b840ee format string 2025-08-25 09:59:27 +07:00
DubbleClick
2558c02470 oopsie 2025-08-25 09:59:06 +07:00
DubbleClick
df60ccff0e also make sure clang version uses dots 2025-08-25 09:52:03 +07:00
DubbleClick
2ed8bbf391 add cflags and ldflags to frankenphp build 2025-08-25 09:29:19 +07:00
DubbleClick
ef3025798d fix gcc compiler version 2025-08-25 09:29:06 +07:00
Marc
bea3bd8392 Merge pull request #861 from crazywhalecc/fix/macos-ar
Add macOS AR and LD
2025-08-22 07:23:49 +02:00
crazywhalecc
99e8900aba Add macOS AR and LD 2025-08-22 13:19:42 +08:00
Marc
1c4a6ca02e Merge pull request #860 from crazywhalecc/brotli-watcher
add brotli and watcher to lib-suggests
2025-08-21 15:31:35 +02:00
DubbleClick
b5fa7be53f add brotli and watcher to lib-suggests 2025-08-20 13:40:54 +07:00
43 changed files with 1740 additions and 1058 deletions

View File

@@ -12,5 +12,5 @@ trim_trailing_whitespace = true
trim_trailing_whitespace = false
indent_size = 2
[*.{yml,yaml, vue}]
[*.{yml,yaml,vue,ts}]
indent_size = 2

View File

@@ -65,7 +65,7 @@ jobs:
- sqlsrv
- ssh2
- swoole
- swoole,swoole-hook-pgsql,swoole-hook-mysql,swoole-hook-sqlite
- swoole,swoole-hook-pgsql,swoole-hook-mysql,swoole-hook-sqlite,swoole-hook-odbc
- swow
- sysvmsg,sysvsem,sysvshm
- tidy
@@ -82,7 +82,7 @@ jobs:
- zlib
- zstd
php-version:
- "8.5"
- "8.4"
operating-system:
- "ubuntu-latest"
#- "macos-13"

View File

@@ -21,7 +21,6 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18
cache: yarn
- run: yarn install --frozen-lockfile

View File

@@ -124,6 +124,8 @@ SPC_TARGET=native-macos
; compiler environments
CC=clang
CXX=clang++
AR=ar
LD=ld
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
SPC_DEFAULT_C_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"
SPC_DEFAULT_CXX_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"

View File

@@ -842,14 +842,23 @@
"nghttp2",
"zlib"
],
"lib-suggests": [
"zstd"
],
"lib-suggests-linux": [
"zstd",
"liburing"
],
"ext-depends": [
"openssl",
"curl"
],
"ext-suggests": [
"sockets",
"swoole-hook-pgsql",
"swoole-hook-mysql",
"swoole-hook-sqlite"
"swoole-hook-sqlite",
"swoole-hook-odbc"
]
},
"swoole-hook-mysql": {
@@ -859,11 +868,12 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"mysqlnd",
"pdo",
"pdo_mysql"
"pdo_mysql",
"swoole"
],
"ext-suggests": [
"mysqli"
@@ -877,10 +887,11 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"pgsql",
"pdo"
"pdo",
"swoole"
]
},
"swoole-hook-sqlite": {
@@ -890,10 +901,27 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"sqlite3",
"pdo"
"pdo",
"swoole"
]
},
"swoole-hook-odbc": {
"support": {
"Windows": "no",
"BSD": "wip"
},
"notes": true,
"type": "addon",
"arg-type": "none",
"ext-depends": [
"pdo",
"swoole"
],
"lib-depends": [
"unixodbc"
]
},
"swow": {

View File

@@ -1,9 +1,6 @@
{
"lib-base": {
"type": "root",
"lib-depends-unix": [
"pkg-config"
]
"type": "root"
},
"php": {
"type": "root",
@@ -13,7 +10,13 @@
"micro"
],
"lib-suggests-linux": [
"libacl"
"libacl",
"brotli",
"watcher"
],
"lib-suggests-unix": [
"brotli",
"watcher"
]
},
"micro": {
@@ -919,5 +922,20 @@
"zstd.h",
"zstd_errors.h"
]
},
"liburing": {
"source": "liburing",
"pkg-configs": [
"liburing",
"liburing-ffi"
],
"static-libs-linux": [
"liburing.a",
"liburing-ffi.a"
],
"headers-linux": [
"liburing/",
"liburing.h"
]
}
}

View File

@@ -1,4 +1,16 @@
{
"go-xcaddy-aarch64-linux": {
"type": "custom"
},
"go-xcaddy-aarch64-macos": {
"type": "custom"
},
"go-xcaddy-x86_64-linux": {
"type": "custom"
},
"go-xcaddy-x86_64-macos": {
"type": "custom"
},
"musl-toolchain-aarch64-linux": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz"
@@ -15,6 +27,38 @@
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
}
},
"pkg-config-aarch64-linux": {
"type": "ghrel",
"repo": "static-php/static-php-cli-hosted",
"match": "pkg-config-aarch64-linux-musl-1.2.5.txz",
"extract-files": {
"bin/pkg-config": "{pkg_root_path}/bin/pkg-config"
}
},
"pkg-config-aarch64-macos": {
"type": "ghrel",
"repo": "static-php/static-php-cli-hosted",
"match": "pkg-config-aarch64-darwin.txz",
"extract-files": {
"bin/pkg-config": "{pkg_root_path}/bin/pkg-config"
}
},
"pkg-config-x86_64-linux": {
"type": "ghrel",
"repo": "static-php/static-php-cli-hosted",
"match": "pkg-config-x86_64-linux-musl-1.2.5.txz",
"extract-files": {
"bin/pkg-config": "{pkg_root_path}/bin/pkg-config"
}
},
"pkg-config-x86_64-macos": {
"type": "ghrel",
"repo": "static-php/static-php-cli-hosted",
"match": "pkg-config-x86_64-darwin.txz",
"extract-files": {
"bin/pkg-config": "{pkg_root_path}/bin/pkg-config"
}
},
"strawberry-perl-x86_64-win": {
"type": "url",
"url": "https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip"
@@ -43,30 +87,18 @@
"upx-*-win64/upx.exe": "{pkg_root_path}/bin/upx.exe"
}
},
"go-xcaddy-x86_64-linux": {
"zig-aarch64-linux": {
"type": "custom"
},
"go-xcaddy-aarch64-linux": {
"type": "custom"
},
"go-xcaddy-x86_64-macos": {
"type": "custom"
},
"go-xcaddy-aarch64-macos": {
"zig-aarch64-macos": {
"type": "custom"
},
"zig-x86_64-linux": {
"type": "custom"
},
"zig-aarch64-linux": {
"type": "custom"
},
"zig-x86_64-macos": {
"type": "custom"
},
"zig-aarch64-macos": {
"type": "custom"
},
"zig-x86_64-win": {
"type": "custom"
}

View File

@@ -1136,5 +1136,14 @@
"type": "file",
"path": "LICENSE"
}
},
"liburing": {
"type": "ghtar",
"repo": "axboe/liburing",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,14 @@ export default {
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2023-present crazywhalecc'
}
},
search: {
provider: 'algolia',
options: {
appId: 'IHJHUB1SF1',
apiKey: '8266d31cc2ffbd0e059f1c6e5bdaf8fc',
indexName: 'static-php docs',
},
},
}
}

View File

@@ -46,6 +46,14 @@ If you use `swoole,swoole-hook-sqlite`, you will enable the coroutine mode of Sw
swoole-hook-sqlite conflicts with the `pdo_sqlite` extension. If you want to use Swoole and `pdo_sqlite`, please delete the pdo_sqlite extension and enable `swoole` and `swoole-hook-sqlite`.
This extension contains an implementation of the coroutine environment for `pdo_sqlite`.
## swoole-hook-odbc
swoole-hook-odbc is not an extension, it's a Hook feature of Swoole.
If you use `swoole,swoole-hook-odbc`, you will enable the coroutine mode of Swoole's `odbc` extension.
swoole-hook-odbc conflicts with the `pdo_odbc` extension. If you want to use Swoole and `pdo_odbc`, please delete the `pdo_odbc` extension and enable `swoole` and `swoole-hook-odbc`.
This extension contains an implementation of the coroutine environment for `pdo_odbc`.
## swow
1. Only PHP 8.0+ is supported.

View File

@@ -43,6 +43,14 @@ swoole-hook-sqlite 不是一个扩展,而是 Swoole 的 Hook 特性。
swoole-hook-sqlite 与 `pdo_sqlite` 扩展冲突。如需使用 Swoole 和 `pdo_sqlite`,请删除 pdo_sqlite 扩展,启用 `swoole``swoole-hook-sqlite` 即可。
该扩展包含了 `pdo_sqlite` 的协程环境的实现。
## swoole-hook-odbc
swoole-hook-odbc 不是一个扩展,而是 Swoole 的 Hook 特性。
如果你在编译时添加了 `swoole,swoole-hook-odbc`,你将启用 Swoole 的 `odbc` 扩展的协程模式。
swoole-hook-odbc 与 `pdo_odbc` 扩展冲突。如需使用 Swoole 和 `pdo_odbc`,请删除 `pdo_odbc` 扩展,启用 `swoole``swoole-hook-odbc` 即可。
该扩展包含了 `pdo_odbc` 的协程环境的实现。
## swow
1. swow 仅支持 PHP 8.0+ 版本。

View File

@@ -268,11 +268,11 @@ abstract class BuilderBase
{
$ret = [];
foreach ($this->getExts() as $ext) {
$arg = $ext->getConfigureArg();
$arg = null;
if ($ext->isBuildShared() && !$ext->isBuildStatic()) {
if (
(Config::getExt($ext->getName(), 'type') === 'builtin' &&
!file_exists(SOURCE_PATH . '/php-src/ext/' . $ext->getName() . '/config.m4')) ||
!file_exists(SOURCE_PATH . '/php-src/ext/' . $ext->getName() . '/config.m4')) ||
Config::getExt($ext->getName(), 'build-with-php') === true
) {
$arg = $ext->getConfigureArg(true);
@@ -280,6 +280,7 @@ abstract class BuilderBase
continue;
}
}
$arg ??= $ext->getConfigureArg();
logger()->info($ext->getName() . ' is using ' . $arg);
$ret[] = trim($arg);
}

View File

@@ -252,12 +252,15 @@ class Extension
$order = [];
$resolve = function ($extension) use (&$resolve, &$loaded, &$order) {
if (!$extension instanceof Extension) {
return;
}
if (isset($loaded[$extension->getName()])) {
return;
}
$loaded[$extension->getName()] = true;
foreach ($this->dependencies as $dependency) {
foreach ($extension->dependencies as $dependency) {
$resolve($dependency);
}
@@ -269,6 +272,9 @@ class Extension
$ret = '';
foreach ($order as $ext) {
if ($ext instanceof self && $ext->isBuildShared()) {
if (Config::getExt($ext->getName(), 'type', false) === 'addon') {
continue;
}
if (Config::getExt($ext->getName(), 'zend-extension', false) === true) {
$ret .= " -d \"zend_extension={$ext->getName()}\"";
} else {
@@ -350,7 +356,7 @@ class Extension
/**
* Build shared extension
*/
public function buildShared(): void
public function buildShared(array $visited = []): void
{
try {
if (Config::getExt($this->getName(), 'type') === 'builtin' || Config::getExt($this->getName(), 'build-with-php') === true) {
@@ -366,17 +372,21 @@ class Extension
}
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
return;
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
continue;
}
if (!$dependency->isBuildStatic()) {
if (!$dependency->isBuildStatic() && !in_array($dependency->getName(), $visited)) {
logger()->info('extension ' . $this->getName() . ' requires extension ' . $dependency->getName());
$dependency->buildShared();
$dependency->buildShared([...$visited, $this->getName()]);
}
}
if (Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),

View File

@@ -12,9 +12,9 @@ class mongodb extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = ' --enable-mongodb ';
$arg = ' --enable-mongodb' . ($shared ? '=shared' : '') . ' ';
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';
$arg .= ' --with-mongodb-sasl=no ';
$arg .= ' --with-mongodb-sasl=no ';
if ($this->builder->getLib('openssl')) {
$arg .= '--with-mongodb-ssl=openssl';
}
@@ -22,6 +22,6 @@ class mongodb extends Extension
$arg .= $this->builder->getLib('zstd') ? ' --with-mongodb-zstd=yes ' : ' --with-mongodb-zstd=no ';
// $arg .= $this->builder->getLib('snappy') ? ' --with-mongodb-snappy=yes ' : ' --with-mongodb-snappy=no ';
$arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled ';
return $arg;
return clean_spaces($arg);
}
}

View File

@@ -8,6 +8,7 @@ use SPC\builder\Extension;
use SPC\exception\WrongUsageException;
use SPC\store\SourcePatcher;
use SPC\util\CustomExt;
use SPC\util\SPCTarget;
#[CustomExt('opcache')]
class opcache extends Extension
@@ -46,7 +47,18 @@ class opcache extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-opcache';
$phpVersionID = $this->builder->getPHPVersionID();
$opcache_jit = ' --enable-opcache-jit';
if ((SPCTarget::getTargetOS() === 'Linux' &&
SPCTarget::getLibc() === 'musl' &&
$this->builder->getOption('enable-zts') &&
arch2gnu(php_uname('m')) === 'x86_64' &&
$phpVersionID < 80500) ||
$this->builder->getOption('disable-opcache-jit')
) {
$opcache_jit = ' --disable-opcache-jit';
}
return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit;
}
public function getDistName(): string

View File

@@ -8,6 +8,8 @@ use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
#[CustomExt('swoole')]
class swoole extends Extension
@@ -43,32 +45,40 @@ class swoole extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole
$arg = '--enable-swoole';
$arg = '--enable-swoole' . ($shared ? '=shared' : '');
// commonly-used feature: coroutine-time, disable-thread-context
$arg .= ' --enable-swoole-coro-time --disable-thread-context';
// commonly used feature: coroutine-time
$arg .= ' --enable-swoole-coro-time --with-pic';
// required feature: curl, openssl (but curl hook is buggy for php 8.0)
$arg .= $this->builder->getOption('enable-zts') ? ' --enable-swoole-thread --disable-thread-context' : ' --disable-swoole-thread --enable-thread-context';
// required features: curl, openssl (but curl hook is buggy for php 8.0)
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
$arg .= ' --enable-openssl';
// additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature)
// additional features that only require libraries
$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') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : '';
$arg .= $this->builder->getLib('zstd') ? ' --enable-zstd' : '';
$arg .= $this->builder->getLib('liburing') ? ' --enable-iouring' : '';
$arg .= $this->builder->getExt('sockets') ? ' --enable-sockets' : '';
// additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc.
// so this is a tricky way (enable ext [pgsql,pdo] to add postgresql hook and pdo_pgsql support)
$arg .= $this->builder->getExt('swoole-hook-pgsql') ? '' : ' --disable-swoole-pgsql';
// enable additional features that require the pdo extension, but conflict with pdo_* extensions
// to make sure everything works as it should, this is done in fake addon extensions
$arg .= $this->builder->getExt('swoole-hook-pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql';
$arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd';
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite';
// enable this feature , need remove pdo_sqlite
// more info : https://wenda.swoole.com/detail/109023
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? '' : ' --disable-swoole-sqlite';
if ($this->builder->getExt('swoole-hook-odbc')) {
$config = (new SPCConfigUtil($this->builder, ['libs_only_deps' => true]))->config([], ['unixodbc']);
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}
if (SPCTarget::getTargetOS() === 'Darwin') {
$arg .= ' ac_cv_lib_pthread_pthread_barrier_init=no';
}
// enable this feature , need stop pdo_*
// $arg .= $this->builder->getLib('unixodbc') ? ' --with-swoole-odbc=unixODBC,' : ' ';
return $arg;
}
}

View File

@@ -16,26 +16,15 @@ class swoole_hook_mysql extends Extension
return 'swoole';
}
public function getUnixConfigureArg(bool $shared = false): string
{
// pdo_mysql doesn't need to be disabled
// enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options
return '';
}
public function runCliCheckUnix(): void
{
// skip if not enable swoole
if ($this->builder->getExt('swoole') === null) {
return;
}
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $this->getSharedExtensionLoadString() . ' --ri "swoole"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: 'extension swoole_hook_mysql sanity check');
}
if (!str_contains($out, 'mysqlnd')) {
throw new ValidationException('swoole mysql hook is not enabled correctly.', validation_module: 'Extension swoole mysql hook avilability check');
throw new ValidationException('swoole mysql hook is not enabled correctly.', validation_module: 'Extension swoole mysql hook availability check');
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\util\CustomExt;
#[CustomExt('swoole-hook-odbc')]
class swoole_hook_odbc extends Extension
{
public function getDistName(): string
{
return 'swoole';
}
public function validate(): void
{
// pdo_pgsql need to be disabled
if ($this->builder->getExt('pdo_odbc')?->isBuildStatic()) {
throw new WrongUsageException('swoole-hook-odbc provides pdo_odbc, if you enable odbc hook for swoole, you must remove pdo_odbc extension.');
}
}
public function runCliCheckUnix(): void
{
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: "Extension {$this->getName()} sanity check");
}
if (!str_contains($out, 'coroutine_odbc')) {
throw new ValidationException('swoole odbc hook is not enabled correctly.', validation_module: 'Extension swoole odbc hook availability check');
}
}
}

View File

@@ -20,25 +20,15 @@ class swoole_hook_pgsql extends Extension
public function validate(): void
{
// pdo_pgsql need to be disabled
if ($this->builder->getExt('pdo_pgsql') !== null) {
if ($this->builder->getExt('pdo_pgsql')?->isBuildStatic()) {
throw new WrongUsageException('swoole-hook-pgsql provides pdo_pgsql, if you enable pgsql hook for swoole, you must remove pdo_pgsql extension.');
}
}
public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole pgsql hook
return '--enable-swoole-pgsql';
}
public function runCliCheckUnix(): void
{
// skip if not enable swoole
if ($this->builder->getExt('swoole') === null) {
return;
}
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new ValidationException(

View File

@@ -20,25 +20,15 @@ class swoole_hook_sqlite extends Extension
public function validate(): void
{
// pdo_pgsql need to be disabled
if ($this->builder->getExt('pdo_sqlite') !== null) {
if ($this->builder->getExt('pdo_sqlite')?->isBuildStatic()) {
throw new WrongUsageException('swoole-hook-sqlite provides pdo_sqlite, if you enable sqlite hook for swoole, you must remove pdo_sqlite extension.');
}
}
public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole pgsql hook
return '--enable-swoole-sqlite';
}
public function runCliCheckUnix(): void
{
// skip if not enable swoole
if ($this->builder->getExt('swoole') === null) {
return;
}
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new ValidationException("extension {$this->getName()} failed compile check: php-cli returned {$ret}", validation_module: "Extension {$this->getName()} sanity check");

View File

@@ -25,10 +25,6 @@ class BSDBuilder extends UnixBuilderBase
f_putenv('CXX=' . $this->getOption('cxx', 'clang++'));
// set PATH
f_putenv('PATH=' . BUILD_ROOT_PATH . '/bin:' . getenv('PATH'));
// set PKG_CONFIG
f_putenv('PKG_CONFIG=' . BUILD_ROOT_PATH . '/bin/pkg-config');
// set PKG_CONFIG_PATH
f_putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig/');
// set arch (default: current)
$this->setOptionIfNotExist('arch', php_uname('m'));
@@ -122,6 +118,11 @@ class BSDBuilder extends UnixBuilderBase
}
$this->buildEmbed();
}
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
if (!empty($shared_extensions)) {
logger()->info('Building shared extensions ...');
$this->buildSharedExts();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();

View File

@@ -64,10 +64,7 @@ class LinuxBuilder extends UnixBuilderBase
// if opcache_jit is enabled for 8.5 or opcache enabled,
// we need to disable undefined behavior sanitizer.
f_putenv('SPC_COMPILER_EXTRA=-fno-sanitize=undefined');
} elseif ($opcache_jit) {
$opcache_jit = false;
}
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit ' : '--disable-opcache-jit ';
if ($this->getOption('enable-zts', false)) {
$maxExecutionTimers = $phpVersionID >= 80100 ? '--enable-zend-max-execution-timers ' : '';
@@ -115,7 +112,6 @@ class LinuxBuilder extends UnixBuilderBase
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
$config_file_path .
$config_file_scan_dir .
$opcache_jit_arg .
$json_74 .
$zts .
$maxExecutionTimers .
@@ -146,6 +142,12 @@ class LinuxBuilder extends UnixBuilderBase
}
$this->buildEmbed();
}
// build dynamic extensions if needed, must happen before building FrankenPHP to make sure we export all necessary, undefined symbols
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
if (!empty($shared_extensions)) {
logger()->info('Building shared extensions ...');
$this->buildSharedExts();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
@@ -316,6 +318,8 @@ class LinuxBuilder extends UnixBuilderBase
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') {
$AR = getenv('AR') ?: 'ar';
f_passthru("{$AR} -t " . BUILD_LIB_PATH . "/libphp.a | grep '\\.a$' | xargs -n1 {$AR} d " . BUILD_LIB_PATH . '/libphp.a');
// export dynamic symbols
SystemUtil::exportDynamicSymbols(BUILD_LIB_PATH . '/libphp.a');
}
if (!$this->getOption('no-strip', false) && file_exists(BUILD_LIB_PATH . '/' . $realLibName)) {

View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCTarget;
class liburing extends LinuxLibraryBase
{
public const NAME = 'liburing';
public function patchBeforeBuild(): bool
{
if (!SystemUtil::isMuslDist()) {
return false;
}
FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath');
return true;
}
protected function build(): void
{
$use_libc = SPCTarget::getLibc() !== 'glibc' || version_compare(SPCTarget::getLibcVersion(), '2.30', '>=');
$make = UnixAutoconfExecutor::create($this);
if (!$use_libc) {
$make->appendEnv([
'CC' => 'gcc', // libc-less version fails to compile with clang or zig
'CXX' => 'g++',
'AR' => 'ar',
'LD' => 'ld',
]);
} else {
$make->appendEnv([
'CFLAGS' => '-D_GNU_SOURCE',
]);
}
$make
->removeConfigureArgs(
'--disable-shared',
'--enable-static',
'--with-pic',
'--enable-pic',
)
->addConfigureArgs(
$use_libc ? '--use-libc' : '',
)
->configure()
->make('library', 'install ENABLE_SHARED=0', with_clean: false);
$this->patchPkgconfPrefix();
}
}

View File

@@ -90,13 +90,6 @@ class MacOSBuilder extends UnixBuilderBase
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '';
$zts = $this->getOption('enable-zts', false) ? '--enable-zts --disable-zend-signals ' : '';
$opcache_jit = !$this->getOption('disable-opcache-jit', false);
// disable opcache jit for PHP < 8.5.0 when opcache is not enabled
if ($opcache_jit && $phpVersionID < 80500 && !$this->getExt('opcache')) {
$opcache_jit = false;
}
$opcache_jit_arg = $opcache_jit ? '--enable-opcache-jit ' : '--disable-opcache-jit ';
$config_file_path = $this->getOption('with-config-file-path', false) ?
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
@@ -131,7 +124,6 @@ class MacOSBuilder extends UnixBuilderBase
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
$opcache_jit_arg .
$config_file_path .
$config_file_scan_dir .
$json_74 .
@@ -164,6 +156,11 @@ class MacOSBuilder extends UnixBuilderBase
}
$this->buildEmbed();
}
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
if (!empty($shared_extensions)) {
logger()->info('Building shared extensions ...');
$this->buildSharedExts();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
@@ -255,6 +252,8 @@ class MacOSBuilder extends UnixBuilderBase
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') {
$AR = getenv('AR') ?: 'ar';
f_passthru("{$AR} -t " . BUILD_LIB_PATH . "/libphp.a | grep '\\.a$' | xargs -n1 {$AR} d " . BUILD_LIB_PATH . '/libphp.a');
// export dynamic symbols
SystemUtil::exportDynamicSymbols(BUILD_LIB_PATH . '/libphp.a');
}
$this->patchPhpScripts();
}

View File

@@ -4,21 +4,101 @@ declare(strict_types=1);
namespace SPC\builder\traits;
/**
* Unix 系统的工具函数 Trait适用于 Linux、macOS
*/
use SPC\exception\ExecutionException;
use SPC\exception\SPCInternalException;
use SPC\exception\WrongUsageException;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\SPCTarget;
trait UnixSystemUtilTrait
{
/**
* @param string $name 命令名称
* @param array $paths 寻找的目标路径(如果不传入,则使用环境变量 PATH
* @return null|string 找到了返回命令路径,找不到返回 null
* Export static library dynamic symbols to a .dynsym file.
* It will export to "/path/to/libxxx.a.dynsym".
*
* @param string $lib_file Static library file path (e.g. /path/to/libxxx.a)
*/
public static function exportDynamicSymbols(string $lib_file): void
{
// check
if (!is_file($lib_file)) {
throw new WrongUsageException("The lib archive file {$lib_file} does not exist, please build it first.");
}
// shell out
$cmd = 'nm -g --defined-only -P ' . escapeshellarg($lib_file);
$result = shell()->execWithResult($cmd);
if ($result[0] !== 0) {
throw new ExecutionException($cmd, 'Failed to get defined symbols from ' . $lib_file);
}
// parse shell output and filter
$defined = [];
foreach ($result[1] as $line) {
$line = trim($line);
if ($line === '' || str_ends_with($line, '.o:') || str_ends_with($line, '.o]:')) {
continue;
}
$name = strtok($line, " \t");
if (!$name) {
continue;
}
$name = preg_replace('/@.*$/', '', $name);
if ($name !== '' && $name !== false) {
$defined[] = $name;
}
}
$defined = array_unique($defined);
sort($defined);
// export
if (SPCTarget::getTargetOS() === 'Linux') {
file_put_contents("{$lib_file}.dynsym", "{\n" . implode("\n", array_map(fn ($x) => " {$x};", $defined)) . "};\n");
} else {
file_put_contents("{$lib_file}.dynsym", implode("\n", $defined) . "\n");
}
}
/**
* Get linker flag to export dynamic symbols from a static library.
*
* @param string $lib_file Static library file path (e.g. /path/to/libxxx.a)
* @return null|string Linker flag to export dynamic symbols, null if no .dynsym file found
*/
public static function getDynamicExportedSymbols(string $lib_file): ?string
{
$symbol_file = "{$lib_file}.dynsym";
if (!is_file($symbol_file)) {
self::exportDynamicSymbols($lib_file);
}
if (!is_file($symbol_file)) {
throw new SPCInternalException("The symbol file {$symbol_file} does not exist, please check if nm command is available.");
}
// https://github.com/ziglang/zig/issues/24662
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
return '-Wl,--export-dynamic';
}
// macOS
if (SPCTarget::getTargetOS() !== 'Linux') {
return "-Wl,-exported_symbols_list,{$symbol_file}";
}
return "-Wl,--dynamic-list={$symbol_file}";
}
/**
* Find a command in given paths or system PATH.
* If $name is an absolute path, check if it exists.
*
* @param string $name Command name or absolute path
* @param array $paths Paths to search, if empty, use system PATH
* @return null|string Absolute path of the command if found, null otherwise
*/
public static function findCommand(string $name, array $paths = []): ?string
{
if (!$paths) {
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
}
if (str_starts_with($name, '/')) {
return file_exists($name) ? $name : null;
}
foreach ($paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $name)) {
return $path . DIRECTORY_SEPARATOR . $name;
@@ -28,6 +108,8 @@ trait UnixSystemUtilTrait
}
/**
* Make environment variable string for shell command.
*
* @param array $vars Variables, like: ["CFLAGS" => "-Ixxx"]
* @return string like: CFLAGS="-Ixxx"
*/

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\unix;
use SPC\builder\BuilderBase;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\exception\SPCInternalException;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
@@ -13,6 +14,8 @@ use SPC\store\CurlHook;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use SPC\store\pkg\GoXcaddy;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\util\DependencyUtil;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
@@ -135,6 +138,7 @@ abstract class UnixBuilderBase extends BuilderBase
if (SPCTarget::isStatic()) {
$lens .= ' -static';
}
$dynamic_exports = '';
// if someone changed to EMBED_TYPE=shared, we need to add LD_LIBRARY_PATH
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
if (PHP_OS_FAMILY === 'Darwin') {
@@ -149,8 +153,13 @@ abstract class UnixBuilderBase extends BuilderBase
foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) {
unlink($file);
}
// calling linux system util in other unix OS is okay
if ($dynamic_exports = LinuxSystemUtil::getDynamicExportedSymbols(BUILD_LIB_PATH . '/libphp.a')) {
$dynamic_exports = ' ' . $dynamic_exports;
}
}
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
$cc = getenv('CC');
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult("{$cc} -o embed embed.c {$lens} {$dynamic_exports}");
if ($ret !== 0) {
throw new ValidationException(
'embed failed sanity check: build failed. Error message: ' . implode("\n", $out),
@@ -259,31 +268,45 @@ abstract class UnixBuilderBase extends BuilderBase
logger()->warning('caddy-cbrotli module is enabled, but brotli library is not built. Disabling caddy-cbrotli.');
$xcaddyModules = str_replace('--with github.com/dunglas/caddy-cbrotli', '', $xcaddyModules);
}
$lrt = PHP_OS_FAMILY === 'Linux' ? '-lrt' : '';
$releaseInfo = json_decode(Downloader::curlExec(
'https://api.github.com/repos/php/frankenphp/releases/latest',
hooks: [[CurlHook::class, 'setupGithubToken']],
), true);
$frankenPhpVersion = $releaseInfo['tag_name'];
$libphpVersion = $this->getPHPVersion();
$dynamic_exports = '';
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
$libphpVersion = preg_replace('/\.\d$/', '', $libphpVersion);
$libphpVersion = preg_replace('/\.\d+$/', '', $libphpVersion);
} else {
if ($dynamicSymbolsArgument = LinuxSystemUtil::getDynamicExportedSymbols(BUILD_LIB_PATH . '/libphp.a')) {
$dynamic_exports = ' ' . $dynamicSymbolsArgument;
}
}
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
$extLdFlags = "-extldflags '-pie'";
$extLdFlags = "-extldflags '-pie{$dynamic_exports}'";
$muslTags = '';
$staticFlags = '';
if (SPCTarget::isStatic()) {
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'";
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports}'";
$muslTags = 'static_build,';
$staticFlags = '-static-pie';
}
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
$libs = $config['libs'];
$libs .= PHP_OS_FAMILY === 'Linux' ? ' -lrt' : '';
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||
str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) &&
ToolchainManager::getToolchainClass() === GccNativeToolchain::class) {
$cflags .= ' -Wno-error=missing-profile';
$libs .= ' -lgcov';
}
$env = [
'CGO_ENABLED' => '1',
'CGO_CFLAGS' => $config['cflags'],
'CGO_LDFLAGS' => "{$staticFlags} {$config['ldflags']} {$config['libs']} {$lrt}",
'CGO_CFLAGS' => clean_spaces($cflags),
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs}",
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' . $debugFlags .
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .

View File

@@ -211,12 +211,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();
}
$builder->testPHP($rule);
// compile stopwatch :P
@@ -252,7 +246,7 @@ class BuildPHPCommand extends BuildCommand
$path = FileSystem::convertPath("{$build_root_path}/modules/{$ext}.so");
if (file_exists(BUILD_MODULES_PATH . "/{$ext}.so")) {
logger()->info("Shared extension [{$ext}] path{$fixed}: {$path}");
} else {
} elseif (Config::getExt($ext, 'type') !== 'addon') {
logger()->warning("Shared extension [{$ext}] not found, please check!");
}
}

View File

@@ -40,7 +40,7 @@ class LinuxToolCheckList
'tar', 'unzip', 'gzip', 'gcc',
'bzip2', 'cmake', 'patch', 'which',
'xz', 'libtool', 'gettext-devel',
'perl', 'patchelf',
'patchelf',
];
public const TOOLS_ARCH = [
@@ -48,10 +48,12 @@ class LinuxToolCheckList
];
private const PROVIDED_COMMAND = [
'perl' => '/usr/share/perl5/FindBin.pm',
'binutils-gold' => 'ld.gold',
'base-devel' => 'automake',
'gettext-devel' => 'gettextize',
'gettext-dev' => 'gettextize',
'perl-IPC-Cmd' => '/usr/share/doc/perl-IPC-Cmd',
];
/** @noinspection PhpUnused */

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace SPC\doctor\item;
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
use SPC\doctor\OptionalCheck;
use SPC\store\PackageManager;
use SPC\util\PkgConfigUtil;
#[OptionalCheck([self::class, 'optionalCheck'])]
class PkgConfigCheck
{
public static function optionalCheck(): bool
{
return PHP_OS_FAMILY !== 'Windows';
}
/** @noinspection PhpUnused */
#[AsCheckItem('if pkg-config is installed or built', level: 800)]
public function checkPkgConfig(): CheckResult
{
if (!($pkgconf = PkgConfigUtil::findPkgConfig())) {
return CheckResult::fail('pkg-config is not installed', 'install-pkgconfig');
}
return CheckResult::ok($pkgconf);
}
#[AsFixItem('install-pkgconfig')]
public function installPkgConfig(): bool
{
PackageManager::installPackage('pkg-config');
return true;
}
}

View File

@@ -30,6 +30,7 @@ class SourcePatcher
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchImapLicense']);
FileSystem::addSourceExtractHook('ext-imagick', [__CLASS__, 'patchImagickWith84']);
FileSystem::addSourceExtractHook('libaom', [__CLASS__, 'patchLibaomForAlpine']);
FileSystem::addSourceExtractHook('pkg-config', [__CLASS__, 'patchPkgConfigForGcc15']);
FileSystem::addSourceExtractHook('attr', [__CLASS__, 'patchAttrForAlpine']);
FileSystem::addSourceExtractHook('gmssl', [__CLASS__, 'patchGMSSL']);
}
@@ -155,6 +156,7 @@ class SourcePatcher
$spc_micro_patches = getenv('SPC_MICRO_PATCHES');
$spc_micro_patches = $spc_micro_patches === false ? [] : explode(',', $spc_micro_patches);
}
$spc_micro_patches = array_filter($spc_micro_patches, fn ($item) => trim((string) $item) !== '');
$patch_list = $spc_micro_patches;
$patches = [];
$serial = ['80', '81', '82', '83', '84', '85'];
@@ -269,7 +271,12 @@ class SourcePatcher
if ($version === '5.1.3') {
self::patchFile('spc_fix_swoole_50513.patch', SOURCE_PATH . '/php-src/ext/swoole');
}
self::patchFile('swoole_fix_date_time.patch', SOURCE_PATH . '/php-src/ext/swoole');
if (version_compare($version, '6.0.0', '>=') && version_compare($version, '6.1.0', '<')) {
// remove when https://github.com/swoole/swoole-src/pull/5848 is merged
self::patchFile('swoole_fix_date_time.patch', SOURCE_PATH . '/php-src/ext/swoole');
// remove when https://github.com/swoole/swoole-src/pull/5847 is merged
self::patchFile('swoole_fix_odbclibs.patch', SOURCE_PATH . '/php-src/ext/swoole');
}
return true;
}
@@ -493,6 +500,12 @@ class SourcePatcher
return true;
}
public static function patchPkgConfigForGcc15(): bool
{
self::patchFile('pkg-config_gcc15.patch', SOURCE_PATH . '/pkg-config');
return true;
}
public static function patchLibaomForAlpine(): bool
{
if (PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist()) {

View File

@@ -45,7 +45,7 @@ class ClangNativeToolchain implements ToolchainInterface
$compiler = getenv('CC') ?: 'clang';
$version = shell(false)->execWithResult("{$compiler} --version", false);
$head = pathinfo($compiler, PATHINFO_BASENAME);
if ($version[0] === 0 && preg_match('/clang version (\d+.\d+.\d+)/', $version[1][0], $match)) {
if ($version[0] === 0 && preg_match('/clang version (\d+\.\d+\.\d+)/', $version[1][0], $match)) {
return "{$head} {$match[1]}";
}
return $head;

View File

@@ -42,7 +42,7 @@ class GccNativeToolchain implements ToolchainInterface
$compiler = getenv('CC') ?: 'gcc';
$version = shell(false)->execWithResult("{$compiler} --version", false);
$head = pathinfo($compiler, PATHINFO_BASENAME);
if ($version[0] === 0 && preg_match('/gcc.*(\d+.\d+.\d+)/', $version[1][0], $match)) {
if ($version[0] === 0 && preg_match('/gcc.*?(\d+\.\d+\.\d+)/', $version[1][0], $match)) {
return "{$head} {$match[1]}";
}
return $head;

View File

@@ -7,6 +7,7 @@ namespace SPC\toolchain;
use SPC\builder\linux\SystemUtil;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
use SPC\util\PkgConfigUtil;
use SPC\util\SPCTarget;
class ToolchainManager
@@ -56,6 +57,15 @@ class ToolchainManager
if (SPCTarget::getLibc() === 'glibc' && SystemUtil::isMuslDist()) {
throw new WrongUsageException('You are linking against glibc dynamically, which is only supported on glibc distros.');
}
// init pkg-config for unix
if (is_unix()) {
if (($found = PkgConfigUtil::findPkgConfig()) === null) {
throw new WrongUsageException('Cannot find pkg-config executable. Please run `doctor` to fix this.');
}
GlobalEnvManager::putenv("PKG_CONFIG={$found}");
}
$toolchain = getenv('SPC_TOOLCHAIN');
/* @var ToolchainInterface $toolchain */
$instance = new $toolchain();

View File

@@ -39,8 +39,8 @@ class GlobalEnvManager
// Define env vars for unix
if (is_unix()) {
self::addPathIfNotExists(BUILD_BIN_PATH);
self::putenv('PKG_CONFIG=' . BUILD_BIN_PATH . '/pkg-config');
self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig');
self::addPathIfNotExists(PKG_ROOT_PATH . '/bin');
self::putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig');
}
$ini = self::readIniFile();

View File

@@ -14,6 +14,28 @@ use SPC\exception\ExecutionException;
*/
class PkgConfigUtil
{
/**
* Find the pkg-config executable which is compatible with static builds.
*
* @return null|string Path to pkg-config executable, or null if not found
*/
public static function findPkgConfig(): ?string
{
// Find pkg-config executable
$find_list = [
PKG_ROOT_PATH . '/bin/pkg-config',
BUILD_BIN_PATH . '/pkg-config',
];
$found = null;
foreach ($find_list as $file) {
if (file_exists($file) && is_executable($file)) {
$found = $file;
break;
}
}
return $found;
}
/**
* Returns the version of a module.
* This method uses `pkg-config --modversion` to get the version of the specified module.

View File

@@ -52,6 +52,15 @@ class SPCConfigUtil
*/
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
{
$extra_exts = [];
foreach ($extensions as $ext) {
$extra_exts = array_merge($extra_exts, Config::getExt($ext, 'ext-suggests', []));
}
foreach ($extra_exts as $ext) {
if ($this->builder?->getExt($ext) && !in_array($ext, $extensions)) {
$extensions[] = $ext;
}
}
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
ob_start();

View File

@@ -100,6 +100,10 @@ class SPCTarget
public static function getLibcVersion(): ?string
{
if (PHP_OS_FAMILY === 'Linux') {
$target = (string) getenv('SPC_TARGET');
if (str_contains($target, '-gnu.2.')) {
return preg_match('/-gnu\.(2\.\d+)/', $target, $matches) ? $matches[1] : null;
}
$libc = self::getLibc();
return SystemUtil::getLibcVersionIfExists($libc);
}

View File

@@ -8,6 +8,7 @@ use SPC\builder\freebsd\library\BSDLibraryBase;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\store\FileSystem;
use SPC\util\PkgConfigUtil;
use SPC\util\shell\UnixShell;
/**
@@ -184,6 +185,7 @@ class UnixCMakeExecutor extends Executor
$cxx = getenv('CCX');
logger()->debug("making cmake tool chain file for {$os} {$target_arch} with CFLAGS='{$cflags}'");
$root = BUILD_ROOT_PATH;
$pkgConfigExecutable = PkgConfigUtil::findPkgConfig();
$ccLine = '';
if ($cc) {
$ccLine = 'SET(CMAKE_C_COMPILER ' . $cc . ')';
@@ -202,7 +204,7 @@ SET(CMAKE_PREFIX_PATH "{$root}")
SET(CMAKE_INSTALL_PREFIX "{$root}")
SET(CMAKE_INSTALL_LIBDIR "lib")
set(PKG_CONFIG_EXECUTABLE "{$root}/bin/pkg-config")
set(PKG_CONFIG_EXECUTABLE "{$pkgConfigExecutable}")
list(APPEND PKG_CONFIG_EXECUTABLE "--static")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)

View File

@@ -0,0 +1,22 @@
diff --git a/glib/glib/goption.c b/glib/glib/goption.c
index 0a22f6f..f439fd4 100644
--- a/glib/glib/goption.c
+++ b/glib/glib/goption.c
@@ -166,7 +166,7 @@ typedef struct
gpointer arg_data;
union
{
- gboolean bool;
+ gboolean boolean;
gint integer;
gchar *str;
gchar **array;
@@ -1600,7 +1600,7 @@ free_changes_list (GOptionContext *context,
switch (change->arg_type)
{
case G_OPTION_ARG_NONE:
- *(gboolean *)change->arg_data = change->prev.bool;
+ *(gboolean *)change->arg_data = change->prev.boolean;
break;
case G_OPTION_ARG_INT:
*(gint *)change->arg_data = change->prev.integer;

View File

@@ -0,0 +1,90 @@
From d4942a590a301a2552f8885962640f38d60de27b Mon Sep 17 00:00:00 2001
From: DubbleClick <m@pyc.ac>
Date: Tue, 26 Aug 2025 00:08:32 +0700
Subject: [PATCH] add SWOOLE_ODBC_LIBC variable if the odbc library needs more
than to link against a single library
---
config.m4 | 57 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 44 insertions(+), 13 deletions(-)
diff --git a/config.m4 b/config.m4
index 1583cb81c8..683d8891af 100644
--- a/config.m4
+++ b/config.m4
@@ -641,31 +641,62 @@ EOF
AC_MSG_ERROR([Cannot find header file(s) for pdo_odbc])
fi
+ if test -n "$SWOOLE_ODBC_LIBS"; then
+ ODBC_LIBS="$SWOOLE_ODBC_LIBS"
+ else
+ ODBC_LIBS="-l$pdo_odbc_def_lib"
+ fi
+
PDO_ODBC_INCLUDE="$pdo_odbc_def_cflags -I$PDO_ODBC_INCDIR -DPDO_ODBC_TYPE=\\\"$pdo_odbc_flavour\\\""
- PDO_ODBC_LDFLAGS="$pdo_odbc_def_ldflags -L$PDO_ODBC_LIBDIR -l$pdo_odbc_def_lib"
+ PDO_ODBC_LDFLAGS="$pdo_odbc_def_ldflags -L$PDO_ODBC_LIBDIR $ODBC_LIBS"
PHP_EVAL_LIBLINE([$PDO_ODBC_LDFLAGS], [SWOOLE_SHARED_LIBADD])
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$pdo_cv_inc_path $PDO_ODBC_INCLUDE"
dnl Check first for an ODBC 1.0 function to assert that the libraries work
- PHP_CHECK_LIBRARY($pdo_odbc_def_lib, SQLBindCol,
- [
- dnl And now check for an ODBC 3.0 function to assert that they are *good*
- dnl libraries.
- PHP_CHECK_LIBRARY($pdo_odbc_def_lib, SQLAllocHandle,
- [], [
- AC_MSG_ERROR([
+ save_LIBS="$LIBS"
+ LIBS="$LIBS $PDO_ODBC_LDFLAGS"
+
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <sql.h>
+ #include <sqlext.h>]],
+ [[
+ SQLLEN ind = 0;
+ char buf[1];
+ SQLBindCol((SQLHSTMT)0, (SQLUSMALLINT)1, (SQLSMALLINT)SQL_C_CHAR,
+ (SQLPOINTER)buf, (SQLLEN)sizeof(buf), &ind);
+ return 0;
+ ]])],
+ [
+ dnl And now check for an ODBC 3.0 function to assert that they are *good*
+ dnl libraries.
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <sql.h>
+ #include <sqlext.h>]],
+ [[
+ SQLHANDLE out = SQL_NULL_HANDLE;
+ SQLAllocHandle((SQLSMALLINT)SQL_HANDLE_ENV,
+ (SQLHANDLE)SQL_NULL_HANDLE, &out);
+ return 0;
+ ]])],
+ [],
+ [AC_MSG_ERROR([
Your ODBC library does not appear to be ODBC 3 compatible.
You should consider using iODBC or unixODBC instead, and loading your
libraries as a driver in that environment; it will emulate the
functions required for PDO support.
- ])], $PDO_ODBC_LDFLAGS)
- ],[
- AC_MSG_ERROR([Your ODBC library does not exist or there was an error. Check config.log for more information])
- ], $PDO_ODBC_LDFLAGS)
+ ])]
+ )
+ ],
+ [AC_MSG_ERROR([Your ODBC library does not exist or there was an error. Check config.log for more information])]
+ )
+
+ LIBS="$save_LIBS"
- AC_DEFINE(SW_USE_ODBC, 1, [do we enable swoole-odbc coro support])
+ AC_DEFINE(SW_USE_ODBC, 1, [do we enable swoole-odbc coro support])
fi
dnl odbc end

View File

@@ -18,19 +18,19 @@ $test_php_version = [
// '8.3',
'8.4',
// '8.5',
'git',
// 'git',
];
// test os (macos-13, macos-14, macos-15, ubuntu-latest, windows-latest are available)
$test_os = [
// 'macos-13', // bin/spc for x86_64
'macos-13', // bin/spc for x86_64
// 'macos-14', // bin/spc for arm64
// 'macos-15', // bin/spc for arm64
'macos-15', // bin/spc for arm64
'ubuntu-latest', // bin/spc-alpine-docker for x86_64
// 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64
'ubuntu-24.04', // bin/spc for x86_64
'ubuntu-22.04', // bin/spc-gnu-docker for x86_64
// 'ubuntu-24.04', // bin/spc for x86_64
'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64
'ubuntu-24.04-arm', // bin/spc for arm64
// 'ubuntu-24.04-arm', // bin/spc for arm64
// 'windows-latest', // .\bin\spc.ps1
];
@@ -50,19 +50,19 @@ $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' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pdo,pdo_mysql,pdo_sqlite,phar,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip',
'Linux', 'Darwin' => 'bcmath',
'Windows' => 'bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pdo,pdo_mysql,pdo_sqlite,phar,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip',
};
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
$shared_extensions = match (PHP_OS_FAMILY) {
'Linux' => '',
'Linux' => 'zip',
'Darwin' => '',
'Windows' => '',
};
// If you want to test lib-suggests for all extensions and libraries, set it to true.
$with_suggested_libs = false;
$with_suggested_libs = true;
// If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true.
$with_libs = match (PHP_OS_FAMILY) {

1134
yarn.lock

File diff suppressed because it is too large Load Diff