From a5f3cb6f75f31ea7336ce87375cbc30c73360def Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Tue, 28 Feb 2023 19:16:54 +0000 Subject: [PATCH] internal/testenv: use 'go env CGO_ENABLED' instead of a build constraint A build constraint reports whether the test binary was compiled with cgo enabled, but that doesn't necessarily imply that cgo can be used in the environment in which the test binary is run. In particular, cross-compiled builders (such as Android) may compile the test binaries on the host with CGO enabled but not provide a C toolchain on the device that runs the test. For #58775. Change-Id: Ibf2f44c9e956cd3fa898c3de67af4449e8ef2dd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/472215 Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot Run-TryBot: Bryan Mills Auto-Submit: Bryan Mills --- src/internal/testenv/testenv.go | 78 ++++++++++++++++++++--------- src/internal/testenv/testenv_cgo.go | 11 ---- 2 files changed, 54 insertions(+), 35 deletions(-) delete mode 100644 src/internal/testenv/testenv_cgo.go 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 -} -- 2.50.0