Use spc-config instead of SPC_EXTRA_LIBS, trigger extension test

This commit is contained in:
crazywhalecc 2025-07-22 19:59:44 +08:00
parent 95a94da66f
commit 7e977414a7
No known key found for this signature in database
GPG Key ID: 1F4BDD59391F2680
10 changed files with 85 additions and 89 deletions

View File

@ -89,7 +89,7 @@ LD=${SPC_LINUX_DEFAULT_LD}
SPC_DEFAULT_C_FLAGS="-fPIC -Os"
SPC_DEFAULT_CXX_FLAGS="-fPIC -Os"
; extra libs for building php executable, used in `make` command for building php (this value may changed by extension build process, space separated)
SPC_EXTRA_LIBS=
SPC_EXTRA_LIBS=""
; upx executable path
UPX_EXEC=${PKG_ROOT_PATH}/bin/upx
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
@ -119,7 +119,7 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE
; EXTRA_LIBS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm"
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS="-L${BUILD_LIB_PATH}"
; EXTRA_LDFLAGS_PROGRAM for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
@ -134,7 +134,7 @@ CXX=clang++
SPC_DEFAULT_C_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"
SPC_DEFAULT_CXX_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os"
; extra libs for building php executable, used in `make` command for building php (this value may changed by extension build process, space separated)
SPC_EXTRA_LIBS=
SPC_EXTRA_LIBS=""
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
SPC_MICRO_PATCHES=cli_checks,macos_iconv

View File

@ -737,8 +737,8 @@
"openssl": {
"source": "openssl",
"static-libs-unix": [
"libssl.a",
"libcrypto.a"
"libcrypto.a",
"libssl.a"
],
"static-libs-windows": [
"libssl.lib",

View File

@ -63,18 +63,6 @@ class BSDBuilder extends UnixBuilderBase
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
// ---------- Update extra-libs ----------
$extra_libs = $this->getOption('extra-libs', '');
// add libc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lc++ ' : '');
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
logger()->info('bloat linking');
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles())));
}
$this->setOption('extra-libs', $extra_libs);
$this->emitPatchPoint('before-php-buildconf');
SourcePatcher::patchBeforeBuildconf($this);

View File

@ -11,6 +11,7 @@ use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
class LinuxBuilder extends UnixBuilderBase
{
@ -56,17 +57,6 @@ class LinuxBuilder extends UnixBuilderBase
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
// ---------- Update extra-libs ----------
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// bloat means force-load all static libraries, even if they are not used
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", array_filter($this->getAllStaticLibFiles())));
}
// add libstdc++, some extensions or libraries need it
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : '');
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
$cflags = $this->arch_c_flags;
f_putenv('CFLAGS=' . $cflags);
@ -308,9 +298,10 @@ class LinuxBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array
{
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'),
'EXTRA_LIBS' => $config['libs'],
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'),
];

View File

@ -12,6 +12,7 @@ use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
class MacOSBuilder extends UnixBuilderBase
{
@ -88,21 +89,6 @@ class MacOSBuilder extends UnixBuilderBase
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
// ---------- Update extra-libs ----------
// add macOS frameworks
$extra_libs .= (empty($extra_libs) ? '' : ' ') . $this->getFrameworks(true);
// add libc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lc++ ' : '');
// bloat means force-load all static libraries, even if they are not used
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
logger()->info('bloat linking');
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles())));
}
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
$this->emitPatchPoint('before-php-buildconf');
SourcePatcher::patchBeforeBuildconf($this);
@ -291,9 +277,10 @@ class MacOSBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array
{
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'),
'EXTRA_LIBS' => $config['libs'],
];
}
}

View File

@ -18,7 +18,6 @@ abstract class BuildCommand extends BaseCommand
}
$this->addOption('with-clean', null, null, 'fresh build, remove `source` and `buildroot` dir before build');
$this->addOption('bloat', null, null, 'add all libraries into binary');
$this->addOption('rebuild', 'r', null, 'Delete old build and rebuild');
$this->addOption('enable-zts', null, null, 'enable ZTS support');
}

View File

