rust: el triple de Alpine, DENTRO del compilador — el sexto muro, atacado
`recipes/rust-alpine-target.patch` registra `x86_64-alpine-linux-musl` en `rustc_target`: un spec copiado del canónico y una línea en `supported_targets!`. Es lo que hace Alpine en su APKBUILD, y es la única forma que vale para el triple del HOST (un `.json` por `RUST_TARGET_PATH` no alcanza). La única diferencia real con el spec canónico es `crt_static_default = false`, que es lo que habilita dylibs y con ellos los PROC-MACROS: un rustc con crt-static por default no compila `serde_derive` ni `clap_derive` — ni las 44 recetas `cargo-*` del corpus que usan `derive`. ⚠ PROBADO EN SECO ANTES DE ENCOLAR UNA HORA DE BUILD (`patch -p1 --dry-run` contra el árbol real del worker), y no de primera: la cabecera `@@ -0,0 +1,38 @@` del fichero nuevo tenía 37 líneas y `patch` murió con «malformed patch», y el hunk de `mod.rs` lo escribí con números a ojo y falló. El segundo lo generé con `diff -u` de verdad contra una copia. Un parche se COMPRUEBA, no se redacta. ⚠ Y EL `.patch` HAY QUE ENCOLARLO TAMBIÉN: `source.patches` resuelve contra el directorio de la receta, así que con la receta enlazada en `recipes/incoming/` el parche se busca AHÍ. Es exactamente el corolario que `farm-worker-loop.sh` documenta («los `.patch` NO viajan con la receta»), visto desde el otro lado. Con los dos enlaces, el hash de la cola y el canónico coinciden: `b3:53c7f991…`, y el worker calcula el mismo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semantic delta
No definition changed: this change is text, documentation or data.
3 files · +74 −0
diff --git a/recipes/incoming/rust-alpine-target.patch b/recipes/incoming/rust-alpine-target.patch
new file mode 120000
index 00000000..b60f68e8
--- /dev/null
+++ b/recipes/incoming/rust-alpine-target.patch
@@ -0,0 +1 @@
+../rust-alpine-target.patch
\ No newline at end of file
diff --git a/recipes/rust-alpine-target.patch b/recipes/rust-alpine-target.patch
new file mode 100644
index 00000000..80679230
--- /dev/null
+++ b/recipes/rust-alpine-target.patch
@@ -0,0 +1,68 @@
+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,37 @@
++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;
++ // 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;
++
++ 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),
diff --git a/recipes/rust.toml b/recipes/rust.toml
index 272fe2f9..970617ff 100644
--- a/recipes/rust.toml
+++ b/recipes/rust.toml
@@ -25,6 +25,11 @@ license = "MIT OR Apache-2.0"
[source]
tarball = "https://static.rust-lang.org/dist/rustc-1.97.0-src.tar.xz"
sha256 = "de002ee301c1b7422b0a7b09d7c4cb4924cd3224e6cfb24f065dad786dd3ed12"
+# El triple de Alpine, DENTRO del compilador: sin esto el stage 2 muere con «could not find
+# specification for target x86_64-alpine-linux-musl» — el nombre que el stage0 necesita es uno que
+# upstream no conoce. Es lo que hace Alpine en su APKBUILD. Ver SDD 31 §4.bis y la cabecera del
+# propio parche.
+patches = ["rust-alpine-target.patch"]
[build]
compiler = "zig-cc"