diff --git a/recipes/compiler-rt-profile.toml b/recipes/compiler-rt-profile.toml new file mode 100644 index 00000000..c3bbf6cf --- /dev/null +++ b/recipes/compiler-rt-profile.toml @@ -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//`, 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" +'''