compiler-rt-profile: la runtime de perfilado que el lab no trae (b3:32dff740)

libclang_rt.profile.a, 129.178 bytes — la que implementa los __llvm_profile_* y
escribe los .profraw. Hermana nativa de wasi-compiler-rt: mismo tarball de LLVM
22.1.8, mismo patrón, mismo sitio de aterrizaje; cambia el target (x86_64 en vez
de wasm32) y el componente (profile en vez de builtins).

Lo destapó el build del firefox instrumentado, en el minuto 38:56:

    ld.lld: error: cannot open
      /usr/lib/llvm22/lib/clang/22/lib/x86_64-alpine-linux-musl/libclang_rt.profile.a

El lab trae clang 22.1.8 con su include/ pero el lib/ del resource dir NO EXISTE
— que es exactamente lo que wasi-compiler-rt ya documentaba para el caso wasm.
O sea: el PGO no estaba bloqueado por el display (eso se despejó ayer) sino por
una pieza de toolchain que nunca hizo falta hasta ahora.

Se apaga todo menos profile: compiler-rt trae sanitizers, xray, memprof, orc y
ninguno tiene destinatario acá.

La primera corrida murió en el configure con «CMAKE_C_COMPILER_TARGET must also
be set when COMPILER_RT_DEFAULT_TARGET_ONLY is ON» — un error de cmake que dice
exactamente qué falta, cosa que no se puede dar por supuesta esta noche.

