Etapa G: frontera CGO — knob 'cgo=true' (CC=zig cc + static) destraba sqlite bundled-C

vendor_go_deps/BuildSys::Go por defecto compila CGO_ENABLED=0 (Go puro estático). Nuevo campo
[build] cgo=true ⇒ CGO_ENABLED=1 CC="zig cc" (musl nativo del sandbox) + -linkmode=external
-extldflags=-static. Validado: usql + sq (driver sqlite3 mattn, bundled-C) → estáticos y CORREN
(usql 0.0.0-dev, sq v0.0.0-dev). Tests go_cgo_knob_switches_compile_env. cgo contra libs C EXTERNAS
(gpgme/libvirt en werf/minikube/skopeo) aún requiere esas recetas; esto cubre la clase bundled-C.
This commit is contained in:
2026-06-29 11:04:27 -04:00
parent 4bb5e67e82
commit d47be16a8b
4 changed files with 41 additions and 6 deletions
+28 -2
View File
@@ -757,11 +757,23 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result<Phases> {
// 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
+8
View File
@@ -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<String>,
/// 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)]
@@ -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"]
@@ -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"]