From 7bb4a09a3ce28c03d55e50fa76e7c390f7d36014 Mon Sep 17 00:00:00 2001 From: henderkes Date: Tue, 19 May 2026 20:01:50 +0700 Subject: [PATCH] turn llvm-tools into a doctor check. llvm-runtime is a target now --- config/pkg/target/llvm-compiler-rt.yml | 6 + ...{clang-runtime-bits.yml => llvm-tools.yml} | 4 +- ..._runtime_bits.php => llvm_compiler_rt.php} | 79 +++++--- src/Package/Artifact/llvm_tools.php | 180 ++++++++++++++++++ src/StaticPHP/Doctor/Item/LlvmToolsCheck.php | 35 ++++ src/StaticPHP/Doctor/Item/ZigCheck.php | 18 +- src/StaticPHP/Package/PackageBuilder.php | 5 +- src/StaticPHP/Runtime/SystemTarget.php | 25 +++ .../Toolchain/ClangNativeToolchain.php | 1 + src/StaticPHP/Toolchain/ZigToolchain.php | 4 +- src/StaticPHP/Util/Pgo/PgoContext.php | 6 +- src/globals/scripts/zig-cc.sh | 14 +- 12 files changed, 326 insertions(+), 51 deletions(-) create mode 100644 config/pkg/target/llvm-compiler-rt.yml rename config/pkg/target/{clang-runtime-bits.yml => llvm-tools.yml} (58%) rename src/Package/Artifact/{clang_runtime_bits.php => llvm_compiler_rt.php} (67%) create mode 100644 src/Package/Artifact/llvm_tools.php create mode 100644 src/StaticPHP/Doctor/Item/LlvmToolsCheck.php diff --git a/config/pkg/target/llvm-compiler-rt.yml b/config/pkg/target/llvm-compiler-rt.yml new file mode 100644 index 00000000..b7c7da74 --- /dev/null +++ b/config/pkg/target/llvm-compiler-rt.yml @@ -0,0 +1,6 @@ +llvm-compiler-rt: + type: target + artifact: + binary: custom + depends: + - zig diff --git a/config/pkg/target/clang-runtime-bits.yml b/config/pkg/target/llvm-tools.yml similarity index 58% rename from config/pkg/target/clang-runtime-bits.yml rename to config/pkg/target/llvm-tools.yml index aba94f5f..c43721ac 100644 --- a/config/pkg/target/clang-runtime-bits.yml +++ b/config/pkg/target/llvm-tools.yml @@ -1,4 +1,6 @@ -clang-runtime-bits: +llvm-tools: type: target artifact: binary: custom + depends: + - zig diff --git a/src/Package/Artifact/clang_runtime_bits.php b/src/Package/Artifact/llvm_compiler_rt.php similarity index 67% rename from src/Package/Artifact/clang_runtime_bits.php rename to src/Package/Artifact/llvm_compiler_rt.php index 60eb11aa..b6eabbdb 100644 --- a/src/Package/Artifact/clang_runtime_bits.php +++ b/src/Package/Artifact/llvm_compiler_rt.php @@ -11,10 +11,11 @@ use StaticPHP\Attribute\Artifact\AfterBinaryExtract; use StaticPHP\Attribute\Artifact\CustomBinary; use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate; use StaticPHP\Exception\DownloaderException; +use StaticPHP\Runtime\SystemTarget; -class clang_runtime_bits +class llvm_compiler_rt { - #[CustomBinary('clang-runtime-bits', [ + #[CustomBinary('llvm-compiler-rt', [ 'linux-x86_64', 'linux-aarch64', ])] @@ -26,10 +27,10 @@ class clang_runtime_bits $url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{$llvmVersion}/{$tarball}"; $tarballPath = DOWNLOAD_PATH . '/' . $tarball; default_shell()->executeCurlDownload($url, $tarballPath, retries: $downloader->getRetry()); - return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{pkg_root_path}/clang-runtime-bits', verified: false, version: $llvmVersion); + return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{pkg_root_path}/llvm-compiler-rt', verified: false, version: $llvmVersion); } - #[CustomBinaryCheckUpdate('clang-runtime-bits', [ + #[CustomBinaryCheckUpdate('llvm-compiler-rt', [ 'linux-x86_64', 'linux-aarch64', ])] @@ -44,43 +45,61 @@ class clang_runtime_bits ); } - #[AfterBinaryExtract('clang-runtime-bits', [ + #[AfterBinaryExtract('llvm-compiler-rt', [ 'linux-x86_64', 'linux-aarch64', ])] public function postExtract(string $target_path): void { + $this->buildForCurrentTarget($target_path); + } + + public function buildForCurrentTarget(?string $sourceDir = null): bool + { + $sourceDir ??= PKG_ROOT_PATH . '/llvm-compiler-rt'; + $triple = SystemTarget::getCanonicalTriple(); + $libDir = PKG_ROOT_PATH . '/zig/lib/' . $triple; + if ($this->isBuilt($libDir)) { + return true; + } + if (!is_dir($sourceDir)) { + logger()->warning("[llvm-compiler-rt] source dir missing at {$sourceDir}; cannot build runtime bits for {$triple}"); + return false; + } + $llvmVersion = $this->detectZigLlvmVersion(); + if ($llvmVersion === null) { + logger()->warning('[llvm-compiler-rt] could not detect bundled clang version; skipping runtime bit build (PGO + shared libs without __dso_handle will fail to link)'); + return false; + } + logger()->info("Building llvm compiler-rt bits for {$triple} (LLVM {$llvmVersion})"); + $zig = PKG_ROOT_PATH . '/zig/zig'; - $libDir = PKG_ROOT_PATH . '/zig/lib'; + f_mkdir($libDir, recursive: true); $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; - } - - $llvmVersion = $this->detectZigLlvmVersion(); - if ($llvmVersion === null) { - logger()->warning('[clang-runtime-bits] could not detect bundled clang version; skipping runtime bit build (PGO + shared libs without __dso_handle will fail to link)'); - return; - } - logger()->info("Building clang runtime bits for LLVM {$llvmVersion} (zig's bundled clang)"); - - f_mkdir($libDir, recursive: true); if (!file_exists($profileLib)) { - $this->buildProfileRuntime($zig, $target_path, $profileLib); + $this->buildProfileRuntime($zig, $sourceDir, $profileLib, $triple); } if (!file_exists($crtBegin) || !file_exists($crtEnd)) { - $this->buildCrtObjects($zig, $target_path, $crtBegin, $crtEnd); + $this->buildCrtObjects($zig, $sourceDir, $crtBegin, $crtEnd, $triple); } + return $this->isBuilt($libDir); } - private function buildProfileRuntime(string $zig, string $srcRoot, string $libPath): void + public function isBuilt(string $libDir): bool + { + return file_exists("{$libDir}/libclang_rt.profile.a") + && file_exists("{$libDir}/clang_rt.crtbegin.o") + && file_exists("{$libDir}/clang_rt.crtend.o"); + } + + private function buildProfileRuntime(string $zig, string $srcRoot, string $libPath, string $triple): void { $profileSrc = "{$srcRoot}/lib/profile"; $profileInc = "{$srcRoot}/include"; if (!is_dir($profileSrc)) { - logger()->warning("[clang-runtime-bits] profile src dir missing at {$profileSrc} — PGO will not work"); + logger()->warning("[llvm-compiler-rt] profile src dir missing at {$profileSrc} — PGO will not work"); return; } $sources = array_merge( @@ -99,9 +118,9 @@ class clang_runtime_bits return true; }); - $objDir = "{$srcRoot}/obj-profile"; + $objDir = "{$srcRoot}/obj-profile-{$triple}"; f_mkdir($objDir, recursive: true); - $cflags = '-c -O2 -fPIC -fvisibility=hidden ' . + $cflags = "-target {$triple} -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 = []; @@ -117,32 +136,32 @@ class clang_runtime_bits if (!$this->runZigCmd($arCmd, $libPath, 'zig ar failed')) { return; } - logger()->info('[clang-runtime-bits] libclang_rt.profile.a installed (' . filesize($libPath) . ' bytes)'); + logger()->info('[llvm-compiler-rt] libclang_rt.profile.a installed (' . filesize($libPath) . ' bytes)'); } - private function buildCrtObjects(string $zig, string $srcRoot, string $crtBegin, string $crtEnd): void + private function buildCrtObjects(string $zig, string $srcRoot, string $crtBegin, string $crtEnd, string $triple): void { $beginSrc = "{$srcRoot}/lib/builtins/crtbegin.c"; $endSrc = "{$srcRoot}/lib/builtins/crtend.c"; if (!is_file($beginSrc) || !is_file($endSrc)) { - logger()->error("[clang-runtime-bits] crtbegin/crtend source missing under {$srcRoot}/lib/builtins — shared libs will lack __dso_handle"); + logger()->error("[llvm-compiler-rt] 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'; + $cflags = "-target {$triple} -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('[clang-runtime-bits] clang_rt.crtbegin.o + clang_rt.crtend.o installed (' . filesize($crtBegin) . ' + ' . filesize($crtEnd) . ' bytes)'); + logger()->info('[llvm-compiler-rt] 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("[clang-runtime-bits] {$errPrefix}: " . implode("\n", $out)); + logger()->warning("[llvm-compiler-rt] {$errPrefix}: " . implode("\n", $out)); return false; } return true; diff --git a/src/Package/Artifact/llvm_tools.php b/src/Package/Artifact/llvm_tools.php new file mode 100644 index 00000000..89a0345e --- /dev/null +++ b/src/Package/Artifact/llvm_tools.php @@ -0,0 +1,180 @@ +detectLlvmVersion() + ?? throw new DownloaderException('Could not detect a clang version on host; install zig or clang first'); + $tarball = "llvm-project-{$llvmVersion}.src.tar.xz"; + $url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{$llvmVersion}/{$tarball}"; + $tarballPath = DOWNLOAD_PATH . '/' . $tarball; + default_shell()->executeCurlDownload($url, $tarballPath, retries: $downloader->getRetry()); + return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{pkg_root_path}/llvm-tools-src', verified: false, version: $llvmVersion); + } + + #[CustomBinaryCheckUpdate('llvm-tools', [ + 'linux-x86_64', + 'linux-aarch64', + 'macos-x86_64', + 'macos-aarch64', + ])] + public function checkUpdateBinary(?string $old_version, ArtifactDownloader $downloader): CheckUpdateResult + { + $llvmVersion = $this->detectLlvmVersion() + ?? throw new DownloaderException('Could not detect a clang version on host; install zig or clang first'); + return new CheckUpdateResult( + old: $old_version, + new: $llvmVersion, + needUpdate: $old_version === null || $llvmVersion !== $old_version, + ); + } + + #[AfterBinaryExtract('llvm-tools', [ + 'linux-x86_64', + 'linux-aarch64', + 'macos-x86_64', + 'macos-aarch64', + ])] + public function postExtract(string $target_path): void + { + $this->buildForHost($target_path); + } + + public function buildForHost(?string $sourceRoot = null): bool + { + $sourceRoot ??= PKG_ROOT_PATH . '/llvm-tools-src'; + $binDir = PKG_ROOT_PATH . '/llvm-tools/bin'; + if ($this->allBuilt($binDir)) { + return true; + } + $llvmDir = "{$sourceRoot}/llvm"; + if (!is_dir($llvmDir)) { + logger()->error("[llvm-tools] expected llvm/ subdir at {$llvmDir} (extraction layout changed?)"); + return false; + } + $cmake = trim((string) shell_exec('command -v cmake 2>/dev/null')); + if ($cmake === '') { + logger()->error('[llvm-tools] cmake not found on PATH; install cmake first.'); + return false; + } + $generator = trim((string) shell_exec('command -v ninja 2>/dev/null')) !== '' ? 'Ninja' : 'Unix Makefiles'; + $cc = PKG_ROOT_PATH . '/zig/zig-cc'; + $cxx = PKG_ROOT_PATH . '/zig/zig-c++'; + $buildDir = "{$sourceRoot}/build"; + $installDir = PKG_ROOT_PATH . '/llvm-tools'; + f_mkdir($buildDir, recursive: true); + + $cmakeArgs = [ + '-G', $generator, + '-S', $llvmDir, + '-B', $buildDir, + '-DCMAKE_BUILD_TYPE=Release', + '-DLLVM_ENABLE_PROJECTS=', + '-DLLVM_TARGETS_TO_BUILD=', + '-DLLVM_INCLUDE_BENCHMARKS=OFF', + '-DLLVM_INCLUDE_TESTS=OFF', + '-DLLVM_INCLUDE_EXAMPLES=OFF', + '-DLLVM_INCLUDE_DOCS=OFF', + '-DLLVM_ENABLE_ZLIB=OFF', + '-DLLVM_ENABLE_ZSTD=OFF', + '-DLLVM_ENABLE_LIBXML2=OFF', + '-DLLVM_ENABLE_TERMINFO=OFF', + '-DLLVM_ENABLE_LIBEDIT=OFF', + '-DLLVM_ENABLE_LIBPFM=OFF', + '-DLLVM_BUILD_LLVM_DYLIB=OFF', + '-DLLVM_LINK_LLVM_DYLIB=OFF', + '-DBUILD_SHARED_LIBS=OFF', + '-DCMAKE_C_COMPILER=' . $cc, + '-DCMAKE_CXX_COMPILER=' . $cxx, + '-DCMAKE_INSTALL_PREFIX=' . $installDir, + ]; + + $savedTarget = getenv('SPC_TARGET'); + f_putenv('SPC_TARGET=' . GNU_ARCH . '-linux-musl'); + try { + $cmd = escapeshellarg($cmake) . ' ' . implode(' ', array_map('escapeshellarg', $cmakeArgs)) . ' 2>&1'; + logger()->info("Configuring llvm-tools (generator: {$generator}, target: " . getenv('SPC_TARGET') . ')'); + exec($cmd, $out, $rc); + if ($rc !== 0) { + logger()->error('[llvm-tools] cmake configure failed: ' . implode("\n", $out)); + return false; + } + $jobs = (int) (getenv('SPC_CONCURRENCY') ?: CPU_COUNT); + if ($jobs < 1) { + $jobs = 1; + } + $targetArgs = ''; + foreach (self::TOOLS as $t) { + $targetArgs .= ' --target ' . escapeshellarg($t); + } + $buildCmd = 'cmake --build ' . escapeshellarg($buildDir) . $targetArgs + . ($generator === 'Ninja' ? " -j{$jobs}" : " -- -j{$jobs}"); + logger()->info('Building llvm-tools (' . implode(', ', self::TOOLS) . ')'); + exec($buildCmd . ' 2>&1', $out2, $rc2); + if ($rc2 !== 0) { + logger()->error('[llvm-tools] build failed: ' . implode("\n", array_slice($out2, -40))); + return false; + } + } finally { + f_putenv('SPC_TARGET=' . ($savedTarget === false ? '' : $savedTarget)); + } + f_mkdir($binDir, recursive: true); + foreach (self::TOOLS as $t) { + $built = "{$buildDir}/bin/{$t}"; + $dst = "{$binDir}/{$t}"; + if (!is_file($built)) { + logger()->error("[llvm-tools] expected output {$built} not found"); + return false; + } + if (!copy($built, $dst)) { + logger()->error("[llvm-tools] failed to copy {$built} → {$dst}"); + return false; + } + chmod($dst, 0755); + logger()->info("[llvm-tools] installed {$dst} (" . filesize($dst) . ' bytes)'); + } + return true; + } + + public function allBuilt(string $binDir): bool + { + foreach (self::TOOLS as $t) { + $p = "{$binDir}/{$t}"; + if (!is_file($p) || !is_executable($p)) { + return false; + } + } + return true; + } + + private function detectLlvmVersion(): ?string + { + $zig = PKG_ROOT_PATH . '/zig/zig'; + $verLine = trim((string) shell_exec(escapeshellarg($zig) . ' cc --version 2>/dev/null')); + if (preg_match('/clang version (\d+\.\d+\.\d+)/', $verLine, $m)) { + return $m[1]; + } + return null; + } +} diff --git a/src/StaticPHP/Doctor/Item/LlvmToolsCheck.php b/src/StaticPHP/Doctor/Item/LlvmToolsCheck.php new file mode 100644 index 00000000..1a1c7efb --- /dev/null +++ b/src/StaticPHP/Doctor/Item/LlvmToolsCheck.php @@ -0,0 +1,35 @@ +allBuilt($binDir)) { + return CheckResult::ok($binDir); + } + return CheckResult::fail('llvm-tools are not built', 'build-llvm-tools'); + } + + #[FixItem('build-llvm-tools')] + public function fixLlvmTools(): bool + { + $installer = new PackageInstaller(interactive: false); + $installer->addInstallPackage('llvm-tools'); + $installer->run(true); + new llvm_tools()->buildForHost(); + return new llvm_tools()->allBuilt(PKG_ROOT_PATH . '/llvm-tools/bin'); + } +} diff --git a/src/StaticPHP/Doctor/Item/ZigCheck.php b/src/StaticPHP/Doctor/Item/ZigCheck.php index 93bb6749..d64fabbf 100644 --- a/src/StaticPHP/Doctor/Item/ZigCheck.php +++ b/src/StaticPHP/Doctor/Item/ZigCheck.php @@ -10,6 +10,7 @@ use StaticPHP\Attribute\Doctor\OptionalCheck; use StaticPHP\DI\ApplicationContext; use StaticPHP\Doctor\CheckResult; use StaticPHP\Package\PackageInstaller; +use StaticPHP\Runtime\SystemTarget; use StaticPHP\Toolchain\Interface\ToolchainInterface; use StaticPHP\Toolchain\ZigToolchain; @@ -41,30 +42,31 @@ class ZigCheck } /** @noinspection PhpUnused */ - #[CheckItem('if clang runtime bits are built', limit_os: 'Linux', level: 799)] - public function checkClangRuntimeBits(): ?CheckResult + #[CheckItem('if llvm compiler-rt bits are built', limit_os: 'Linux', level: 799)] + public function checkCompilerRtBits(): ?CheckResult { // Skip if zig is not installed yet (zig check runs at level 800) if (!new PackageInstaller()->addInstallPackage('zig')->isPackageInstalled('zig')) { return null; } - $libDir = PKG_ROOT_PATH . '/zig/lib'; + $libDir = PKG_ROOT_PATH . '/zig/lib/' . SystemTarget::getCanonicalTriple(); if (file_exists("{$libDir}/libclang_rt.profile.a") && file_exists("{$libDir}/clang_rt.crtbegin.o") && file_exists("{$libDir}/clang_rt.crtend.o") ) { return CheckResult::ok("{$libDir}/libclang_rt.profile.a"); } - return CheckResult::fail('clang runtime bits are not built', 'build-clang-runtime-bits'); + return CheckResult::fail('llvm compiler-rt bits are not built for ' . SystemTarget::getCanonicalTriple(), 'build-llvm-compiler-rt'); } - #[FixItem('build-clang-runtime-bits')] - public function fixClangRuntimeBits(): bool + #[FixItem('build-llvm-compiler-rt')] + public function fixCompilerRtBits(): bool { $installer = new PackageInstaller(interactive: false); - $installer->addInstallPackage('clang-runtime-bits'); + $installer->addInstallPackage('llvm-compiler-rt'); $installer->run(true); - $libDir = PKG_ROOT_PATH . '/zig/lib'; + new \Package\Artifact\llvm_compiler_rt()->buildForCurrentTarget(); + $libDir = PKG_ROOT_PATH . '/zig/lib/' . SystemTarget::getCanonicalTriple(); return file_exists("{$libDir}/libclang_rt.profile.a") && file_exists("{$libDir}/clang_rt.crtbegin.o") && file_exists("{$libDir}/clang_rt.crtend.o"); diff --git a/src/StaticPHP/Package/PackageBuilder.php b/src/StaticPHP/Package/PackageBuilder.php index e24db6ae..4169e5fb 100644 --- a/src/StaticPHP/Package/PackageBuilder.php +++ b/src/StaticPHP/Package/PackageBuilder.php @@ -15,7 +15,6 @@ use StaticPHP\Util\FileSystem; use StaticPHP\Util\GlobalPathTrait; use StaticPHP\Util\InteractiveTerm; use StaticPHP\Util\System\LinuxUtil; -use StaticPHP\Util\System\UnixUtil; class PackageBuilder { @@ -179,7 +178,7 @@ class PackageBuilder if (SystemTarget::getTargetOS() === 'Darwin') { shell()->exec("dsymutil -f {$binary_path} -o {$debug_file}"); } elseif (SystemTarget::getTargetOS() === 'Linux') { - $objcopy = LinuxUtil::findCommand('llvm-objcopy') ?: 'objcopy'; + $objcopy = getenv('OBJCOPY'); if ($eu_strip = LinuxUtil::findCommand('eu-strip')) { shell() ->exec("{$eu_strip} -f {$debug_file} {$binary_path}") @@ -201,7 +200,7 @@ class PackageBuilder */ public function stripBinary(string $binary_path): void { - $strip = UnixUtil::findCommand('llvm-strip') ?: 'strip'; + $strip = PKG_ROOT_PATH . '/llvm-tools/bin/llvm-strip'; shell()->exec(match (SystemTarget::getTargetOS()) { 'Darwin' => "{$strip} -S {$binary_path}", 'Linux' => "{$strip} --strip-unneeded {$binary_path}", diff --git a/src/StaticPHP/Runtime/SystemTarget.php b/src/StaticPHP/Runtime/SystemTarget.php index b1f086c1..b968dee8 100644 --- a/src/StaticPHP/Runtime/SystemTarget.php +++ b/src/StaticPHP/Runtime/SystemTarget.php @@ -128,6 +128,31 @@ class SystemTarget return in_array(self::getTargetOS(), ['Linux', 'Darwin', 'BSD']); } + /** + * Returns the canonical target triple (arch-os-abi) for per-target build + * artifacts. Always returns a non-null triple, falling back to a host-derived + * triple when SPC_TARGET is unset or names 'native'. + * Strips libc version suffix (-gnu.2.17 → -gnu) and trailing flags (' -dynamic'). + */ + public static function getCanonicalTriple(): string + { + $target = (string) getenv('SPC_TARGET'); + if ($target !== '' && !str_contains($target, 'native')) { + $cleaned = (string) preg_replace('/(-gnu|-musl)\.[\d.]+/', '$1', $target); + $cleaned = preg_split('/\s+/', trim($cleaned))[0] ?? ''; + if ($cleaned !== '') { + return $cleaned; + } + } + $arch = self::getTargetArch(); + return match (self::getTargetOS()) { + 'Linux' => $arch . '-linux-' . (self::getLibc() === 'musl' ? 'musl' : 'gnu'), + 'Darwin' => $arch . '-macos-none', + 'Windows' => $arch . '-windows-gnu', + default => $arch . '-unknown-unknown', + }; + } + /** * Returns a GNU host triple for autoconf --host= when SPC_TARGET names an * architecture different from the build host (true cross-compile). diff --git a/src/StaticPHP/Toolchain/ClangNativeToolchain.php b/src/StaticPHP/Toolchain/ClangNativeToolchain.php index 7602c3ed..0b679852 100644 --- a/src/StaticPHP/Toolchain/ClangNativeToolchain.php +++ b/src/StaticPHP/Toolchain/ClangNativeToolchain.php @@ -38,6 +38,7 @@ class ClangNativeToolchain implements UnixToolchainInterface default => throw new EnvironmentException(__CLASS__ . ' is not supported on ' . PHP_OS_FAMILY . '.'), }; } + GlobalEnvManager::putenv('OBJCOPY=' . PKG_ROOT_PATH . '/llvm-tools/bin/llvm-objcopy'); } public function getCompilerInfo(): ?string diff --git a/src/StaticPHP/Toolchain/ZigToolchain.php b/src/StaticPHP/Toolchain/ZigToolchain.php index 63d2127c..799ce2e4 100644 --- a/src/StaticPHP/Toolchain/ZigToolchain.php +++ b/src/StaticPHP/Toolchain/ZigToolchain.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace StaticPHP\Toolchain; +use StaticPHP\Runtime\SystemTarget; use StaticPHP\Toolchain\Interface\UnixToolchainInterface; use StaticPHP\Util\GlobalEnvManager; use StaticPHP\Util\System\LinuxUtil; @@ -34,7 +35,8 @@ class ZigToolchain implements UnixToolchainInterface GlobalEnvManager::putenv("SPC_DEFAULT_CXXFLAGS={$cxxflags}"); GlobalEnvManager::putenv("SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS={$extraCflags}"); GlobalEnvManager::putenv('RANLIB=zig-ranlib'); - GlobalEnvManager::putenv('OBJCOPY=zig-objcopy'); + GlobalEnvManager::putenv('SPC_COMPILER_RT_DIR=' . PKG_ROOT_PATH . '/zig/lib/' . SystemTarget::getCanonicalTriple()); + GlobalEnvManager::putenv('OBJCOPY=' . PKG_ROOT_PATH . '/llvm-tools/bin/llvm-objcopy'); $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; if (!str_contains($extra_libs, '-lunwind')) { // Add unwind library if not already present diff --git a/src/StaticPHP/Util/Pgo/PgoContext.php b/src/StaticPHP/Util/Pgo/PgoContext.php index 99f447f3..80a8464a 100644 --- a/src/StaticPHP/Util/Pgo/PgoContext.php +++ b/src/StaticPHP/Util/Pgo/PgoContext.php @@ -221,9 +221,6 @@ final class PgoContext public function mergeProfiles(): void { - if (trim((string) shell_exec('command -v llvm-profdata 2>/dev/null')) === '') { - throw new WrongUsageException('PGO --phase=use: llvm-profdata not on PATH'); - } foreach ($this->trainableSapis as $sapi) { $this->mergeSapi($sapi); } @@ -248,7 +245,8 @@ final class PgoContext $out = $this->profDataFile($sapi); $inputs = array_merge($raws, $csRaws); $argv = implode(' ', array_map('escapeshellarg', $inputs)); - shell()->exec('llvm-profdata merge --failure-mode=warn -output=' . escapeshellarg($out) . ' ' . $argv); + $profdata = PKG_ROOT_PATH . '/llvm-tools/bin/llvm-profdata'; + shell()->exec(escapeshellarg($profdata) . ' merge --failure-mode=warn -output=' . escapeshellarg($out) . ' ' . $argv); if (!is_file($out) || filesize($out) === 0) { throw new WrongUsageException("PGO --phase=use: empty merge output for {$sapi}"); } diff --git a/src/globals/scripts/zig-cc.sh b/src/globals/scripts/zig-cc.sh index fe09b466..743ee0bf 100755 --- a/src/globals/scripts/zig-cc.sh +++ b/src/globals/scripts/zig-cc.sh @@ -37,6 +37,10 @@ while [[ $# -gt 0 ]]; do PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}") shift ;; + -mtune=generic) + PARSED_ARGS+=("-mtune=baseline") + 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 @@ -59,11 +63,13 @@ for _a in "${PARSED_ARGS[@]}"; do 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") + +RT_DIR="${SPC_COMPILER_RT_DIR:-}" +if [[ $IS_LINK -eq 1 && $NEED_PROFILE_RT -eq 1 && -n "$RT_DIR" && -f "$RT_DIR/libclang_rt.profile.a" ]]; then + PARSED_ARGS+=("$RT_DIR/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") +if [[ $IS_LINK -eq 1 && $NEED_CRT -eq 1 && -n "$RT_DIR" && -f "$RT_DIR/clang_rt.crtbegin.o" && -f "$RT_DIR/clang_rt.crtend.o" ]]; then + PARSED_ARGS+=("$RT_DIR/clang_rt.crtbegin.o" "$RT_DIR/clang_rt.crtend.o") fi [[ -n "$SPC_TARGET" ]] && TARGET="-target $SPC_TARGET" || TARGET=""