Etapa G: gueto gcc para build-scripts de crates Rust con dep-C (frente sistematico)

La granja revelo una clase entera de fallos Rust: crates con dep-C cuyo build-script
(cc-rs) compila C con zig-cc, que lo RECHAZA/miscompila (delta=libgit2-sys,
gitui=openssl-sys, jless=libc-stdhandle). Mismo frente que file/jq en C puro -> misma
solucion: el GUETO gcc.

FIX (hammer-build/lib.rs, camino Cargo nativo): cuando la receta declara compiler="gcc",
cc-rs usa CC=gcc (el Alpine musl gcc del sandbox, probado en C) para compilar el C de
las deps; el LINKER sigue siendo el wrapper zig-cc. Los .o/.a de gcc-musl y el Rust
zig-musl son ABI-compatibles (ambos musl, mismo ELF x86-64). ADITIVO: una receta Rust
sin compiler= queda en ZigCc -> baseline (ripgrep/fd/...) intacto. 2 tests nuevos.

PROBADO END-TO-END: delta 0.19.2 construye+corre ELF estatico (libgit2-sys vendorea y
compila libgit2 desde decenas de .c con gcc; + dep zlib para -lz que libgit2/libz-sys
enlazan). Publicado al repo firmado (83 paquetes). Corpus 82->83.

