Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e975e15
swoole hooks can be compiled if pgsql/sqlite are not compiled in stat…
henderkes Aug 25, 2025
779a724
go's gcc driver is the dumbest shit to ever exist
henderkes Aug 25, 2025
75f734d
cs fix
henderkes Aug 25, 2025
8104ff7
update checks for shared swoole-hook extensions
henderkes Aug 25, 2025
7e0e909
explicitly enable swoole-mysql too
henderkes Aug 25, 2025
448941f
don't request configurearg if it's not used (ease debugging)
henderkes Aug 25, 2025
b6d4af2
zts -> --enable-swoole-thread
henderkes Aug 25, 2025
93223a9
too much pgo, too little pdo
henderkes Aug 25, 2025
1c7fa01
remove space
henderkes Aug 25, 2025
324ba0d
use type=addon and arg-type=none
henderkes Aug 25, 2025
a46ad7b
cs fix
henderkes Aug 25, 2025
d13e369
test swoole
henderkes Aug 25, 2025
9fe3223
use 8.4 for tests only
henderkes Aug 25, 2025
99ccbf8
@crazywhalecc please look what's wrong with macos
henderkes Aug 25, 2025
2b57bca
remove useless import
henderkes Aug 25, 2025
efdfbf4
use format string
henderkes Aug 25, 2025
868f6d4
only feed -lgcov to the go driver
henderkes Aug 25, 2025
65ee747
suggestion and clean up frankenphp build
henderkes Aug 25, 2025
f80aee5
get rid of $rt
henderkes Aug 25, 2025
37e0f1d
Update src/SPC/command/BuildPHPCommand.php
henderkes Aug 25, 2025
2694dd9
add liburing for swoole
henderkes Aug 25, 2025
b1da64d
add swoole-hook-odbc to work the same way as the other hooks
henderkes Aug 25, 2025
a1f2126
update comments
henderkes Aug 25, 2025
ba32697
prevent infinite recursion if ext suggests addons that depend on the …
henderkes Aug 25, 2025
9803bf6
prevent warning message from addons
henderkes Aug 25, 2025
43352ab
don't print repeated --ri swoole check
henderkes Aug 25, 2025
4eac953
ensure liburing is only pulled in by suggested libs when glibc >= 2.3…
henderkes Aug 26, 2025
00f2625
cs fix
henderkes Aug 26, 2025
2d409db
we don't need a min glibc version, just don't use --use-libc!
henderkes Aug 26, 2025
effefd4
string
henderkes Aug 26, 2025
0d4d428
only `install library` for liburing
henderkes Aug 26, 2025
d9c2247
fix alpine `realpath -s` issue
henderkes Aug 26, 2025
1243fb9
don't test macos as it just fails either way, add odbc test
henderkes Aug 26, 2025
c433aed
fix macos?
henderkes Aug 26, 2025
00892c2
fix odbc libs when iconv is built too
henderkes Aug 26, 2025
ecdb94b
suggestions
henderkes Aug 27, 2025
08ab3c1
fix perl-IPC-Cmd check so it doesn't try installing it every time
henderkes Aug 27, 2025
3da58d5
filter micro patches to not be ''
henderkes Aug 27, 2025
25401e5
cs fix
henderkes Aug 27, 2025
95f1b65
fix perl installation by checking for FindBin
henderkes Aug 27, 2025
5a4b920
pkg-config patch
henderkes Aug 27, 2025
25fe794
trim all items
henderkes Aug 27, 2025
117a54d
extension test
crazywhalecc Aug 28, 2025
5323608
Merge branch 'main' into swoolehooks
crazywhalecc Aug 28, 2025
fc7e8eb
extension test
crazywhalecc Aug 28, 2025
1a7bf2d
test
crazywhalecc Aug 28, 2025
20fbbb1
test
crazywhalecc Aug 28, 2025
f187250
disable opcache jit automatically on alpine target (only required for…
henderkes Aug 28, 2025
866ca26
only disable it for x86_64
henderkes Aug 28, 2025
39a9840
why is phpstan so stupid about this constant?
henderkes Aug 28, 2025
bf55db9
Add swoole-hook-odbc notes
crazywhalecc Aug 28, 2025
0f00501
Update cli generator, add frankenphp SAPI, add copy-to-clipboard func
crazywhalecc Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions config/ext.json
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,16 @@
"nghttp2",
"zlib"
],
"lib-suggests": [
"zstd",
"unixodbc"
],
"ext-depends": [
"openssl",
"curl"
],
"ext-suggests": [
"sockets",
"swoole-hook-pgsql",
"swoole-hook-mysql",
"swoole-hook-sqlite"
Expand All @@ -859,11 +864,12 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"mysqlnd",
"pdo",
"pdo_mysql"
"pdo_mysql",
"swoole"
],
"ext-suggests": [
"mysqli"
Expand All @@ -877,10 +883,11 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"pgsql",
"pdo"
"pdo",
"swoole"
]
},
"swoole-hook-sqlite": {
Expand All @@ -890,10 +897,11 @@
},
"notes": true,
"type": "addon",
"arg-type": "custom",
"arg-type": "none",
"ext-depends": [
"sqlite3",
"pdo"
"pdo",
"swoole"
]
},
"swow": {
Expand Down
5 changes: 3 additions & 2 deletions src/SPC/builder/BuilderBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,18 +268,19 @@ public function makeStaticExtensionArgs(): string
{
$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);
} else {
continue;
}
}
$arg ??= $ext->getConfigureArg();
logger()->info($ext->getName() . ' is using ' . $arg);
$ret[] = trim($arg);
}
Expand Down
11 changes: 10 additions & 1 deletion src/SPC/builder/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,15 @@ public function getSharedExtensionLoadString(): string
$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);
}

