github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/go/internal/envcmd/env.go (about)

     1  // Copyright 2012 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 envcmd implements the ``go env'' command.
     6  package envcmd
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  	"os"
    12  	"runtime"
    13  	"strings"
    14  
    15  	"cmd/go/internal/base"
    16  	"cmd/go/internal/cache"
    17  	"cmd/go/internal/cfg"
    18  	"cmd/go/internal/load"
    19  	"cmd/go/internal/work"
    20  )
    21  
    22  var CmdEnv = &base.Command{
    23  	UsageLine: "env [-json] [var ...]",
    24  	Short:     "print Go environment information",
    25  	Long: `
    26  Env prints Go environment information.
    27  
    28  By default env prints information as a shell script
    29  (on Windows, a batch file). If one or more variable
    30  names is given as arguments, env prints the value of
    31  each named variable on its own line.
    32  
    33  The -json flag prints the environment in JSON format
    34  instead of as a shell script.
    35  
    36  For more about environment variables, see 'go help environment'.
    37  	`,
    38  }
    39  
    40  func init() {
    41  	CmdEnv.Run = runEnv // break init cycle
    42  }
    43  
    44  var envJson = CmdEnv.Flag.Bool("json", false, "")
    45  
    46  func MkEnv() []cfg.EnvVar {
    47  	var b work.Builder
    48  	b.Init()
    49  
    50  	env := []cfg.EnvVar{
    51  		{Name: "GOARCH", Value: cfg.Goarch},
    52  		{Name: "GOBIN", Value: cfg.GOBIN},
    53  		{Name: "GOCACHE", Value: cache.DefaultDir()},
    54  		{Name: "GOEXE", Value: cfg.ExeSuffix},
    55  		{Name: "GOHOSTARCH", Value: runtime.GOARCH},
    56  		{Name: "GOHOSTOS", Value: runtime.GOOS},
    57  		{Name: "GOOS", Value: cfg.Goos},
    58  		{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
    59  		{Name: "GORACE", Value: os.Getenv("GORACE")},
    60  		{Name: "GOROOT", Value: cfg.GOROOT},
    61  		{Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")},
    62  		{Name: "GOTOOLDIR", Value: base.ToolDir},
    63  
    64  		// disable escape codes in clang errors
    65  		{Name: "TERM", Value: "dumb"},
    66  	}
    67  
    68  	if work.GccgoBin != "" {
    69  		env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoBin})
    70  	} else {
    71  		env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName})
    72  	}
    73  
    74  	switch cfg.Goarch {
    75  	case "arm":
    76  		env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM})
    77  	case "386":
    78  		env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
    79  	case "mips", "mipsle":
    80  		env = append(env, cfg.EnvVar{Name: "GOMIPS", Value: cfg.GOMIPS})
    81  	}
    82  
    83  	cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
    84  	if env := strings.Fields(os.Getenv("CC")); len(env) > 0 {
    85  		cc = env[0]
    86  	}
    87  	cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
    88  	if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 {
    89  		cxx = env[0]
    90  	}
    91  	env = append(env, cfg.EnvVar{Name: "CC", Value: cc})
    92  	env = append(env, cfg.EnvVar{Name: "CXX", Value: cxx})
    93  
    94  	if cfg.BuildContext.CgoEnabled {
    95  		env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"})
    96  	} else {
    97  		env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "0"})
    98  	}
    99  
   100  	return env
   101  }
   102  
   103  func findEnv(env []cfg.EnvVar, name string) string {
   104  	for _, e := range env {
   105  		if e.Name == name {
   106  			return e.Value
   107  		}
   108  	}
   109  	return ""
   110  }
   111  
   112  // ExtraEnvVars returns environment variables that should not leak into child processes.
   113  func ExtraEnvVars() []cfg.EnvVar {
   114  	var b work.Builder
   115  	b.Init()
   116  	cppflags, cflags, cxxflags, fflags, ldflags, err := b.CFlags(&load.Package{})
   117  	if err != nil {
   118  		// Should not happen - b.CFlags was given an empty package.
   119  		fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err)
   120  		return nil
   121  	}
   122  	cmd := b.GccCmd(".", "")
   123  	return []cfg.EnvVar{
   124  		// Note: Update the switch in runEnv below when adding to this list.
   125  		{Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")},
   126  		{Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")},
   127  		{Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")},
   128  		{Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")},
   129  		{Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")},
   130  		{Name: "PKG_CONFIG", Value: b.PkgconfigCmd()},
   131  		{Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")},
   132  	}
   133  }
   134  
   135  func runEnv(cmd *base.Command, args []string) {
   136  	env := cfg.CmdEnv
   137  
   138  	// Do we need to call ExtraEnvVars, which is a bit expensive?
   139  	// Only if we're listing all environment variables ("go env")
   140  	// or the variables being requested are in the extra list.
   141  	needExtra := true
   142  	if len(args) > 0 {
   143  		needExtra = false
   144  		for _, arg := range args {
   145  			switch arg {
   146  			case "CGO_CFLAGS",
   147  				"CGO_CPPFLAGS",
   148  				"CGO_CXXFLAGS",
   149  				"CGO_FFLAGS",
   150  				"CGO_LDFLAGS",
   151  				"PKG_CONFIG",
   152  				"GOGCCFLAGS":
   153  				needExtra = true
   154  			}
   155  		}
   156  	}
   157  	if needExtra {
   158  		env = append(env, ExtraEnvVars()...)
   159  	}
   160  
   161  	if len(args) > 0 {
   162  		if *envJson {
   163  			var es []cfg.EnvVar
   164  			for _, name := range args {
   165  				e := cfg.EnvVar{Name: name, Value: findEnv(env, name)}
   166  				es = append(es, e)
   167  			}
   168  			printEnvAsJSON(es)
   169  		} else {
   170  			for _, name := range args {
   171  				fmt.Printf("%s\n", findEnv(env, name))
   172  			}
   173  		}
   174  		return
   175  	}
   176  
   177  	if *envJson {
   178  		printEnvAsJSON(env)
   179  		return
   180  	}
   181  
   182  	for _, e := range env {
   183  		if e.Name != "TERM" {
   184  			switch runtime.GOOS {
   185  			default:
   186  				fmt.Printf("%s=\"%s\"\n", e.Name, e.Value)
   187  			case "plan9":
   188  				if strings.IndexByte(e.Value, '\x00') < 0 {
   189  					fmt.Printf("%s='%s'\n", e.Name, strings.Replace(e.Value, "'", "''", -1))
   190  				} else {
   191  					v := strings.Split(e.Value, "\x00")
   192  					fmt.Printf("%s=(", e.Name)
   193  					for x, s := range v {
   194  						if x > 0 {
   195  							fmt.Printf(" ")
   196  						}
   197  						fmt.Printf("%s", s)
   198  					}
   199  					fmt.Printf(")\n")
   200  				}
   201  			case "windows":
   202  				fmt.Printf("set %s=%s\n", e.Name, e.Value)
   203  			}
   204  		}
   205  	}
   206  }
   207  
   208  func printEnvAsJSON(env []cfg.EnvVar) {
   209  	m := make(map[string]string)
   210  	for _, e := range env {
   211  		if e.Name == "TERM" {
   212  			continue
   213  		}
   214  		m[e.Name] = e.Value
   215  	}
   216  	enc := json.NewEncoder(os.Stdout)
   217  	enc.SetIndent("", "\t")
   218  	if err := enc.Encode(m); err != nil {
   219  		base.Fatalf("%s", err)
   220  	}
   221  }