diff --git a/crates/hammer-build/src/lib.rs b/crates/hammer-build/src/lib.rs index f7ea30c7..2b3524fb 100644 --- a/crates/hammer-build/src/lib.rs +++ b/crates/hammer-build/src/lib.rs @@ -757,11 +757,23 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result { // disco tenga sitio. /src es el árbol de fuentes bind-montado (en disco) y no se sella // (sólo /out) ⇒ inocuo. GOTMPDIR debe pre-existir. No entra al hash de input (es la // fase generada, no un campo de la receta) ⇒ no re-sella el corpus Go. + // CGO opt-in (recipe `cgo = true`): drivers con C bundled (sqlite3 de mattn en + // usql/sq/dolt) necesitan cgo. CC="zig cc" (musl nativo del sandbox) + link estático + // por el linker externo (`-linkmode=external -extldflags=-static`). Default: CGO off + // (Go puro estático). Validado: usql (sqlite, estático y corre). + let (cgo_env, ldflags) = if recipe.build.cgo { + ( + "CGO_ENABLED=1 CC=\"zig cc\" CXX=\"zig c++\"", + "-ldflags=\"-buildid= -linkmode=external -extldflags=-static\"", + ) + } else { + ("CGO_ENABLED=0", "-ldflags=-buildid=") + }; Some(format!( "export GOCACHE=/src/.gocache GOTMPDIR=/src/.gotmp GOPATH=/tmp/gopath \ - GOTOOLCHAIN=local CGO_ENABLED=0 GOFLAGS=-mod=vendor GOPROXY=off \ + GOTOOLCHAIN=local {cgo_env} GOFLAGS=-mod=vendor GOPROXY=off \ GOBIN=/out/usr/bin; mkdir -p /src/.gotmp; \ - go install -trimpath -ldflags=-buildid= {pkg}" + go install -trimpath {ldflags} {pkg}" )) } BuildSys::Unknown => None, @@ -837,6 +849,20 @@ commit = "deadbeef" assert_eq!(p.install.as_deref(), Some("true")); } + #[test] + fn go_cgo_knob_switches_compile_env() { + // cgo=false (default) ⇒ CGO_ENABLED=0, Go puro; cgo=true ⇒ CGO_ENABLED=1 + CC zig + estático. + let d = tempfile::tempdir().unwrap(); + touch(d.path(), "go.mod"); + std::fs::write(d.path().join("main.go"), b"package main\nfunc main(){}\n").unwrap(); + let off = resolve_phases(&recipe(&[]), d.path()).unwrap().compile.unwrap(); + assert!(off.contains("CGO_ENABLED=0"), "{off}"); + let mut r = recipe(&[]); + r.build.cgo = true; + let on = resolve_phases(&r, d.path()).unwrap().compile.unwrap(); + assert!(on.contains("CGO_ENABLED=1") && on.contains("zig cc") && on.contains("-extldflags=-static"), "{on}"); + } + #[test] fn detect_go_when_only_go_work() { // workspace multimódulo sin go.mod en la raíz (sólo go.work) ⇒ sigue siendo Go (antes caía a diff --git a/crates/hammer-core/src/recipe.rs b/crates/hammer-core/src/recipe.rs index 0a9fe00a..9c54c18a 100644 --- a/crates/hammer-core/src/recipe.rs +++ b/crates/hammer-core/src/recipe.rs @@ -103,6 +103,14 @@ pub struct Build { /// herramientas, no inputs del of_tree del 4/4). `None` ⇒ el zig por defecto. Ver SDD 11 §7.2b. #[serde(default, skip_serializing_if = "Option::is_none")] pub zig_version: Option, + /// Habilita CGO en un build Go (`BuildSys::Go`). Por defecto el lab compila con `CGO_ENABLED=0` + /// (Go puro, estático, sin C). Algunos proyectos necesitan cgo para drivers con C bundled (p.ej. + /// el driver sqlite3 de mattn en usql/sq/dolt): con `cgo = true` el compile usa `CGO_ENABLED=1` + /// + `CC="zig cc"` (musl nativo del sandbox) y liga estático (`-linkmode=external -extldflags= + /// -static`). Sólo para C bundled; cgo contra libs C EXTERNAS (gpgme/libvirt) requiere además + /// esas recetas en el sandbox. No-op fuera de BuildSys::Go. + #[serde(default)] + pub cgo: bool, /// Overrides explícitos de las fases del build. Lo no especificado se decide por /// heurística en el lab (ver `docs/02-build-lab.md` §4). #[serde(default)] diff --git a/tandas/staged-fallidos/sq.toml b/recipes/sq.toml similarity index 78% rename from tandas/staged-fallidos/sq.toml rename to recipes/sq.toml index 1fc3527b..5bce2a95 100644 --- a/tandas/staged-fallidos/sq.toml +++ b/recipes/sq.toml @@ -1,4 +1,3 @@ -# DIFERIDA (finde): driver sqlite3 necesita CGO (undefined driveri/DBTypeForKind con CGO off), como usql. # 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. @@ -15,7 +14,8 @@ compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" flags = [] +cgo = true # driver sqlite3 con C bundled — necesita cgo -# buildInputs de nix (no usados con CGO off): go +# buildInputs de nix: go [deps] build = ["go"] diff --git a/tandas/staged-fallidos/usql.toml b/recipes/usql.toml similarity index 73% rename from tandas/staged-fallidos/usql.toml rename to recipes/usql.toml index d7e7ce00..a871b9ce 100644 --- a/tandas/staged-fallidos/usql.toml +++ b/recipes/usql.toml @@ -1,4 +1,3 @@ -# DIFERIDA (go-13): driver SQLite necesita CGO (cgo-sqlite); con CGO_ENABLED=0 → 'undefined: sqlite'. Necesita build CGO + libs de DB. # 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. @@ -15,7 +14,9 @@ compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" flags = [] +cgo = true # driver sqlite3 (mattn) con C bundled — necesita cgo -# buildInputs de nix (no usados con CGO off): go, unixodbc, icu4c +# buildInputs de nix: go, unixodbc, icu4c [deps] build = ["go"] +