Expand All @@ -269,6 +272,9 @@ public function getSharedExtensionLoadString(): string
$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 {
Expand Down Expand Up @@ -352,6 +358,9 @@ public function validate(): void
*/
public function buildShared(): void
{
if (Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
try {
if (Config::getExt($this->getName(), 'type') === 'builtin' || Config::getExt($this->getName(), 'build-with-php') === true) {
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
Expand Down
20 changes: 14 additions & 6 deletions src/SPC/builder/extension/swoole.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ public function getExtVersion(): ?string
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';

$arg .= $this->builder->getOption('enable-zts') ? ' --enable-swoole-thread --disable-thread-context' : ' --disable-swoole-thread --enable-thread-context';

// required feature: curl, openssl (but curl hook is buggy for php 8.0)
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
Expand All @@ -58,17 +60,23 @@ public function getUnixConfigureArg(bool $shared = false): string
$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('iouring') ? ' --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';
$arg .= $this->builder->getExt('swoole-hook-pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql';

// additional feature: swoole-mysql
$arg .= $this->builder->getExt('swoole-hook-mysql') ? ' --enable-mysqlnd' : ' --disable-mysqlnd';

// 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';
$arg .= $this->builder->getExt('swoole-hook-sqlite') ? ' --enable-swoole-sqlite' : ' --disable-swoole-sqlite';

// enable this feature , need stop pdo_*
// $arg .= $this->builder->getLib('unixodbc') ? ' --with-swoole-odbc=unixODBC,' : ' ';
$arg .= $this->builder->getLib('unixodbc') && !$this->builder->getExt('pdo')?->isBuildStatic() ? ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH : '';
return $arg;
}
}
11 changes: 2 additions & 9 deletions src/SPC/builder/extension/swoole_hook_mysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,19 @@ public function getDistName(): string
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);
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $this->getSharedExtensionLoadString() . ' --ri "swoole"');
$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');
}
}
}
8 changes: 1 addition & 7 deletions src/SPC/builder/extension/swoole_hook_pgsql.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,11 @@ public function getDistName(): string
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
Expand Down
8 changes: 1 addition & 7 deletions src/SPC/builder/extension/swoole_hook_sqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,11 @@ public function getDistName(): string
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
Expand Down
16 changes: 13 additions & 3 deletions src/SPC/builder/unix/UnixBuilderBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
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;
Expand Down Expand Up @@ -259,7 +261,6 @@ protected function buildFrankenphp(): void
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']],
Expand All @@ -280,10 +281,19 @@ protected function buildFrankenphp(): void
}

$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' : '';
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' => $this->arch_c_flags . ' ' . $config['cflags'],
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$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 ' .
Expand Down
2 changes: 1 addition & 1 deletion src/SPC/command/BuildPHPCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public function handle(): int
$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 (!str_contains($ext, 'swoole-hook')) {
logger()->warning("Shared extension [{$ext}] not found, please check!");
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/SPC/util/SPCConfigUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ public function __construct(?BuilderBase $builder = null, array $options = [])
*/
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;
}
}
Comment on lines +55 to +63
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DependencyUtil::getExtsAndLibs will automatically sort the suggested extensions. And is there any reason we need to add suggested extensions here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Example: swoole suggests ext swoole-hook-pgsql. Swoole-hook-pgsql requires pdo and pgsql libs. If we get the config from swoole, it doesn't directly depend on pgsql, but when pgsql hook is enabled, it does.

It's the same way where libraries become dependencies of libraries that suggest them, when they are enabled.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But DependencyUtil::getExtsAndLibs will automatically add suggested extension's dependencies if defined. The DependencyUtil's platExtToLibs also includes ext-suggests.

I also tested the difference with and without this code, and for bin/spc spc-config swoole,swoole-hook-pgsql, the output is exactly the same.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bin/spc spc-config swoole,swoole-hook-pgsql

Extension::buildShared calls SpcConfigUtil::config([$ext->name]).

So it only passes swoole but swoole-hook-pgsql is enabled in the builder. This code turns ['swoole'] into ['swoole', 'swoole-hook-pgsql'] before DependencyUtil.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean: bin/spc build swoole-hook-pgsql --build-shared=swoole like this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

I made bin/spc build bcmath --build-shared=swoole,swoole-hook-pgsql work too, by the way, because it's nicer to have them next to each other.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that makes sense. My initial thought was to provide the full list of extensions in buildShared, but that seems more complicated than this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would not work because it would pull in definitions for symbols that should not be available (looking at you, postgresql, defining libc methods...)

[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);

ob_start();
Expand Down
10 changes: 5 additions & 5 deletions src/globals/test-extensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
// '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
Expand All @@ -50,7 +50,7 @@

// 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' => 'swoole,swoole-hook-mysql,swoole-hook-pgsql,swoole-hook-sqlite',
'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',
};

Expand All @@ -62,7 +62,7 @@
};

// 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) {
Expand Down
Loading