Source file src/internal/buildcfg/cfg.go

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package buildcfg provides access to the build configuration
     6  // described by the current environment. It is for use by build tools
     7  // such as cmd/go or cmd/compile and for setting up go/build's Default context.
     8  //
     9  // Note that it does NOT provide access to the build configuration used to
    10  // build the currently-running binary. For that, use runtime.GOOS etc
    11  // as well as internal/goexperiment.
    12  package buildcfg
    13  
    14  import (
    15  	"fmt"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"strconv"
    20  	"strings"
    21  )
    22  
    23  var (
    24  	GOROOT   = runtime.GOROOT() // cached for efficiency
    25  	GOARCH   = envOr("GOARCH", defaultGOARCH)
    26  	GOOS     = envOr("GOOS", defaultGOOS)
    27  	GO386    = envOr("GO386", defaultGO386)
    28  	GOAMD64  = goamd64()
    29  	GOARM    = goarm()
    30  	GOMIPS   = gomips()
    31  	GOMIPS64 = gomips64()
    32  	GOPPC64  = goppc64()
    33  	GOWASM   = gowasm()
    34  	ToolTags = toolTags()
    35  	GO_LDSO  = defaultGO_LDSO
    36  	Version  = version
    37  )
    38  
    39  // Error is one of the errors found (if any) in the build configuration.
    40  var Error error
    41  
    42  // Check exits the program with a fatal error if Error is non-nil.
    43  func Check() {
    44  	if Error != nil {
    45  		fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), Error)
    46  		os.Exit(2)
    47  	}
    48  }
    49  
    50  func envOr(key, value string) string {
    51  	if x := os.Getenv(key); x != "" {
    52  		return x
    53  	}
    54  	return value
    55  }
    56  
    57  func goamd64() int {
    58  	switch v := envOr("GOAMD64", defaultGOAMD64); v {
    59  	case "v1":
    60  		return 1
    61  	case "v2":
    62  		return 2
    63  	case "v3":
    64  		return 3
    65  	case "v4":
    66  		return 4
    67  	}
    68  	Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4")
    69  	return int(defaultGOAMD64[len("v")] - '0')
    70  }
    71  
    72  type goarmFeatures struct {
    73  	Version   int
    74  	SoftFloat bool
    75  }
    76  
    77  func (g goarmFeatures) String() string {
    78  	armStr := strconv.Itoa(g.Version)
    79  	if g.SoftFloat {
    80  		armStr += ",softfloat"
    81  	} else {
    82  		armStr += ",hardfloat"
    83  	}
    84  	return armStr
    85  }
    86  
    87  func goarm() (g goarmFeatures) {
    88  	const (
    89  		softFloatOpt = ",softfloat"
    90  		hardFloatOpt = ",hardfloat"
    91  	)
    92  	def := defaultGOARM
    93  	if GOOS == "android" && GOARCH == "arm" {
    94  		// Android arm devices always support GOARM=7.
    95  		def = "7"
    96  	}
    97  	v := envOr("GOARM", def)
    98  
    99  	floatSpecified := false
   100  	if strings.HasSuffix(v, softFloatOpt) {
   101  		g.SoftFloat = true
   102  		floatSpecified = true
   103  		v = v[:len(v)-len(softFloatOpt)]
   104  	}
   105  	if strings.HasSuffix(v, hardFloatOpt) {
   106  		floatSpecified = true
   107  		v = v[:len(v)-len(hardFloatOpt)]
   108  	}
   109  
   110  	switch v {
   111  	case "5":
   112  		g.Version = 5
   113  	case "6":
   114  		g.Version = 6
   115  	case "7":
   116  		g.Version = 7
   117  	default:
   118  		Error = fmt.Errorf("invalid GOARM: must start with 5, 6, or 7, and may optionally end in either %q or %q", hardFloatOpt, softFloatOpt)
   119  		g.Version = int(def[0] - '0')
   120  	}
   121  
   122  	// 5 defaults to softfloat. 6 and 7 default to hardfloat.
   123  	if !floatSpecified && g.Version == 5 {
   124  		g.SoftFloat = true
   125  	}
   126  	return
   127  }
   128  
   129  func gomips() string {
   130  	switch v := envOr("GOMIPS", defaultGOMIPS); v {
   131  	case "hardfloat", "softfloat":
   132  		return v
   133  	}
   134  	Error = fmt.Errorf("invalid GOMIPS: must be hardfloat, softfloat")
   135  	return defaultGOMIPS
   136  }
   137  
   138  func gomips64() string {
   139  	switch v := envOr("GOMIPS64", defaultGOMIPS64); v {
   140  	case "hardfloat", "softfloat":
   141  		return v
   142  	}
   143  	Error = fmt.Errorf("invalid GOMIPS64: must be hardfloat, softfloat")
   144  	return defaultGOMIPS64
   145  }
   146  
   147  func goppc64() int {
   148  	switch v := envOr("GOPPC64", defaultGOPPC64); v {
   149  	case "power8":
   150  		return 8
   151  	case "power9":
   152  		return 9
   153  	case "power10":
   154  		return 10
   155  	}
   156  	Error = fmt.Errorf("invalid GOPPC64: must be power8, power9, power10")
   157  	return int(defaultGOPPC64[len("power")] - '0')
   158  }
   159  
   160  type gowasmFeatures struct {
   161  	SatConv bool
   162  	SignExt bool
   163  }
   164  
   165  func (f gowasmFeatures) String() string {
   166  	var flags []string
   167  	if f.SatConv {
   168  		flags = append(flags, "satconv")
   169  	}
   170  	if f.SignExt {
   171  		flags = append(flags, "signext")
   172  	}
   173  	return strings.Join(flags, ",")
   174  }
   175  
   176  func gowasm() (f gowasmFeatures) {
   177  	for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
   178  		switch opt {
   179  		case "satconv":
   180  			f.SatConv = true
   181  		case "signext":
   182  			f.SignExt = true
   183  		case "":
   184  			// ignore
   185  		default:
   186  			Error = fmt.Errorf("invalid GOWASM: no such feature %q", opt)
   187  		}
   188  	}
   189  	return
   190  }
   191  
   192  func Getgoextlinkenabled() string {
   193  	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
   194  }
   195  
   196  func toolTags() []string {
   197  	tags := experimentTags()
   198  	tags = append(tags, gogoarchTags()...)
   199  	return tags
   200  }
   201  
   202  func experimentTags() []string {
   203  	var list []string
   204  	// For each experiment that has been enabled in the toolchain, define a
   205  	// build tag with the same name but prefixed by "goexperiment." which can be
   206  	// used for compiling alternative files for the experiment. This allows
   207  	// changes for the experiment, like extra struct fields in the runtime,
   208  	// without affecting the base non-experiment code at all.
   209  	for _, exp := range Experiment.Enabled() {
   210  		list = append(list, "goexperiment."+exp)
   211  	}
   212  	return list
   213  }
   214  
   215  // GOGOARCH returns the name and value of the GO$GOARCH setting.
   216  // For example, if GOARCH is "amd64" it might return "GOAMD64", "v2".
   217  func GOGOARCH() (name, value string) {
   218  	switch GOARCH {
   219  	case "386":
   220  		return "GO386", GO386
   221  	case "amd64":
   222  		return "GOAMD64", fmt.Sprintf("v%d", GOAMD64)
   223  	case "arm":
   224  		return "GOARM", GOARM.String()
   225  	case "mips", "mipsle":
   226  		return "GOMIPS", GOMIPS
   227  	case "mips64", "mips64le":
   228  		return "GOMIPS64", GOMIPS64
   229  	case "ppc64", "ppc64le":
   230  		return "GOPPC64", fmt.Sprintf("power%d", GOPPC64)
   231  	case "wasm":
   232  		return "GOWASM", GOWASM.String()
   233  	}
   234  	return "", ""
   235  }
   236  
   237  func gogoarchTags() []string {
   238  	switch GOARCH {
   239  	case "386":
   240  		return []string{GOARCH + "." + GO386}
   241  	case "amd64":
   242  		var list []string
   243  		for i := 1; i <= GOAMD64; i++ {
   244  			list = append(list, fmt.Sprintf("%s.v%d", GOARCH, i))
   245  		}
   246  		return list
   247  	case "arm":
   248  		var list []string
   249  		for i := 5; i <= GOARM.Version; i++ {
   250  			list = append(list, fmt.Sprintf("%s.%d", GOARCH, i))
   251  		}
   252  		return list
   253  	case "mips", "mipsle":
   254  		return []string{GOARCH + "." + GOMIPS}
   255  	case "mips64", "mips64le":
   256  		return []string{GOARCH + "." + GOMIPS64}
   257  	case "ppc64", "ppc64le":
   258  		var list []string
   259  		for i := 8; i <= GOPPC64; i++ {
   260  			list = append(list, fmt.Sprintf("%s.power%d", GOARCH, i))
   261  		}
   262  		return list
   263  	case "wasm":
   264  		var list []string
   265  		if GOWASM.SatConv {
   266  			list = append(list, GOARCH+".satconv")
   267  		}
   268  		if GOWASM.SignExt {
   269  			list = append(list, GOARCH+".signext")
   270  		}
   271  		return list
   272  	}
   273  	return nil
   274  }
   275  

View as plain text