Skip to content

Commit 2c92b23

Browse files
author
Bryan C. Mills
committed
internal/buildcfg: extract logic specific to cmd/go
cmd/go/internal/cfg duplicates many of the fields of internal/buildcfg, but initializes them from a Go environment file in addition to the usual process environment. internal/buildcfg doesn't (and shouldn't) know or care about that environment file, but prior to this CL it exposed hooks for cmd/go/internal/cfg to write data back to internal/buildcfg to incorporate information from the file. It also produced quirky GOEXPERIMENT strings when a non-trivial default was overridden, seemingly so that 'go env' would produce those same quirky strings in edge-cases where they are needed. This change reverses that information flow: internal/buildcfg now exports a structured type with methods — instead of top-level functions communicating through global state — so that cmd/go can utilize its marshaling and unmarshaling functionality without also needing to write results back into buildcfg package state. The quirks specific to 'go env' have been eliminated by distinguishing between the raw GOEXPERIMENT value set by the user (which is what we should report from 'go env') and the cleaned, canonical equivalent (which is what we should use in the build cache key). For #51461. Change-Id: I4ef5b7c58b1fb3468497649a6d2fb6c19aa06c70 Reviewed-on: https://go-review.googlesource.com/c/go/+/393574 Trust: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent d8bee94 commit 2c92b23

File tree

12 files changed

+118
-92
lines changed

12 files changed

+118
-92
lines changed

