cmd/dist: refactor generated cgo-support logic

During bootstrapping, cmd/dist writes a file indicating which
GOOS/GOARCH combinations are valid, and which support cgo-enabled
builds. That information previously went into the go/build package,
but today it fits in more naturally in the internal/platform package
(which already has a number of functions indicating feature support
for GOOS/GOARCH combinations).

Moreover, as of CL 450739 the cmd/go logic for determining whether to
use cgo is somewhat more nuanced than the go/build logic: cmd/go
checks for the presence of a C compiler, whereas go/build does not
(mostly because it determines its configuration at package-init time,
and checking $PATH for a C compiler is somewhat expensive).

To simplify this situation, this change:

	- consolidates the “cgo supported” check in internal/platform
	  (alongside many other platform-support checks) instead of making
	  it a one-off in go/build,

	- and updates a couple of tests to use testenv.HasCGO instead of
	  build.Default.CgoEnabled to decide whether to test a cgo-specific
	  behavior.

For #58884.
For #59500.

Change-Id: I0bb2502dba4545a3d98c9e915727382ce536a0f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/483695
Auto-Submit: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Bryan Mills <bcmills@google.com>
This commit is contained in:
Bryan C. Mills 2023-04-11 14:27:45 +00:00 committed by Gopher Robot
parent 0d699b6cb3
commit d22f287f12
15 changed files with 55 additions and 49 deletions

1
.gitignore vendored
View File

@ -38,6 +38,7 @@ _testmain.go
/src/go/build/zcgo.go /src/go/build/zcgo.go
/src/go/doc/headscan /src/go/doc/headscan
/src/internal/buildcfg/zbootstrap.go /src/internal/buildcfg/zbootstrap.go
/src/internal/platform/zosarch.go
/src/runtime/internal/sys/zversion.go /src/runtime/internal/sys/zversion.go
/src/unicode/maketables /src/unicode/maketables
/src/time/tzdata/zzipdata.go /src/time/tzdata/zzipdata.go

11
src/cmd/dist/build.go vendored
View File

@ -626,14 +626,16 @@ var deptab = []struct {
}{ }{
{"cmd/go/internal/cfg", []string{ {"cmd/go/internal/cfg", []string{
"zdefaultcc.go", "zdefaultcc.go",
}},
{"go/build", []string{
"zcgo.go",
}},
{"internal/platform", []string{
"zosarch.go", "zosarch.go",
}}, }},
{"runtime/internal/sys", []string{ {"runtime/internal/sys", []string{
"zversion.go", "zversion.go",
}}, }},
{"go/build", []string{
"zcgo.go",
}},
{"time/tzdata", []string{ {"time/tzdata", []string{
"zzipdata.go", "zzipdata.go",
}}, }},
@ -650,10 +652,10 @@ var gentab = []struct {
nameprefix string nameprefix string
gen func(string, string) gen func(string, string)
}{ }{
{"zcgo.go", mkzcgo},
{"zdefaultcc.go", mkzdefaultcc}, {"zdefaultcc.go", mkzdefaultcc},
{"zosarch.go", mkzosarch}, {"zosarch.go", mkzosarch},
{"zversion.go", mkzversion}, {"zversion.go", mkzversion},
{"zcgo.go", mkzcgo},
{"zzipdata.go", mktzdata}, {"zzipdata.go", mktzdata},
// not generated anymore, but delete the file if we see it // not generated anymore, but delete the file if we see it
@ -1196,6 +1198,7 @@ var cleanlist = []string{
"runtime/internal/sys", "runtime/internal/sys",
"cmd/cgo", "cmd/cgo",
"cmd/go/internal/cfg", "cmd/go/internal/cfg",
"internal/platform",
"go/build", "go/build",
} }

View File

@ -91,55 +91,19 @@ func defaultCCFunc(name string, defaultcc map[string]string) string {
return buf.String() return buf.String()
} }
// mkzosarch writes zosarch.go for cmd/go.
func mkzosarch(dir, file string) {
// sort for deterministic zosarch.go file
var list []string
for plat := range cgoEnabled {
list = append(list, plat)
}
sort.Strings(list)
var buf strings.Builder
fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n\n")
fmt.Fprintf(&buf, "package cfg\n\n")
fmt.Fprintf(&buf, "var OSArchSupportsCgo = map[string]bool{\n")
for _, plat := range list {
fmt.Fprintf(&buf, "\t%s: %v,\n", quote(plat), cgoEnabled[plat])
}
fmt.Fprintf(&buf, "}\n")
writefile(buf.String(), file, writeSkipSame)
}
// mkzcgo writes zcgo.go for the go/build package: // mkzcgo writes zcgo.go for the go/build package:
// //
// package build // package build
// var cgoEnabled = map[string]bool{} // const defaultCGO_ENABLED = <CGO_ENABLED>
// //
// It is invoked to write go/build/zcgo.go. // It is invoked to write go/build/zcgo.go.
func mkzcgo(dir, file string) { func mkzcgo(dir, file string) {
// sort for deterministic zcgo.go file
var list []string
for plat, hasCgo := range cgoEnabled {
if hasCgo {
list = append(list, plat)
}
}
sort.Strings(list)
var buf strings.Builder var buf strings.Builder
fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n") fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n")
fmt.Fprintln(&buf) fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "package build\n") fmt.Fprintf(&buf, "package build\n")
fmt.Fprintln(&buf) fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "const defaultCGO_ENABLED = %s\n", quote(os.Getenv("CGO_ENABLED"))) fmt.Fprintf(&buf, "const defaultCGO_ENABLED = %s\n", quote(os.Getenv("CGO_ENABLED")))
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "var cgoEnabled = map[string]bool{\n")
for _, plat := range list {
fmt.Fprintf(&buf, "\t%s: true,\n", quote(plat))
}
fmt.Fprintf(&buf, "}\n")
writefile(buf.String(), file, writeSkipSame) writefile(buf.String(), file, writeSkipSame)
} }

