From efa7946c146480d16252593a8261e60606702903 Mon Sep 17 00:00:00 2001 From: henderkes Date: Tue, 19 May 2026 20:44:47 +0700 Subject: [PATCH] build in SOURCE_PATH --- src/Package/Artifact/llvm_compiler_rt.php | 84 +++++----------- src/Package/Artifact/llvm_tools.php | 95 ++++++------------- src/StaticPHP/Artifact/ArtifactDownloader.php | 5 +- src/StaticPHP/Command/ExtractCommand.php | 2 + src/StaticPHP/Doctor/Item/ZigCheck.php | 32 ------- 5 files changed, 59 insertions(+), 159 deletions(-) diff --git a/src/Package/Artifact/llvm_compiler_rt.php b/src/Package/Artifact/llvm_compiler_rt.php index b6eabbdb..d713cc72 100644 --- a/src/Package/Artifact/llvm_compiler_rt.php +++ b/src/Package/Artifact/llvm_compiler_rt.php @@ -10,6 +10,7 @@ use StaticPHP\Artifact\Downloader\Type\CheckUpdateResult; use StaticPHP\Attribute\Artifact\AfterBinaryExtract; use StaticPHP\Attribute\Artifact\CustomBinary; use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate; +use StaticPHP\Exception\BuildFailureException; use StaticPHP\Exception\DownloaderException; use StaticPHP\Runtime\SystemTarget; @@ -27,7 +28,7 @@ class llvm_compiler_rt $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-compiler-rt', verified: false, version: $llvmVersion); + return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{source_path}/llvm-compiler-rt', verified: false, version: $llvmVersion); } #[CustomBinaryCheckUpdate('llvm-compiler-rt', [ @@ -54,25 +55,17 @@ class llvm_compiler_rt $this->buildForCurrentTarget($target_path); } - public function buildForCurrentTarget(?string $sourceDir = null): bool + public function buildForCurrentTarget(?string $sourceDir = null): void { - $sourceDir ??= PKG_ROOT_PATH . '/llvm-compiler-rt'; + $sourceDir ??= SOURCE_PATH . '/llvm-compiler-rt'; $triple = SystemTarget::getCanonicalTriple(); $libDir = PKG_ROOT_PATH . '/zig/lib/' . $triple; if ($this->isBuilt($libDir)) { - return true; + return; } if (!is_dir($sourceDir)) { - logger()->warning("[llvm-compiler-rt] source dir missing at {$sourceDir}; cannot build runtime bits for {$triple}"); - return false; + throw new BuildFailureException("llvm-compiler-rt: missing source at {$sourceDir}"); } - $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'; f_mkdir($libDir, recursive: true); $profileLib = "{$libDir}/libclang_rt.profile.a"; @@ -84,7 +77,6 @@ class llvm_compiler_rt if (!file_exists($crtBegin) || !file_exists($crtEnd)) { $this->buildCrtObjects($zig, $sourceDir, $crtBegin, $crtEnd, $triple); } - return $this->isBuilt($libDir); } public function isBuilt(string $libDir): bool @@ -99,44 +91,27 @@ class llvm_compiler_rt $profileSrc = "{$srcRoot}/lib/profile"; $profileInc = "{$srcRoot}/include"; if (!is_dir($profileSrc)) { - logger()->warning("[llvm-compiler-rt] profile src dir missing at {$profileSrc} — PGO will not work"); - return; + throw new BuildFailureException("llvm-compiler-rt: profile src dir missing at {$profileSrc}"); } - $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 OS-specific sources we can't satisfy without their 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; - }); + $sources = array_filter( + array_merge(glob("{$profileSrc}/*.c") ?: [], glob("{$profileSrc}/*.cpp") ?: []), + fn ($f) => !array_any($skip, fn ($s) => str_contains($f, $s)), + ); $objDir = "{$srcRoot}/obj-profile-{$triple}"; f_mkdir($objDir, recursive: true); - $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'; + $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 = []; 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; - } + shell()->exec(escapeshellarg($zig) . ' cc ' . $cflags . ' -o ' . escapeshellarg($obj) . ' ' . escapeshellarg($src)); $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('[llvm-compiler-rt] libclang_rt.profile.a installed (' . filesize($libPath) . ' bytes)'); + shell()->exec(escapeshellarg($zig) . ' ar rcs ' . escapeshellarg($libPath) . ' ' . implode(' ', array_map('escapeshellarg', $objs))); } private function buildCrtObjects(string $zig, string $srcRoot, string $crtBegin, string $crtEnd, string $triple): void @@ -144,27 +119,12 @@ class llvm_compiler_rt $beginSrc = "{$srcRoot}/lib/builtins/crtbegin.c"; $endSrc = "{$srcRoot}/lib/builtins/crtend.c"; if (!is_file($beginSrc) || !is_file($endSrc)) { - logger()->error("[llvm-compiler-rt] crtbegin/crtend source missing under {$srcRoot}/lib/builtins — shared libs will lack __dso_handle"); - return; + throw new BuildFailureException("llvm-compiler-rt: crtbegin/crtend source missing under {$srcRoot}/lib/builtins"); } $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; - } + shell()->exec(escapeshellarg($zig) . ' cc ' . $cflags . ' -o ' . escapeshellarg($dst) . ' ' . escapeshellarg($src)); } - 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("[llvm-compiler-rt] {$errPrefix}: " . implode("\n", $out)); - return false; - } - return true; } private function detectZigLlvmVersion(): ?string @@ -173,10 +133,10 @@ class llvm_compiler_rt if (!is_file($zig)) { return null; } - $verLine = trim((string) shell_exec(escapeshellarg($zig) . ' cc --version 2>/dev/null')); - if (!preg_match('/clang version (\d+\.\d+\.\d+)/', $verLine, $m)) { + [$rc, $out] = shell()->execWithResult(escapeshellarg($zig) . ' cc --version', false); + if ($rc !== 0) { return null; } - return $m[1]; + return preg_match('/clang version (\d+\.\d+\.\d+)/', implode("\n", $out), $m) ? $m[1] : null; } } diff --git a/src/Package/Artifact/llvm_tools.php b/src/Package/Artifact/llvm_tools.php index 89a0345e..5dd26214 100644 --- a/src/Package/Artifact/llvm_tools.php +++ b/src/Package/Artifact/llvm_tools.php @@ -10,11 +10,14 @@ use StaticPHP\Artifact\Downloader\Type\CheckUpdateResult; use StaticPHP\Attribute\Artifact\AfterBinaryExtract; use StaticPHP\Attribute\Artifact\CustomBinary; use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate; +use StaticPHP\DI\ApplicationContext; +use StaticPHP\Exception\BuildFailureException; use StaticPHP\Exception\DownloaderException; +use StaticPHP\Package\PackageBuilder; class llvm_tools { - public const TOOLS = ['llvm-objcopy', 'llvm-strip', 'llvm-profdata']; + public const array TOOLS = ['llvm-objcopy', 'llvm-strip', 'llvm-profdata']; #[CustomBinary('llvm-tools', [ 'linux-x86_64', @@ -30,7 +33,7 @@ class llvm_tools $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); + return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{source_path}/llvm-tools', verified: false, version: $llvmVersion); } #[CustomBinaryCheckUpdate('llvm-tools', [ @@ -61,32 +64,23 @@ class llvm_tools $this->buildForHost($target_path); } - public function buildForHost(?string $sourceRoot = null): bool + public function buildForHost(?string $sourceRoot = null): void { - $sourceRoot ??= PKG_ROOT_PATH . '/llvm-tools-src'; + $sourceRoot ??= SOURCE_PATH . '/llvm-tools'; $binDir = PKG_ROOT_PATH . '/llvm-tools/bin'; if ($this->allBuilt($binDir)) { - return true; + return; } $llvmDir = "{$sourceRoot}/llvm"; if (!is_dir($llvmDir)) { - logger()->error("[llvm-tools] expected llvm/ subdir at {$llvmDir} (extraction layout changed?)"); - return false; + throw new BuildFailureException("llvm-tools: missing source at {$llvmDir} (extraction layout changed?)"); } - $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); + f_mkdir($binDir, recursive: true); - $cmakeArgs = [ - '-G', $generator, + $cmakeArgs = implode(' ', array_map('escapeshellarg', [ '-S', $llvmDir, '-B', $buildDir, '-DCMAKE_BUILD_TYPE=Release', @@ -105,56 +99,26 @@ class llvm_tools '-DLLVM_BUILD_LLVM_DYLIB=OFF', '-DLLVM_LINK_LLVM_DYLIB=OFF', '-DBUILD_SHARED_LIBS=OFF', - '-DCMAKE_C_COMPILER=' . $cc, - '-DCMAKE_CXX_COMPILER=' . $cxx, + '-DCMAKE_C_COMPILER=' . PKG_ROOT_PATH . '/zig/zig-cc', + '-DCMAKE_CXX_COMPILER=' . PKG_ROOT_PATH . '/zig/zig-c++', '-DCMAKE_INSTALL_PREFIX=' . $installDir, - ]; + ])); + $jobs = ApplicationContext::get(PackageBuilder::class)->concurrency; + $targetArgs = implode(' ', array_map(fn ($t) => '--target ' . escapeshellarg($t), self::TOOLS)); + + shell() + ->setEnv(['SPC_TARGET' => GNU_ARCH . '-linux-musl']) + ->exec('cmake ' . $cmakeArgs) + ->exec('cmake --build ' . escapeshellarg($buildDir) . ' ' . $targetArgs . " -j {$jobs}"); - $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; + throw new BuildFailureException("llvm-tools: missing build output {$built}"); } - 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)'); + copy($built, "{$binDir}/{$t}"); + chmod("{$binDir}/{$t}", 0755); } - return true; } public function allBuilt(string $binDir): bool @@ -171,10 +135,13 @@ class llvm_tools 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]; + if (!is_file($zig)) { + return null; } - return null; + [$rc, $out] = shell()->execWithResult(escapeshellarg($zig) . ' cc --version', false); + if ($rc !== 0) { + return null; + } + return preg_match('/clang version (\d+\.\d+\.\d+)/', implode("\n", $out), $m) ? $m[1] : null; } } diff --git a/src/StaticPHP/Artifact/ArtifactDownloader.php b/src/StaticPHP/Artifact/ArtifactDownloader.php index 345f9120..83e80f31 100644 --- a/src/StaticPHP/Artifact/ArtifactDownloader.php +++ b/src/StaticPHP/Artifact/ArtifactDownloader.php @@ -317,7 +317,10 @@ class ArtifactDownloader if (!is_dir(DOWNLOAD_PATH)) { FileSystem::createDir(DOWNLOAD_PATH); } - logger()->info('Downloading' . implode(', ', array_map(fn ($x) => " '{$x->getName()}'", $this->artifacts)) . " with concurrency {$this->parallel} ..."); + $pending = array_values(array_filter($this->artifacts, fn ($a) => $this->generateQueue($a) !== [])); + if ($pending !== []) { + logger()->info('Downloading' . implode(', ', array_map(fn ($x) => " '{$x->getName()}'", $pending)) . " with concurrency {$this->parallel} ..."); + } // Download artifacts parallelly if ($this->parallel > 1) { $this->downloadWithConcurrency(); diff --git a/src/StaticPHP/Command/ExtractCommand.php b/src/StaticPHP/Command/ExtractCommand.php index e2e79bdf..8be8bf4b 100644 --- a/src/StaticPHP/Command/ExtractCommand.php +++ b/src/StaticPHP/Command/ExtractCommand.php @@ -10,6 +10,7 @@ use StaticPHP\DI\ApplicationContext; use StaticPHP\Registry\ArtifactLoader; use StaticPHP\Registry\PackageLoader; use StaticPHP\Util\DependencyResolver; +use StaticPHP\Util\GlobalEnvManager; use StaticPHP\Util\InteractiveTerm; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; @@ -34,6 +35,7 @@ class ExtractCommand extends BaseCommand public function handle(): int { + GlobalEnvManager::afterInit(); $cache = ApplicationContext::get(ArtifactCache::class); $extractor = new ArtifactExtractor($cache); $force_source = (bool) $this->getOption('source-only'); diff --git a/src/StaticPHP/Doctor/Item/ZigCheck.php b/src/StaticPHP/Doctor/Item/ZigCheck.php index d64fabbf..ec140fd7 100644 --- a/src/StaticPHP/Doctor/Item/ZigCheck.php +++ b/src/StaticPHP/Doctor/Item/ZigCheck.php @@ -10,7 +10,6 @@ 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; @@ -40,35 +39,4 @@ class ZigCheck $installer->run(true); return $installer->isPackageInstalled('zig'); } - - /** @noinspection PhpUnused */ - #[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/' . 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('llvm compiler-rt bits are not built for ' . SystemTarget::getCanonicalTriple(), 'build-llvm-compiler-rt'); - } - - #[FixItem('build-llvm-compiler-rt')] - public function fixCompilerRtBits(): bool - { - $installer = new PackageInstaller(interactive: false); - $installer->addInstallPackage('llvm-compiler-rt'); - $installer->run(true); - 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"); - } }