Compare commits

...

19 Commits

Author SHA1 Message Date
Marc
8dfe722e14 Merge branch 'main' into fix/grpc-shared 2025-09-19 15:31:25 +02:00
henderkes
dcbfe1e0ab e-dant/watcher is a c++ library too 2025-09-19 15:29:49 +02:00
Marc
e11946fd10 also install g++ with doctor (not preinstalled on ubuntu, not include… (#904) 2025-09-19 15:22:17 +02:00
henderkes
44399cd185 remove -Wl,--as-needed for imagemagick build 2025-09-19 09:21:17 +02:00
henderkes
927d7f55ba make sure -ldl is not taken as needed, problem on EL8 2025-09-18 22:47:01 +02:00
henderkes
e323d7b155 revert to private 2025-09-18 21:41:35 +02:00
henderkes
d0b253c346 not required 2025-09-18 21:36:38 +02:00
henderkes
81430e6853 also use libstdc++.a for grpc? 2025-09-18 21:29:46 +02:00
henderkes
83696e92b7 remove whitespace 2025-09-18 20:12:41 +02:00
henderkes
b0538c09bf deduplicate those to make it more readable 2025-09-18 20:09:17 +02:00
henderkes
40f89d1dca is shared_libadd enough? 2025-09-18 19:44:48 +02:00
henderkes
fa2e041cc9 test shared grpc, imagick 2025-09-18 19:01:10 +02:00
Marc
3c614663a3 Merge branch 'main' into fix/grpc-shared 2025-09-18 18:22:42 +02:00
henderkes
b5c7185374 add comment for new method 2025-09-18 18:20:26 +02:00
henderkes
d0a9a3a594 fix return of array 2025-09-18 18:17:48 +02:00
henderkes
2e6329bb86 add cpp-library for imagemagick too 2025-09-18 18:16:42 +02:00
henderkes
d3ba04fc5b fix grpc shared build (ignores CXXFLAGS, needs CPPFLAGS) 2025-09-18 18:16:41 +02:00
Marc
7a78ea0185 Merge branch 'main' into fix/g++ 2025-09-18 17:35:44 +02:00
henderkes
36b04f9eba also install g++ with doctor (not preinstalled on ubuntu, not included in gcc package) 2025-09-18 17:24:08 +02:00
8 changed files with 79 additions and 57 deletions

View File

@@ -202,6 +202,7 @@
"openssl", "openssl",
"libcares" "libcares"
], ],
"cpp-library": true,
"provide-pre-built": true, "provide-pre-built": true,
"frameworks": [ "frameworks": [
"CoreFoundation" "CoreFoundation"
@@ -230,6 +231,7 @@
}, },
"imagemagick": { "imagemagick": {
"source": "imagemagick", "source": "imagemagick",
"cpp-library": true,
"pkg-configs": [ "pkg-configs": [
"Magick++-7.Q16HDRI", "Magick++-7.Q16HDRI",
"MagickCore-7.Q16HDRI", "MagickCore-7.Q16HDRI",
@@ -867,6 +869,7 @@
}, },
"watcher": { "watcher": {
"source": "watcher", "source": "watcher",
"cpp-library": true,
"static-libs-unix": [ "static-libs-unix": [
"libwatcher-c.a" "libwatcher-c.a"
], ],

View File

@@ -5,16 +5,11 @@ declare(strict_types=1);
namespace SPC\builder; namespace SPC\builder;
use SPC\exception\EnvironmentException; use SPC\exception\EnvironmentException;
use SPC\exception\FileSystemException;
use SPC\exception\SPCException; use SPC\exception\SPCException;
use SPC\exception\ValidationException; use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\toolchain\ClangNativeToolchain;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\SPCConfigUtil; use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget; use SPC\util\SPCTarget;
@@ -226,12 +221,24 @@ class Extension
public function patchBeforeSharedMake(): bool public function patchBeforeSharedMake(): bool
{ {
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs())); $config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
[$staticLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
FileSystem::replaceFileRegex( $lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
$this->source_dir . '/Makefile', $lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
'$1 ' . trim($staticLibs) $makefileContent = file_get_contents($this->source_dir . '/Makefile');
); if (preg_match('/^(.*_SHARED_LIBADD\s*=\s*)(.*)$/m', $makefileContent, $matches)) {
$prefix = $matches[1];
$currentLibs = trim($matches[2]);
$newLibs = trim("{$currentLibs} {$staticLibs} {$lstdcpp}");
$deduplicatedLibs = deduplicate_flags($newLibs);
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
$prefix . $deduplicatedLibs
);
}
if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) { if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) {
FileSystem::replaceFileRegex( FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile', $this->source_dir . '/Makefile',
@@ -405,42 +412,7 @@ class Extension
*/ */
public function buildUnixShared(): void public function buildUnixShared(): void
{ {
$config = (new SPCConfigUtil($this->builder))->config( $env = $this->getSharedExtensionEnv();
[$this->getName()],
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
$this->builder->getOption('with-suggested-exts'),
$this->builder->getOption('with-suggested-libs'),
);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
$env = [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
if (str_contains($env['LIBS'], '-lstdc++') && SPCTarget::getTargetOS() === 'Linux') {
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$env['SPC_COMPILER_EXTRA'] = '-lstdc++';
} elseif (ToolchainManager::getToolchainClass() === GccNativeToolchain::class || ToolchainManager::getToolchainClass() === ClangNativeToolchain::class) {
try {
$content = FileSystem::readFile($this->source_dir . '/config.m4');
if ($content && !str_contains($content, 'PHP_ADD_LIBRARY(stdc++')) {
$pattern = '/(PHP_NEW_EXTENSION\(' . $this->name . ',.*\))/m';
$replacement = "$1\nPHP_ADD_LIBRARY(stdc++, 1, " . strtoupper($this->name) . '_SHARED_LIBADD)';
FileSystem::replaceFileRegex(
$this->source_dir . '/config.m4',
$pattern,
$replacement
);
}
} catch (FileSystemException) {
}
}
}
if ($this->patchBeforeSharedPhpize()) { if ($this->patchBeforeSharedPhpize()) {
logger()->info("Extension [{$this->getName()}] patched before shared phpize"); logger()->info("Extension [{$this->getName()}] patched before shared phpize");
} }
@@ -512,6 +484,30 @@ class Extension
return $this->build_static; return $this->build_static;
} }
/**
* Returns the environment variables a shared extension needs to be built.
* CFLAGS, CXXFLAGS, LDFLAGS and so on.
*/
protected function getSharedExtensionEnv(): array
{
$config = (new SPCConfigUtil($this->builder))->config(
[$this->getName()],
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
$this->builder->getOption('with-suggested-exts'),
$this->builder->getOption('with-suggested-libs'),
);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
return [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
}
protected function addLibraryDependency(string $name, bool $optional = false): void protected function addLibraryDependency(string $name, bool $optional = false): void
{ {
$depLib = $this->builder->getLib($name); $depLib = $this->builder->getLib($name);
@@ -584,12 +580,12 @@ class Extension
$added = 0; $added = 0;
foreach ($ret as $depName => $dep) { foreach ($ret as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) { foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!in_array($depdepName, array_keys($deps), true)) { if (!array_key_exists($depdepName, $deps)) {
$deps[$depdepName] = $depdep; $deps[$depdepName] = $depdep;
++$added; ++$added;
} }
} }
if (!in_array($depName, array_keys($deps), true)) { if (!array_key_exists($depName, $deps)) {
$deps[$depName] = $dep; $deps[$depName] = $dep;
} }
} }

View File

@@ -56,4 +56,11 @@ class grpc extends Extension
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes'); GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
return true; return true;
} }
protected function getSharedExtensionEnv(): array
{
$env = parent::getSharedExtensionEnv();
$env['CPPFLAGS'] = $env['CXXFLAGS'] . ' -Wno-attributes';
return $env;
}
} }

View File

@@ -291,11 +291,11 @@ abstract class UnixBuilderBase extends BuilderBase
} }
} }
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : ''; $debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
$extLdFlags = "-extldflags '-pie{$dynamic_exports}'"; $extLdFlags = "-extldflags '-pie{$dynamic_exports} {$this->arch_ld_flags}'";
$muslTags = ''; $muslTags = '';
$staticFlags = ''; $staticFlags = '';
if (SPCTarget::isStatic()) { if (SPCTarget::isStatic()) {
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports}'"; $extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports} {$this->arch_ld_flags}'";
$muslTags = 'static_build,'; $muslTags = 'static_build,';
$staticFlags = '-static-pie'; $staticFlags = '-static-pie';
} }
@@ -303,7 +303,6 @@ abstract class UnixBuilderBase extends BuilderBase
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list); $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'); $cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
$libs = $config['libs']; $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. // 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') || if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||
str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) && str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) &&