View File

@ -6,6 +6,7 @@ package main
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
) )
@ -82,3 +83,26 @@ func mkobjabi(file string) {
writefile(buf.String(), file, writeSkipSame) writefile(buf.String(), file, writeSkipSame)
} }
// mkzosarch writes zosarch.go for internal/platform.
func mkzosarch(dir, file string) {
// sort for deterministic file contents.
var list []string
for plat := range cgoEnabled {
list = append(list, plat)
}
sort.Strings(list)
var buf strings.Builder
fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "package platform\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n")
for _, plat := range list {
fmt.Fprintf(&buf, "\t\t%s: %v,\n", quote(plat), cgoEnabled[plat])
}
fmt.Fprintf(&buf, "}\n")
writefile(buf.String(), file, writeSkipSame)
}

View File

@ -121,6 +121,7 @@ func bootstrapBuildTools() {
mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot)) mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot)) mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
mkzosarch("", pathf("%s/src/internal/platform/zosarch.go", goroot))
// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root. // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
// We use a subdirectory of $GOROOT/pkg because that's the // We use a subdirectory of $GOROOT/pkg because that's the

View File

@ -141,6 +141,7 @@ func defaultContext() build.Context {
// (1) environment, (2) go/env file, (3) runtime constants, // (1) environment, (2) go/env file, (3) runtime constants,
// while go/build.Default.GOOS/GOARCH are derived from the preference list // while go/build.Default.GOOS/GOARCH are derived from the preference list
// (1) environment, (2) runtime constants. // (1) environment, (2) runtime constants.
//
// We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH; // We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
// no matter how that happened, go/build.Default will make the // no matter how that happened, go/build.Default will make the
// same decision (either the environment variables are set explicitly // same decision (either the environment variables are set explicitly

View File

@ -14,6 +14,7 @@ import (
"debug/elf" "debug/elf"
"encoding/json" "encoding/json"
"fmt" "fmt"
"internal/platform"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -355,7 +356,7 @@ func closeBuilders() {
} }
func CheckGOOSARCHPair(goos, goarch string) error { func CheckGOOSARCHPair(goos, goarch string) error {
if _, ok := cfg.OSArchSupportsCgo[goos+"/"+goarch]; !ok && cfg.BuildContext.Compiler == "gc" { if !platform.BuildModeSupported(cfg.BuildContext.Compiler, "default", goos, goarch) {
return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch) return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch)
} }
return nil return nil

View File

@ -283,7 +283,7 @@ func buildModeInit() {
base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode) base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
} }
if !platform.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) { if cfg.BuildBuildmode != "default" && !platform.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) {
base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
} }

