diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 82fdfb6ff6..65a82fd5f7 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -193,28 +193,40 @@ func GOROOT(t testing.TB) string { // GoTool reports the path to the Go tool. func GoTool() (string, error) { - if !HasGoBuild() { - return "", errors.New("platform cannot run go tool") - } - var exeSuffix string - if runtime.GOOS == "windows" { - exeSuffix = ".exe" - } - goroot, err := findGOROOT() - if err != nil { - return "", fmt.Errorf("cannot find go tool: %w", err) - } - path := filepath.Join(goroot, "bin", "go"+exeSuffix) - if _, err := os.Stat(path); err == nil { - return path, nil - } - goBin, err := exec.LookPath("go" + exeSuffix) - if err != nil { - return "", errors.New("cannot find go tool: " + err.Error()) - } - return goBin, nil + goToolOnce.Do(func() { + goToolPath, goToolErr = func() (string, error) { + if !HasGoBuild() { + return "", errors.New("platform cannot run go tool") + } + var exeSuffix string + if runtime.GOOS == "windows" { + exeSuffix = ".exe" + } + goroot, err := findGOROOT() + if err != nil { + return "", fmt.Errorf("cannot find go tool: %w", err) + } + path := filepath.Join(goroot, "bin", "go"+exeSuffix) + if _, err := os.Stat(path); err == nil { + return path, nil + } + goBin, err := exec.LookPath("go" + exeSuffix) + if err != nil { + return "", errors.New("cannot find go tool: " + err.Error()) + } + return goBin, nil + }() + }) + + return goToolPath, goToolErr } +var ( + goToolOnce sync.Once + goToolPath string + goToolErr error +) + // HasSrc reports whether the entire source tree is available under GOROOT. func HasSrc() bool { switch runtime.GOOS { @@ -242,16 +254,34 @@ func MustHaveExternalNetwork(t testing.TB) { } } -var haveCGO bool - // HasCGO reports whether the current system can use cgo. func HasCGO() bool { - return haveCGO + hasCgoOnce.Do(func() { + goTool, err := GoTool() + if err != nil { + return + } + cmd := exec.Command(goTool, "env", "CGO_ENABLED") + out, err := cmd.Output() + if err != nil { + panic(fmt.Sprintf("%v: %v", cmd, out)) + } + hasCgo, err = strconv.ParseBool(string(bytes.TrimSpace(out))) + if err != nil { + panic(fmt.Sprintf("%v: non-boolean output %q", cmd, out)) + } + }) + return hasCgo } +var ( + hasCgoOnce sync.Once + hasCgo bool +) + // MustHaveCGO calls t.Skip if cgo is not available. func MustHaveCGO(t testing.TB) { - if !haveCGO { + if !HasCGO() { t.Skipf("skipping test: no cgo") } } diff --git a/src/internal/testenv/testenv_cgo.go b/src/internal/testenv/testenv_cgo.go deleted file mode 100644 index 7426a29c1a..0000000000 --- a/src/internal/testenv/testenv_cgo.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build cgo - -package testenv - -func init() { - haveCGO = true -}