use the host's GOEXE when building the linker

We're building the linker binary for the host GOOS,
not the target GOOS that we happen to be building for.

I noticed that, after running `go test`, my garble cache
would contain both link and link.exe, which made no sense
as I run linux and not windows.

`go env` has GOHOSTOS to mirror GOOS, but there is no
GOHOSTEXE to mirror GOEXE, so we reconstruct it from
runtime.GOOS, which is equivalent to GOHOSTOS.

Add a regression test as well.
pull/703/head
Daniel Martí 1 year ago
parent b87830eb97
commit cf49f7f3b1

@ -16,6 +16,7 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"github.com/bluekeyes/go-gitdiff/gitdiff" "github.com/bluekeyes/go-gitdiff/gitdiff"
"github.com/rogpeppe/go-internal/lockedfile" "github.com/rogpeppe/go-internal/lockedfile"
@ -138,7 +139,7 @@ func applyPatches(srcDir, workingDir string, modFiles map[string]bool, patches [
return mod, nil return mod, nil
} }
func cachePath(goExe string) (string, error) { func cachePath() (string, error) {
var cacheDir string var cacheDir string
if val, ok := os.LookupEnv(garbleCacheDir); ok { if val, ok := os.LookupEnv(garbleCacheDir); ok {
cacheDir = val cacheDir = val
@ -155,6 +156,11 @@ func cachePath(goExe string) (string, error) {
return "", err return "", err
} }
goExe := ""
if runtime.GOOS == "windows" {
goExe = ".exe"
}
// Note that we only keep one patched and built linker in the cache. // Note that we only keep one patched and built linker in the cache.
// If the user switches between Go versions or garble versions often, // If the user switches between Go versions or garble versions often,
// this may result in rebuilds since we don't keep multiple binaries in the cache. // this may result in rebuilds since we don't keep multiple binaries in the cache.
@ -220,13 +226,13 @@ func buildLinker(workingDir string, overlay map[string]string, outputLinkPath st
return nil return nil
} }
func PatchLinker(goRoot, goVersion, goExe, tempDir string) (string, func(), error) { func PatchLinker(goRoot, goVersion, tempDir string) (string, func(), error) {
patchesVer, modFiles, patches, err := loadLinkerPatches() patchesVer, modFiles, patches, err := loadLinkerPatches()
if err != nil { if err != nil {
panic(fmt.Errorf("cannot retrieve linker patches: %v", err)) panic(fmt.Errorf("cannot retrieve linker patches: %v", err))
} }
outputLinkPath, err := cachePath(goExe) outputLinkPath, err := cachePath()
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }

@ -441,7 +441,7 @@ func mainErr(args []string) error {
executablePath := args[0] executablePath := args[0]
if tool == "link" { if tool == "link" {
modifiedLinkPath, unlock, err := linker.PatchLinker(cache.GoEnv.GOROOT, cache.GoEnv.GOVERSION, cache.GoEnv.GOEXE, sharedTempDir) modifiedLinkPath, unlock, err := linker.PatchLinker(cache.GoEnv.GOROOT, cache.GoEnv.GOVERSION, sharedTempDir)
if err != nil { if err != nil {
return fmt.Errorf("cannot get modified linker: %v", err) return fmt.Errorf("cannot get modified linker: %v", err)
} }
@ -2378,7 +2378,7 @@ func flagSetValue(flags []string, name, value string) []string {
func fetchGoEnv() error { func fetchGoEnv() error {
out, err := exec.Command("go", "env", "-json", out, err := exec.Command("go", "env", "-json",
// Keep in sync with sharedCache.GoEnv. // Keep in sync with sharedCache.GoEnv.
"GOOS", "GOMOD", "GOVERSION", "GOROOT", "GOEXE", "GOOS", "GOMOD", "GOVERSION", "GOROOT",
).CombinedOutput() ).CombinedOutput()
if err != nil { if err != nil {
// TODO: cover this in the tests. // TODO: cover this in the tests.

@ -54,7 +54,6 @@ type sharedCache struct {
GOMOD string GOMOD string
GOVERSION string GOVERSION string
GOROOT string GOROOT string
GOEXE string
} }
} }

@ -14,9 +14,23 @@ exec ./main
[short] stop # no need to verify this with -short [short] stop # no need to verify this with -short
# The rebuilt linker should use the executable extension for the host GOOS,
# not the target one. Not doing so might be harmless, but can result in
# building the linker twice, wasting CPU and disk.
[!windows] env GOOS=windows
[windows] env GOOS=linux
garble build
[!windows] [exec:git] exists ${GARBLE_CACHE_DIR}/garble/link
[!windows] [exec:git] ! exists ${GARBLE_CACHE_DIR}/garble/link.exe
[windows] [exec:git] ! exists ${GARBLE_CACHE_DIR}/garble/link
[windows] [exec:git] exists ${GARBLE_CACHE_DIR}/garble/link.exe
env GOOS=
# Verify a build without garble.
go build go build
exec ./main exec ./main
cmp stderr main.stderr cmp stderr main.stderr
-- go.mod -- -- go.mod --
module test/main module test/main

Loading…
Cancel
Save