La prueba de la caja recién instalada —`cargo build` en un proyecto nuevo, sin flags ni rutas a mano— falló con `linker `cc` not found`, y destapó que la pieza que había empaquetado era falsa: **cargo NO LEE `/etc/cargo/config.toml`**. Sólo lee `$CARGO_HOME/config.toml`, los `.cargo/config.toml` del proyecto y sus padres, y lo que se le pase con `--config` — que es lo que yo venía pasando a mano en cada prueba, y por eso «funcionaba». Y el arreglo no era mover el fichero: **el que enlaza es `rustc`, y rustc no lee la config de cargo**. Las flags van DENTRO del compilador, en el spec del triple: · `linker = "ld.lld"` + `linker_flavor = Gnu(Cc::No, Lld::Yes)` — sin esto rustc busca `cc`, que una caja takana no tiene. · `crt_static_default = true` — sin esto enlaza dinámico y pide `-lgcc`, que no existe (la distro se construye con zig, que trae compiler-rt). · `crt_static_allows_dylibs = true` — su pareja obligatoria: sin ella `crt-static` apaga los dylibs y con ellos los PROC-MACROS (serde_derive, clap_derive, las 44 recetas `cargo-*` con `derive`). El compilador en sí sigue dinámico: el `bootstrap.toml` fija `crt-static = false` para el build, y eso gana sobre el default del spec. ⇒ `cargo-config` (receta, árbol y copia en scripts/) se van enteros: un paquete que instala un fichero que nadie abre es peor que no tenerlo. Y de paso, `lld21` instala los cuatro alias como SYMLINKS y no como copias: cmake los duplicaba, 5 × 96 M = 478 M de artefacto para 97 M de enlazador. Ahora 108 M, y `ld.lld` sigue despachando por `argv[0]`, que es como upstream lo diseñó. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
83 lines
4.9 KiB
TOML
83 lines
4.9 KiB
TOML
# LLD 21.1.2 — el ENLAZADOR de la distro. Mismo `llvm-project` que `llvm21`, construido aparte.
|
||
#
|
||
# ══ POR QUÉ EXISTE (SDD 31, muro 8) ════════════════════════════════════════════════════════════
|
||
# `rust` desde fuente selló, corre y **no puede enlazar**: en una caja sin `cc` —cualquier takana que
|
||
# no sea un hub— `rustc hola.rs` muere con `linker \`lld\` not found`, y con el `ld` de binutils con
|
||
# `cannot find -lgcc`. La causa está en una línea del log del propio build que parece informativa:
|
||
#
|
||
# skipping llvm-tools (x86_64-alpine-linux-musl): external LLVM
|
||
#
|
||
# Al usar un LLVM externo —que es lo que queremos, porque `llvm21` es del corpus— x.py se salta las
|
||
# herramientas de LLVM, y `rust-lld` es una de ellas.
|
||
#
|
||
# ⚠ Y la vía obvia está CERRADA por el propio bootstrap, medido: `rust.lld = true` contesta
|
||
# «Cannot enable LLD with `rust.lld = true` when using external llvm-config». La guarda tiene
|
||
# sentido —LLD y LLVM comparten ABI de C++— pero deja una sola salida: construir LLD nosotros.
|
||
#
|
||
# ⚠ Y `llvm21` no servía de repuesto: sobre sus 1,6 G de artefacto **no publica ningún `lld`**
|
||
# (`-DLLVM_ENABLE_PROJECTS=""`). Encenderlo ahí re-hashearía llvm21 y con él `rust`; separado, esto
|
||
# suma sin mover nada.
|
||
#
|
||
# ══ QUÉ CAMBIA FRENTE A llvm21 ═════════════════════════════════════════════════════════════════
|
||
# Se compila SÓLO el subproyecto `lld` (`cmake -S lld`), contra el LLVM ya instalado por la dep:
|
||
# minutos en vez de horas, y nada de volver a compilar los 1,6 G de librerías.
|
||
name = "lld21"
|
||
version = "21.1.2"
|
||
license = "Apache-2.0 WITH LLVM-exception"
|
||
|
||
[source]
|
||
# El mismo tarball que `llvm21`, byte por byte: la URL es locator y el sha256 es la identidad
|
||
# (ADR 0013), así que compartir fuente entre dos recetas no cuesta nada.
|
||
tarball = "https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.2/llvm-project-21.1.2.src.tar.xz"
|
||
sha256 = "1a417d1c8faf8d93e73fec1cbb76d393ed3218974c2283c7bac9672d3d47c54b"
|
||
|
||
[build]
|
||
compiler = "zig-cc"
|
||
target = "x86_64-linux-musl"
|
||
# ⚠ `dynamic` NO es una preferencia: con `static` el binario SELLA, arranca y **se muere en cuanto
|
||
# hace algo** (medido 2026-09-16). `ld.lld --version` y `--help` contestan bien; cualquier enlace
|
||
# —incluso uno que sólo debería dar un error, como un fichero de entrada inexistente— termina en
|
||
# SIGSEGV con el banner de LLVM y un «Stack dump:» vacío. La firma es la de los registros estáticos
|
||
# de LLVM: `cl::opt`, `TargetRegistry` y compañía se inicializan desde constructores globales que
|
||
# viven en objetos de las `.a`, y un enlace estático agresivo los DESCARTA por no estar
|
||
# referenciados — lo que funciona es lo que no los necesita (`--version`), y lo que no, revienta.
|
||
# Es la misma familia que `link-static-mentira-libtool`: el flag global de la receta decide cosas
|
||
# que la receta no dice.
|
||
link = "dynamic"
|
||
strip_debug = true
|
||
|
||
[deps]
|
||
# `llvm21` NO es un adorno: el build standalone de lld necesita su `lib/cmake/llvm/LLVMConfig.cmake`
|
||
# y sus `.a`. Es la misma dep que el paso `Lld` del bootstrap de rustc habría usado.
|
||
build = ["llvm21", "cmake", "samurai", "python3", "pkgconf", "zlib"]
|
||
|
||
[build.phases]
|
||
# ⚠ `LLVM_ENABLE_ZLIB` va ENCENDIDO —al revés que en `llvm21`— y lo decidió un error, no el gusto:
|
||
#
|
||
# lld: error: …/self-contained/crtn.o:(.debug_line) is compressed with ELFCOMPRESS_ZLIB,
|
||
# but lld is not built with zlib support
|
||
#
|
||
# Los objetos `crt*` que rust trae en su sysroot llevan las secciones de depuración COMPRIMIDAS, así
|
||
# que un enlazador sin zlib no puede ni leerlos. Para `llvm21` apagarlo era gratis; para el
|
||
# ENLAZADOR no lo es.
|
||
#
|
||
# `g++` con los runtimes estáticos, igual que `llvm21` y `cmake`: C++ a escala con zig sigue siendo
|
||
# terreno minado, y además LLD tiene que casar ABI con el LLVM contra el que enlaza — que se
|
||
# construyó exactamente así.
|
||
configure = '''
|
||
CC=gcc CXX='g++ -static-libstdc++ -static-libgcc' \
|
||
cmake -S lld -B build -G Ninja \
|
||
-DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||
-DLLVM_DIR=/usr/lib/cmake/llvm \
|
||
-DLLVM_INCLUDE_TESTS=OFF \
|
||
-DLLVM_ENABLE_ZSTD=OFF \
|
||
-DLLVM_ENABLE_LIBXML2=OFF
|
||
'''
|
||
compile = "ninja -C build"
|
||
# ⚠ LOS CINCO `lld` SON EL MISMO BINARIO, Y cmake LOS INSTALA COMO CINCO COPIAS: medido, 5 × 96 M =
|
||
# **478 M de artefacto para 97 M de enlazador**. `lld` despacha por `argv[0]`, así que los cuatro
|
||
# alias son symlinks por diseño de upstream — instalarlos como copias es sólo cómo quedó su cmake.
|
||
# En una caja cuya raíz son 5,8 G, 380 M de duplicado no son un detalle.
|
||
install = "DESTDIR=/out ninja -C build install && cd /out/usr/bin && for f in ld.lld ld64.lld lld-link wasm-ld; do ln -sf lld \"$f\"; done"
|