diff --git a/go/go2nix/pkg/resolve/builder.go b/go/go2nix/pkg/resolve/builder.go index 26935df..c26ecdc 100644 --- a/go/go2nix/pkg/resolve/builder.go +++ b/go/go2nix/pkg/resolve/builder.go @@ -47,9 +47,9 @@ func compileScript(go2nixBin string) string { b.WriteString("export HOME=\"$TMPDIR\"\n") b.WriteString("mkdir -p \"$out\"\n\n") - // Write importcfg from env var (placeholders resolved by Nix at build time). - // Use absolute path since compile-package changes CWD to srcdir. - b.WriteString("printf '%s\\n' \"$importcfg_entries\" > \"$NIX_BUILD_TOP/importcfg\"\n\n") + // Write importcfg from passAsFile (placeholders resolved by Nix at build + // time). passAsFile keeps the derivation's exec env under MAX_ARG_STRLEN. + b.WriteString("cat \"$importcfg_entriesPath\" > \"$NIX_BUILD_TOP/importcfg\"\n\n") // Write compile manifest from env var (JSON generated at derivation creation time). // Replace @@IMPORTCFG@@ placeholder with the actual importcfg path so that @@ -83,8 +83,9 @@ func linkScript(goStorePath, pname, buildMode string) string { b.WriteString("export HOME=\"$TMPDIR\"\n") b.WriteString("mkdir -p \"$out/bin\"\n\n") - // Write importcfg for all transitive deps - b.WriteString("printf '%s\\n' \"$importcfg_entries\" > \"$NIX_BUILD_TOP/importcfg\"\n\n") + // Write importcfg for all transitive deps. passAsFile keeps the exec + // env under MAX_ARG_STRLEN — torture's full closure is ~400KB. + b.WriteString("cat \"$importcfg_entriesPath\" > \"$NIX_BUILD_TOP/importcfg\"\n\n") // Set GOROOT so the linker embeds it as runtime.defaultGOROOT, // enabling runtime.GOROOT() in the resulting binary. diff --git a/go/go2nix/pkg/resolve/builder_test.go b/go/go2nix/pkg/resolve/builder_test.go index e5e17bc..d123754 100644 --- a/go/go2nix/pkg/resolve/builder_test.go +++ b/go/go2nix/pkg/resolve/builder_test.go @@ -87,8 +87,8 @@ func TestCompileScript(t *testing.T) { if !strings.Contains(script, "compile-package") { t.Error("missing compile-package call") } - if !strings.Contains(script, "$importcfg_entries") { - t.Error("missing importcfg_entries reference") + if !strings.Contains(script, "$importcfg_entriesPath") { + t.Error("missing importcfg_entriesPath reference") } if !strings.Contains(script, "${compileManifestJSON//@@IMPORTCFG@@/$NIX_BUILD_TOP/importcfg}") { t.Error("missing compileManifestJSON with @@IMPORTCFG@@ expansion") @@ -331,9 +331,9 @@ func TestBuildImportcfgMissingDrvPath(t *testing.T) { } } -// TestImportcfgEntriesBashWrite verifies that the multi-line importcfg_entries -// env var is correctly written to a file by the bash printf in both -// compileScript and linkScript. +// TestImportcfgEntriesBashWrite verifies that the importcfg_entries content +// (delivered via passAsFile) is correctly copied to NIX_BUILD_TOP/importcfg +// by the bash snippet in both compileScript and linkScript. func TestImportcfgEntriesBashWrite(t *testing.T) { entries := strings.Join([]string{ "packagefile fmt=/nix/store/stdlib/fmt.a", @@ -342,13 +342,18 @@ func TestImportcfgEntriesBashWrite(t *testing.T) { }, "\n") tmpDir := t.TempDir() + inFile := filepath.Join(tmpDir, "passAsFile-importcfg_entries") outFile := filepath.Join(tmpDir, "importcfg") + if err := os.WriteFile(inFile, []byte(entries), 0o644); err != nil { + t.Fatal(err) + } // Run the same bash snippet used by both compileScript and linkScript. - script := `printf '%s\n' "$importcfg_entries" > "$outfile"` + script := `cat "$importcfg_entriesPath" > "$outfile"` cmd := exec.Command("bash", "-c", script) cmd.Env = []string{ - "importcfg_entries=" + entries, + "PATH=" + os.Getenv("PATH"), + "importcfg_entriesPath=" + inFile, "outfile=" + outFile, } if out, err := cmd.CombinedOutput(); err != nil { diff --git a/go/go2nix/pkg/resolve/resolve.go b/go/go2nix/pkg/resolve/resolve.go index f6461d6..2cb94a6 100644 --- a/go/go2nix/pkg/resolve/resolve.go +++ b/go/go2nix/pkg/resolve/resolve.go @@ -685,6 +685,7 @@ func buildPackageDrv( return nil, fmt.Errorf("marshaling compile manifest: %w", err) } drv.SetEnv("compileManifestJSON", string(manifestJSON)) + drv.SetEnv("passAsFile", "importcfg_entries") if pkg.GoVersion != "" { drv.SetEnv("goVersion", compile.LangVersion(pkg.GoVersion)) @@ -1030,6 +1031,7 @@ func buildLinkDrv( } drv.SetEnv("importcfg_entries", strings.Join(importcfgEntries, "\n")) + drv.SetEnv("passAsFile", "importcfg_entries") drv.SetEnv("ldflags", cfg.LDFlags) // Propagate sanitizer flags (-race, -msan, -asan) from gcflags to the