View File

@@ -12,6 +12,11 @@ trait imagemagick
{ {
protected function build(): void protected function build(): void
{ {
$original_ldflags = $this->builder->arch_ld_flags;
if (str_contains($this->builder->arch_ld_flags, '-Wl,--as-needed')) {
$this->builder->arch_ld_flags = str_replace('-Wl,--as-needed', '', $original_ldflags);
}
$ac = UnixAutoconfExecutor::create($this) $ac = UnixAutoconfExecutor::create($this)
->optionalLib('libzip', ...ac_with_args('zip')) ->optionalLib('libzip', ...ac_with_args('zip'))
->optionalLib('libjpeg', ...ac_with_args('jpeg')) ->optionalLib('libjpeg', ...ac_with_args('jpeg'))
@@ -32,7 +37,7 @@ trait imagemagick
); );
// special: linux-static target needs `-static` // special: linux-static target needs `-static`
$ldflags = SPCTarget::isStatic() ? ('-static -ldl') : '-ldl'; $ldflags = SPCTarget::isStatic() ? '-static -ldl' : '-ldl';
// special: macOS needs -iconv // special: macOS needs -iconv
$libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : ''; $libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
@@ -45,6 +50,8 @@ trait imagemagick
$ac->configure()->make(); $ac->configure()->make();
$this->builder->arch_ld_flags = $original_ldflags;
$filelist = [ $filelist = [
'ImageMagick.pc', 'ImageMagick.pc',
'ImageMagick-7.Q16HDRI.pc', 'ImageMagick-7.Q16HDRI.pc',

View File

@@ -28,7 +28,7 @@ class LinuxToolCheckList
public const TOOLS_DEBIAN = [ public const TOOLS_DEBIAN = [
'make', 'bison', 're2c', 'flex', 'make', 'bison', 're2c', 'flex',
'git', 'autoconf', 'automake', 'autopoint', 'git', 'autoconf', 'automake', 'autopoint',
'tar', 'unzip', 'gzip', 'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch', 'bzip2', 'cmake', 'patch',
'xz', 'libtoolize', 'which', 'xz', 'libtoolize', 'which',
'patchelf', 'patchelf',
@@ -37,7 +37,7 @@ class LinuxToolCheckList
public const TOOLS_RHEL = [ public const TOOLS_RHEL = [
'perl', 'make', 'bison', 're2c', 'flex', 'perl', 'make', 'bison', 're2c', 'flex',
'git', 'autoconf', 'automake', 'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip', 'gcc', 'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch', 'which', 'bzip2', 'cmake', 'patch', 'which',
'xz', 'libtool', 'gettext-devel', 'xz', 'libtool', 'gettext-devel',
'patchelf', 'patchelf',

View File

@@ -245,6 +245,16 @@ function clean_spaces(string $string): string
return trim(preg_replace('/\s+/', ' ', $string)); return trim(preg_replace('/\s+/', ' ', $string));
} }
function deduplicate_flags(string $flags): string
{
$tokens = preg_split('/\s+/', trim($flags));
// Reverse, unique, reverse back - keeps last occurrence of duplicates
$deduplicated = array_reverse(array_unique(array_reverse($tokens)));
return implode(' ', $deduplicated);
}
/** /**
* Register a callback function to handle keyboard interrupts (Ctrl+C). * Register a callback function to handle keyboard interrupts (Ctrl+C).
* *

View File

@@ -26,7 +26,7 @@ $test_os = [
'macos-13', // bin/spc for x86_64 'macos-13', // bin/spc for x86_64
// 'macos-14', // bin/spc for arm64 // '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-latest', // bin/spc-alpine-docker for x86_64
'ubuntu-22.04', // bin/spc-gnu-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-22.04-arm', // bin/spc-gnu-docker for arm64
@@ -56,7 +56,7 @@ $extensions = match (PHP_OS_FAMILY) {
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
$shared_extensions = match (PHP_OS_FAMILY) { $shared_extensions = match (PHP_OS_FAMILY) {
'Linux' => 'zip', 'Linux' => 'grpc,imagick',
'Darwin' => '', 'Darwin' => '',
'Windows' => '', 'Windows' => '',
}; };