Files
TheRock/build_tools/posix_ccache_compiler_check.py
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

120 lines
4.3 KiB
Python

# Copyright Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Script meant to be used in the ccache compiler_check directive on POSIX.
Syntax:
posix_ccache_compiler_check.py compiler_check_cache_dir compiler_path
It expects one argument for the compiler path to check and will print a
fingerprint for the compiler that should be stable across builds. CCache then
will hash this fingerprint and include it in the cache key for any uses of the
compiler.
Currently, the algorithm simply passes the compiler binary and every valid
shared library (skipping loader libraries) to sha256sum and post processes
it to eliminate absolute path names that cause false cache misses. This result
should be deterministic for all compilers built in the same way.
Because this script is very hot (it is invoked for every invocation of ccache),
we take some extra pains to maintain directory of fingerprint caches. This
directory consists of sha256sums of the mtime and full path to the compiler
and merely serves to save excess fingerprinting. It is always safe to
delete this cache, and it doesn't cost much to store excess variants, so we
take no effort to maintain it.
This script is typically snapshotted into the ccache directory and hardcoded
in configurations.
If making changes to this script, please validate it by running
./hack/ccache/test_ccache_sanity.sh and studying logs. If you don't know how
ccache works, consult with someone who does.
"""
import hashlib
from pathlib import Path
import sys
compiler_hash_cache_dir = Path(sys.argv[1])
compiler_exe = Path(sys.argv[2]).resolve()
compiler_exe_stat = compiler_exe.stat()
# First hash the canonical path of the compiler and the mtime. We use this to
# store a full compiler check output in the compiler_hash dir by this hash.
fingerprint_version = 1
hasher = hashlib.sha256()
hasher.update(f"{fingerprint_version},{compiler_exe_stat.st_mtime},".encode())
hasher.update(str(compiler_exe).encode())
compiler_exe_path_hash = hasher.hexdigest()
compiler_exe_path_hash_file = compiler_hash_cache_dir / compiler_exe_path_hash
# Common case: We have previously computed this. Just read the file and print it.
if compiler_exe_path_hash_file.exists():
print(compiler_exe_path_hash_file.read_text())
sys.exit(0)
# Cache miss: compute a full content hash.
import os
import re
import subprocess
def compute_compiler_fingerprint():
ldd_lines = (
subprocess.check_output(["ldd", str(compiler_exe)]).decode().splitlines()
)
# Matching ldd output lines like:
# linux-vdso.so.1 (0x00007481bc7ed000)
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007481bc400000)
# /lib64/ld-linux-x86-64.so.2 (0x00007481bc7ef000)
# Ignores optional soname (group1). Captures path (group2). Ignores addr.
ldd_pattern = re.compile(r"^(.+ => )?(.+) \(.+\)$")
lib_paths = [str(compiler_exe)]
for ldd_line in ldd_lines:
m = re.match(ldd_pattern, ldd_line)
if not m:
print(f"Could not match ldd output: {ldd_line}")
sys.exit(1)
lib_path_str = m.group(2).strip()
lib_path = Path(lib_path_str)
if not lib_path.is_absolute():
# Skip loaders like vdso.
continue
lib_paths.append(lib_path_str)
def _norm_fingerprint_path(line: str):
# Line is: {hash} {path}
# Rewrite the path to just be the basename.
hash, path_str = line.split(None, 2)
path_str = str(Path(path_str).name)
return f"{hash}\t{path_str}"
raw_fingerprint_lines = (
subprocess.check_output(["sha256sum"] + lib_paths).decode().splitlines()
)
fingerprint_lines = [_norm_fingerprint_path(line) for line in raw_fingerprint_lines]
return "\n".join(fingerprint_lines)
compiler_fingerprint = compute_compiler_fingerprint()
# Atomically write the hash cache file using rename. It is ok if this is
# racy: we just need it to be atomic.
hash_commit_file = Path(f"{compiler_exe_path_hash_file}.tmp{os.getpid()}")
hash_commit_file.parent.mkdir(parents=True, exist_ok=True)
try:
hash_commit_file.write_text(compiler_fingerprint)
os.rename(hash_commit_file, compiler_exe_path_hash_file)
except OSError:
# Ignore.
...
try:
hash_commit_file.unlink()
except OSError:
# Ignore.
...
print(compiler_fingerprint)