Files
takana/recipes/rust-alpine-target.patch
SergioandClaude Opus 5 e903f486d9 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>
2026-09-16 13:07:56 +00:00

85 lines
4.6 KiB
Diff

Registra el triple de Alpine `x86_64-alpine-linux-musl` como target de rustc.
POR QUÉ (SDD 31 §4.bis). El build usa el triple de Alpine en todas partes porque el stage0 es el
rustc del LAB y Alpine RENOMBRA su triple: con el canónico, el stage0 no tiene la std
(`can't find crate for std`). Pero ese nombre lo conoce el rustc de Alpine y NO el de upstream, así
que en el stage 2 —cuando toma el relevo el compilador que acabamos de construir— el build muere:
error: error loading target specification: could not find specification for target
"x86_64-alpine-linux-musl"
O sea: el triple que hace falta para ARRANCAR el build es el que el PRODUCTO del build no tiene.
Esto lo mete DENTRO del compilador, que es lo que hace Alpine en su APKBUILD, y por eso vale en
todos los stages (un `.json` por `RUST_TARGET_PATH` no sirve para el triple del HOST).
La única diferencia real con el spec canónico es `crt_static_default = false`: es lo que habilita
dylibs y, con ellos, los PROC-MACROS. Un rustc con `crt-static` por default no puede compilar
`serde_derive` ni `clap_derive` — ni las 44 recetas `cargo-*` del corpus que usan `derive`.
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_alpine_linux_musl.rs
@@ -0,0 +1,53 @@
+use crate::spec::{
+ Arch, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+};
+
+pub(crate) fn target() -> Target {
+ let mut base = base::linux_musl::opts();
+ base.cpu = "x86-64".into();
+ base.plt_by_default = false;
+ base.max_atomic_width = Some(64);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::Inline;
+ base.static_position_independent_executables = true;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
+ base.supports_xray = true;
+ // ── 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(),
+ metadata: TargetMetadata {
+ description: Some("64-bit Alpine Linux with musl (triple propio de Alpine)".into()),
+ tier: Some(3),
+ host_tools: Some(true),
+ std: Some(true),
+ },
+ pointer_width: 64,
+ data_layout:
+ "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+ arch: Arch::X86_64,
+ options: base,
+ }
+}
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1506,6 +1506,7 @@
("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl),
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
+ ("x86_64-alpine-linux-musl", x86_64_alpine_linux_musl),
("i686-unknown-linux-musl", i686_unknown_linux_musl),
("i586-unknown-linux-musl", i586_unknown_linux_musl),
("mips-unknown-linux-musl", mips_unknown_linux_musl),