@ -23,6 +23,8 @@ class SPCConfigCommand extends BaseCommand
$this->addOption('with-suggested-exts', 'E', null, 'Build with suggested extensions for selected exts');
$this->addOption('includes', null, null, 'Add additional include path');
$this->addOption('libs', null, null, 'Add additional libs path');
$this->addOption('libs-only-deps', null, null, 'Output dependent libraries with -l prefix');
$this->addOption('absolute-libs', null, null, 'Output absolute paths for libraries');
$this->addOption('no-php', null, null, 'Do not link to PHP library');
}
@ -38,16 +40,19 @@ class SPCConfigCommand extends BaseCommand
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
$util = new SPCConfigUtil(link_php: !$this->getOption('no-php'));
$util = new SPCConfigUtil(options: [
'no_php' => $this->getOption('no-php'),
'libs_only_deps' => $this->getOption('libs-only-deps'),
'absolute_libs' => $this->getOption('absolute-libs'),
]);
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
if ($this->getOption('includes')) {
$this->output->writeln($config['cflags']);
} elseif ($this->getOption('libs')) {
$this->output->writeln("{$config['ldflags']} {$config['libs']}");
} else {
$this->output->writeln("{$config['cflags']} {$config['ldflags']} {$config['libs']}");
}
$this->output->writeln(match (true) {
$this->getOption('includes') => $config['cflags'],
$this->getOption('libs-only-deps') => $config['libs'],
$this->getOption('libs') => "{$config['ldflags']} {$config['libs']}",
default => "{$config['cflags']} {$config['ldflags']} {$config['libs']}",
});
return 0;
}

View File

