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 1569Shell 203Rust 109Markdown 993728 Definiciones

harness: -static cede ante TODO link dinámico (no sólo -shared)

El wrapper anterior (quita -static con -shared) destrabó la extensión Python de
g-i, pero g-i es dinámico en 3 puntos y el fallo saltó a los otros dos:
"error: using shared libraries requires dynamic linking" en (a) las tools que
linkean libgirepository-1.0.so y (b) el dumper del scanner con -Wl,--export-dynamic.

Generalizo la regla del wrapper: -static se quita ante cualquier marcador de link
dinámico — -shared, -rdynamic, --export-dynamic, o un shared object (.so/.so.N) en
la línea. Todos son casos donde -static es contradictorio de por sí. El link
estático normal (exe/.a sin marcadores) y el compile puro quedan byte-idénticos.
Verificado contra las 2 líneas reales que fallaban + 2 casos de no-regresión.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

d4eb77df1440f38018ec634f02dcaf26cac4904e · por sergio · (hace 2 meses) · padre 437d5bb10 · ver el árbol en este commit

Delta semántico · 1

crates/hammer-build/src/sandbox.rs

1 archivos · +21 −12

diff --git a/crates/hammer-build/src/sandbox.rs b/crates/hammer-build/src/sandbox.rs
index 3bdc9fed..c0f5f8e2 100644
--- a/crates/hammer-build/src/sandbox.rs
+++ b/crates/hammer-build/src/sandbox.rs
@@ -530,31 +530,40 @@ pub const CC_WRAPPER: &str = "hammer-zig-cc";
 pub const CXX_WRAPPER: &str = "hammer-zig-cxx";
 
 /// Materializa en el rootfs dos wrappers de linker-driver (`hammer-zig-cc`/`-cxx`) que envuelven a
-/// `zig cc`/`zig c++`. Su ÚNICO efecto es QUITAR `-static` cuando el link también lleva `-shared`.
+/// `zig cc`/`zig c++`. Su ÚNICO efecto es QUITAR `-static` cuando el link REQUIERE enlace dinámico.
 ///
 /// El harness inyecta `LDFLAGS=-static` para las recetas `link=static` (binario monolítico que pide
-/// la hidratación primaria). Pero meson/autotools aplican ese LDFLAGS a TODOS los targets por igual,
-/// incluidas las extensiones Python (`python.extension_module` → `shared_module`): un `.so` que el
-/// intérprete del sandbox debe `dlopen`. `-static` + `-shared` es contradictorio ⇒ el `.so` sale
-/// ET_EXEC y `dlopen` da `Exec format error` (el muro de gobject-introspection: `_giscanner.so`).
+/// la hidratación primaria). Pero meson/autotools/giscanner aplican ese LDFLAGS a TODOS los links por
+/// igual, incluidos algunos que son INTRÍNSECAMENTE dinámicos y con los que `-static` es
+/// contradictorio (`error: using shared libraries requires dynamic linking`). El caso que lo destapó
+/// es gobject-introspection, dinámico por naturaleza en TRES puntos:
+///   1. `_giscanner.cpython-*.so`: extensión Python (`shared_module`) que el intérprete `dlopen`ea.
+///      Con `-static` sale ET_EXEC ⇒ `dlopen` da `Exec format error`.
+///   2. las tools (`g-ir-compiler`/`-generate`/`-inspect`) linkean la `libgirepository-1.0.so`.
+///   3. el "dumper" del scanner usa `-Wl,--export-dynamic` (necesita la symtab dinámica para
+///      introspectar GTypes en runtime) — incompatible con `-static`.
 ///
-/// Quitar `-static` SÓLO cuando hay `-shared` es correcto por construcción: un objeto compartido
-/// nunca debe ser estático. Para todo link normal (ejecutable/`.a`) el wrapper es transparente ⇒
-/// byte-idéntico a `zig cc`. El ArtifactHash se deriva de inputs (receta+deps), no de los bytes ⇒
-/// este cambio NO re-hashea nada sellado; sólo destraba builds nuevos con extensiones dinámicas.
+/// Regla principista: **`-static` cede ante cualquier link que requiera dinámico** — `-shared`,
+/// `--export-dynamic`/`-rdynamic`, o un objeto compartido (`.so`/`.so.N`) en la línea. En todos esos
+/// casos `-static` no puede sostenerse; quitarlo es correcto por construcción. Para el link normal
+/// (ejecutable estático / `.a`) el wrapper es TRANSPARENTE ⇒ byte-idéntico a `zig cc`, y el resto del
+/// árbol sigue estático. El ArtifactHash se deriva de inputs (receta+deps), no de los bytes ⇒ este
+/// cambio NO re-hashea nada sellado; sólo destraba builds nuevos con enlace dinámico irreducible.
 fn write_cc_wrappers(rootfs: &Path) -> hammer_core::Result<()> {
     use std::os::unix::fs::PermissionsExt;
     let bindir = rootfs.join("usr/local/bin");
     std::fs::create_dir_all(&bindir).map_err(|e| {
         hammer_core::Error::Other(anyhow::anyhow!("no pude crear {}: {e}", bindir.display()))
     })?;
-    // `case " $* "` detecta `-shared` como palabra completa; el bucle rota los positional params
-    // (pop del frente, push al fondo salvo `-static`) ⇒ filtra preservando orden y seguro con espacios.
+    // `case " $* "` detecta como palabra los marcadores de "este link es dinámico": -shared,
+    // -rdynamic, --export-dynamic, o un shared object en la línea (`…​.so ` final o `…​.so.N` versionado).
+    // El bucle rota los positional params (pop del frente, push al fondo salvo `-static`) ⇒ filtra
+    // preservando orden y seguro con espacios.
     let body = |driver: &str| {
         format!(
             "#!/bin/sh\n\
              case \" $* \" in\n\
-             \x20 *\" -shared \"*)\n\
+             \x20 *\" -shared \"* | *\" -rdynamic \"* | *\"--export-dynamic\"* | *\".so \"* | *\".so.\"*)\n\
              \x20   n=$#\n\
              \x20   while [ \"$n\" -gt 0 ]; do\n\
              \x20     arg=$1; shift\n\