diff --git a/docs/state/targets.toml b/docs/state/targets.toml index 5dfcc287..237b4391 100644 --- a/docs/state/targets.toml +++ b/docs/state/targets.toml @@ -32,6 +32,14 @@ paquetes = [ "iproute2", "iputils", "dhcpcd", "e2fsprogs", "dosfstools", "parted", "rsync", "sed", "tzdata", "vim", "dbus", "ca-certificates", "gnupg", "lsof", "strace", "pciutils", "usbutils", "mandoc", + # `musl-shared` (2026-09-11): EL CARGADOR DINÁMICO. Va en `base` y no en un perfil concreto porque + # sin él cualquier binario dinámico de la clausura queda INERTE — presente y sin poder ejecutarse. + # Medido en la imagen del perfil `servidor`: **23 binarios de 726** pedían + # `/lib/ld-musl-x86_64.so.1` y NINGÚN artefacto del corpus lo publicaba; funcionaban en el hub sólo + # porque el rootfs Alpine del LAB lo presta. Entre ellos, `python3` y `perl` — o sea TODO el + # instrumental del proyecto. El síntoma era `sh: python3: not found` con `command -v python3` + # contestando `/usr/bin/python3`: no falta, no arranca. Ver SDD 28 §6.4. + "musl-shared", ] [perfil.cli] diff --git a/recipes/musl-shared.toml b/recipes/musl-shared.toml new file mode 100644 index 00000000..f9056956 --- /dev/null +++ b/recipes/musl-shared.toml @@ -0,0 +1,68 @@ +# musl-shared 1.2.5 — variante DINÁMICA de musl: el CARGADOR y `libc.so`. +# +# ── POR QUÉ EXISTE ────────────────────────────────────────────────────────────────────────────── +# El musl canónico (`recipes/musl.toml`) es `--disable-shared`: emite headers, `libc.a` y los +# `crt*.o`, que es lo que quiere el enlace estático del corpus. Su comentario decía que el artefacto +# aportaba «el loader, para uso dinámico futuro» — y era FALSO: con `--disable-shared` musl no +# construye ni `libc.so` ni `ld-musl-x86_64.so.1`. Corregido allá; acá está el loader de verdad. +# +# ── EL AGUJERO QUE TAPA, MEDIDO (2026-09-10, SDD 28 §6.4) ─────────────────────────────────────── +# La imagen del `perfil.servidor` traía **23 binarios que no podían correr**: +# +# $ python3 -c "print(1)" +# sh: python3: not found ← y `command -v python3` decía /usr/bin/python3 +# +# No faltaban: eran ELF DINÁMICOS pidiendo `/lib/ld-musl-x86_64.so.1`, y **ningún artefacto del +# corpus publicaba ese fichero**. Funcionaban en el hub sólo porque el rootfs Alpine del LAB lo +# presta (`.dev-fs/alpine/lib/ld-musl-x86_64.so.1`) — la misma fuga de soberanía que documentan +# `zlib-shared` y `expat-shared`, un piso más abajo, y con el agravante de que el lab NO entra en +# `hash_inputs`: la dependencia era invisible para el store. +# +# Los 23: la suite `binutils` entera (ar as ld nm objcopy objdump ranlib readelf strip addr2line +# c++filt elfedit gprof size ld.bfd) más `perl`, `python3`, `sqlite3`, `flex` y `nft`. Entre ellos +# está TODO el instrumental del proyecto, que es Python. +# +# ── POR QUÉ UNA VARIANTE Y NO `--enable-shared` EN LA CANÓNICA ────────────────────────────────── +# `musl` es componente de **Stage 1** (musl + busybox + hammerd + arje-zero) y su `of_tree` es el +# baseline de `selfhost-verify.sh`. Re-hashearlo obliga a rehacer ese baseline A PROPÓSITO, y eso es +# su propia unidad de trabajo, no algo que se arrastra de rebote. El patrón `*-shared` deja la +# canónica intacta: el nombre es DISTINTO, así que conviven en el mismo store y cada consumidor toma +# la que necesita. Mismo criterio que zlib-shared / expat-shared / ncurses-shared. +# +# ⚠ Y no es dep de nadie: medido, `musl` no aparece en el `[deps]` de ninguna receta del corpus +# (sólo la suya). El enlace estático lo resuelve el musl que trae zig. Por eso esta variante suma +# sin mover un solo ArtifactHash. + +name = "musl-shared" +version = "1.2.5" +license = "MIT" + +[source] +tarball = "https://musl.libc.org/releases/musl-1.2.5.tar.gz" +sha256 = "a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4" + +[build] +# ⚠ `gcc` Y NO `zig-cc`, y es MEDIDO. Con zig cc el `libc.so` sale con 1586 símbolos dinámicos +# contra los 1654 del musl de Alpine, y los 68 que faltan son EXACTAMENTE los que musl implementa en +# ensamblador x86_64 —`memset`, `memcpy`, `memmove`, `memcmp`, `strlen` y toda la familia matemática +# (`ceil floor sqrt fmod exp log sin cos tan fma round trunc`)— más los `__stack_chk_*`. +# +# No es que no se compilen: en el `libc.a` del musl canónico están. Lo que pasa es que zig los +# RESUELVE CON SU PROPIO musl y los deja ocultos — medido: `memset` aparece como +# `FUNC LOCAL HIDDEN` de tamaño 0, así que no entra en la tabla dinámica. El resultado es un +# cargador que arranca, empieza a relocar y muere con `memset: symbol not found`, que se lee como +# "el binario está roto" y no como "a la libc le faltan símbolos". +compiler = "gcc" +target = "x86_64-linux-musl" +link = "dynamic" + +[deps] +build = ["make"] + +[build.phases] +# `--enable-shared` produce `libc.so`; `make install` lo pone en `/usr/lib/libc.so` y crea el +# cargador en `$syslibdir` (`/lib/ld-musl-x86_64.so.1`), que es literalmente el mismo fichero: en +# musl el loader Y la libc son el mismo objeto. +configure = "./configure --prefix=/usr --syslibdir=/lib --enable-shared --disable-static" +compile = "make -j\"$(nproc)\"" +install = "make DESTDIR=/out install" diff --git a/recipes/musl.toml b/recipes/musl.toml index 6eb2807e..92fb8c6d 100644 --- a/recipes/musl.toml +++ b/recipes/musl.toml @@ -1,8 +1,14 @@ # musl libc 1.2.5 — libc del target para el userland mínimo del Stage 1 (SDD 11 §3). # -# Se compila estática con `zig cc` cross al target. El artefacto aporta headers + libc.a (y el -# loader, para uso dinámico futuro) al rootfs sellado. Tarball release pinned por sha256: igual de -# fuerte que un commit git para reproducibilidad (ADR 0006). +# Se compila estática con `zig cc` cross al target. El artefacto aporta headers + libc.a + los +# `crt*.o`. Tarball release pinned por sha256: igual de fuerte que un commit git para +# reproducibilidad (ADR 0006). +# +# ⚠ ANTES ESTE COMENTARIO DECÍA «y el loader, para uso dinámico futuro». Era FALSO y costó caro: con +# `--disable-shared` musl NO construye `libc.so` ni `ld-musl-x86_64.so.1`, así que el corpus no +# publicaba ningún cargador dinámico y los 23 binarios dinámicos de una imagen quedaban INERTES +# (SDD 28 §6.4). El loader vive ahora en `recipes/musl-shared.toml`; esta receta sigue siendo +# estática pura, que es lo que Stage 1 necesita. name = "musl" version = "1.2.5"