lld21: el enlazador de la distro — porque el bootstrap de rust se NIEGA a construirlo

La vía (a) está CERRADA, y lo dice el propio bootstrap en una línea:

    Cannot enable LLD with `rust.lld = true` when using external llvm-config.

Había leído el paso `Lld` —que compila desde el `src/llvm-project/lld` del tarball y reusa el
`llvm-config` externo— y me faltó mirar la VALIDACIÓN de config, que rechaza la combinación antes de
llegar a ese paso. La guarda tiene sentido: LLD y LLVM comparten ABI de C++, y con un llvm-config
externo el bootstrap no puede garantizar que casen. O sea: mientras usemos el `llvm21` del corpus
—que es lo que queremos— el toolchain NO se va a construir su propio `rust-lld`.

⇒ `recipes/lld21.toml` construye el MISMO `lld`, del mismo `llvm-project` (mismo tarball y mismo
sha256 que `llvm21`, byte por byte), pero SÓLO el subproyecto: `cmake -S lld` contra el LLVM ya
instalado por la dep. Minutos en vez de horas, y sin re-hashear `llvm21` —que encender
`LLVM_ENABLE_PROJECTS=lld` ahí dentro habría arrastrado a `rust` con él.

⚠ Y al revertir el flag aprendí algo que vale para todas las recetas con heredoc: el texto del
`bootstrap.toml` que la fase escribe **es parte de la fase, o sea ENTRADA DE HASH**. Mi comentario
explicando el fallo, puesto ahí adentro, cambiaba el hash del compilador entero: hora y media de
granja por un párrafo. Va fuera, como comentario de la receta, y el hash vuelve a `015a07fb…` — el
artefacto que ya está sellado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-09-16 01:02:49 +00:00
co-authored by Claude Opus 5
parent 8a6c928803
commit a9911785e1
3 changed files with 79 additions and 15 deletions
+1
View File
@@ -0,0 +1 @@
../lld21.toml
+61
View File
@@ -0,0 +1,61 @@
# 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"
link = "static"
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"]
[build.phases]
# `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_ZLIB=OFF \
-DLLVM_ENABLE_ZSTD=OFF \
-DLLVM_ENABLE_LIBXML2=OFF
'''
compile = "ninja -C build"
install = "DESTDIR=/out ninja -C build install"
+17 -15
View File
@@ -56,6 +56,23 @@ flags = []
# el mismo defecto y no podría compilar ni una receta del corpus que use `derive`.
build = ["llvm21", "cmake", "samurai", "python3", "pkgconf", "curl", "openssl-threads"]
# ⚠⚠ `lld = true` EN EL `[rust]` DE ARRIBA NO SE PUEDE, y lo dice el propio bootstrap en una línea:
#
# Cannot enable LLD with `rust.lld = true` when using external llvm-config.
#
# O sea: que el toolchain se construya su propio `rust-lld` está CERRADO mientras usemos el `llvm21`
# del corpus — y usar el nuestro es justamente lo que queremos. Leí el paso `Lld` del bootstrap (que
# compila desde el `src/llvm-project/lld` del tarball y reusa el `llvm-config` externo) y me faltó
# mirar la VALIDACIÓN de config, que rechaza la combinación antes de llegar a ese paso. La guarda
# tiene sentido: LLD y LLVM comparten ABI de C++ y con un llvm-config externo no se puede garantizar
# que casen.
#
# ⇒ El enlazador entra por el otro lado: `recipes/lld21.toml` construye el MISMO `lld`, del mismo
# `llvm-project`, contra el `llvm21` ya sellado. Se usa con `-C linker-flavor=ld.lld`.
#
# ⚠ Y el comentario va ACÁ y no adentro del heredoc de `bootstrap.toml` a propósito: ese texto es
# parte de la fase, o sea **entrada de hash**. Explicar algo ahí adentro re-sella el compilador
# entero — hora y media de granja por un párrafo.
[build.phases]
# El fichero de configuración de x.py se llama `bootstrap.toml` desde 1.8x; se escribe también
# `config.toml` porque el nombre viejo sigue siendo el que busca media documentación, y un fichero
@@ -100,21 +117,6 @@ channel = "stable"
codegen-tests = false
deny-warnings = false
musl-root = "/usr"
# ⚠ SIN ESTO EL COMPILADOR NO PUEDE ENLAZAR, y el primer sellado lo demostró: `rustc hola.rs` en una
# caja sin `cc` daba «linker `lld` not found», y con el `ld` de binutils «cannot find -lgcc». La
# causa estaba en una línea del log que parece informativa —`skipping llvm-tools (…): 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. El prebuilt oficial sí la trae, y por
# eso el escalón 1 enlazaba y el 2 no.
#
# `lld = true` construye LLD desde el `src/llvm-project/lld` que YA VIENE en el tarball (1,1 G de
# fuente) contra el cmake del LLVM externo — comprobado que `llvm21` publica su
# `lib/cmake/llvm/LLVMConfig.cmake`, que es lo que ese paso necesita, y que NO dispara un build de
# LLVM entero (el paso `Lld` reusa el `llvm-config` externo). Después, `dist.rs` lo copia al sysroot
# como `rust-lld` sólo `if builder.config.lld_enabled`.
#
# ⚠ `llvm21` no servía de repuesto: medido sobre sus 1,6 G, **no publica ningún `lld`**.
lld = true
[target.x86_64-alpine-linux-musl]
llvm-config = "/usr/bin/llvm-config"