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 }