las proc-macros SÍ se pueden compilar en la caja: falta un cc, no un parche

Con rust sellado, la caja compila estáticos sin tocar nada, pero ninguna dylib —y eso incluye todas
las proc-macros—. El `-L /usr/lib` obvio EMPEORA las cosas: rompe los estáticos, porque rustc enlaza
musl static-PIE con su copia self-contained y ese camino le hace preferir la libc.a del sistema, que
no es PIC. Cuatro controles lo aíslan y el error nombra al culpable (`__malloc_size_classes`). O sea
que ningún RUSTFLAGS global sirve: apaga un caso y enciende el otro.

Quien distingue los dos casos es un driver de C. La caja no tiene gcc ni clang —clang18 en el store
son sólo cabeceras—, pero sí tiene zig: el artefacto seed-zig del bootstrap trae zig 0.16.0 y corre.
Con `cc → zig cc` y `-C linker=cc -C linker-flavor=gcc -C link-self-contained=no` la cadena completa
funciona: la proc-macro enlaza, el programa que la usa compila e imprime, y el estático sigue bien.
Las tres banderas son necesarias; la variante fina `=-linker` es inestable en este triple.

Lo que queda es una decisión, no trabajo: seed-zig no tiene receta —es producto del bootstrap—, y
volverlo el `cc` del sistema es elegir el compilador de C de la distro.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-09-18 10:08:11 +00:00
co-authored by Claude Opus 5
parent 67e61583fe
commit a170885357
+74
View File
@@ -3159,6 +3159,80 @@ En la caja, hidratado y con la reescritura a SSH **apagada**, `git clone https:/
Las reescrituras `url.insteadOf` quedaron **retiradas** de la caja: ya no hacen falta.
`scripts/servidor/fuentes-por-ssh.sh` se conserva como salida de emergencia, no como el camino normal.
### 6.52 🧩 Las proc-macros SÍ se pueden compilar en la caja — falta un `cc`, no un parche *(2026-09-18)*
Con `rust` sellado, la caja compila y corre binarios **estáticos** sin tocar nada. Lo que no compilaba
es cualquier **dylib**, y eso incluye **todas las proc-macros** (`serde_derive`, `clap_derive`…), o sea
media ecología de Rust:
```
ld.lld: error: unable to find library -lgcc_s
ld.lld: error: unable to find library -lc
```
#### Por qué el `-L` obvio empeora las cosas
La reacción natural es darle el camino: `-L /usr/lib`. **Y eso rompe los estáticos**, que hoy
funcionan. Cuatro controles lo aíslan:
| | enlace | resultado |
|---|---|---|
| A | estático, sin `-L` | ✅ enlaza — es lo que hay hoy |
| B | estático, con `libgcc.a` a la vista | ✅ enlaza — el arreglo de `gcc-libs` no rompe nada |
| C | estático, con `-L /usr/lib` + `libgcc.a` | ❌ rompe |
| D | estático, **sólo** con `-L /usr/lib` | ❌ rompe ← la culpable |
```
ld.lld: error: relocation R_X86_64_32S cannot be used against symbol '__malloc_size_classes';
recompile with -fPIC ← sale de /usr/lib/libc.a, que NO es PIC
```
rustc enlaza musl **static-PIE** con su copia *self-contained*; meter `/usr/lib` en el camino le hace
preferir la `libc.a` del sistema, que no sirve para PIE. **El camino de librerías no puede ser
global: el estático lo quiere fuera y el dinámico lo quiere dentro.** Ningún `RUSTFLAGS` global
arregla esto — apaga un caso y enciende el otro.
#### Lo que sí funciona, medido de punta a punta
Quien sabe distinguir los dos casos es un **driver de C**. La caja no tiene `gcc` ni `clang`
—`clang18` en el store son sólo cabeceras y librerías, sin binario— **pero sí tiene `zig`**: el
artefacto `seed-zig` del bootstrap trae `zig 0.16.0` y **corre**. `zig cc` es un driver de C completo
con musl adentro.
```
cc → zig cc
RUSTFLAGS → -C linker=cc -C linker-flavor=gcc -C link-self-contained=no
```
Las tres banderas hacen falta y cada una por su motivo: `linker`+`linker-flavor` para que el enlace
pase por el driver, y `link-self-contained=no` porque si no rustc pide su propio `rust-lld` —que este
toolchain **no tiene**, ya que `rust.lld = true` es incompatible con el `llvm-config` externo (§ la
receta lo documenta)— y muere con *«the self-contained linker was requested… it wasn't found»*.
⚠ La variante fina `-C link-self-contained=-linker` **no sirve**: es inestable en este triple y exige
`-Z unstable-options`. La gruesa, `=no`, es estable.
Con eso, la cadena completa que nunca había compilado:
```
1. la proc-macro ⇒ libpm.so
2. el programa que la usa ⇒ imprime «PROC-MACRO VIVA»
3. y el estático de siempre ⇒ sigue enlazando
```
#### Lo que falta es una DECISIÓN, no trabajo
`seed-zig` **no tiene receta en `recipes/`**: es un producto del bootstrap (SDD 11), como
`stage1-rootfs`. Convertirlo en el `cc` del sistema es elegir el compilador de C de la distro, y eso
se decide, no se hace de paso. Las opciones, honestas:
- **receta `zig` + `/usr/bin/cc`** — pinear el tarball de zig por sha256 y envolverlo. Da un driver de
C de verdad a cualquier caja takana, útil mucho más allá de Rust.
- **dejarlo como está y documentar las tres banderas** — cero coste, y quien compile una proc-macro
tiene que saberlas.
Mientras no se decida, **lo medido vale igual**: la capacidad existe y está probada; lo que no hay es
el envoltorio.
### 6.51 🔥 Me dejé afuera de la caja — 20 minutos caída, y tres causas encadenadas *(2026-09-17)*
Crear una cuenta de usuario tiró el servidor de producción. Queda escrito entero porque **ninguna de