tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1346Shell 97Rust 63Markdown 571650 Sutichaykuna

⎇ main recipes/rust.toml TOML · 229 siq'ikuna · 14.2 KB Ñawpa willay ch'uya

tres arreglos que pidió el agente de adentro, y uno era mío 2f9253886 · Sergio ·

1# rust 1.97.0 DESDE FUENTE — el paso 2 de los tres, y el que hace que el compilador sea nuestro.
2#
3# ══ LA CADENA, Y POR QUÉ ESTE ES EL SEGUNDO ESCALÓN ════════════════════════════════════════════
4#   1. `rust-toolchain-bin` — el tarball oficial, `foreign`, sellado tal cual. Desbloqueó que una
5#      caja takana compile Rust (probado: `rustc 1.97.0` y un binario que corre). Es el escalón.
6#   2. **esto** — rustc construido acá, con `llvm21` del corpus y con el (1) como **stage0**. Un
7#      prebuilt ajeno sirve exactamente para esto: ser el escalón que permite dejar de necesitarlo.
8#   3. La cadena `mrustc → 1.90 → 1.91.0 → 1.91.1` del selfhost, que quita hasta ese escalón.
9#
10# ⚠ **`local-rebuild = true` NO es un detalle.** El bootstrap de rustc espera que el stage0 sea el
11# compilador ANTERIOR (o el beta de esta versión); acá el stage0 es **1.97.0 construyendo 1.97.0**, y
12# sin esa opción x.py aborta por «stage0 compiler version mismatch». Es el modo que usan las distros
13# para reconstruir la misma versión con la misma versión.
14#
15# ⚠ **El LLVM es EXTERNO y tiene que ser ≥21**, medido en el propio bootstrap:
16# `panic!("bad LLVM version: {version}, need >=21")`. Por eso existe `llvm21` y por eso `llvm18` —que
17# ya estaba sellado— no servía: lo usa mesa, que no soporta 21. Ver `recipes/llvm21.toml`.
18#
19# ⚠ Sin red: el tarball `-src` trae `vendor/` con todas las deps de cargo. Es la única forma de que
20# esto construya dentro del sandbox, que no tiene red después del fetch.
21name    = "rust"
22version = "1.97.0"
23license = "MIT OR Apache-2.0"
24
25[source]
26tarball = "https://static.rust-lang.org/dist/rustc-1.97.0-src.tar.xz"
27sha256  = "de002ee301c1b7422b0a7b09d7c4cb4924cd3224e6cfb24f065dad786dd3ed12"
28# El triple de Alpine, DENTRO del compilador: sin esto el stage 2 muere con «could not find
29# specification for target x86_64-alpine-linux-musl» — el nombre que el stage0 necesita es uno que
30# upstream no conoce. Es lo que hace Alpine en su APKBUILD. Ver SDD 31 §4.bis y la cabecera del
31# propio parche.
32patches = ["rust-alpine-target.patch"]
33
34[build]
35compiler = "zig-cc"
36target   = "x86_64-linux-musl"
37link     = "dynamic"
38flags    = []
39
40[deps]
41# `rust-toolchain-bin` es el STAGE0: el compilador con el que arranca el build. `llvm21` aporta el
42# `llvm-config` y las librerías. `cmake`/`samurai`/`pkgconf` los pide el propio bootstrap aunque el
43# LLVM venga hecho (compila algunas cosas nativas: `compiler-rt` para los sanitizers, jemalloc…).
44# ⚠ EL STAGE0 **NO** ES `rust-toolchain-bin`, Y ESO SE APRENDIÓ CHOCANDO. El toolchain musl oficial
45# de rust-lang está compilado con `crt-static = true`, y un rustc así **no puede producir
46# proc-macros** — que son dylibs. El primer intento murió en el primer minuto:
47#
48#     error: cannot produce proc-macro for `clap_derive v4.5.18` as the target
49#            `x86_64-unknown-linux-musl` does not support these crate types
50#
51# …compilando el PROPIO bootstrap de rustc, que usa `clap` con derive. O sea: el prebuilt oficial
52# sirve para compilar programas (probado: un binario que corre) y **no** para arrancar el build de
53# rustc. El stage0 es el `rustc` del LAB, que Alpine construye con soporte de dylib.
54#
55# Y por eso abajo va `crt-static = false` para el host: sin eso, el rustc que salga de acá heredaría
56# el mismo defecto y no podría compilar ni una receta del corpus que use `derive`.
57build = ["llvm21", "cmake", "samurai", "python3", "pkgconf", "curl", "openssl-threads"]
58
59# ⚠⚠ `lld = true` EN EL `[rust]` DE ARRIBA NO SE PUEDE, y lo dice el propio bootstrap en una línea:
60#
61#     Cannot enable LLD with `rust.lld = true` when using external llvm-config.
62#
63# O sea: que el toolchain se construya su propio `rust-lld` está CERRADO mientras usemos el `llvm21`
64# del corpus — y usar el nuestro es justamente lo que queremos. Leí el paso `Lld` del bootstrap (que
65# compila desde el `src/llvm-project/lld` del tarball y reusa el `llvm-config` externo) y me faltó
66# mirar la VALIDACIÓN de config, que rechaza la combinación antes de llegar a ese paso. La guarda
67# tiene sentido: LLD y LLVM comparten ABI de C++ y con un llvm-config externo no se puede garantizar
68# que casen.
69#
70# ⇒ El enlazador entra por el otro lado: `recipes/lld21.toml` construye el MISMO `lld`, del mismo
71# `llvm-project`, contra el `llvm21` ya sellado. Se usa con `-C linker-flavor=ld.lld`.
72#
73# ⚠ Y el comentario va ACÁ y no adentro del heredoc de `bootstrap.toml` a propósito: ese texto es
74# parte de la fase, o sea **entrada de hash**. Explicar algo ahí adentro re-sella el compilador
75# entero — hora y media de granja por un párrafo.
76[build.phases]
77# El fichero de configuración de x.py se llama `bootstrap.toml` desde 1.8x; se escribe también
78# `config.toml` porque el nombre viejo sigue siendo el que busca media documentación, y un fichero
79# de más no cuesta nada mientras el de verdad esté.
80configure = '''
81cat > bootstrap.toml <<'CFG'
82profile = "dist"
83change-id = "ignore"
84
85[build]
86# ⚠⚠ EL TRIPLE ES EL DE ALPINE, `x86_64-alpine-linux-musl`, Y NO EL CANÓNICO. Cuesta dos fallos
87# seguidos entenderlo:
88#   · Sin decir `build`, x.py detecta el del `cc` del sandbox (el de Alpine) y entonces una sección
89#     `[target.x86_64-alpine-linux-musl]` **no aplica a nada**: ignora el `llvm-config` externo y se
90#     pone a construir LLVM él solo — se vio porque entró en `/src/build/x86_64-alpine-linux-musl/`.
91#   · Y al forzar el canónico, el stage0 del LAB **no tiene la std de ese triple**:
92#     `error[E0463]: can't find crate for std`. Alpine RENOMBRA el triple, y su rustc sólo trae la
93#     std del suyo.
94# Así que se usa el de Alpine en todas partes, que además es el triple con el que ya se compila todo
95# el corpus. Es el mismo camino que toma el APKBUILD de rust de Alpine.
96build = "x86_64-alpine-linux-musl"
97docs = false
98extended = true
99# ⚠ `rustdoc` ENTRA (2026-09-18). Antes iba sólo `cargo`, y el artefacto salía con
100# `cargo rustc rust-gdb rust-gdbgui rust-lldb` y **sin rustdoc**: o sea que en una caja takana
101# `cargo doc` no existe. Para una distro que ENVÍA un toolchain de Rust es un hueco de la misma
102# familia que las proc-macros que no enlazaban: todo presente, y una cosa que la gente hace a
103# diario, imposible. Lo levantó el agente que trabaja enjaulado.
104# `docs = false` se QUEDA: eso construye la documentación de la `std` —cientos de MB y mucho rato— y
105# es otra decisión. Esto agrega sólo la HERRAMIENTA, para documentar el código de uno.
106# Radio medido antes de tocar: `yupana radio rust` da 0 dependientes de build; toca la imagen
107# `servidor`, que es re-ensamblar, no reconstruir.
108tools = ["cargo", "rustdoc"]
109local-rebuild = true
110# Hay que NOMBRAR el stage0 aunque ya esté en el PATH: sin estas dos líneas, x.py se salta el
111# compilador local y va a DESCARGAR el toolchain de `static.rust-lang.org` — que en un sandbox sin
112# red muere con un `RuntimeError: failed verification` en `download_toolchain()`, un mensaje que no
113# menciona ni la red ni el stage0. Estas rutas son las del LAB, no las del prebuilt (ver arriba).
114rustc = "/usr/bin/rustc"
115cargo = "/usr/bin/cargo"
116target = ["x86_64-alpine-linux-musl"]
117host = ["x86_64-alpine-linux-musl"]
118vendor = true
119
120[llvm]
121download-ci-llvm = false
122link-shared = false
123
124[rust]
125channel = "stable"
126codegen-tests = false
127deny-warnings = false
128musl-root = "/usr"
129# ⚠ `rpath = false` es la pareja de haber puesto `ld.lld` como enlazador en el spec del triple.
130# Con el enlazador INVOCADO DIRECTO (sin driver de C), los `-Wl,…` que el bootstrap añade para el
131# rpath de sus propios binarios llegan tal cual a lld, que no los entiende:
132#
133#     ld.lld: error: unknown argument '-Wl,-z,origin'
134#     ld.lld: error: unknown argument '-Wl,-rpath,$ORIGIN/../lib'
135#
136# …y muere compilando `std`. El rpath sobra igual: con `prefix = "/usr"` las librerías quedan en
137# `/usr/lib`, que YA está en el camino del cargador. Es lo que hacen las distros que empaquetan rust.
138rpath = false
139
140[install]
141# ⚠ SIN ESTO EL TOOLCHAIN QUEDA FUERA DEL PATH, y es la trampa de «existe ≠ se encuentra»: el
142# default de x.py es `/usr/local`, y el PATH de una caja takana es `/bin:/usr/bin:/sbin:/usr/sbin`
143# — medido en la caja de producción. O sea que el perfil proyectaría un `rustc` perfecto que nadie
144# puede invocar. El resto del corpus instala en `/usr`; esto se alinea.
145prefix = "/usr"
146
147[target.x86_64-alpine-linux-musl]
148llvm-config = "/usr/bin/llvm-config"
149# El ENLAZADOR es `gcc`, no `ld.lld` directo. Tres intentos fueron persiguiendo síntomas de lo
150# mismo: `-lgcc` no se encuentra, después `-lgcc_s` y `-lc` en los build scripts del stage2. La
151# causa única es que **un enlazador invocado sin driver de C no conoce los caminos del sistema**:
152# ese `-L /usr/lib`, el directorio privado de gcc y las libs implícitas las agrega `gcc`, no `ld`.
153# Dárselos a mano es una lista sin fondo —cada etapa del bootstrap enlaza cosas distintas— y encima
154# `RUSTFLAGS_BOOTSTRAP`/`_NOT_BOOTSTRAP` NO llegaron a los build scripts: se comprobó mirando el
155# renglón de enlace, donde el `-L /usr/lib` no aparecía.
156# Con `gcc` de driver, además, los `-Wl,-rpath,…` del bootstrap vuelven a ser válidos (eran lo que
157# obligó a `rpath = false`, que se deja igual porque sigue siendo lo correcto para un prefijo /usr).
158linker = "gcc"
159# `false` a propósito: habilita dylibs, y sin dylibs no hay PROC-MACROS. Un rustc con
160# `crt-static = true` no puede compilar `serde_derive`, `clap_derive` ni ninguna de las 44 recetas
161# `cargo-*` del corpus que usan `derive`.
162crt-static = false
163CFG
164cp bootstrap.toml config.toml
165# La versión del stage0 se COMPRUEBA, no se asume: `local-rebuild` sólo es correcto si el compilador
166# de arranque es exactamente esta versión, y si alguien mueve el pin de `rust-toolchain-bin` esto
167# tiene que fallar acá y no tres horas después.
168rustc --version | grep -q '1[.]97[.]0' || { echo "stage0 NO es 1.97.0: $(rustc --version)" >&2; exit 1; }
169llvm-config --version
170
171'''
172# `CC`/`CXX` de GCC para los build scripts nativos (jemalloc, compiler-rt): con el wrapper de zig,
173# cmake declara el compilador «broken» en su prueba de ABI. Mismo motivo por el que `llvm21` y
174# `cmake` usan g++ en vez de zig.
175# ── EL OPENSSL DE CARGO, Y POR QUÉ ES LA VARIANTE CON THREADS ──────────────────────────────────
176# `tools = ["cargo"]` arrastra `openssl-sys`, que sin openssl en el lab corta con «The system library
177# `openssl` required by crate `openssl-sys` was not found» — y eso pasa DESPUÉS de compilar las 400
178# crates del compilador, o sea a la hora y media de build.
179#
180# La dep es `openssl-threads` y NO la canónica, aunque las dos publiquen sólo `.a`: el `Configure` de
181# openssl **apaga los threads en cuanto ve `-static` en LDFLAGS**, y la canónica se construye así. Un
182# cargo —que es masivamente multihilo— enlazado contra un openssl sin soporte de hilos es la clase de
183# fallo que no se ve al construir ni al arrancar. La variante existe por lo mismo para `python3`.
184#
185# `OPENSSL_STATIC`/`OPENSSL_DIR`: el lab publica `.a` y ningún `.so`, y sin decírselo `openssl-sys`
186# busca la dinámica y falla con un mensaje que habla de pkg-config y no de eso.
187# ⚠⚠ DOS COSAS QUE COSTARON UN INTENTO CADA UNA (worker, 2026-09-17).
188#
189# 1. **`-lgcc` no se encuentra.** Es la otra cara de invocar `ld.lld` DIRECTO (ver `rpath = false`
190#    arriba): el build muere a los 6 minutos enlazando `libstd.so` con
191#
192#        ld.lld: error: unable to find library -lgcc
193#        error: could not compile `std` (lib)
194#
195#    `libgcc_s.so` sí está en /usr/lib —por eso `-lgcc_s` pasa y sólo falla el estático—, pero
196#    `libgcc.a` vive en el directorio privado de gcc, que un enlazador SIN driver de C no tiene por
197#    qué conocer: ese `-L` lo agrega `gcc`, no `ld`. El renglón que falla ya busca en `/usr/lib`,
198#    así que basta con dejarla ahí. La ruta sale de `gcc -print-libgcc-file-name` y NO escrita a
199#    mano: la versión (hoy 15.2.0) es del LAB, que no entra en `hash_inputs`, y una ruta literal se
200#    rompería en silencio el día que el lab cambie de gcc.
201#
202# 2. **Y va acá, no en `configure`, porque LAS FASES NO COMPARTEN SISTEMA DE FICHEROS.** Cada fase
203#    es un `bwrap` nuevo con `--tmp-overlay /`: una capa tmpfs DESCARTABLE. El primer arreglo hizo
204#    el enlace en `configure` y lo comprobó ahí mismo — la comprobación dio ✓ y el enlace se
205#    evaporó antes de `compile`. El log lo mostraba con una claridad cruel:
206#
207#        rust: libgcc.a enlazada desde /usr/lib/gcc/x86_64-alpine-linux-musl/15.2.0/libgcc.a
208#        …
209#        ld.lld: error: unable to find library -lgcc
210#
211#    Un guardián que comprueba en la misma fase en la que escribe confirma algo que ya no será
212#    cierto cuando importe. Lo que cambia el entorno de una fase se hace EN esa fase.
213#
214# 3. **Y con `-lgcc` resuelto aparece el siguiente, más adentro**: los BUILD SCRIPTS del stage2
215#    (`libc`, `proc-macro2`, `quote`) mueren con
216#
217#        ld.lld: error: unable to find library -lgcc_s
218#        ld.lld: error: unable to find library -lc
219#
220#    Mirando el renglón de enlace entero, esos `-L` son sólo sus propios directorios de build: **no
221#    lleva `/usr/lib`**. El enlace de `std` sí lo llevaba —de ahí `musl-root = "/usr"`— pero eso
222#    aplica al TARGET, no a los binarios de host que el bootstrap compila por el camino. Otra vez lo
223#    mismo: sin driver de C, nadie agrega los caminos del sistema. Probé dárselos por `RUSTFLAGS`
224#    (`_BOOTSTRAP` y `_NOT_BOOTSTRAP`) y **no llegaron**: el renglón de enlace seguía sin `/usr/lib`.
225#    Ahí paré de tapar síntomas: la cura está en el `[target…]` de `bootstrap.toml` —`linker = "gcc"`—
226#    y se explica allá. El `ln -sf` de `libgcc.a` de acá abajo queda como cinturón: con gcc de driver
227#    ya no hace falta, pero no estorba y documenta dónde vive esa librería.
228compile = "LIBGCC=$(gcc -print-libgcc-file-name) && ln -sf \"$LIBGCC\" /usr/lib/libgcc.a && export CC=gcc CXX=g++ AR=ar RANLIB=ranlib OPENSSL_STATIC=1 OPENSSL_DIR=/usr && python3 x.py build --stage 2"
229install = "LIBGCC=$(gcc -print-libgcc-file-name) && ln -sf \"$LIBGCC\" /usr/lib/libgcc.a && export CC=gcc CXX=g++ AR=ar RANLIB=ranlib OPENSSL_STATIC=1 OPENSSL_DIR=/usr && DESTDIR=/out python3 x.py install --stage 2"