@ -32,7 +32,7 @@ class PkgConfigUtil
* @return array Unique libs array, e.g. [-lz, -lxml, ...]
* @throws RuntimeException
*/
public static function getLibsArray(string $pkg_config_str): array
public static function getLibsArray(string $pkg_config_str, bool $force_short_name = true): array
{
// Use this instead of shell() to avoid unnecessary outputs
$result = self::execWithResult("pkg-config --static --libs-only-l {$pkg_config_str}");
@ -44,7 +44,7 @@ class PkgConfigUtil
$exp = explode(' ', trim($result));
foreach ($exp as $item) {
// if item ends with .a, convert it to -lxxx
if (str_ends_with($item, '.a') && str_starts_with($item, 'lib')) {
if (str_ends_with($item, '.a') && str_starts_with($item, 'lib') && $force_short_name) {
$name = pathinfo($item, PATHINFO_BASENAME);
$name = substr($name, 3, -2); // remove 'lib' prefix and '.a' suffix
$libs[] = "-l{$name}";

View File

@ -6,7 +6,6 @@ namespace SPC\util;
use SPC\builder\BuilderBase;
use SPC\builder\BuilderProvider;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
@ -17,11 +16,27 @@ class SPCConfigUtil
{
private ?BuilderBase $builder = null;
public function __construct(?BuilderBase $builder = null, private bool $link_php = true)
private bool $no_php;
private bool $libs_only_deps;
private bool $absolute_libs;
/**
* @param array{
* no_php?: bool,
* libs_only_deps?: bool,
* absolute_libs?: bool
* } $options Options pass to spc-config
*/
public function __construct(?BuilderBase $builder = null, array $options = [])
{
if ($builder !== null) {
$this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
}
$this->no_php = $options['no_php'] ?? false;
$this->libs_only_deps = $options['libs_only_deps'] ?? false;
$this->absolute_libs = $options['absolute_libs'] ?? false;
}
/**
@ -54,24 +69,35 @@ class SPCConfigUtil
}
ob_get_clean();
$ldflags = $this->getLdflagsString();
$libs = $this->getLibsString($libraries);
if (SPCTarget::getTargetOS() === 'Darwin') {
$libs .= " {$this->getFrameworksString($extensions)}";
}
$cflags = $this->getIncludesString($libraries);
$libs = $this->getLibsString($libraries, !$this->absolute_libs);
$libs = trim("-lc {$libs}");
// embed
if ($this->link_php) {
$libs = "-lphp {$libs}";
}
// additional OS-specific libraries (e.g. macOS -lresolv)
$extra_env = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS');
if (is_string($extra_env)) {
$libs .= ' ' . trim($extra_env, '"');
}
// c++
if ($this->builder->hasCpp()) {
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
$extra_env = getenv('SPC_EXTRA_LIBS');
if (is_string($extra_env)) {
$libs .= " {$extra_env}";
}
// extension frameworks
if (SPCTarget::getTargetOS() === 'Darwin') {
$libs .= " {$this->getFrameworksString($extensions)}";
}
if ($this->libs_only_deps) {
return [
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
'libs' => trim(getenv('LIBS') . ' ' . $libs),
];
}
$libs = trim("-lc {$libs}");
// embed
if (!$this->no_php) {
$libs = "-lphp {$libs}";
}
// mimalloc must come first
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
@ -90,7 +116,7 @@ class SPCConfigUtil
$includes = ["-I{$base}"];
// link with libphp
if ($this->link_php) {
if (!$this->no_php) {
$includes = [
...$includes,
"-I{$base}/php",
@ -118,9 +144,9 @@ class SPCConfigUtil
return '-L' . BUILD_LIB_PATH;
}
private function getLibsString(array $libraries): string
private function getLibsString(array $libraries, bool $use_short_libs = true): string
{
$short_name = [];
$lib_names = [];
$frameworks = [];
foreach ($libraries as $library) {
@ -131,7 +157,7 @@ class SPCConfigUtil
if (!file_exists(BUILD_LIB_PATH . "/{$lib}")) {
throw new WrongUsageException("Library file '{$lib}' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "'. Please build it first.");
}
$short_name[] = $this->getShortLibName($lib);
$lib_names[] = $use_short_libs ? $this->getShortLibName($lib) : (BUILD_LIB_PATH . "/{$lib}");
}
// add frameworks for macOS
if (SPCTarget::getTargetOS() === 'Darwin') {
@ -146,29 +172,29 @@ class SPCConfigUtil
}
$pkg_configs = implode(' ', $pkg_configs);
if ($pkg_configs !== '') {
$pc_libs = PkgConfigUtil::getLibsArray($pkg_configs);
$short_name = [...$short_name, ...$pc_libs];
$pc_libs = array_reverse(PkgConfigUtil::getLibsArray($pkg_configs, $use_short_libs));
$lib_names = [...$lib_names, ...$pc_libs];
}
}
// post-process
$short_name = array_unique(array_reverse($short_name));
$frameworks = array_unique(array_reverse($frameworks));
$lib_names = array_unique(array_reverse($lib_names));
$frameworks = array_unique($frameworks);
// process frameworks to short_name
if (SPCTarget::getTargetOS() === 'Darwin') {
foreach ($frameworks as $fw) {
$ks = '-framework ' . $fw;
if (!in_array($ks, $short_name)) {
$short_name[] = $ks;
if (!in_array($ks, $lib_names)) {
$lib_names[] = $ks;
}
}
}
if (in_array('imap', $libraries) && SPCTarget::getLibc() === 'glibc') {
$short_name[] = '-lcrypt';
$lib_names[] = '-lcrypt';
}
return implode(' ', $short_name);
return implode(' ', $lib_names);
}
private function getShortLibName(string $lib): string

View File

@ -13,7 +13,7 @@ declare(strict_types=1);
// test php version (8.1 ~ 8.4 available, multiple for matrix)
$test_php_version = [
'8.1',
// '8.1',
// '8.2',
// '8.3',
'8.4',
@ -24,16 +24,16 @@ $test_os = [
'macos-13', // bin/spc for x86_64
// 'macos-14', // bin/spc for arm64
'macos-15', // bin/spc for arm64
// 'ubuntu-latest', // bin/spc-alpine-docker for x86_64
'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-arm', // bin/spc-gnu-docker for arm64
'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
// 'windows-latest', // .\bin\spc.ps1
];
// whether enable thread safe
$zts = true;
$zts = false;
$no_strip = false;
@ -54,7 +54,7 @@ $extensions = match (PHP_OS_FAMILY) {
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
$shared_extensions = match (PHP_OS_FAMILY) {
'Linux' => 'imagick',
'Linux' => '',
'Darwin' => '',
'Windows' => '',
};
@ -72,7 +72,7 @@ $with_libs = match (PHP_OS_FAMILY) {
// You can use `common`, `bulk`, `minimal` or `none`.
// note: combination is only available for *nix platform. Windows must use `none` combination
$base_combination = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'minimal',
'Linux', 'Darwin' => 'bulk',
'Windows' => 'none',
};