View File

@ -5,7 +5,7 @@
package main_test package main_test
import ( import (
"go/build" "internal/testenv"
"runtime" "runtime"
"testing" "testing"
@ -32,7 +32,7 @@ func TestNoteReading(t *testing.T) {
} }
switch { switch {
case !build.Default.CgoEnabled: case !testenv.HasCGO():
t.Skipf("skipping - no cgo, so assuming external linking not available") t.Skipf("skipping - no cgo, so assuming external linking not available")
case runtime.GOOS == "plan9": case runtime.GOOS == "plan9":
t.Skipf("skipping - external linking not supported") t.Skipf("skipping - external linking not supported")

View File

@ -1,5 +1,6 @@
# go list all should work with GOOS=linux because all packages build on Linux # go list all should work with GOOS=linux because all packages build on Linux
env GOOS=linux env GOOS=linux
env GOARCH=amd64
go list all go list all
# go list all should work with GOOS=darwin, but it used to fail because # go list all should work with GOOS=darwin, but it used to fail because

View File

@ -1,3 +1,5 @@
env GOOS=linux
env GOARCH=amd64 env GOARCH=amd64
env GOAMD64=v3 env GOAMD64=v3
go list -f '{{context.ToolTags}}' go list -f '{{context.ToolTags}}'

View File

@ -8,7 +8,6 @@ import (
"cmd/internal/notsha256" "cmd/internal/notsha256"
"flag" "flag"
"fmt" "fmt"
"go/build"
"internal/platform" "internal/platform"
"internal/testenv" "internal/testenv"
"os" "os"
@ -253,7 +252,7 @@ func testDisasm(t *testing.T, srcfname string, printCode bool, printGnuAsm bool,
func testGoAndCgoDisasm(t *testing.T, printCode bool, printGnuAsm bool) { func testGoAndCgoDisasm(t *testing.T, printCode bool, printGnuAsm bool) {
t.Parallel() t.Parallel()
testDisasm(t, "fmthello.go", printCode, printGnuAsm) testDisasm(t, "fmthello.go", printCode, printGnuAsm)
if build.Default.CgoEnabled { if testenv.HasCGO() {
testDisasm(t, "fmthellocgo.go", printCode, printGnuAsm) testDisasm(t, "fmthellocgo.go", printCode, printGnuAsm)
} }
} }

View File

@ -16,6 +16,7 @@ import (
"internal/godebug" "internal/godebug"
"internal/goroot" "internal/goroot"
"internal/goversion" "internal/goversion"
"internal/platform"
"io" "io"
"io/fs" "io/fs"
"os" "os"
@ -345,7 +346,7 @@ func defaultContext() Context {
default: default:
// cgo must be explicitly enabled for cross compilation builds // cgo must be explicitly enabled for cross compilation builds
if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS { if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH] c.CgoEnabled = platform.CgoSupported(c.GOOS, c.GOARCH)
break break
} }
c.CgoEnabled = false c.CgoEnabled = false

View File

@ -292,7 +292,7 @@ var depsRules = `
FMT, internal/goexperiment FMT, internal/goexperiment
< internal/buildcfg; < internal/buildcfg;
go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion, internal/platform
< go/build; < go/build;
# databases # databases

View File

@ -126,6 +126,9 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
} }
platform := goos + "/" + goarch platform := goos + "/" + goarch
if _, ok := osArchSupportsCgo[platform]; !ok {
return false // platform unrecognized
}
switch buildmode { switch buildmode {
case "archive": case "archive":
@ -237,3 +240,8 @@ func DefaultPIE(goos, goarch string, isRace bool) bool {
} }
return false return false
} }
// CgoSupported reports whether goos/goarch supports cgo.\n")
func CgoSupported(goos, goarch string) bool {
return osArchSupportsCgo[goos+"/"+goarch]
}