src/cmd/asm/internal/lex/input.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func predefine(defines flags.MultiFlag) map[string]*Macro {
5050
// Set macros for GOEXPERIMENTs so we can easily switch
5151
// runtime assembly code based on them.
5252
if *flags.CompilingRuntime {
53-
for _, exp := range buildcfg.EnabledExperiments() {
53+
for _, exp := range buildcfg.Experiment.Enabled() {
5454
// Define macro.
5555
name := "GOEXPERIMENT_" + exp
5656
macros[name] = &Macro{

src/cmd/go/internal/cfg/cfg.go

+52-32
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ import (
2222
"cmd/go/internal/fsys"
2323
)
2424

25+
// Global build parameters (used during package load)
26+
var (
27+
Goos = envOr("GOOS", build.Default.GOOS)
28+
Goarch = envOr("GOARCH", build.Default.GOARCH)
29+
30+
ExeSuffix = exeSuffix()
31+
32+
// ModulesEnabled specifies whether the go command is running
33+
// in module-aware mode (as opposed to GOPATH mode).
34+
// It is equal to modload.Enabled, but not all packages can import modload.
35+
ModulesEnabled bool
36+
)
37+
38+
func exeSuffix() string {
39+
if Goos == "windows" {
40+
return ".exe"
41+
}
42+
return ""
43+
}
44+
2545
// These are general "build flags" used by build and other commands.
2646
var (
2747
BuildA bool // -a flag
@@ -60,8 +80,6 @@ var (
6080
// GoPathError is set when GOPATH is not set. it contains an
6181
// explanation why GOPATH is unset.
6282
GoPathError string
63-
64-
GOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)
6583
)
6684

6785
func defaultContext() build.Context {
@@ -79,20 +97,15 @@ func defaultContext() build.Context {
7997
build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
8098
}
8199

82-
ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
83-
84100
// Override defaults computed in go/build with defaults
85101
// from go environment configuration file, if known.
86-
ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
87-
ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
102+
ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
103+
ctxt.GOOS = Goos
104+
ctxt.GOARCH = Goarch
88105

89-
// The experiments flags are based on GOARCH, so they may
90-
// need to change. TODO: This should be cleaned up.
91-
buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, GOEXPERIMENT)
106+
// ToolTags are based on GOEXPERIMENT, which we will parse and
107+
// initialize later.
92108
ctxt.ToolTags = nil
93-
for _, exp := range buildcfg.EnabledExperiments() {
94-
ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
95-
}
96109

97110
// The go/build rule for whether cgo is enabled is:
98111
// 1. If $CGO_ENABLED is set, respect it.
@@ -137,6 +150,33 @@ func init() {
137150
BuildToolchainLinker = func() string { return "missing-linker" }
138151
}
139152

153+
// Experiment configuration.
154+
var (
155+
// RawGOEXPERIMENT is the GOEXPERIMENT value set by the user.
156+
RawGOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)
157+
// CleanGOEXPERIMENT is the minimal GOEXPERIMENT value needed to reproduce the
158+
// experiments enabled by RawGOEXPERIMENT.
159+
CleanGOEXPERIMENT = RawGOEXPERIMENT
160+
161+
Experiment *buildcfg.ExperimentFlags
162+
ExperimentErr error
163+
)
164+
165+
func init() {
166+
Experiment, ExperimentErr = buildcfg.ParseGOEXPERIMENT(Goos, Goarch, RawGOEXPERIMENT)
167+
if ExperimentErr != nil {
168+
return
169+
}
170+
171+
// GOEXPERIMENT is valid, so convert it to canonical form.
172+
CleanGOEXPERIMENT = Experiment.String()
173+
174+
// Add build tags based on the experiments in effect.
175+
for _, exp := range Experiment.Enabled() {
176+
BuildContext.ToolTags = append(BuildContext.ToolTags, "goexperiment."+exp)
177+
}
178+
}
179+
140180
// An EnvVar is an environment variable Name=Value.
141181
type EnvVar struct {
142182
Name string
@@ -151,26 +191,6 @@ var OrigEnv []string
151191
// not CmdEnv.
152192
var CmdEnv []EnvVar
153193

154-
// Global build parameters (used during package load)
155-
var (
156-
Goarch = BuildContext.GOARCH
157-
Goos = BuildContext.GOOS
158-
159-
ExeSuffix = exeSuffix()
160-
161-
// ModulesEnabled specifies whether the go command is running
162-
// in module-aware mode (as opposed to GOPATH mode).
163-
// It is equal to modload.Enabled, but not all packages can import modload.
164-
ModulesEnabled bool
165-
)
166-
167-
func exeSuffix() string {
168-
if Goos == "windows" {
169-
return ".exe"
170-
}
171-
return ""
172-
}
173-
174194
var envCache struct {
175195
once sync.Once
176196
m map[string]string

src/cmd/go/internal/envcmd/env.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,14 @@ func MkEnv() []cfg.EnvVar {
7474
{Name: "GOCACHE", Value: cache.DefaultDir()},
7575
{Name: "GOENV", Value: envFile},
7676
{Name: "GOEXE", Value: cfg.ExeSuffix},
77-
{Name: "GOEXPERIMENT", Value: buildcfg.GOEXPERIMENT()},
77+
78+
// List the raw value of GOEXPERIMENT, not the cleaned one.
79+
// The set of default experiments may change from one release
80+
// to the next, so a GOEXPERIMENT setting that is redundant
81+
// with the current toolchain might actually be relevant with
82+
// a different version (for example, when bisecting a regression).
83+
{Name: "GOEXPERIMENT", Value: cfg.RawGOEXPERIMENT},
84+
7885
{Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")},
7986
{Name: "GOHOSTARCH", Value: runtime.GOARCH},
8087
{Name: "GOHOSTOS", Value: runtime.GOOS},
@@ -222,6 +229,9 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
222229
}
223230

224231
buildcfg.Check()
232+
if cfg.ExperimentErr != nil {
233+
base.Fatalf("go: %v", cfg.ExperimentErr)
234+
}
225235

226236
env := cfg.CmdEnv
227237
env = append(env, ExtraEnvVars()...)
@@ -374,9 +384,9 @@ func checkBuildConfig(add map[string]string, del map[string]bool) error {
374384
}
375385
}
376386

377-
goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", buildcfg.GOEXPERIMENT(), "")
387+
goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", cfg.RawGOEXPERIMENT, buildcfg.DefaultGOEXPERIMENT)
378388
if okGOEXPERIMENT {
379-
if _, _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil {
389+
if _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil {
380390
return err
381391
}
382392
}

src/cmd/go/internal/load/pkg.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2334,8 +2334,8 @@ func (p *Package) setBuildInfo() {
23342334
}
23352335
}
23362336
appendSetting("GOARCH", cfg.BuildContext.GOARCH)
2337-
if cfg.GOEXPERIMENT != "" {
2338-
appendSetting("GOEXPERIMENT", cfg.GOEXPERIMENT)
2337+
if cfg.RawGOEXPERIMENT != "" {
2338+
appendSetting("GOEXPERIMENT", cfg.RawGOEXPERIMENT)
23392339
}
23402340
appendSetting("GOOS", cfg.BuildContext.GOOS)
23412341
if key, val := cfg.GetArchEnv(); key != "" && val != "" {

src/cmd/go/internal/work/exec.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"encoding/json"
1313
"errors"
1414
"fmt"
15-
"internal/buildcfg"
1615
exec "internal/execabs"
1716
"internal/lazyregexp"
1817
"io"
@@ -320,8 +319,8 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
320319
key, val := cfg.GetArchEnv()
321320
fmt.Fprintf(h, "%s=%s\n", key, val)
322321

323-
if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
324-
fmt.Fprintf(h, "GOEXPERIMENT=%q\n", goexperiment)
322+
if cfg.CleanGOEXPERIMENT != "" {
323+
fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)
325324
}
326325

327326
// TODO(rsc): Convince compiler team not to add more magic environment variables,
@@ -1301,8 +1300,8 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
13011300
key, val := cfg.GetArchEnv()
13021301
fmt.Fprintf(h, "%s=%s\n", key, val)
13031302

1304-
if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
1305-
fmt.Fprintf(h, "GOEXPERIMENT=%q\n", goexperiment)
1303+
if cfg.CleanGOEXPERIMENT != "" {
1304+
fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)
13061305
}
13071306

13081307
// The linker writes source file paths that say GOROOT_FINAL, but

src/cmd/go/internal/work/gc.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bufio"
99
"bytes"
1010
"fmt"
11-
"internal/buildcfg"
1211
"io"
1312
"log"
1413
"os"
@@ -245,7 +244,7 @@ CheckFlags:
245244
}
246245

247246
// TODO: Test and delete these conditions.
248-
if buildcfg.Experiment.FieldTrack || buildcfg.Experiment.PreemptibleLoops {
247+
if cfg.ExperimentErr != nil || cfg.Experiment.FieldTrack || cfg.Experiment.PreemptibleLoops {
249248
canDashC = false
250249
}
251250

src/cmd/go/main.go

+3
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ func invoke(cmd *base.Command, args []string) {
190190
// 'go env' handles checking the build config
191191
if cmd != envcmd.CmdEnv {
192192
buildcfg.Check()
193+
if cfg.ExperimentErr != nil {
194+
base.Fatalf("go: %v", cfg.ExperimentErr)
195+
}
193196
}
194197

195198
// Set environment (GOOS, GOARCH, etc) explicitly.

src/cmd/internal/objabi/flag.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ func (versionFlag) Set(s string) error {
9999
if s == "goexperiment" {
100100
// test/run.go uses this to discover the full set of
101101
// experiment tags. Report everything.
102-
p = " X:" + strings.Join(buildcfg.AllExperiments(), ",")
102+
p = " X:" + strings.Join(buildcfg.Experiment.All(), ",")
103103
} else {
104-
// If the enabled experiments differ from the defaults,
104+
// If the enabled experiments differ from the baseline,
105105
// include that difference.
106-
if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
106+
if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {
107107
p = " X:" + goexperiment
108108
}
109109
}

src/cmd/internal/objabi/util.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ const (
2222
// or link object files that are incompatible with each other. This
2323
// string always starts with "go object ".
2424
func HeaderString() string {
25-
return fmt.Sprintf("go object %s %s %s X:%s\n", buildcfg.GOOS, buildcfg.GOARCH, buildcfg.Version, strings.Join(buildcfg.EnabledExperiments(), ","))
25+
return fmt.Sprintf("go object %s %s %s X:%s\n", buildcfg.GOOS, buildcfg.GOARCH, buildcfg.Version, strings.Join(buildcfg.Experiment.Enabled(), ","))
2626
}

src/cmd/link/internal/ld/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func Main(arch *sys.Arch, theArch Arch) {
124124
addstrdata1(ctxt, "internal/buildcfg.defaultGOROOT="+final)
125125

126126
buildVersion := buildcfg.Version
127-
if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
127+
if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {
128128
buildVersion += " X:" + goexperiment
129129
}
130130
addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)

src/go/build/build.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ func defaultContext() Context {
311311
// used for compiling alternative files for the experiment. This allows
312312
// changes for the experiment, like extra struct fields in the runtime,
313313
// without affecting the base non-experiment code at all.
314-
for _, exp := range buildcfg.EnabledExperiments() {
314+
for _, exp := range buildcfg.Experiment.Enabled() {
315315
c.ToolTags = append(c.ToolTags, "goexperiment."+exp)
316316
}
317317
defaultToolTags = append([]string{}, c.ToolTags...) // our own private copy

0 commit comments

Comments
 (0)