Dos guardianes. El primero exige la RUTA LITERAL del error y no «alguna
libclang_rt»: el layout per-target es una opción de cmake y equivocarla deja la
librería donde clang no mira, que es el mismo fallo que la libstdc++ en
/usr/lib64 de hace unas horas. El segundo es la prueba del consumidor: que
DEFINA __llvm_profile_write_file y compañía, para que un .a vacío no se descubra
al final de una corrida de perfilado.
This commit is contained in:
Sergio
2026-09-06 23:58:53 +00:00
parent 26a0dd31c7
commit f9d4572077
+103
View File
@@ -0,0 +1,103 @@
# compiler-rt-profile — la runtime de PERFILADO de compiler-rt para el target nativo.
#
# QUÉ ES: `libclang_rt.profile.a`, la librería que implementa los `__llvm_profile_*` y que ESCRIBE
# los ficheros `.profraw`. Sin ella, `-fprofile-generate` compila y no enlaza.
#
# ══ POR QUÉ EXISTE: EL LAB NO TRAE NINGUNA RUNTIME DE COMPILER-RT ══════════════════════════════
# Lo descubrió el build del firefox instrumentado, en el minuto 38:56:
#
# ld.lld: error: cannot open
# /usr/lib/llvm22/lib/clang/22/lib/x86_64-alpine-linux-musl/libclang_rt.profile.a
#
# El lab trae clang 22.1.8 con su `include/` pero **el `lib/` del resource dir no existe** — es
# exactamente lo que ya documentaba `recipes/wasi-compiler-rt.toml` para el caso wasm. Esta receta
# es su HERMANA NATIVA: mismo tarball, mismo patrón, mismo sitio de aterrizaje; lo que cambia es el
# target (x86_64 en vez de wasm32) y el componente (profile en vez de builtins).
#
# ⚠ LA VERSIÓN SIGUE A LA DEL LAB, igual que su hermana y por lo mismo: la runtime de perfilado es
# un contrato con el clang que la va a usar (el formato del `.profraw` tiene versión). El tarball es
# 22.1.8 y el lab trae llvm22 22.1.8-r1. Como `clang`/`llvm` son prefijos de `TOOLCHAIN_PREFIXES`,
# un bump del lab mueve la huella y re-hashea esto solo: la alineación está vigilada, no confiada.
#
# DÓNDE ATERRIZA: `/usr/lib/llvm22/lib/clang/22/lib/<triple>/`, que es donde clang la busca sin que
# nadie le pase un flag — el layout "per-target runtime dir", que es el que nombra el error. En el
# lab ese directorio no existe y las deps se apilan como overlay BAJO el rootfs, así que esta receta
# lo CREA sin pisar nada.
name = "compiler-rt-profile"
version = "22.1.8"
license = "Apache-2.0 WITH LLVM-exception"
[source]
tarball = "https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/llvm-project-22.1.8.src.tar.xz"
sha256 = "922f1817a0df7b1489272d18134ee0087a8b068828f87ac63b9861b1a9965888"
[build]
compiler = "clang"
[deps]
# `python3` por lo mismo que en la hermana: el CMakeLists de compiler-rt busca Python3 y sin él cae
# a un `find_package(Python2 ... REQUIRED)` que muere diciendo «Could NOT find Python2» — el mensaje
# nombra el fallback, no la causa.
build = ["cmake", "samurai", "python3"]
[build.phases]
configure = '''
set -e
# Se apaga TODO menos profile. compiler-rt trae sanitizers, xray, memprof, orc… y ninguno hace falta
# acá; construirlos multiplicaría el tiempo y ampliaría la superficie de fallo sin destinatario.
unset CFLAGS CXXFLAGS LDFLAGS
cmake -B build -G Ninja -S compiler-rt -Wno-dev \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_AR=/usr/bin/llvm-ar \
-DCMAKE_RANLIB=/usr/bin/llvm-ranlib \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
-DCMAKE_C_COMPILER_TARGET=x86_64-alpine-linux-musl \
-DCMAKE_CXX_COMPILER_TARGET=x86_64-alpine-linux-musl \
-DCMAKE_ASM_COMPILER_TARGET=x86_64-alpine-linux-musl \
-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON \
-DCOMPILER_RT_BUILD_PROFILE=ON \
-DCOMPILER_RT_BUILD_BUILTINS=OFF \
-DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF \
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
-DCOMPILER_RT_BUILD_ORC=OFF \
-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF \
-DCOMPILER_RT_INCLUDE_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=/usr/lib/llvm22/lib/clang/22/
'''
compile = 'cmake --build build'
install = '''
set -e
DESTDIR=/out cmake --install build
RES=/out/usr/lib/llvm22/lib/clang/22
# El `include/` del resource dir es del LAB (los headers de clang). Instalarlo desde acá lo taparía
# con una copia del tarball — la misma trampa que su hermana wasm documenta y evita.
rm -rf "$RES/include"
# ── GUARDIÁN 1: el fichero EXACTO que el enlazador pidió ─────────────────────────────────────
# No «alguna libclang_rt»: la ruta literal del error, porque el layout per-target es una opción de
# cmake y equivocarla deja la librería instalada donde clang no mira. Es el mismo fallo que la
# libstdc++ en /usr/lib64 de esta misma noche, un directorio más allá.
A="$RES/lib/x86_64-alpine-linux-musl/libclang_rt.profile.a"
test -s "$A" || {
echo "!! no está $A — ¿cambió el layout del resource dir?" >&2
find /out -name 'libclang_rt*' >&2
exit 1
}
echo "guardián: $A ($(stat -c%s "$A") bytes)"
# ── GUARDIÁN 2: LA PRUEBA DEL CONSUMIDOR ─────────────────────────────────────────────────────
# «Existe» no es «sirve». Se exige que DEFINA lo que un binario instrumentado va a buscar: la
# función que vuelca el `.profraw` y el contador de versión del formato. Si el `.a` sale vacío o
# con otro componente dentro, esto lo caza acá y no al final de una corrida de perfilado.
falta=""
for s in __llvm_profile_write_file __llvm_profile_get_version __llvm_profile_initialize_file; do
llvm-nm --defined-only "$A" 2>/dev/null | grep -qE " $s(@|$)" || falta="$falta $s"
done
test -z "$falta" || { echo "!! el .a no define:$falta" >&2; exit 1; }
echo "guardián: define los símbolos que emite -fprofile-generate"
'''