From 460eb02086d86f368f21958d209936ef8bb3fd63 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 08:45:58 +0700 Subject: [PATCH 01/16] build frankenphp and embed after shared extensions, make sure the linker doesn't drop libphp.a symbols that extensions need --- src/SPC/builder/freebsd/BSDBuilder.php | 5 ++ src/SPC/builder/linux/LinuxBuilder.php | 6 ++ src/SPC/builder/macos/MacOSBuilder.php | 5 ++ src/SPC/builder/unix/UnixBuilderBase.php | 85 +++++++++++++++++++++++- src/SPC/command/BuildPHPCommand.php | 6 -- 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/SPC/builder/freebsd/BSDBuilder.php b/src/SPC/builder/freebsd/BSDBuilder.php index dcaa5a2d..dcfe2433 100644 --- a/src/SPC/builder/freebsd/BSDBuilder.php +++ b/src/SPC/builder/freebsd/BSDBuilder.php @@ -122,6 +122,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(); diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 373e1b21..90d5c7b9 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -142,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(); diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 00c1da8c..a67161c5 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -156,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(); diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index c09a9e1b..64d19478 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -31,6 +31,63 @@ abstract class UnixBuilderBase extends BuilderBase /** @var string LD flags */ public string $arch_ld_flags; + private static array $undefined_symbols = []; + + public static function getUndefinedSymbols(): array + { + if (count(self::$undefined_symbols)) { + return self::$undefined_symbols; + } + + $undefined = []; + + $addSymbolsFromString = function (string $out, &$list) { + foreach (preg_split('/\R/', trim($out)) as $line) { + if ($line === '') { + continue; + } + $name = strtok($line, " \t"); + if (!$name) { + continue; + } + $name = preg_replace('/@.*$/', '', $name); + if ($name !== '' && $name !== false) { + $list[$name] = true; + } + } + }; + + // collect undefined symbols from shared extensions + $files = glob(rtrim(BUILD_MODULES_PATH, '/') . DIRECTORY_SEPARATOR . '*.so') ?: []; + foreach ($files as $so) { + $cmd = 'nm -D --undefined-only -P ' . escapeshellarg($so) . ' 2>/dev/null'; + $out = shell_exec($cmd); + if ($out !== '') { + $addSymbolsFromString($out, $undefined); + } + } + + // keep only symbols defined in libphp.a + $defined = []; + $libphp = BUILD_LIB_PATH . '/libphp.a'; + if (!is_file($libphp)) { + throw new WrongUsageException('You must build libphp.a statically before calling this function.'); + } + $cmd = 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null'; + $out = shell_exec($cmd) ?: ''; + if ($out !== '') { + $addSymbolsFromString($out, $defined); + } + // intersect: only undefined symbols that libphp.a actually defines + $keys = array_intersect_key($undefined, $defined); + + $list = array_keys($keys); + sort($list, SORT_STRING); + + self::$undefined_symbols = $list; + return $list; + } + public function proveLibs(array $sorted_libraries): void { // search all supported libs @@ -137,6 +194,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') { @@ -151,8 +209,17 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } + $symbols = self::getUndefinedSymbols(); // returns unique, version-stripped names + // turn list into many --export-dynamic-symbol=... flags + $dynamic_exports = implode( + ' ', + array_map( + static fn (string $s) => '-Wl,--export-dynamic-symbol=' . escapeshellarg($s), + $symbols + ) + ); } - [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens); + [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('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), @@ -271,11 +338,23 @@ abstract class UnixBuilderBase extends BuilderBase $libphpVersion = preg_replace('/\.\d$/', '', $libphpVersion); } $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; - $extLdFlags = "-extldflags '-pie'"; + $dynamic_exports = ''; + if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { + $symbols = self::getUndefinedSymbols(); // returns unique, version-stripped names + // turn list into many --export-dynamic-symbol=... flags + $dynamic_exports = ' ' . implode( + ' ', + array_map( + static fn (string $s) => '-Wl,--export-dynamic-symbol="' . $s . '"', + $symbols + ) + ); + } + $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'; } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index fb14e47c..58b6059b 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -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 From fad23145399b06b6c5fac628ce234fcecef18ff1 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 09:25:32 +0700 Subject: [PATCH 02/16] found ENABLE_SHARED option in liburing! --- src/SPC/builder/linux/library/liburing.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SPC/builder/linux/library/liburing.php b/src/SPC/builder/linux/library/liburing.php index 668659ec..82249cf8 100644 --- a/src/SPC/builder/linux/library/liburing.php +++ b/src/SPC/builder/linux/library/liburing.php @@ -51,8 +51,7 @@ class liburing extends LinuxLibraryBase $use_libc ? '--use-libc' : '', ) ->configure() - ->make('library', with_clean: false) - ->exec("rm -rf {$this->getLibDir()}/liburing*.so*"); + ->make('library', 'install ENABLE_SHARED=0', with_clean: false); $this->patchPkgconfPrefix(); } From 56c90ca4a39f2d78c1ab7f7a6ae32219d27ac2af Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 10:24:51 +0700 Subject: [PATCH 03/16] use all symbols from libphp.a, so we don't need to build shared extensions --- src/SPC/builder/unix/UnixBuilderBase.php | 54 +++++++++--------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 64d19478..5207ddfe 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -33,15 +33,25 @@ abstract class UnixBuilderBase extends BuilderBase private static array $undefined_symbols = []; - public static function getUndefinedSymbols(): array + public static function getDynamicExportSymbols(): array { if (count(self::$undefined_symbols)) { return self::$undefined_symbols; } - $undefined = []; + if (SPCTarget::isStatic()) { // no reason to keep symbols when we can't load shared extensions! + return []; + } - $addSymbolsFromString = function (string $out, &$list) { + // keep all symbols defined in libphp.a + $defined = []; + $libphp = BUILD_LIB_PATH . '/libphp.a'; + if (!is_file($libphp)) { + throw new WrongUsageException('You must build libphp.a before calling this function.'); + } + $cmd = 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null'; + $out = shell_exec($cmd) ?: ''; + if ($out !== '') { foreach (preg_split('/\R/', trim($out)) as $line) { if ($line === '') { continue; @@ -52,40 +62,14 @@ abstract class UnixBuilderBase extends BuilderBase } $name = preg_replace('/@.*$/', '', $name); if ($name !== '' && $name !== false) { - $list[$name] = true; + $defined[$name] = true; } } - }; - - // collect undefined symbols from shared extensions - $files = glob(rtrim(BUILD_MODULES_PATH, '/') . DIRECTORY_SEPARATOR . '*.so') ?: []; - foreach ($files as $so) { - $cmd = 'nm -D --undefined-only -P ' . escapeshellarg($so) . ' 2>/dev/null'; - $out = shell_exec($cmd); - if ($out !== '') { - $addSymbolsFromString($out, $undefined); - } } + sort($defined, SORT_STRING); - // keep only symbols defined in libphp.a - $defined = []; - $libphp = BUILD_LIB_PATH . '/libphp.a'; - if (!is_file($libphp)) { - throw new WrongUsageException('You must build libphp.a statically before calling this function.'); - } - $cmd = 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null'; - $out = shell_exec($cmd) ?: ''; - if ($out !== '') { - $addSymbolsFromString($out, $defined); - } - // intersect: only undefined symbols that libphp.a actually defines - $keys = array_intersect_key($undefined, $defined); - - $list = array_keys($keys); - sort($list, SORT_STRING); - - self::$undefined_symbols = $list; - return $list; + self::$undefined_symbols = $defined; + return self::$undefined_symbols; } public function proveLibs(array $sorted_libraries): void @@ -209,7 +193,7 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } - $symbols = self::getUndefinedSymbols(); // returns unique, version-stripped names + $symbols = self::getDynamicExportSymbols(); // returns unique, version-stripped names // turn list into many --export-dynamic-symbol=... flags $dynamic_exports = implode( ' ', @@ -340,7 +324,7 @@ abstract class UnixBuilderBase extends BuilderBase $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $dynamic_exports = ''; if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { - $symbols = self::getUndefinedSymbols(); // returns unique, version-stripped names + $symbols = self::getDynamicExportSymbols(); // returns unique, version-stripped names // turn list into many --export-dynamic-symbol=... flags $dynamic_exports = ' ' . implode( ' ', From 20db00afcc740c11e25e6b23e724ae5e7cf8ba2f Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 10:26:46 +0700 Subject: [PATCH 04/16] no need to test all static targets, nothing changes for them --- src/globals/test-extensions.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 939a25ff..7d117dad 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,9 +13,9 @@ declare(strict_types=1); // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - '8.1', - '8.2', - '8.3', + // '8.1', + // '8.2', + // '8.3', '8.4', // '8.5', // 'git', @@ -28,9 +28,9 @@ $test_os = [ '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-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 ]; From 4b4ae9b014514470016ed2848ce1a38b4f890913 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 10:53:38 +0700 Subject: [PATCH 05/16] write to a --dynamic-list file see https://sourceware.org/binutils/docs-2.36/ld/Options.html --- src/SPC/builder/unix/UnixBuilderBase.php | 59 +++++++++++------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 5207ddfe..9f1ba866 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -31,24 +31,23 @@ abstract class UnixBuilderBase extends BuilderBase /** @var string LD flags */ public string $arch_ld_flags; - private static array $undefined_symbols = []; + private ?string $dynamic_export_list = null; - public static function getDynamicExportSymbols(): array + public function getDynamicExportSymbolsFile(): ?string { - if (count(self::$undefined_symbols)) { - return self::$undefined_symbols; + if ($this->dynamic_export_list) { + return $this->dynamic_export_list; + } + if (SPCTarget::isStatic()) { + return null; } - if (SPCTarget::isStatic()) { // no reason to keep symbols when we can't load shared extensions! - return []; - } - - // keep all symbols defined in libphp.a $defined = []; $libphp = BUILD_LIB_PATH . '/libphp.a'; if (!is_file($libphp)) { throw new WrongUsageException('You must build libphp.a before calling this function.'); } + $cmd = 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null'; $out = shell_exec($cmd) ?: ''; if ($out !== '') { @@ -61,15 +60,25 @@ abstract class UnixBuilderBase extends BuilderBase continue; } $name = preg_replace('/@.*$/', '', $name); - if ($name !== '' && $name !== false) { - $defined[$name] = true; + if ($name !== '' && $name !== false && !str_starts_with($name, $libphp)) { + $defined[] = $name; } } } - sort($defined, SORT_STRING); + $defined = array_unique($defined); + sort($defined); - self::$undefined_symbols = $defined; - return self::$undefined_symbols; + $exportList = BUILD_LIB_PATH . '/export-dynamic.list'; + $lines = []; + $lines[] = '{'; + foreach ($defined as $sym) { + $lines[] = " {$sym};"; + } + $lines[] = '};'; + file_put_contents($exportList, implode("\n", $lines) . "\n"); + + $this->dynamic_export_list = $exportList; + return $exportList; } public function proveLibs(array $sorted_libraries): void @@ -193,15 +202,8 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } - $symbols = self::getDynamicExportSymbols(); // returns unique, version-stripped names - // turn list into many --export-dynamic-symbol=... flags - $dynamic_exports = implode( - ' ', - array_map( - static fn (string $s) => '-Wl,--export-dynamic-symbol=' . escapeshellarg($s), - $symbols - ) - ); + $symbolList = $this->getDynamicExportSymbolsFile(); + $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens . ' ' . $dynamic_exports); if ($ret !== 0) { @@ -324,15 +326,8 @@ abstract class UnixBuilderBase extends BuilderBase $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $dynamic_exports = ''; if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { - $symbols = self::getDynamicExportSymbols(); // returns unique, version-stripped names - // turn list into many --export-dynamic-symbol=... flags - $dynamic_exports = ' ' . implode( - ' ', - array_map( - static fn (string $s) => '-Wl,--export-dynamic-symbol="' . $s . '"', - $symbols - ) - ); + $symbolList = $this->getDynamicExportSymbolsFile(); + $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; } $extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $muslTags = ''; From 2972ab31d7b9997892ec17db589fcf271154986d Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 12:15:56 +0700 Subject: [PATCH 06/16] don't add empty dynamic list x) --- src/SPC/builder/unix/UnixBuilderBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 9f1ba866..2d7b8760 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -203,7 +203,7 @@ abstract class UnixBuilderBase extends BuilderBase unlink($file); } $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; + $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list=' . $symbolList) : ''; } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens . ' ' . $dynamic_exports); if ($ret !== 0) { @@ -327,7 +327,7 @@ abstract class UnixBuilderBase extends BuilderBase $dynamic_exports = ''; if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; + $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list=' . $symbolList) : ''; } $extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $muslTags = ''; From 190be6c7b9a5f3d1a0efdde389a5375cb3205028 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 14:12:00 +0700 Subject: [PATCH 07/16] macos? --- src/SPC/builder/unix/UnixBuilderBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 2d7b8760..4633b3b0 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -203,7 +203,7 @@ abstract class UnixBuilderBase extends BuilderBase unlink($file); } $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list=' . $symbolList) : ''; + $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list' . (SPCTarget::getTargetOS() === 'Darwin' ? '-file' : '') . '=' . $symbolList) : ''; } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens . ' ' . $dynamic_exports); if ($ret !== 0) { @@ -327,7 +327,7 @@ abstract class UnixBuilderBase extends BuilderBase $dynamic_exports = ''; if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list=' . $symbolList) : ''; + $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list' . (SPCTarget::getTargetOS() === 'Darwin' ? '-file' : '') . '=' . $symbolList) : ''; } $extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $muslTags = ''; From 0da8dcf04adc9686d187403cfa0a117d9b013287 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 15:14:54 +0700 Subject: [PATCH 08/16] macos? 2 --- src/SPC/builder/unix/UnixBuilderBase.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 4633b3b0..d87d4376 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -70,11 +70,17 @@ abstract class UnixBuilderBase extends BuilderBase $exportList = BUILD_LIB_PATH . '/export-dynamic.list'; $lines = []; - $lines[] = '{'; - foreach ($defined as $sym) { - $lines[] = " {$sym};"; + if (SPCTarget::getTargetOS() === 'Linux') { + $lines[] = '{'; + foreach ($defined as $sym) { + $lines[] = " {$sym};"; + } + $lines[] = '};'; + } else { + foreach ($defined as $sym) { + $lines[] = "_{$sym}"; + } } - $lines[] = '};'; file_put_contents($exportList, implode("\n", $lines) . "\n"); $this->dynamic_export_list = $exportList; @@ -202,8 +208,14 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } - $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list' . (SPCTarget::getTargetOS() === 'Darwin' ? '-file' : '') . '=' . $symbolList) : ''; + + if ($symbolList = $this->getDynamicExportSymbolsFile()) { + if (SPCTarget::getTargetOS() === 'Linux') { + $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; + } else { + $dynamic_exports = ' -Wl,-exported_symbols_list,' . $symbolList; + } + } } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens . ' ' . $dynamic_exports); if ($ret !== 0) { From f6cc6af39c9894503df1ad7db972b0b01ff61104 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 16:36:43 +0700 Subject: [PATCH 09/16] macos? 3 --- src/SPC/builder/unix/UnixBuilderBase.php | 31 ++++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index d87d4376..013a19c0 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -15,6 +15,7 @@ use SPC\store\FileSystem; use SPC\store\pkg\GoXcaddy; use SPC\toolchain\GccNativeToolchain; use SPC\toolchain\ToolchainManager; +use SPC\toolchain\ZigToolchain; use SPC\util\DependencyUtil; use SPC\util\GlobalEnvManager; use SPC\util\SPCConfigUtil; @@ -33,7 +34,7 @@ abstract class UnixBuilderBase extends BuilderBase private ?string $dynamic_export_list = null; - public function getDynamicExportSymbolsFile(): ?string + public function getDynamicExportSymbolsArgument(): ?string { if ($this->dynamic_export_list) { return $this->dynamic_export_list; @@ -78,13 +79,21 @@ abstract class UnixBuilderBase extends BuilderBase $lines[] = '};'; } else { foreach ($defined as $sym) { - $lines[] = "_{$sym}"; + $lines[] = $sym; } } file_put_contents($exportList, implode("\n", $lines) . "\n"); - $this->dynamic_export_list = $exportList; - return $exportList; + $argument = "-Wl,--dynamic-list={$exportList}"; + if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { + $argument = "-Wl,--export-dynamic"; + } + if (SPCTarget::getTargetOS() !== 'Linux') { + $argument = "-Wl,-exported_symbols_list {$exportList}"; + } + + $this->dynamic_export_list = $argument; + return $argument; } public function proveLibs(array $sorted_libraries): void @@ -208,13 +217,8 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } - - if ($symbolList = $this->getDynamicExportSymbolsFile()) { - if (SPCTarget::getTargetOS() === 'Linux') { - $dynamic_exports = ' -Wl,--dynamic-list=' . $symbolList; - } else { - $dynamic_exports = ' -Wl,-exported_symbols_list,' . $symbolList; - } + if ($dynamicSymbolsArgument = $this->getDynamicExportSymbolsArgument()) { + $dynamic_exports = ' ' . $dynamicSymbolsArgument; } } [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens . ' ' . $dynamic_exports); @@ -338,8 +342,9 @@ abstract class UnixBuilderBase extends BuilderBase $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $dynamic_exports = ''; if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { - $symbolList = $this->getDynamicExportSymbolsFile(); - $dynamic_exports = $symbolList ? (' -Wl,--dynamic-list' . (SPCTarget::getTargetOS() === 'Darwin' ? '-file' : '') . '=' . $symbolList) : ''; + if ($dynamicSymbolsArgument = $this->getDynamicExportSymbolsArgument()) { + $dynamic_exports = ' ' . $dynamicSymbolsArgument; + } } $extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $muslTags = ''; From 66902d74c48043595d857b141248943596af8233 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 16:38:48 +0700 Subject: [PATCH 10/16] cs fix --- src/SPC/builder/unix/UnixBuilderBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 013a19c0..2afb1251 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -86,7 +86,7 @@ abstract class UnixBuilderBase extends BuilderBase $argument = "-Wl,--dynamic-list={$exportList}"; if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { - $argument = "-Wl,--export-dynamic"; + $argument = '-Wl,--export-dynamic'; // https://github.com/ziglang/zig/issues/24662 } if (SPCTarget::getTargetOS() !== 'Linux') { $argument = "-Wl,-exported_symbols_list {$exportList}"; From 75db184077fce34cd66c49e1803828c68eeaba2a Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 29 Aug 2025 17:50:47 +0700 Subject: [PATCH 11/16] fix macos command to print defined symbols? --- src/SPC/builder/unix/UnixBuilderBase.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 2afb1251..00dd4539 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -49,7 +49,9 @@ abstract class UnixBuilderBase extends BuilderBase throw new WrongUsageException('You must build libphp.a before calling this function.'); } - $cmd = 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null'; + $cmd = (SPCTarget::getTargetOS() === 'Linux') + ? 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null' + : 'nm -gUj ' . escapeshellarg($libphp) . ' 2>/dev/null'; $out = shell_exec($cmd) ?: ''; if ($out !== '') { foreach (preg_split('/\R/', trim($out)) as $line) { @@ -89,7 +91,7 @@ abstract class UnixBuilderBase extends BuilderBase $argument = '-Wl,--export-dynamic'; // https://github.com/ziglang/zig/issues/24662 } if (SPCTarget::getTargetOS() !== 'Linux') { - $argument = "-Wl,-exported_symbols_list {$exportList}"; + $argument = "-Wl,-exported_symbols_list,{$exportList}"; } $this->dynamic_export_list = $argument; From 1ba92ccc997b69faaa1893231ff77c3528e0b31e Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 30 Aug 2025 12:02:15 +0700 Subject: [PATCH 12/16] fix patch version stripping (.\d -> .\d+) --- src/SPC/builder/unix/UnixBuilderBase.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 00dd4539..ac9fb631 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -338,16 +338,15 @@ abstract class UnixBuilderBase extends BuilderBase ), true); $frankenPhpVersion = $releaseInfo['tag_name']; $libphpVersion = $this->getPHPVersion(); - if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { - $libphpVersion = preg_replace('/\.\d$/', '', $libphpVersion); - } - $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $dynamic_exports = ''; - if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') { + if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { + $libphpVersion = preg_replace('/\.\d+$/', '', $libphpVersion); + } else { if ($dynamicSymbolsArgument = $this->getDynamicExportSymbolsArgument()) { $dynamic_exports = ' ' . $dynamicSymbolsArgument; } } + $debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $muslTags = ''; $staticFlags = ''; From 3f74d585035d444107dfdaacdda80b43be163d99 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 30 Aug 2025 14:12:13 +0700 Subject: [PATCH 13/16] fix macos, for real this time --- src/SPC/builder/unix/UnixBuilderBase.php | 8 ++------ src/globals/test-extensions.php | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index ac9fb631..eaceabd4 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -49,13 +49,9 @@ abstract class UnixBuilderBase extends BuilderBase throw new WrongUsageException('You must build libphp.a before calling this function.'); } - $cmd = (SPCTarget::getTargetOS() === 'Linux') - ? 'nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null' - : 'nm -gUj ' . escapeshellarg($libphp) . ' 2>/dev/null'; - $out = shell_exec($cmd) ?: ''; - if ($out !== '') { + if ($out = shell_exec('nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null')) { foreach (preg_split('/\R/', trim($out)) as $line) { - if ($line === '') { + if ($line === '' || str_ends_with($line, '.o:')) { continue; } $name = strtok($line, " \t"); diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 7d117dad..764cfc7d 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -50,13 +50,13 @@ $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' => 'swoole,swoole-hook-mysql,swoole-hook-pgsql,swoole-hook-sqlite,swoole-hook-odbc,apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,event,exif,fileinfo,filter,ftp,gd,gmp,iconv,imagick,intl,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,swoole,sysvmsg,sysvsem,sysvshm,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib', + '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' => '', }; From d533a0591b7f9131120de52b66792fdbcfe75e5d Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 30 Aug 2025 19:31:22 +0700 Subject: [PATCH 14/16] skip line before preg_replacing --- src/SPC/builder/unix/UnixBuilderBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index eaceabd4..64fe32b3 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -51,7 +51,7 @@ abstract class UnixBuilderBase extends BuilderBase if ($out = shell_exec('nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null')) { foreach (preg_split('/\R/', trim($out)) as $line) { - if ($line === '' || str_ends_with($line, '.o:')) { + if ($line === '' || str_ends_with($line, '.o:') || str_ends_with($line, '.o]:')) { continue; } $name = strtok($line, " \t"); @@ -59,7 +59,7 @@ abstract class UnixBuilderBase extends BuilderBase continue; } $name = preg_replace('/@.*$/', '', $name); - if ($name !== '' && $name !== false && !str_starts_with($name, $libphp)) { + if ($name !== '' && $name !== false) { $defined[] = $name; } } From 465bd3ce8528d62c58887facb488e845b7b12902 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 31 Aug 2025 14:24:28 +0800 Subject: [PATCH 15/16] Use separated functions for exporting symbols --- src/SPC/builder/linux/LinuxBuilder.php | 2 + src/SPC/builder/macos/MacOSBuilder.php | 2 + .../builder/traits/UnixSystemUtilTrait.php | 87 +++++++++++++++++-- src/SPC/builder/unix/UnixBuilderBase.php | 74 ++-------------- 4 files changed, 92 insertions(+), 73 deletions(-) diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 90d5c7b9..3d8a30f7 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -318,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)) { diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index a67161c5..66e9a399 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -252,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(); } diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index a64c2d94..a4e18b62 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -4,15 +4,88 @@ declare(strict_types=1); namespace SPC\builder\traits; -/** - * Unix 系统的工具函数 Trait,适用于 Linux、macOS - */ +use SPC\exception\ExecutionException; +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)) { + return null; + } + // 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 { @@ -31,6 +104,8 @@ trait UnixSystemUtilTrait } /** + * Make environment variable string for shell command. + * * @param array $vars Variables, like: ["CFLAGS" => "-Ixxx"] * @return string like: CFLAGS="-Ixxx" */ diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 64fe32b3..9e96c7a2 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -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; @@ -15,7 +16,6 @@ use SPC\store\FileSystem; use SPC\store\pkg\GoXcaddy; use SPC\toolchain\GccNativeToolchain; use SPC\toolchain\ToolchainManager; -use SPC\toolchain\ZigToolchain; use SPC\util\DependencyUtil; use SPC\util\GlobalEnvManager; use SPC\util\SPCConfigUtil; @@ -32,68 +32,6 @@ abstract class UnixBuilderBase extends BuilderBase /** @var string LD flags */ public string $arch_ld_flags; - private ?string $dynamic_export_list = null; - - public function getDynamicExportSymbolsArgument(): ?string - { - if ($this->dynamic_export_list) { - return $this->dynamic_export_list; - } - if (SPCTarget::isStatic()) { - return null; - } - - $defined = []; - $libphp = BUILD_LIB_PATH . '/libphp.a'; - if (!is_file($libphp)) { - throw new WrongUsageException('You must build libphp.a before calling this function.'); - } - - if ($out = shell_exec('nm -g --defined-only -P ' . escapeshellarg($libphp) . ' 2>/dev/null')) { - foreach (preg_split('/\R/', trim($out)) as $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); - - $exportList = BUILD_LIB_PATH . '/export-dynamic.list'; - $lines = []; - if (SPCTarget::getTargetOS() === 'Linux') { - $lines[] = '{'; - foreach ($defined as $sym) { - $lines[] = " {$sym};"; - } - $lines[] = '};'; - } else { - foreach ($defined as $sym) { - $lines[] = $sym; - } - } - file_put_contents($exportList, implode("\n", $lines) . "\n"); - - $argument = "-Wl,--dynamic-list={$exportList}"; - if (ToolchainManager::getToolchainClass() === ZigToolchain::class) { - $argument = '-Wl,--export-dynamic'; // https://github.com/ziglang/zig/issues/24662 - } - if (SPCTarget::getTargetOS() !== 'Linux') { - $argument = "-Wl,-exported_symbols_list,{$exportList}"; - } - - $this->dynamic_export_list = $argument; - return $argument; - } - public function proveLibs(array $sorted_libraries): void { // search all supported libs @@ -215,11 +153,13 @@ abstract class UnixBuilderBase extends BuilderBase foreach (glob(BUILD_LIB_PATH . "/libphp*.{$suffix}") as $file) { unlink($file); } - if ($dynamicSymbolsArgument = $this->getDynamicExportSymbolsArgument()) { - $dynamic_exports = ' ' . $dynamicSymbolsArgument; + // 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 . ' ' . $dynamic_exports); + $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), @@ -338,7 +278,7 @@ abstract class UnixBuilderBase extends BuilderBase if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { $libphpVersion = preg_replace('/\.\d+$/', '', $libphpVersion); } else { - if ($dynamicSymbolsArgument = $this->getDynamicExportSymbolsArgument()) { + if ($dynamicSymbolsArgument = LinuxSystemUtil::getDynamicExportedSymbols(BUILD_LIB_PATH . '/libphp.a')) { $dynamic_exports = ' ' . $dynamicSymbolsArgument; } } From 08a68796bfa9d54ab2ac079ea718d781fd3de15c Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 31 Aug 2025 18:05:09 +0800 Subject: [PATCH 16/16] Call export in dynamic symbol getter --- src/SPC/builder/traits/UnixSystemUtilTrait.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index a4e18b62..b1ef9db4 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace SPC\builder\traits; use SPC\exception\ExecutionException; +use SPC\exception\SPCInternalException; use SPC\exception\WrongUsageException; use SPC\toolchain\ToolchainManager; use SPC\toolchain\ZigToolchain; @@ -66,7 +67,10 @@ trait UnixSystemUtilTrait { $symbol_file = "{$lib_file}.dynsym"; if (!is_file($symbol_file)) { - return null; + 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) {