From 41aec1704896afa6148c5edd86632ed793c87f62 Mon Sep 17 00:00:00 2001 From: sergio Date: Sun, 21 Jun 2026 08:57:05 -0400 Subject: [PATCH] =?UTF-8?q?Etapa=20G=20Fase=203:=20flags=20autotools=20$CB?= =?UTF-8?q?UILD/$CHOST=20=E2=80=94=20el=20lab=20provee=20el=20triple=20nat?= =?UTF-8?q?ivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El residuo autotools de los imports de Alpine (configure --build=$CBUILD --host=$CHOST del abuild) ya no es trabajo a mano: - El lab exporta CBUILD/CHOST con el triple nativo SANEADO (x86_64-linux-musl, el mismo que el wrapper zig-cc emite) ⇒ las fases traducidas de Alpine que referencian $CBUILD/$CHOST literal resuelven en runtime en vez de quedar vacías (config.guess detectaría x86_64-alpine-linux-musl, vendor que zig rechaza). - La heurística autotools inyecta --build/--host al triple saneado cuando la receta no los puso ya (juicio per-paquete gana). build==host ⇒ NATIVO: autotools sigue corriendo sus AC_RUN tests; sólo normaliza el triple. - Inerte para Cargo/CMake/Meson (no leen esas envs ni el triple). VALIDADO REAL: e2e autotools BUILDEA (configure 'cross compiling... no', sella+corre). 3 tests nuevos de heurística + import comment actualizado. Co-Authored-By: Claude Opus 4.8 --- crates/hammer-build/src/lib.rs | 61 +++++++++++++++++++++++++- crates/hammer-cli/src/alpine_import.rs | 7 +-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/crates/hammer-build/src/lib.rs b/crates/hammer-build/src/lib.rs index 3682913c..4a39d7b8 100644 --- a/crates/hammer-build/src/lib.rs +++ b/crates/hammer-build/src/lib.rs @@ -217,6 +217,15 @@ pub fn build( env.push(("AR".into(), "llvm-ar".into())); } } + // Autotools (Etapa G Fase 3): exporta CBUILD/CHOST con el triple nativo SANEADO del sandbox + // (`x86_64-linux-musl`, el mismo que el wrapper zig-cc emite). Las recetas importadas de Alpine + // traducen `./configure --build=$CBUILD --host=$CHOST` literal del abuild (`translate_abuild` los + // deja intactos a propósito); sin estas envs `$CBUILD/$CHOST` quedan VACÍAS y autotools cae a + // `config.guess`, que detecta `x86_64-alpine-linux-musl` — vendor que zig NO conoce + // (`UnknownOperatingSystem`). Resuelve el residuo autotools que antes era trabajo a mano. Inerte + // para Cargo/CMake/Meson (no leen estas envs). + env.push(("CBUILD".into(), SANDBOX_NATIVE_TARGET.to_string())); + env.push(("CHOST".into(), SANDBOX_NATIVE_TARGET.to_string())); if let Some(cache) = &cfg.cache_root { std::fs::create_dir_all(cache.join("zig"))?; } @@ -450,12 +459,26 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result { let flags = recipe.build.flags.join(" "); let flags_suffix = if flags.is_empty() { String::new() } else { format!(" {flags}") }; + // Autotools (Etapa G Fase 3): fija `--build`/`--host` al triple nativo saneado para que + // `config.guess` no detecte el vendor `alpine` que zig rechaza, e iguala lo que el wrapper zig-cc + // produce. Sólo si la receta no los puso ya en sus flags (juicio per-paquete gana). build==host + // ⇒ NATIVO (no cross): autotools sigue corriendo sus AC_RUN tests; sólo normaliza el triple. + let autotools_triple = if recipe.build.flags.iter().any(|f| { + f.starts_with("--build=") || f.starts_with("--host=") + }) { + String::new() + } else { + format!(" --build={SANDBOX_NATIVE_TARGET} --host={SANDBOX_NATIVE_TARGET}") + }; + if out.configure.is_none() { out.configure = match bs { BuildSys::AutoconfRaw => Some(format!( - "autoreconf -fi && ./configure --prefix=/usr{flags_suffix}" + "autoreconf -fi && ./configure --prefix=/usr{autotools_triple}{flags_suffix}" )), - BuildSys::AutoconfReady => Some(format!("./configure --prefix=/usr{flags_suffix}")), + BuildSys::AutoconfReady => { + Some(format!("./configure --prefix=/usr{autotools_triple}{flags_suffix}")) + } BuildSys::CMake => Some(format!( "cmake -S . -B _build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release{flags_suffix}" )), @@ -623,6 +646,40 @@ commit = "deadbeef" assert!(c.ends_with("--enable-foo"), "{c}"); } + #[test] + fn autotools_injects_native_triple() { + // Etapa G Fase 3: configure heurístico fija --build/--host al triple saneado. + let d = tempfile::tempdir().unwrap(); + touch(d.path(), "configure.ac"); + touch(d.path(), "configure"); + let c = resolve_phases(&recipe(&[]), d.path()).unwrap().configure.unwrap(); + assert!(c.contains("--build=x86_64-linux-musl"), "{c}"); + assert!(c.contains("--host=x86_64-linux-musl"), "{c}"); + } + + #[test] + fn autotools_triple_yields_to_recipe_flags() { + // Si la receta ya fija el triple (juicio per-paquete), no duplicamos. + let d = tempfile::tempdir().unwrap(); + touch(d.path(), "configure.ac"); + touch(d.path(), "configure"); + let c = resolve_phases(&recipe(&["--host=aarch64-linux-musl"]), d.path()) + .unwrap() + .configure + .unwrap(); + assert!(c.contains("--host=aarch64-linux-musl"), "{c}"); + assert!(!c.contains("x86_64-linux-musl"), "no inyecta si la receta ya lo puso ({c})"); + } + + #[test] + fn cmake_ignores_autotools_triple() { + // El triple es exclusivo de autotools; CMake/Meson/Cargo no lo reciben. + let d = tempfile::tempdir().unwrap(); + touch(d.path(), "CMakeLists.txt"); + let c = resolve_phases(&recipe(&[]), d.path()).unwrap().configure.unwrap(); + assert!(!c.contains("--host="), "{c}"); + } + #[test] fn detect_cmake() { let d = tempfile::tempdir().unwrap(); diff --git a/crates/hammer-cli/src/alpine_import.rs b/crates/hammer-cli/src/alpine_import.rs index 4c53c5d5..2e850925 100644 --- a/crates/hammer-cli/src/alpine_import.rs +++ b/crates/hammer-cli/src/alpine_import.rs @@ -106,7 +106,7 @@ pub fn recipe_from_apkbuild(text: &str) -> Result { let mut s = String::from("\n[build.phases]\n"); if let Some(b) = compile { let t = translate_abuild(&b, &pkgname, &version); - s.push_str(&format!("# de build() de Alpine (traducido; revisá $CBUILD/$CHOST/--shared para estático):\ncompile = {}\n", toml_multiline(&t))); + s.push_str(&format!("# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):\ncompile = {}\n", toml_multiline(&t))); } if let Some(p) = install { let t = translate_abuild(&p, &pkgname, &version); @@ -249,8 +249,9 @@ fn func_body(text: &str, name: &str) -> Option { /// Traduce las variables de abuild a su equivalente en el lab de hammer. Substituciones SEGURAS /// (inequívocas): `$pkgdir`→`/out` (el DESTDIR del lab), `$pkgname`→nombre, `$pkgver`→versión. -/// NO toca `$CBUILD/$CHOST/$srcdir/$builddir` ni `--shared` (juicio por-paquete; quedan para el -/// humano, marcados en el comentario de la fase). `make DESTDIR="$pkgdir"` → `make DESTDIR="/out"`. +/// NO toca `$CBUILD/$CHOST/$srcdir/$builddir` ni `--shared`. `$CBUILD/$CHOST` los RESUELVE el lab en +/// runtime (env con el triple nativo saneado, Etapa G Fase 3 — `hammer-build`); `$srcdir/$builddir` y +/// `--shared` quedan para el humano. `make DESTDIR="$pkgdir"` → `make DESTDIR="/out"`. fn translate_abuild(body: &str, name: &str, version: &str) -> String { body.replace("${pkgdir}", "/out") .replace("$pkgdir", "/out")