"GOCACHE=" + testGOCACHE,
"GODEBUG=" + os.Getenv("GODEBUG"),
"GOEXE=" + cfg.ExeSuffix,
- "GOEXPSTRING=" + objabi.Expstring()[2:],
+ "GOEXPERIMENT=" + objabi.GOEXPERIMENT(),
"GOOS=" + runtime.GOOS,
"GOPATH=" + filepath.Join(ts.workdir, "gopath"),
"GOPROXY=" + proxyURL,
GOARCH=<target GOARCH>
GOCACHE=<actual GOCACHE being used outside the test>
GOEXE=<executable file suffix: .exe on Windows, empty on other systems>
- GOEXPSTRING=<value of objabi.Expstring(), from GOEXPERIMENT when toolchain built>
+ GOEXPERIMENT=<value of objabi.GOEXPERIMENT>
GOOS=<target GOOS>
GOPATH=$WORK/gopath
GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
# compile_ext will fail if the buildtags that are enabled (or not enabled) for the
# framepointer and fieldtrack experiments are not consistent with the value of
-# GOEXPSTRING (which comes from objabi.Expstring()).
+# objabi.GOEXPERIMENT.
[short] skip
go run m
}
func hasExpEntry(s string) bool {
- // script_test.go defines GOEXPSTRING to be the value of
- // objabi.Expstring(), which gives the enabled experiments baked into the
- // toolchain.
- g := os.Getenv("GOEXPSTRING")
+ // script_test.go defines GOEXPERIMENT to be the enabled experiments.
+ g := os.Getenv("GOEXPERIMENT")
for _, f := range strings.Split(g, ",") {
if f == s {
return true
func fp() {
if hasExpEntry("framepointer") {
- fmt.Println("in !framepointer build, but objabi.Expstring() has 'framepointer'")
+ fmt.Println("in !framepointer build, but objabi.GOEXPERIMENT has 'framepointer'")
os.Exit(1)
}
}
func fp() {
if !hasExpEntry("framepointer") {
- fmt.Println("in framepointer build, but objabi.Expstring() does not have 'framepointer', is", os.Getenv("GOEXPSTRING"))
+ fmt.Println("in framepointer build, but objabi.GOEXPERIMENT does not have 'framepointer', is", os.Getenv("GOEXPERIMENT"))
os.Exit(1)
}
}
func ft() {
if hasExpEntry("fieldtrack") {
- fmt.Println("in !fieldtrack build, but objabi.Expstring() has 'fieldtrack'")
+ fmt.Println("in !fieldtrack build, but objabi.GOEXPERIMENT has 'fieldtrack'")
os.Exit(1)
}
}
func ft() {
if !hasExpEntry("fieldtrack") {
- fmt.Println("in fieldtrack build, but objabi.Expstring() does not have 'fieldtrack', is", os.Getenv("GOEXPSTRING"))
+ fmt.Println("in fieldtrack build, but objabi.GOEXPERIMENT does not have 'fieldtrack', is", os.Getenv("GOEXPERIMENT"))
os.Exit(1)
}
}
// was built with.)
var Experiment goexperiment.Flags
-var defaultExpstring string // Set by package init
-
// FramePointerEnabled enables the use of platform conventions for
// saving frame pointers.
//
var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
func init() {
- // Capture "default" experiments.
- defaultExpstring = Expstring()
+ // Start with the baseline configuration.
+ Experiment = goexperiment.BaselineFlags
- goexperiment := envOr("GOEXPERIMENT", defaultGOEXPERIMENT)
+ // Pick up any changes to the baseline configuration from the
+ // GOEXPERIMENT environment. This can be set at make.bash time
+ // and overridden at build time.
+ env := envOr("GOEXPERIMENT", defaultGOEXPERIMENT)
- // GOEXPERIMENT=none overrides all experiments enabled at dist time.
- if goexperiment != "none" {
+ if env != "" {
// Create a map of known experiment names.
names := make(map[string]reflect.Value)
rv := reflect.ValueOf(&Experiment).Elem()
}
// Parse names.
- for _, f := range strings.Split(goexperiment, ",") {
+ for _, f := range strings.Split(env, ",") {
if f == "" {
continue
}
+ if f == "none" {
+ // GOEXPERIMENT=none restores the baseline configuration.
+ // (This is useful for overriding make.bash-time settings.)
+ Experiment = goexperiment.BaselineFlags
+ continue
+ }
val := true
if strings.HasPrefix(f, "no") {
f, val = f[2:], false
}
}
-// expList returns the list of enabled GOEXPERIMENTs names.
-func expList(flags *goexperiment.Flags) []string {
+// expList returns the list of lower-cased experiment names for
+// experiments that differ from base. base may be nil to indicate no
+// experiments.
+func expList(exp, base *goexperiment.Flags) []string {
var list []string
- rv := reflect.ValueOf(&Experiment).Elem()
+ rv := reflect.ValueOf(exp).Elem()
+ var rBase reflect.Value
+ if base != nil {
+ rBase = reflect.ValueOf(base).Elem()
+ }
rt := rv.Type()
for i := 0; i < rt.NumField(); i++ {
+ name := strings.ToLower(rt.Field(i).Name)
val := rv.Field(i).Bool()
- if val {
- field := rt.Field(i)
- list = append(list, strings.ToLower(field.Name))
+ baseVal := false
+ if base != nil {
+ baseVal = rBase.Field(i).Bool()
+ }
+ if val != baseVal {
+ if val {
+ list = append(list, name)
+ } else {
+ list = append(list, "no"+name)
+ }
}
}
return list
}
-// Expstring returns the GOEXPERIMENT string that should appear in Go
-// version signatures. This always starts with "X:".
-func Expstring() string {
- list := expList(&Experiment)
- if len(list) == 0 {
- return "X:none"
- }
- return "X:" + strings.Join(list, ",")
-}
-
-// GOEXPERIMENT returns a comma-separated list of enabled experiments.
-// This is derived from the GOEXPERIMENT environment variable if set,
-// or the value of GOEXPERIMENT when make.bash was run if not.
+// GOEXPERIMENT is a comma-separated list of enabled or disabled
+// experiments that differ from the baseline experiment configuration.
+// GOEXPERIMENT is exactly what a user would set on the command line
+// to get the set of enabled experiments.
func GOEXPERIMENT() string {
- return strings.Join(expList(&Experiment), ",")
+ return strings.Join(expList(&Experiment, &goexperiment.BaselineFlags), ",")
}
// EnabledExperiments returns a list of enabled experiments, as
// lower-cased experiment names.
func EnabledExperiments() []string {
- return expList(&Experiment)
+ return expList(&Experiment, nil)
}
name = name[strings.LastIndex(name, `\`)+1:]
name = strings.TrimSuffix(name, ".exe")
- // If there's an active experiment, include that,
- // to distinguish go1.10.2 with an experiment
- // from go1.10.2 without an experiment.
- p := Expstring()
- if p == defaultExpstring {
- p = ""
- }
- sep := ""
- if p != "" {
- sep = " "
+ p := ""
+
+ // If the enabled experiments differ from the defaults,
+ // include that difference.
+ if goexperiment := GOEXPERIMENT(); goexperiment != "" {
+ p = " X:" + goexperiment
}
// The go command invokes -V=full to get a unique identifier
}
}
- fmt.Printf("%s version %s%s%s\n", name, Version, sep, p)
+ fmt.Printf("%s version %s%s\n", name, Version, p)
os.Exit(0)
return nil
}
// or link object files that are incompatible with each other. This
// string always starts with "go object ".
func HeaderString() string {
- return fmt.Sprintf("go object %s %s %s %s\n", GOOS, GOARCH, Version, Expstring())
+ return fmt.Sprintf("go object %s %s %s X:%s\n", GOOS, GOARCH, Version, strings.Join(EnabledExperiments(), ","))
}
// register arguments to defer/go).
RegabiArgs bool
}
+
+// BaselineFlags specifies the experiment flags that are enabled by
+// default in the current toolchain. This is, in effect, the "control"
+// configuration and any variation from this is an experiment.
+var BaselineFlags = Flags{}