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"
"path/filepath"
"regexp"
"runtime"
"github.com/bluekeyes/go-gitdiff/gitdiff"
"github.com/rogpeppe/go-internal/lockedfile"
@ -138,7 +139,7 @@ func applyPatches(srcDir, workingDir string, modFiles map[string]bool, patches [
return mod, nil
}
func cachePath(goExe string) (string, error) {
func cachePath() (string, error) {
var cacheDir string
if val, ok := os.LookupEnv(garbleCacheDir); ok {
cacheDir = val
@ -155,6 +156,11 @@ func cachePath(goExe string) (string, error) {
return "", err
}
goExe := ""
if runtime.GOOS == "windows" {
goExe = ".exe"
}
// Note that we only keep one patched and built linker in the cache.
// 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.
@ -220,13 +226,13 @@ func buildLinker(workingDir string, overlay map[string]string, outputLinkPath st
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()
if err != nil {
panic(fmt.Errorf("cannot retrieve linker patches: %v", err))
}
outputLinkPath, err := cachePath(goExe)
outputLinkPath, err := cachePath()
if err != nil {
return "", nil, err
}

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

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

@ -14,9 +14,23 @@ exec ./main
[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
exec ./main
cmp stderr main.stderr
-- go.mod --
module test/main

Loading…
Cancel
Save