LEVERAGE: libgit2-sys/openssl-sys/onig_sys/libc-stdhandle aparecen en CIENTOS de crates
-> el gueto gcc (+ resolver libs externas via deps.build) destraba esa clase entera, no
solo delta. jless queda staged (su feature de clipboard pide libxcb/X11, fuera de
alcance, NO toolchain). gitui (openssl-src vendoreado) deberia construir con el mismo
patron (compiler=gcc), pendiente de correr.
This commit is contained in:
2026-06-21 14:27:16 -04:00
parent 70be258ccd
commit 7c1a2ac8d5
4 changed files with 76 additions and 3 deletions
+40 -1
View File
@@ -539,6 +539,19 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result<Phases> {
// (i.e. un rust vanilla como el hammer-rust del frente self-host); para Alpine,
// omitirlo. RUSTFLAGS alcanza a todas las unidades; los `bin_flags` (cargo rustc
// --) sólo a la top.
// CC para los build-scripts (cc-rs compila el C de deps como libgit2-sys,
// openssl-sys, libc-stdhandle). Por defecto = el wrapper zig-cc. PERO zig-cc
// MISCOMPILA/RECHAZA muchos de esos C (mismo frente que file/jq en C puro: la
// granja lo reveló — delta/gitui/jless mueren ahí). Con `compiler="gcc"` la receta
// declara el GUETO: cc-rs usa gcc (el Alpine musl gcc del sandbox, probado en C),
// y el linker sigue siendo zig-cc — los .o/.a de gcc-musl y el Rust zig-musl son
// ABI-compatibles (ambos musl, mismo ELF x86-64). Aditivo: una receta Rust sin
// `compiler=` queda en ZigCc ⇒ baseline (ripgrep/fd/…) intacto.
let cc_for_scripts = match recipe.build.compiler {
Compiler::Gcc => "gcc",
Compiler::Clang => "clang",
Compiler::ZigCc => "$PWD/.hammer-zig-cc",
};
Some(format!(
"printf '%s\\n' '#!/bin/sh' 'for a do' \
'case \"$a\" in --target=*) a=--target=x86_64-linux-musl ;; esac' \
@@ -546,7 +559,7 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result<Phases> {
> \"$PWD/.hammer-zig-cc\" && chmod +x \"$PWD/.hammer-zig-cc\" && \
RF=\"-C linker=$PWD/.hammer-zig-cc\"; \
rustc -vV | grep -q 'host: .*-alpine-' || RF=\"$RF -C link-self-contained=no\"; \
CC=\"$PWD/.hammer-zig-cc\" RUSTFLAGS=\"$RF\" \
CC=\"{cc_for_scripts}\" RUSTFLAGS=\"$RF\" \
cargo rustc --release --locked --offline{flags_suffix} -- {bin_flags}"
))
} else {
@@ -728,6 +741,32 @@ commit = "deadbeef"
assert!(i.contains("find target/release"), "nativo instala de target/release ({i})");
}
#[test]
fn cargo_gcc_ghetto_uses_gcc_for_build_scripts() {
// Receta Rust con `compiler="gcc"`: el GUETO para crates con dep-C (libgit2-sys/openssl-sys/
// libc-stdhandle) que zig-cc rechaza. cc-rs debe usar gcc (CC=gcc), pero el LINKER sigue
// siendo el wrapper zig-cc (objetos gcc-musl + Rust zig-musl son ABI-compatibles).
let d = tempfile::tempdir().unwrap();
touch(d.path(), "Cargo.toml");
let mut r = recipe(&[]);
r.build.compiler = Compiler::Gcc;
let c = resolve_phases(&r, d.path()).unwrap().compile.unwrap();
assert!(c.contains("CC=\"gcc\""), "cc-rs usa gcc en el gueto ({c})");
assert!(!c.contains("CC=\"$PWD/.hammer-zig-cc\""), "CC ya no es el wrapper ({c})");
// El linker NO cambia: sigue el wrapper zig-cc.
assert!(c.contains("RF=\"-C linker=$PWD/.hammer-zig-cc"), "linker sigue zig-cc ({c})");
assert!(c.contains("cargo rustc --release"), "sigue el camino cargo nativo ({c})");
}
#[test]
fn cargo_default_compiler_keeps_zig_cc_for_build_scripts() {
// Sin `compiler=` (default ZigCc): CC sigue siendo el wrapper — baseline ripgrep/fd intacto.
let d = tempfile::tempdir().unwrap();
touch(d.path(), "Cargo.toml");
let c = resolve_phases(&recipe(&[]), d.path()).unwrap().compile.unwrap();
assert!(c.contains("CC=\"$PWD/.hammer-zig-cc\""), "default: cc-rs usa el wrapper zig ({c})");
}
#[test]
fn cargo_cross_target_keeps_triple() {
// Un target NO nativo (cross real) sí pasa --target + el linker per-triple.
+29
View File
@@ -0,0 +1,29 @@
# Importada de nixpkgs por `hammer import-nix` (Etapa G). PUNTO DE PARTIDA, no final:
# - el build usa el lab de hammer (zig-cc / musl estático), NO el stdenv de nix ⇒ revisá
# compiler/link/phases y adaptá hasta que compile.
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "delta"
version = "0.19.2"
[source]
repo = "https://github.com/dandavison/delta"
commit = "1502986e81c8e3fa27bfb5b84bac6b281a6b1edd"
# GUETO gcc para los build-scripts: delta trae `libgit2-sys`, que vendorea y COMPILA libgit2 desde
# C (decenas de .c). zig-cc los rechaza (la granja lo reveló: ToolExecError en apply.c/attr_file.c/…).
# `compiler="gcc"` ⇒ cc-rs compila ese C con el Alpine musl gcc (probado en C); el linker sigue zig-cc.
[build]
compiler = "gcc"
target = "x86_64-linux-musl"
link = "static"
flags = ["--bin", "delta"]
[build.phases]
install = "mkdir -p /out/usr/bin && cp target/release/delta /out/usr/bin/delta"
# libgit2-sys y libz-sys enlazan `-lz`; el lab materializa zlib (libz.a en /usr/lib) como capa overlay.
[deps]
build = ["zlib"]
# buildInputs de nix (NO deps de hammer — cargo vendorea; backend Rust por
# defecto). Si algún sys-crate C falla, adaptá per-paquete (patch/feature): git, oniguruma
+3 -1
View File
@@ -9,8 +9,10 @@ version = "0.28.1"
repo = "https://github.com/gitui-org/gitui"
commit = "e24fb45df1584ee8d8ebdc4258531b4a91ca975d"
# GUETO gcc para build-scripts: gitui trae openssl-src (vendorea+compila openssl 3.4 desde C) +
# libgit2-sys; zig-cc los rechaza. compiler="gcc" -> cc-rs usa el Alpine musl gcc; linker zig-cc.
[build]
compiler = "zig-cc"
compiler = "gcc"
target = "x86_64-linux-musl"
link = "static"
flags = ["--bin", "gitui"]
+4 -1
View File
@@ -9,8 +9,11 @@ version = "0.9.0"
repo = "https://github.com/PaulJuliusMartinez/jless"
commit = "21dd6100edb47145bb9570931bec29697bcd0d9b"
# GUETO gcc para los build-scripts: jless trae `libc-stdhandle` (un sys-crate con un imp.c que
# cc-rs compila); zig-cc lo rechaza (mismo frente que file/jq en C puro). `compiler="gcc"` ⇒ cc-rs
# usa el Alpine musl gcc para ese C; el linker sigue zig-cc (ABI musl compatible).
[build]
compiler = "zig-cc"
compiler = "gcc"
target = "x86_64-linux-musl"
link = "static"
flags = ["--bin", "jless"]