mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-02 14:25:41 +08:00
toolchain fixes forward port from v2-pgo
This commit is contained in:
@@ -100,6 +100,7 @@ SPC_TARGET=${GNU_ARCH}-linux-musl
|
||||
CC=${SPC_DEFAULT_CC}
|
||||
CXX=${SPC_DEFAULT_CXX}
|
||||
AR=${SPC_DEFAULT_AR}
|
||||
RANLIB=${SPC_DEFAULT_RANLIB}
|
||||
LD=${SPC_DEFAULT_LD}
|
||||
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
|
||||
SPC_DEFAULT_CFLAGS="-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections"
|
||||
@@ -125,6 +126,8 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS="-g -fstack-protector-strong -fno-ident -fPIE -fvisibility=hidden -fvisibility-inlines-hidden ${SPC_DEFAULT_CXXFLAGS}"
|
||||
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
|
||||
; EXTRA_LDFLAGS_PROGRAM for `make` php; appended only to SAPI executable links (cli/fpm/cgi/micro/embed). Used by PGO to inject -fprofile-use= without polluting libphp.{a,so}.
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM=""
|
||||
|
||||
; optional, path to openssl conf. This affects where openssl will look for the default CA.
|
||||
; default on Debian/Alpine: /etc/ssl, default on RHEL: /etc/pki/tls
|
||||
@@ -140,6 +143,7 @@ SPC_USE_LLVM=system
|
||||
CC=${SPC_DEFAULT_CC}
|
||||
CXX=${SPC_DEFAULT_CXX}
|
||||
AR=${SPC_DEFAULT_AR}
|
||||
RANLIB=${SPC_DEFAULT_RANLIB}
|
||||
LD=${SPC_DEFAULT_LD}
|
||||
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
|
||||
SPC_DEFAULT_CFLAGS="--target=${MAC_ARCH}-apple-darwin -O3 -fno-plt -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections"
|
||||
@@ -163,5 +167,7 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -fvis
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS="-g -fstack-protector-strong -fno-ident -fpie -fvisibility=hidden -fvisibility-inlines-hidden -Werror=unknown-warning-option ${SPC_DEFAULT_CXXFLAGS}"
|
||||
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.dylib
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
|
||||
; EXTRA_LDFLAGS_PROGRAM for `make` php; appended only to SAPI executable links (cli/fpm/cgi/micro/embed). Used by PGO to inject -fprofile-use= without polluting libphp.{a,dylib}.
|
||||
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM=""
|
||||
; minimum compatible macOS version (LLVM vars, availability not guaranteed)
|
||||
MACOSX_DEPLOYMENT_TARGET=12.0
|
||||
|
||||
@@ -109,7 +109,7 @@ class go_xcaddy
|
||||
'GOROOT' => "{$target_path}",
|
||||
'GOBIN' => "{$target_path}/bin",
|
||||
'GOPATH' => "{$target_path}/go",
|
||||
])->exec('CC=cc go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest');
|
||||
])->exec('CGO_ENABLED=0 go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest');
|
||||
GlobalEnvManager::addPathIfNotExists("{$target_path}/bin");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use StaticPHP\Attribute\Artifact\CustomBinary;
|
||||
use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate;
|
||||
use StaticPHP\Exception\DownloaderException;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
class zig
|
||||
{
|
||||
@@ -131,5 +132,151 @@ class zig
|
||||
chmod("{$target_path}/zig-ld.lld", 0755);
|
||||
chmod("{$target_path}/zig-ranlib", 0755);
|
||||
chmod("{$target_path}/zig-objcopy", 0755);
|
||||
|
||||
// Build the clang runtime bits zig 0.15+ doesn't ship: profile runtime
|
||||
// (so -fprofile-generate actually emits .profraw) and crtbegin/crtend
|
||||
// (so shared libs get __dso_handle and the __cxa_finalize atexit hook).
|
||||
// These get auto-linked by the zig-cc wrapper when the right flags fly past.
|
||||
$this->buildClangRuntimeBits($target_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the bundled clang version and build the missing clang runtime
|
||||
* archives into `<zig>/lib/`. Compiles from a 2 MB compiler-rt-<llvm>.src
|
||||
* tarball — far cheaper than fetching the 2 GB prebuilt LLVM tarball.
|
||||
*/
|
||||
private function buildClangRuntimeBits(string $zig_bin_dir): void
|
||||
{
|
||||
if (PHP_OS_FAMILY !== 'Linux') {
|
||||
return;
|
||||
}
|
||||
$libDir = "{$zig_bin_dir}/lib";
|
||||
$profileLib = "{$libDir}/libclang_rt.profile.a";
|
||||
$crtBegin = "{$libDir}/clang_rt.crtbegin.o";
|
||||
$crtEnd = "{$libDir}/clang_rt.crtend.o";
|
||||
if (file_exists($profileLib) && file_exists($crtBegin) && file_exists($crtEnd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$zig = "{$zig_bin_dir}/zig";
|
||||
$verLine = trim((string) shell_exec(escapeshellarg($zig) . ' cc --version 2>/dev/null'));
|
||||
if (!preg_match('/clang version (\d+\.\d+\.\d+)/', $verLine, $m)) {
|
||||
logger()->warning('[zig] could not detect bundled clang version; skipping runtime bit build (PGO + shared libs without __dso_handle will fail to link)');
|
||||
return;
|
||||
}
|
||||
$llvmVersion = $m[1];
|
||||
logger()->info("Building clang runtime bits for LLVM {$llvmVersion} (zig's bundled clang)");
|
||||
|
||||
$srcRoot = $this->fetchCompilerRtSource($llvmVersion);
|
||||
if ($srcRoot === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
f_mkdir($libDir, recursive: true);
|
||||
if (!file_exists($profileLib)) {
|
||||
$this->buildProfileRuntime($zig, $srcRoot, $profileLib);
|
||||
}
|
||||
if (!file_exists($crtBegin) || !file_exists($crtEnd)) {
|
||||
$this->buildCrtObjects($zig, $srcRoot, $crtBegin, $crtEnd);
|
||||
}
|
||||
FileSystem::removeDir($srcRoot);
|
||||
}
|
||||
|
||||
private function fetchCompilerRtSource(string $llvmVersion): ?string
|
||||
{
|
||||
$tarball = "compiler-rt-{$llvmVersion}.src.tar.xz";
|
||||
$url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{$llvmVersion}/{$tarball}";
|
||||
$tarballPath = DOWNLOAD_PATH . '/' . $tarball;
|
||||
if (!file_exists($tarballPath)) {
|
||||
try {
|
||||
default_shell()->executeCurlDownload($url, $tarballPath);
|
||||
} catch (\Throwable $e) {
|
||||
logger()->warning("[zig] failed to download {$tarball}: {$e->getMessage()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$srcRoot = PKG_ROOT_PATH . "/compiler-rt-src-{$llvmVersion}";
|
||||
FileSystem::removeDir($srcRoot);
|
||||
FileSystem::createDir($srcRoot);
|
||||
try {
|
||||
default_shell()->executeTarExtract($tarballPath, $srcRoot, 'xz');
|
||||
} catch (\Throwable $e) {
|
||||
logger()->warning("[zig] failed to extract {$tarball}: {$e->getMessage()}");
|
||||
return null;
|
||||
}
|
||||
return $srcRoot;
|
||||
}
|
||||
|
||||
private function buildProfileRuntime(string $zig, string $srcRoot, string $libPath): void
|
||||
{
|
||||
$profileSrc = "{$srcRoot}/lib/profile";
|
||||
$profileInc = "{$srcRoot}/include";
|
||||
if (!is_dir($profileSrc)) {
|
||||
logger()->warning("[zig] profile src dir missing at {$profileSrc} — PGO will not work");
|
||||
return;
|
||||
}
|
||||
$sources = array_merge(
|
||||
glob("{$profileSrc}/*.c") ?: [],
|
||||
glob("{$profileSrc}/*.cpp") ?: []
|
||||
);
|
||||
// Keep Linux-only compilation units; the others bring in OS-specific headers
|
||||
// we can't satisfy without their respective SDKs.
|
||||
$skip = ['/PlatformAIX', '/PlatformDarwin', '/PlatformFuchsia', '/PlatformOther', '/PlatformWindows', '/WindowsMMap'];
|
||||
$sources = array_filter($sources, function ($f) use ($skip) {
|
||||
foreach ($skip as $s) {
|
||||
if (str_contains($f, $s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$objDir = "{$srcRoot}/obj-profile";
|
||||
f_mkdir($objDir, recursive: true);
|
||||
$cflags = '-c -O2 -fPIC -fvisibility=hidden ' .
|
||||
'-I' . escapeshellarg($profileInc) . ' ' .
|
||||
'-DCOMPILER_RT_HAS_ATOMICS=1 -DCOMPILER_RT_HAS_FCNTL_LCK=1 -DCOMPILER_RT_HAS_UNAME=1';
|
||||
$objs = [];
|
||||
foreach ($sources as $src) {
|
||||
$obj = $objDir . '/' . pathinfo($src, PATHINFO_FILENAME) . '.o';
|
||||
$cmd = escapeshellarg($zig) . ' cc ' . $cflags . ' -o ' . escapeshellarg($obj) . ' ' . escapeshellarg($src) . ' 2>&1';
|
||||
if (!$this->runZigCmd($cmd, $obj, "failed to compile {$src}")) {
|
||||
return;
|
||||
}
|
||||
$objs[] = $obj;
|
||||
}
|
||||
$arCmd = escapeshellarg($zig) . ' ar rcs ' . escapeshellarg($libPath) . ' ' . implode(' ', array_map('escapeshellarg', $objs)) . ' 2>&1';
|
||||
if (!$this->runZigCmd($arCmd, $libPath, 'zig ar failed')) {
|
||||
return;
|
||||
}
|
||||
logger()->info('[zig] libclang_rt.profile.a installed (' . filesize($libPath) . ' bytes)');
|
||||
}
|
||||
|
||||
private function buildCrtObjects(string $zig, string $srcRoot, string $crtBegin, string $crtEnd): void
|
||||
{
|
||||
$beginSrc = "{$srcRoot}/lib/builtins/crtbegin.c";
|
||||
$endSrc = "{$srcRoot}/lib/builtins/crtend.c";
|
||||
if (!is_file($beginSrc) || !is_file($endSrc)) {
|
||||
logger()->error("[zig] crtbegin/crtend source missing under {$srcRoot}/lib/builtins — shared libs will lack __dso_handle");
|
||||
return;
|
||||
}
|
||||
$cflags = '-c -O2 -fPIC -fvisibility=hidden -DCRT_HAS_INITFINI_ARRAY';
|
||||
foreach ([[$beginSrc, $crtBegin], [$endSrc, $crtEnd]] as [$src, $dst]) {
|
||||
$cmd = escapeshellarg($zig) . ' cc ' . $cflags . ' -o ' . escapeshellarg($dst) . ' ' . escapeshellarg($src) . ' 2>&1';
|
||||
if (!$this->runZigCmd($cmd, $dst, "failed to compile {$src}")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
logger()->info('[zig] clang_rt.crtbegin.o + clang_rt.crtend.o installed (' . filesize($crtBegin) . ' + ' . filesize($crtEnd) . ' bytes)');
|
||||
}
|
||||
|
||||
private function runZigCmd(string $cmd, string $dst, string $errPrefix): bool
|
||||
{
|
||||
exec($cmd, $out, $rc);
|
||||
if ($rc !== 0 || !is_file($dst)) {
|
||||
logger()->warning("[zig] {$errPrefix}: " . implode("\n", $out));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,20 @@ class LinuxMuslCheck
|
||||
$prefix = 'sudo ';
|
||||
logger()->warning('Current user is not root, using sudo for running command');
|
||||
}
|
||||
$sysEnv = ['CC' => 'gcc', 'CXX' => 'g++', 'AR' => 'ar', 'LD' => 'ld', 'RANLIB' => 'ranlib'];
|
||||
$envFlags = '';
|
||||
foreach ($sysEnv as $k => $v) {
|
||||
$envFlags .= "{$k}={$v} ";
|
||||
}
|
||||
$envFlags = rtrim($envFlags);
|
||||
$shell = shell()->cd(SOURCE_PATH . '/musl-wrapper')
|
||||
->exec('CC=gcc CXX=g++ AR=ar LD=ld ./configure --disable-gcc-wrapper')
|
||||
->exec('CC=gcc CXX=g++ AR=ar LD=ld make -j');
|
||||
->setEnv($sysEnv)
|
||||
->exec('./configure --disable-gcc-wrapper')
|
||||
->exec('make -j');
|
||||
if ($prefix !== '') {
|
||||
f_passthru('cd ' . SOURCE_PATH . "/musl-wrapper && CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
|
||||
f_passthru('cd ' . SOURCE_PATH . "/musl-wrapper && {$envFlags} {$prefix}make install");
|
||||
} else {
|
||||
$shell->exec("CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
|
||||
$shell->exec("{$prefix}make install");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -274,14 +274,20 @@ class PhpExtensionPackage extends Package
|
||||
$compiler_extra = trim($compiler_extra . ' -lcompiler_rt');
|
||||
GlobalEnvManager::putenv("SPC_COMPILER_EXTRA={$compiler_extra}");
|
||||
}
|
||||
$config = (new SPCConfigUtil())->getExtensionConfig($this);
|
||||
// include_suggests so transitive optional libs (e.g. librdkafka → lz4/zstd/ssl) are in the link line
|
||||
$config = (new SPCConfigUtil())->getExtensionConfig($this, include_suggests: true);
|
||||
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
||||
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
|
||||
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
|
||||
// -Wl,-Bsymbolic: bind zend_* refs to the .so's own copies, not via global lookup
|
||||
$ldflags = (string) $config['ldflags'];
|
||||
if (PHP_OS_FAMILY !== 'Darwin' && !str_contains($ldflags, '-Wl,-Bsymbolic')) {
|
||||
$ldflags = clean_spaces($ldflags . ' -Wl,-Bsymbolic');
|
||||
}
|
||||
return [
|
||||
'CFLAGS' => $config['cflags'],
|
||||
'CXXFLAGS' => $config['cflags'],
|
||||
'LDFLAGS' => $config['ldflags'],
|
||||
'LDFLAGS' => $ldflags,
|
||||
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
|
||||
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
|
||||
];
|
||||
@@ -303,10 +309,11 @@ class PhpExtensionPackage extends Package
|
||||
public function configureForUnix(array $env, PhpExtensionPackage $package): void
|
||||
{
|
||||
$phpvars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
|
||||
// CustomPhpConfigureArg keys are OS names ('Linux'/'Darwin'), not platform strings
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($env)
|
||||
->exec(
|
||||
'./configure ' . $this->getPhpConfigureArg(SystemTarget::getCurrentPlatformString(), true) .
|
||||
'./configure ' . $this->getPhpConfigureArg(SystemTarget::getTargetOS(), true) .
|
||||
' --with-php-config=' . BUILD_BIN_PATH . '/php-config ' .
|
||||
"--enable-shared --disable-static {$phpvars}"
|
||||
);
|
||||
@@ -318,6 +325,8 @@ class PhpExtensionPackage extends Package
|
||||
#[Stage]
|
||||
public function makeForUnix(array $env, PhpExtensionPackage $package, PackageBuilder $builder): void
|
||||
{
|
||||
// phpize Makefile's _SHARED_LIBADD line misses our static archives — splice them in
|
||||
$package->patchSharedLibAdd();
|
||||
shell()->cd($package->getSourceDir())
|
||||
->setEnv($env)
|
||||
->exec('make clean')
|
||||
@@ -325,6 +334,34 @@ class PhpExtensionPackage extends Package
|
||||
->exec('make install');
|
||||
}
|
||||
|
||||
public function patchSharedLibAdd(): void
|
||||
{
|
||||
// include_suggests so transitive optional libs (e.g. librdkafka → lz4/zstd/ssl) are in the link line
|
||||
$config = (new SPCConfigUtil())->getExtensionConfig($this, include_suggests: true);
|
||||
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
||||
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a')
|
||||
? '-l:libstdc++.a'
|
||||
: (str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '');
|
||||
|
||||
$makefile = $this->getSourceDir() . '/Makefile';
|
||||
if (!is_file($makefile)) {
|
||||
return;
|
||||
}
|
||||
$content = (string) file_get_contents($makefile);
|
||||
if (!preg_match('/^(.*_SHARED_LIBADD\s*=\s*)(.*)$/m', $content, $m)) {
|
||||
return;
|
||||
}
|
||||
$prefix = $m[1];
|
||||
$current = trim($m[2]);
|
||||
$merged = clean_spaces("{$current} {$staticLibs} {$lstdcpp}");
|
||||
$merged = deduplicate_flags($merged);
|
||||
\StaticPHP\Util\FileSystem::replaceFileRegex(
|
||||
$makefile,
|
||||
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
|
||||
$prefix . $merged
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build shared extension on Unix-like systems.
|
||||
* Only for internal calling. For external use, call buildShared() instead.
|
||||
@@ -333,6 +370,21 @@ class PhpExtensionPackage extends Package
|
||||
*/
|
||||
public function buildSharedForUnix(PackageBuilder $builder): void
|
||||
{
|
||||
// skip virtual addons (arg-type=none + display-name → owning ext); the parent ext built it
|
||||
$argType = $this->extension_config['arg-type'] ?? null;
|
||||
$displayName = $this->extension_config['display-name'] ?? null;
|
||||
if ($argType === 'none' && $displayName !== null && $displayName !== $this->getExtensionName()) {
|
||||
logger()->info("Skipping virtual extension [{$this->getName()}] — it's part of [{$displayName}].");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_dir($this->getSourceDir())) {
|
||||
throw new ValidationException(
|
||||
"Extension source directory not found: {$this->getSourceDir()}",
|
||||
validation_module: "Extension {$this->getName()} source"
|
||||
);
|
||||
}
|
||||
|
||||
$env = $this->getSharedExtensionEnv();
|
||||
|
||||
$this->runStage([$this, 'phpizeForUnix'], ['env' => $env]);
|
||||
|
||||
@@ -230,7 +230,7 @@ class UnixCMakeExecutor extends Executor
|
||||
|
||||
// EXE linker flags: base system libs + framework flags for target packages
|
||||
$exeLinkerFlags = SystemTarget::getRuntimeLibs();
|
||||
if ($this->package instanceof TargetPackage) {
|
||||
if ($this->package instanceof TargetPackage && SystemTarget::getTargetOS() === 'Darwin') {
|
||||
$resolvedNames = array_keys($this->installer->getResolvedPackages());
|
||||
$resolvedNames[] = $this->package->getName();
|
||||
$fwFlags = new SPCConfigUtil()->getFrameworksString($resolvedNames);
|
||||
@@ -302,9 +302,12 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "{$include}")
|
||||
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES "{$include}")
|
||||
CMAKE;
|
||||
// Whoops, linux may need CMAKE_AR sometimes
|
||||
// pin AR/RANLIB so cmake uses zig-ar/zig-ranlib instead of system /usr/bin/ranlib (zig archives need it)
|
||||
if (PHP_OS_FAMILY === 'Linux') {
|
||||
$toolchain .= "\nSET(CMAKE_AR \"ar\")";
|
||||
$ar = getenv('SPC_DEFAULT_AR') ?: getenv('AR') ?: 'ar';
|
||||
$ranlib = getenv('SPC_DEFAULT_RANLIB') ?: (getenv('RANLIB') ?: 'ranlib');
|
||||
$toolchain .= "\nSET(CMAKE_AR \"{$ar}\")";
|
||||
$toolchain .= "\nSET(CMAKE_RANLIB \"{$ranlib}\")";
|
||||
}
|
||||
FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain);
|
||||
return $created = realpath(SOURCE_PATH . '/toolchain.cmake');
|
||||
|
||||
@@ -15,6 +15,7 @@ class ClangBrewToolchain extends ClangNativeToolchain
|
||||
GlobalEnvManager::putenv("SPC_DEFAULT_CC={$homebrew_prefix}/opt/llvm/bin/clang");
|
||||
GlobalEnvManager::putenv("SPC_DEFAULT_CXX={$homebrew_prefix}/opt/llvm/bin/clang++");
|
||||
GlobalEnvManager::putenv("SPC_DEFAULT_AR={$homebrew_prefix}/opt/llvm/bin/llvm-ar");
|
||||
GlobalEnvManager::putenv("SPC_DEFAULT_RANLIB={$homebrew_prefix}/opt/llvm/bin/llvm-ranlib");
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
|
||||
GlobalEnvManager::addPathIfNotExists("{$homebrew_prefix}/opt/llvm/bin");
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class ClangNativeToolchain implements UnixToolchainInterface
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CC=clang');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=clang++');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=ranlib');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ class GccNativeToolchain implements UnixToolchainInterface
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CC=gcc');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=g++');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=ranlib');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
|
||||
}
|
||||
|
||||
|
||||
@@ -16,28 +16,8 @@ class ZigToolchain implements UnixToolchainInterface
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CC=zig-cc');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=zig-c++');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_AR=zig-ar');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=zig-ranlib');
|
||||
GlobalEnvManager::putenv('SPC_DEFAULT_LD=zig-ld.lld');
|
||||
|
||||
// Generate additional objects needed for zig toolchain
|
||||
$paths = ['/usr/lib/gcc', '/usr/local/lib/gcc'];
|
||||
$objects = ['crtbeginS.o', 'crtendS.o'];
|
||||
$found = [];
|
||||
|
||||
foreach ($objects as $obj) {
|
||||
$located = null;
|
||||
foreach ($paths as $base) {
|
||||
$output = shell_exec("find {$base} -name {$obj} 2>/dev/null | grep -v '/32/' | head -n 1");
|
||||
$line = trim((string) $output);
|
||||
if ($line !== '') {
|
||||
$located = $line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($located) {
|
||||
$found[] = $located;
|
||||
}
|
||||
}
|
||||
GlobalEnvManager::putenv('SPC_EXTRA_RUNTIME_OBJECTS=' . implode(' ', $found));
|
||||
}
|
||||
|
||||
public function afterInit(): void
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||
BUILDROOT_ABS="${BUILD_ROOT_PATH:-$(realpath "$SCRIPT_DIR/../../../buildroot/include" 2>/dev/null || true)}"
|
||||
BUILDROOT_INC="${BUILD_INCLUDE_PATH:-$SCRIPT_DIR/../../../buildroot/include}"
|
||||
BUILDROOT_ABS="$(realpath "$BUILDROOT_INC" 2>/dev/null || true)"
|
||||
PARSED_ARGS=()
|
||||
|
||||
is_buildroot_inc() {
|
||||
[[ -n "$BUILDROOT_ABS" && "$1" == "$BUILDROOT_ABS" ]]
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-isystem)
|
||||
@@ -11,13 +16,13 @@ while [[ $# -gt 0 ]]; do
|
||||
ARG="$1"
|
||||
shift
|
||||
ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
|
||||
[[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem" "$ARG")
|
||||
is_buildroot_inc "$ARG_ABS" && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem" "$ARG")
|
||||
;;
|
||||
-isystem*)
|
||||
ARG="${1#-isystem}"
|
||||
shift
|
||||
ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
|
||||
[[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem$ARG")
|
||||
is_buildroot_inc "$ARG_ABS" && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem$ARG")
|
||||
;;
|
||||
-march=*|-mcpu=*)
|
||||
OPT_NAME="${1%%=*}"
|
||||
@@ -32,6 +37,10 @@ while [[ $# -gt 0 ]]; do
|
||||
PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}")
|
||||
shift
|
||||
;;
|
||||
-Wlogical-op|-Wduplicated-cond|-Wduplicated-branches|-Wno-clobbered|-Wjump-misses-init|-Wformat-truncation|-Warray-bounds=*|-Wimplicit-fallthrough=*)
|
||||
# GCC-only warning flags that clang/zig doesn't recognize; drop to silence -Wunknown-warning-option noise
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
PARSED_ARGS+=("$1")
|
||||
shift
|
||||
@@ -39,6 +48,24 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
IS_LINK=1
|
||||
NEED_PROFILE_RT=0 # https://codeberg.org/ziglang/zig/issues/32066
|
||||
NEED_CRT=0 # https://codeberg.org/ziglang/zig/issues/32064
|
||||
for _a in "${PARSED_ARGS[@]}"; do
|
||||
case "$_a" in
|
||||
-c|-S|-E|-M|-MM) IS_LINK=0 ;;
|
||||
-fprofile-generate*|-fprofile-instr-generate*|-fcs-profile-generate*) NEED_PROFILE_RT=1 ;;
|
||||
-shared) NEED_CRT=1 ;;
|
||||
esac
|
||||
done
|
||||
[[ "$SPC_COMPILER_EXTRA" == *-fprofile-generate* || "$SPC_COMPILER_EXTRA" == *-fcs-profile-generate* ]] && NEED_PROFILE_RT=1
|
||||
if [[ $IS_LINK -eq 1 && $NEED_PROFILE_RT -eq 1 && -f "$SCRIPT_DIR/lib/libclang_rt.profile.a" ]]; then
|
||||
PARSED_ARGS+=("$SCRIPT_DIR/lib/libclang_rt.profile.a" "-Wl,-u,__llvm_profile_runtime")
|
||||
fi
|
||||
if [[ $IS_LINK -eq 1 && $NEED_CRT -eq 1 && -f "$SCRIPT_DIR/lib/clang_rt.crtbegin.o" && -f "$SCRIPT_DIR/lib/clang_rt.crtend.o" ]]; then
|
||||
PARSED_ARGS+=("$SCRIPT_DIR/lib/clang_rt.crtbegin.o" "$SCRIPT_DIR/lib/clang_rt.crtend.o")
|
||||
fi
|
||||
|
||||
[[ -n "$SPC_TARGET" ]] && TARGET="-target $SPC_TARGET" || TARGET=""
|
||||
|
||||
if [[ "$SPC_TARGET" =~ \.[0-9]+\.[0-9]+ ]]; then
|
||||
|
||||
Reference in New Issue
Block a user