el enlazador va DENTRO del compilador — /etc/cargo/config.toml es una ruta que cargo no lee
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>
This commit is contained in:
@@ -1361,14 +1361,19 @@ paquetes = [
|
||||
# · `rust` el compilador y cargo, construidos por la granja desde fuente (353 M).
|
||||
# · `lld21` el enlazador. NO es opcional: una caja takana **no tiene `cc`**, y sin
|
||||
# enlazador `rustc` compila objetos y no produce un ejecutable.
|
||||
# · `cargo-config` las tres flags que unen a los dos (`/etc/cargo/config.toml`). Sin ellas,
|
||||
# `cargo build` muere con `linker \`cc\` not found` — el toolchain estaría
|
||||
# completo y mudo.
|
||||
#
|
||||
# ⚠ Acá estuvo 20 minutos un tercer paquete, `cargo-config`, que publicaba `/etc/cargo/config.toml`
|
||||
# con las flags del enlazador. **Cargo NO LEE ESA RUTA** —sólo `$CARGO_HOME/config.toml`, los
|
||||
# `.cargo/config.toml` del proyecto y sus padres, y lo que se le pase con `--config`— así que el
|
||||
# paquete habría instalado un fichero que nadie abre. La prueba que lo destapó fue la única que
|
||||
# valía: `cargo build` en un proyecto nuevo, sin flags y sin rutas, en la caja. 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 (`recipes/rust-alpine-target.patch`).
|
||||
#
|
||||
# ⚠ Va en `servidor` y NO en `base` por tamaño y por sentido: una imagen de escritorio no compila
|
||||
# nada; la caja que sirve el repo y construye, sí. Y sigue siendo el paso 2 de tres: el 3 es la
|
||||
# cadena mrustc del selfhost, que es lo único que quita la dependencia del LAB para arrancar.
|
||||
"rust", "lld21", "cargo-config",
|
||||
"rust", "lld21",
|
||||
# `netup` (2026-09-10): el cliente DHCP propio que levanta la red al arrancar. Entra como RAÍZ
|
||||
# aunque su binario YA venga dentro del `product-rootfs`, y por una razón concreta: el del producto
|
||||
# está congelado en el artefacto sellado del bootstrap, así que un arreglo de netup no llega nunca
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# cargo-config — la config que hace que `cargo build` FUNCIONE en una caja takana.
|
||||
#
|
||||
# ── POR QUÉ ES UNA RECETA Y NO UN FICHERO SUELTO (SDD 31) ───────────────────────────────────────
|
||||
# Una distro sin compilador de C puede compilar Rust —está probado— pero **no de fábrica**: sin esta
|
||||
# config, `cargo build` muere con `linker \`cc\` not found`. Un toolchain que sella, se instala y no
|
||||
# enlaza es [[subcomando-sin-driver]] otra vez, y la pieza que falta son tres flags.
|
||||
#
|
||||
# Va junto a `rust` y `lld21` en el perfil: los tres son el mismo hecho —«esta caja compila Rust»—
|
||||
# partido en un compilador, un enlazador y la línea que los une.
|
||||
#
|
||||
# ⚠ Es config de SISTEMA, no de usuario: `/etc/cargo/config.toml` lo lee cualquier `cargo` de
|
||||
# cualquier cuenta. Un `~/.cargo/config.toml` haría que el toolchain funcione para quien lo escribió
|
||||
# y no para el siguiente.
|
||||
name = "cargo-config"
|
||||
version = "1"
|
||||
license = "MIT"
|
||||
|
||||
[source]
|
||||
dir = "cargo-config/tree"
|
||||
|
||||
[build]
|
||||
compiler = "zig-cc"
|
||||
target = "x86_64-linux-musl"
|
||||
link = "static"
|
||||
flags = []
|
||||
|
||||
[build.phases]
|
||||
configure = "true"
|
||||
compile = "true"
|
||||
# `cp -r` y no `cp -a`: en el sandbox no hay privilegio para preservar el propietario (la lección de
|
||||
# `os-release`). El dueño real lo pone la proyección del artefacto.
|
||||
install = "mkdir -p /out/etc && cp -r /src/etc/. /out/etc/"
|
||||
@@ -1,19 +0,0 @@
|
||||
# Config del SITIO para cargo/rustc — SDD 31.
|
||||
#
|
||||
# ⚠ Sin esto, `cargo build` en una caja takana falla con `linker `cc` not found`: la distro NO TIENE
|
||||
# compilador de C, y no hace falta que lo tenga. Lo que hace falta es decirle a rustc que el
|
||||
# enlazador es el `ld` de binutils y que el modo es estático, que es el natural de musl.
|
||||
#
|
||||
# Por qué CADA flag, todos medidos el 2026-09-16 contra el rustc que construimos:
|
||||
# · `linker-flavor=ld.lld` + `linker=/usr/bin/ld.lld` — el `lld` del corpus (`recipes/lld21.toml`).
|
||||
# Hasta el 2026-09-16 acá decía el `ld` de binutils, porque el `lld` heredaba `LLVM_ENABLE_ZLIB=0`
|
||||
# de `llvm21` y no podía leer las secciones de depuración COMPRIMIDAS de la libc del lab. Con
|
||||
# `llvm21` reconstruido con zlib, lld enlaza y es más rápido. El `ld` de binutils sigue
|
||||
# funcionando como alternativa: `-C linker-flavor=ld -C linker=/usr/bin/ld`.
|
||||
# · `target-feature=+crt-static` — sin esto rustc pide `-lgcc`/`-lgcc_s` para el desenrollado y el
|
||||
# enlace muere en `cannot find -lgcc`: la distro se construye con zig, que trae compiler-rt y no
|
||||
# libgcc. Estático es además el modo natural de musl.
|
||||
# · `link-self-contained=yes` — usa los `crt*.o` y la `libc.a` que el propio toolchain trae.
|
||||
[target.x86_64-alpine-linux-musl]
|
||||
linker = "/usr/bin/ld.lld"
|
||||
rustflags = ["-C", "linker-flavor=ld.lld", "-C", "target-feature=+crt-static", "-C", "link-self-contained=yes"]
|
||||
@@ -1 +0,0 @@
|
||||
../cargo-config.toml
|
||||
+5
-1
@@ -75,4 +75,8 @@ cmake -S lld -B build -G Ninja \
|
||||
-DLLVM_ENABLE_LIBXML2=OFF
|
||||
'''
|
||||
compile = "ninja -C build"
|
||||
install = "DESTDIR=/out ninja -C build install"
|
||||
# ⚠ 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"
|
||||
|
||||
@@ -18,7 +18,7 @@ dylibs y, con ellos, los PROC-MACROS. Un rustc con `crt-static` por default no p
|
||||
|
||||
--- /dev/null
|
||||
+++ b/compiler/rustc_target/src/spec/targets/x86_64_alpine_linux_musl.rs
|
||||
@@ -0,0 +1,37 @@
|
||||
@@ -0,0 +1,53 @@
|
||||
+use crate::spec::{
|
||||
+ Arch, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
|
||||
+};
|
||||
@@ -37,9 +37,25 @@ dylibs y, con ellos, los PROC-MACROS. Un rustc con `crt-static` por default no p
|
||||
+ | SanitizerSet::MEMORY
|
||||
+ | SanitizerSet::THREAD;
|
||||
+ base.supports_xray = true;
|
||||
+ // A DIFERENCIA del spec canónico, que lo deja en `true`: sin esto no hay dylibs, y sin dylibs
|
||||
+ // no hay proc-macros. Es el mismo valor que usa Alpine en su rustc.
|
||||
+ base.crt_static_default = false;
|
||||
+ // ── ESTÁTICO POR DEFECTO, PERO CON DYLIBS ─────────────────────────────────────────────────
|
||||
+ // `crt_static_default = true` es lo que hace que un `rustc hola.rs` produzca un binario que
|
||||
+ // CORRE en una caja takana: sin él, rustc enlaza dinámico y pide `-lgcc`, que no existe —la
|
||||
+ // distro se construye con zig, que trae compiler-rt—, y el enlace muere en `cannot find -lgcc`.
|
||||
+ // `crt_static_allows_dylibs = true` es su pareja obligatoria: sin ella, `crt-static` apaga los
|
||||
+ // dylibs y con ellos los PROC-MACROS (`serde_derive`, `clap_derive` y las 44 recetas `cargo-*`
|
||||
+ // del corpus que usan `derive`). Los dos juntos = binarios estáticos y proc-macros vivos.
|
||||
+ // El compilador EN SÍ sigue siendo dinámico: el `bootstrap.toml` fija `crt-static = false` para
|
||||
+ // el build, que gana sobre este default.
|
||||
+ base.crt_static_default = true;
|
||||
+ base.crt_static_allows_dylibs = true;
|
||||
+
|
||||
+ // ── EL ENLAZADOR, EN EL COMPILADOR Y NO EN UN FICHERO DE CONFIG ───────────────────────────
|
||||
+ // Sin esto, `rustc` busca `cc` —que una caja takana NO TIENE— y falla con `linker \`cc\` not
|
||||
+ // found`. Ponerlo acá y no en un `config.toml` de cargo es la diferencia entre «takana compila
|
||||
+ // Rust» y «takana compila Rust si sabés tres flags»: el que compila es rustc, y rustc no lee la
|
||||
+ // config de cargo. `ld.lld` lo publica `recipes/lld21.toml`, que va en el mismo perfil.
|
||||
+ base.linker = Some("ld.lld".into());
|
||||
+ base.linker_flavor = LinkerFlavor::Gnu(Cc::No, Lld::Yes);
|
||||
+
|
||||
+ Target {
|
||||
+ llvm_target: "x86_64-alpine-linux-musl".into(),
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Config del SITIO para cargo/rustc — SDD 31.
|
||||
#
|
||||
# ⚠ Sin esto, `cargo build` en una caja takana falla con `linker `cc` not found`: la distro NO TIENE
|
||||
# compilador de C, y no hace falta que lo tenga. Lo que hace falta es decirle a rustc que el
|
||||
# enlazador es el `ld` de binutils y que el modo es estático, que es el natural de musl.
|
||||
#
|
||||
# Por qué CADA flag, todos medidos el 2026-09-16 contra el rustc que construimos:
|
||||
# · `linker-flavor=ld.lld` + `linker=/usr/bin/ld.lld` — el `lld` del corpus (`recipes/lld21.toml`).
|
||||
# Hasta el 2026-09-16 acá decía el `ld` de binutils, porque el `lld` heredaba `LLVM_ENABLE_ZLIB=0`
|
||||
# de `llvm21` y no podía leer las secciones de depuración COMPRIMIDAS de la libc del lab. Con
|
||||
# `llvm21` reconstruido con zlib, lld enlaza y es más rápido. El `ld` de binutils sigue
|
||||
# funcionando como alternativa: `-C linker-flavor=ld -C linker=/usr/bin/ld`.
|
||||
# · `target-feature=+crt-static` — sin esto rustc pide `-lgcc`/`-lgcc_s` para el desenrollado y el
|
||||
# enlace muere en `cannot find -lgcc`: la distro se construye con zig, que trae compiler-rt y no
|
||||
# libgcc. Estático es además el modo natural de musl.
|
||||
# · `link-self-contained=yes` — usa los `crt*.o` y la `libc.a` que el propio toolchain trae.
|
||||
[target.x86_64-alpine-linux-musl]
|
||||
linker = "/usr/bin/ld.lld"
|
||||
rustflags = ["-C", "linker-flavor=ld.lld", "-C", "target-feature=+crt-static", "-C", "link-self-contained=yes"]
|
||||
Reference in New Issue
Block a user