mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-07 00:35:41 +08:00
add --pgi and --pgo to facilitate PGO builds
This commit is contained in:
@@ -116,18 +116,17 @@ class Zig extends CustomPackage
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($all_exist) {
|
||||
return;
|
||||
if (!$all_exist) {
|
||||
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
||||
$source_type = $lock[$name]['source_type'];
|
||||
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
||||
$extract = "{$pkgroot}/zig";
|
||||
|
||||
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
||||
|
||||
$this->createZigCcScript($zig_bin_dir);
|
||||
}
|
||||
|
||||
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
||||
$source_type = $lock[$name]['source_type'];
|
||||
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
||||
$extract = "{$pkgroot}/zig";
|
||||
|
||||
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
||||
|
||||
$this->createZigCcScript($zig_bin_dir);
|
||||
$this->buildClangRuntimeBits($zig_bin_dir);
|
||||
}
|
||||
|
||||
public static function getEnvironment(): array
|
||||
@@ -140,6 +139,145 @@ class Zig extends CustomPackage
|
||||
return PKG_ROOT_PATH . '/zig';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the bits of clang's runtime that zig 0.16 doesn't ship: the
|
||||
* profile runtime (so -fprofile-generate actually emits .profraw) and
|
||||
* crtbegin.o/crtend.o (so shared libraries get __dso_handle and the
|
||||
* __cxa_finalize atexit hook).
|
||||
*
|
||||
* Build from 2mb compiler-rt-<llvm>.src tar
|
||||
* to avoid downloading 2gb full prebuilt 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)');
|
||||
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
|
||||
{
|
||||
$pkgName = "compiler-rt-{$llvmVersion}";
|
||||
$tarball = "compiler-rt-{$llvmVersion}.src.tar.xz";
|
||||
$url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{$llvmVersion}/{$tarball}";
|
||||
try {
|
||||
Downloader::downloadPackage($pkgName, [
|
||||
'type' => 'url',
|
||||
'url' => $url,
|
||||
'filename' => $tarball,
|
||||
]);
|
||||
}
|
||||
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::extractPackage($pkgName, SPC_SOURCE_ARCHIVE, DOWNLOAD_PATH . '/' . $tarball, $srcRoot);
|
||||
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") ?: []
|
||||
);
|
||||
$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;
|
||||
}
|
||||
|
||||
private function createZigCcScript(string $bin_dir): void
|
||||
{
|
||||
$script_path = __DIR__ . '/../scripts/zig-cc.sh';
|
||||
|
||||
@@ -39,6 +39,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*) NEED_PROFILE_RT=1 ;;
|
||||
-shared) NEED_CRT=1 ;;
|
||||
esac
|
||||
done
|
||||
[[ "$SPC_COMPILER_EXTRA" == *-fprofile-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