1// Copyright 2011 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 5package work 6 7import ( 8 "errors" 9 "fmt" 10 "go/build" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "runtime" 15 "strings" 16 17 "cmd/go/internal/base" 18 "cmd/go/internal/cfg" 19 "cmd/go/internal/load" 20 "cmd/go/internal/search" 21) 22 23var CmdBuild = &base.Command{ 24 UsageLine: "go build [-o output] [-i] [build flags] [packages]", 25 Short: "compile packages and dependencies", 26 Long: ` 27Build compiles the packages named by the import paths, 28along with their dependencies, but it does not install the results. 29 30If the arguments to build are a list of .go files from a single directory, 31build treats them as a list of source files specifying a single package. 32 33When compiling packages, build ignores files that end in '_test.go'. 34 35When compiling a single main package, build writes 36the resulting executable to an output file named after 37the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') 38or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). 39The '.exe' suffix is added when writing a Windows executable. 40 41When compiling multiple packages or a single non-main package, 42build compiles the packages but discards the resulting object, 43serving only as a check that the packages can be built. 44 45The -o flag forces build to write the resulting executable or object 46to the named output file or directory, instead of the default behavior described 47in the last two paragraphs. If the named output is a directory that exists, 48then any resulting executables will be written to that directory. 49 50The -i flag installs the packages that are dependencies of the target. 51 52The build flags are shared by the build, clean, get, install, list, run, 53and test commands: 54 55 -a 56 force rebuilding of packages that are already up-to-date. 57 -n 58 print the commands but do not run them. 59 -p n 60 the number of programs, such as build commands or 61 test binaries, that can be run in parallel. 62 The default is the number of CPUs available. 63 -race 64 enable data race detection. 65 Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, 66 linux/ppc64le and linux/arm64 (only for 48-bit VMA). 67 -msan 68 enable interoperation with memory sanitizer. 69 Supported only on linux/amd64, linux/arm64 70 and only with Clang/LLVM as the host C compiler. 71 On linux/arm64, pie build mode will be used. 72 -v 73 print the names of packages as they are compiled. 74 -work 75 print the name of the temporary work directory and 76 do not delete it when exiting. 77 -x 78 print the commands. 79 80 -asmflags '[pattern=]arg list' 81 arguments to pass on each go tool asm invocation. 82 -buildmode mode 83 build mode to use. See 'go help buildmode' for more. 84 -compiler name 85 name of compiler to use, as in runtime.Compiler (gccgo or gc). 86 -gccgoflags '[pattern=]arg list' 87 arguments to pass on each gccgo compiler/linker invocation. 88 -gcflags '[pattern=]arg list' 89 arguments to pass on each go tool compile invocation. 90 -installsuffix suffix 91 a suffix to use in the name of the package installation directory, 92 in order to keep output separate from default builds. 93 If using the -race flag, the install suffix is automatically set to race 94 or, if set explicitly, has _race appended to it. Likewise for the -msan 95 flag. Using a -buildmode option that requires non-default compile flags 96 has a similar effect. 97 -ldflags '[pattern=]arg list' 98 arguments to pass on each go tool link invocation. 99 -linkshared 100 build code that will be linked against shared libraries previously 101 created with -buildmode=shared. 102 -mod mode 103 module download mode to use: readonly, vendor, or mod. 104 See 'go help modules' for more. 105 -modcacherw 106 leave newly-created directories in the module cache read-write 107 instead of making them read-only. 108 -modfile file 109 in module aware mode, read (and possibly write) an alternate go.mod 110 file instead of the one in the module root directory. A file named 111 "go.mod" must still be present in order to determine the module root 112 directory, but it is not accessed. When -modfile is specified, an 113 alternate go.sum file is also used: its path is derived from the 114 -modfile flag by trimming the ".mod" extension and appending ".sum". 115 -pkgdir dir 116 install and load all packages from dir instead of the usual locations. 117 For example, when building with a non-standard configuration, 118 use -pkgdir to keep generated packages in a separate location. 119 -tags tag,list 120 a comma-separated list of build tags to consider satisfied during the 121 build. For more information about build tags, see the description of 122 build constraints in the documentation for the go/build package. 123 (Earlier versions of Go used a space-separated list, and that form 124 is deprecated but still recognized.) 125 -trimpath 126 remove all file system paths from the resulting executable. 127 Instead of absolute file system paths, the recorded file names 128 will begin with either "go" (for the standard library), 129 or a module path@version (when using modules), 130 or a plain import path (when using GOPATH). 131 -toolexec 'cmd args' 132 a program to use to invoke toolchain programs like vet and asm. 133 For example, instead of running asm, the go command will run 134 'cmd args /path/to/asm <arguments for asm>'. 135 136The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a 137space-separated list of arguments to pass to an underlying tool 138during the build. To embed spaces in an element in the list, surround 139it with either single or double quotes. The argument list may be 140preceded by a package pattern and an equal sign, which restricts 141the use of that argument list to the building of packages matching 142that pattern (see 'go help packages' for a description of package 143patterns). Without a pattern, the argument list applies only to the 144packages named on the command line. The flags may be repeated 145with different patterns in order to specify different arguments for 146different sets of packages. If a package matches patterns given in 147multiple flags, the latest match on the command line wins. 148For example, 'go build -gcflags=-S fmt' prints the disassembly 149only for package fmt, while 'go build -gcflags=all=-S fmt' 150prints the disassembly for fmt and all its dependencies. 151 152For more about specifying packages, see 'go help packages'. 153For more about where packages and binaries are installed, 154run 'go help gopath'. 155For more about calling between Go and C/C++, run 'go help c'. 156 157Note: Build adheres to certain conventions such as those described 158by 'go help gopath'. Not all projects can follow these conventions, 159however. Installations that have their own conventions or that use 160a separate software build system may choose to use lower-level 161invocations such as 'go tool compile' and 'go tool link' to avoid 162some of the overheads and design decisions of the build tool. 163 164See also: go install, go get, go clean. 165 `, 166} 167 168const concurrentGCBackendCompilationEnabledByDefault = true 169 170func init() { 171 // break init cycle 172 CmdBuild.Run = runBuild 173 CmdInstall.Run = runInstall 174 175 CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "") 176 CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file or directory") 177 178 CmdInstall.Flag.BoolVar(&cfg.BuildI, "i", false, "") 179 180 AddBuildFlags(CmdBuild, DefaultBuildFlags) 181 AddBuildFlags(CmdInstall, DefaultBuildFlags) 182} 183 184// Note that flags consulted by other parts of the code 185// (for example, buildV) are in cmd/go/internal/cfg. 186 187var ( 188 forcedAsmflags []string // internally-forced flags for cmd/asm 189 forcedGcflags []string // internally-forced flags for cmd/compile 190 forcedLdflags []string // internally-forced flags for cmd/link 191 forcedGccgoflags []string // internally-forced flags for gccgo 192) 193 194var BuildToolchain toolchain = noToolchain{} 195var ldBuildmode string 196 197// buildCompiler implements flag.Var. 198// It implements Set by updating both 199// BuildToolchain and buildContext.Compiler. 200type buildCompiler struct{} 201 202func (c buildCompiler) Set(value string) error { 203 switch value { 204 case "gc": 205 BuildToolchain = gcToolchain{} 206 case "gccgo": 207 BuildToolchain = gccgoToolchain{} 208 default: 209 return fmt.Errorf("unknown compiler %q", value) 210 } 211 cfg.BuildToolchainName = value 212 cfg.BuildToolchainCompiler = BuildToolchain.compiler 213 cfg.BuildToolchainLinker = BuildToolchain.linker 214 cfg.BuildContext.Compiler = value 215 return nil 216} 217 218func (c buildCompiler) String() string { 219 return cfg.BuildContext.Compiler 220} 221 222func init() { 223 switch build.Default.Compiler { 224 case "gc", "gccgo": 225 buildCompiler{}.Set(build.Default.Compiler) 226 } 227} 228 229type BuildFlagMask int 230 231const ( 232 DefaultBuildFlags BuildFlagMask = 0 233 OmitModFlag BuildFlagMask = 1 << iota 234 OmitModCommonFlags 235) 236 237// AddBuildFlags adds the flags common to the build, clean, get, 238// install, list, run, and test commands. 239func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) { 240 cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "") 241 cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "") 242 cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "") 243 cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "") 244 cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "") 245 246 cmd.Flag.Var(&load.BuildAsmflags, "asmflags", "") 247 cmd.Flag.Var(buildCompiler{}, "compiler", "") 248 cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "") 249 cmd.Flag.Var(&load.BuildGcflags, "gcflags", "") 250 cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "") 251 if mask&OmitModFlag == 0 { 252 cmd.Flag.StringVar(&cfg.BuildMod, "mod", "", "") 253 } 254 if mask&OmitModCommonFlags == 0 { 255 AddModCommonFlags(cmd) 256 } 257 cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") 258 cmd.Flag.Var(&load.BuildLdflags, "ldflags", "") 259 cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") 260 cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "") 261 cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "") 262 cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "") 263 cmd.Flag.Var((*tagsFlag)(&cfg.BuildContext.BuildTags), "tags", "") 264 cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "") 265 cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "") 266 cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "") 267 268 // Undocumented, unstable debugging flags. 269 cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "") 270} 271 272// AddModCommonFlags adds the module-related flags common to build commands 273// and 'go mod' subcommands. 274func AddModCommonFlags(cmd *base.Command) { 275 cmd.Flag.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "") 276 cmd.Flag.StringVar(&cfg.ModFile, "modfile", "", "") 277} 278 279// tagsFlag is the implementation of the -tags flag. 280type tagsFlag []string 281 282func (v *tagsFlag) Set(s string) error { 283 // For compatibility with Go 1.12 and earlier, allow "-tags='a b c'" or even just "-tags='a'". 284 if strings.Contains(s, " ") || strings.Contains(s, "'") { 285 return (*base.StringsFlag)(v).Set(s) 286 } 287 288 // Split on commas, ignore empty strings. 289 *v = []string{} 290 for _, s := range strings.Split(s, ",") { 291 if s != "" { 292 *v = append(*v, s) 293 } 294 } 295 return nil 296} 297 298func (v *tagsFlag) String() string { 299 return "<TagsFlag>" 300} 301 302// fileExtSplit expects a filename and returns the name 303// and ext (without the dot). If the file has no 304// extension, ext will be empty. 305func fileExtSplit(file string) (name, ext string) { 306 dotExt := filepath.Ext(file) 307 name = file[:len(file)-len(dotExt)] 308 if dotExt != "" { 309 ext = dotExt[1:] 310 } 311 return 312} 313 314func pkgsMain(pkgs []*load.Package) (res []*load.Package) { 315 for _, p := range pkgs { 316 if p.Name == "main" { 317 res = append(res, p) 318 } 319 } 320 return res 321} 322 323func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) { 324 for _, p := range pkgs { 325 if p.Name != "main" { 326 res = append(res, p) 327 } 328 } 329 return res 330} 331 332func oneMainPkg(pkgs []*load.Package) []*load.Package { 333 if len(pkgs) != 1 || pkgs[0].Name != "main" { 334 base.Fatalf("-buildmode=%s requires exactly one main package", cfg.BuildBuildmode) 335 } 336 return pkgs 337} 338 339var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } 340 341var runtimeVersion = runtime.Version() 342 343func runBuild(cmd *base.Command, args []string) { 344 BuildInit() 345 var b Builder 346 b.Init() 347 348 pkgs := load.PackagesForBuild(args) 349 350 explicitO := len(cfg.BuildO) > 0 351 352 if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" { 353 cfg.BuildO = pkgs[0].DefaultExecName() 354 cfg.BuildO += cfg.ExeSuffix 355 } 356 357 // sanity check some often mis-used options 358 switch cfg.BuildContext.Compiler { 359 case "gccgo": 360 if load.BuildGcflags.Present() { 361 fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags") 362 } 363 if load.BuildLdflags.Present() { 364 fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags") 365 } 366 case "gc": 367 if load.BuildGccgoflags.Present() { 368 fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags") 369 } 370 } 371 372 depMode := ModeBuild 373 if cfg.BuildI { 374 depMode = ModeInstall 375 } 376 377 pkgs = omitTestOnly(pkgsFilter(load.Packages(args))) 378 379 // Special case -o /dev/null by not writing at all. 380 if cfg.BuildO == os.DevNull { 381 cfg.BuildO = "" 382 } 383 384 if cfg.BuildO != "" { 385 // If the -o name exists and is a directory, then 386 // write all main packages to that directory. 387 // Otherwise require only a single package be built. 388 if fi, err := os.Stat(cfg.BuildO); err == nil && fi.IsDir() { 389 if !explicitO { 390 base.Fatalf("go build: build output %q already exists and is a directory", cfg.BuildO) 391 } 392 a := &Action{Mode: "go build"} 393 for _, p := range pkgs { 394 if p.Name != "main" { 395 continue 396 } 397 398 p.Target = filepath.Join(cfg.BuildO, p.DefaultExecName()) 399 p.Target += cfg.ExeSuffix 400 p.Stale = true 401 p.StaleReason = "build -o flag in use" 402 a.Deps = append(a.Deps, b.AutoAction(ModeInstall, depMode, p)) 403 } 404 if len(a.Deps) == 0 { 405 base.Fatalf("go build: no main packages to build") 406 } 407 b.Do(a) 408 return 409 } 410 if len(pkgs) > 1 { 411 base.Fatalf("go build: cannot write multiple packages to non-directory %s", cfg.BuildO) 412 } else if len(pkgs) == 0 { 413 base.Fatalf("no packages to build") 414 } 415 p := pkgs[0] 416 p.Target = cfg.BuildO 417 p.Stale = true // must build - not up to date 418 p.StaleReason = "build -o flag in use" 419 a := b.AutoAction(ModeInstall, depMode, p) 420 b.Do(a) 421 return 422 } 423 424 a := &Action{Mode: "go build"} 425 for _, p := range pkgs { 426 a.Deps = append(a.Deps, b.AutoAction(ModeBuild, depMode, p)) 427 } 428 if cfg.BuildBuildmode == "shared" { 429 a = b.buildmodeShared(ModeBuild, depMode, args, pkgs, a) 430 } 431 b.Do(a) 432} 433 434var CmdInstall = &base.Command{ 435 UsageLine: "go install [-i] [build flags] [packages]", 436 Short: "compile and install packages and dependencies", 437 Long: ` 438Install compiles and installs the packages named by the import paths. 439 440Executables are installed in the directory named by the GOBIN environment 441variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH 442environment variable is not set. Executables in $GOROOT 443are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN. 444 445When module-aware mode is disabled, other packages are installed in the 446directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled, 447other packages are built and cached but not installed. 448 449The -i flag installs the dependencies of the named packages as well. 450 451For more about the build flags, see 'go help build'. 452For more about specifying packages, see 'go help packages'. 453 454See also: go build, go get, go clean. 455 `, 456} 457 458// libname returns the filename to use for the shared library when using 459// -buildmode=shared. The rules we use are: 460// Use arguments for special 'meta' packages: 461// std --> libstd.so 462// std cmd --> libstd,cmd.so 463// A single non-meta argument with trailing "/..." is special cased: 464// foo/... --> libfoo.so 465// (A relative path like "./..." expands the "." first) 466// Use import paths for other cases, changing '/' to '-': 467// somelib --> libsubdir-somelib.so 468// ./ or ../ --> libsubdir-somelib.so 469// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so 470// a/... b/... ---> liba/c,b/d.so - all matching import paths 471// Name parts are joined with ','. 472func libname(args []string, pkgs []*load.Package) (string, error) { 473 var libname string 474 appendName := func(arg string) { 475 if libname == "" { 476 libname = arg 477 } else { 478 libname += "," + arg 479 } 480 } 481 var haveNonMeta bool 482 for _, arg := range args { 483 if search.IsMetaPackage(arg) { 484 appendName(arg) 485 } else { 486 haveNonMeta = true 487 } 488 } 489 if len(libname) == 0 { // non-meta packages only. use import paths 490 if len(args) == 1 && strings.HasSuffix(args[0], "/...") { 491 // Special case of "foo/..." as mentioned above. 492 arg := strings.TrimSuffix(args[0], "/...") 493 if build.IsLocalImport(arg) { 494 cwd, _ := os.Getwd() 495 bp, _ := cfg.BuildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly) 496 if bp.ImportPath != "" && bp.ImportPath != "." { 497 arg = bp.ImportPath 498 } 499 } 500 appendName(strings.ReplaceAll(arg, "/", "-")) 501 } else { 502 for _, pkg := range pkgs { 503 appendName(strings.ReplaceAll(pkg.ImportPath, "/", "-")) 504 } 505 } 506 } else if haveNonMeta { // have both meta package and a non-meta one 507 return "", errors.New("mixing of meta and non-meta packages is not allowed") 508 } 509 // TODO(mwhudson): Needs to change for platforms that use different naming 510 // conventions... 511 return "lib" + libname + ".so", nil 512} 513 514func runInstall(cmd *base.Command, args []string) { 515 BuildInit() 516 InstallPackages(args, load.PackagesForBuild(args)) 517} 518 519// omitTestOnly returns pkgs with test-only packages removed. 520func omitTestOnly(pkgs []*load.Package) []*load.Package { 521 var list []*load.Package 522 for _, p := range pkgs { 523 if len(p.GoFiles)+len(p.CgoFiles) == 0 && !p.Internal.CmdlinePkgLiteral { 524 // Package has no source files, 525 // perhaps due to build tags or perhaps due to only having *_test.go files. 526 // Also, it is only being processed as the result of a wildcard match 527 // like ./..., not because it was listed as a literal path on the command line. 528 // Ignore it. 529 continue 530 } 531 list = append(list, p) 532 } 533 return list 534} 535 536func InstallPackages(patterns []string, pkgs []*load.Package) { 537 if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) { 538 base.Fatalf("cannot install, GOBIN must be an absolute path") 539 } 540 541 pkgs = omitTestOnly(pkgsFilter(pkgs)) 542 for _, p := range pkgs { 543 if p.Target == "" { 544 switch { 545 case p.Standard && p.ImportPath == "unsafe": 546 // unsafe is a built-in package, has no target 547 case p.Name != "main" && p.Internal.Local && p.ConflictDir == "": 548 // Non-executables outside GOPATH need not have a target: 549 // we can use the cache to hold the built package archive for use in future builds. 550 // The ones inside GOPATH should have a target (in GOPATH/pkg) 551 // or else something is wrong and worth reporting (like a ConflictDir). 552 case p.Name != "main" && p.Module != nil: 553 // Non-executables have no target (except the cache) when building with modules. 554 case p.Internal.GobinSubdir: 555 base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName) 556 case p.Internal.CmdlineFiles: 557 base.Errorf("go %s: no install location for .go files listed on command line (GOBIN not set)", cfg.CmdName) 558 case p.ConflictDir != "": 559 base.Errorf("go %s: no install location for %s: hidden by %s", cfg.CmdName, p.Dir, p.ConflictDir) 560 default: 561 base.Errorf("go %s: no install location for directory %s outside GOPATH\n"+ 562 "\tFor more details see: 'go help gopath'", cfg.CmdName, p.Dir) 563 } 564 } 565 } 566 base.ExitIfErrors() 567 568 var b Builder 569 b.Init() 570 depMode := ModeBuild 571 if cfg.BuildI { 572 depMode = ModeInstall 573 } 574 a := &Action{Mode: "go install"} 575 var tools []*Action 576 for _, p := range pkgs { 577 // If p is a tool, delay the installation until the end of the build. 578 // This avoids installing assemblers/compilers that are being executed 579 // by other steps in the build. 580 a1 := b.AutoAction(ModeInstall, depMode, p) 581 if load.InstallTargetDir(p) == load.ToTool { 582 a.Deps = append(a.Deps, a1.Deps...) 583 a1.Deps = append(a1.Deps, a) 584 tools = append(tools, a1) 585 continue 586 } 587 a.Deps = append(a.Deps, a1) 588 } 589 if len(tools) > 0 { 590 a = &Action{ 591 Mode: "go install (tools)", 592 Deps: tools, 593 } 594 } 595 596 if cfg.BuildBuildmode == "shared" { 597 // Note: If buildmode=shared then only non-main packages 598 // are present in the pkgs list, so all the special case code about 599 // tools above did not apply, and a is just a simple Action 600 // with a list of Deps, one per package named in pkgs, 601 // the same as in runBuild. 602 a = b.buildmodeShared(ModeInstall, ModeInstall, patterns, pkgs, a) 603 } 604 605 b.Do(a) 606 base.ExitIfErrors() 607 608 // Success. If this command is 'go install' with no arguments 609 // and the current directory (the implicit argument) is a command, 610 // remove any leftover command binary from a previous 'go build'. 611 // The binary is installed; it's not needed here anymore. 612 // And worse it might be a stale copy, which you don't want to find 613 // instead of the installed one if $PATH contains dot. 614 // One way to view this behavior is that it is as if 'go install' first 615 // runs 'go build' and the moves the generated file to the install dir. 616 // See issue 9645. 617 if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { 618 // Compute file 'go build' would have created. 619 // If it exists and is an executable file, remove it. 620 targ := pkgs[0].DefaultExecName() 621 targ += cfg.ExeSuffix 622 if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory 623 fi, err := os.Stat(targ) 624 if err == nil { 625 m := fi.Mode() 626 if m.IsRegular() { 627 if m&0111 != 0 || cfg.Goos == "windows" { // windows never sets executable bit 628 os.Remove(targ) 629 } 630 } 631 } 632 } 633 } 634} 635 636// ExecCmd is the command to use to run user binaries. 637// Normally it is empty, meaning run the binaries directly. 638// If cross-compiling and running on a remote system or 639// simulator, it is typically go_GOOS_GOARCH_exec, with 640// the target GOOS and GOARCH substituted. 641// The -exec flag overrides these defaults. 642var ExecCmd []string 643 644// FindExecCmd derives the value of ExecCmd to use. 645// It returns that value and leaves ExecCmd set for direct use. 646func FindExecCmd() []string { 647 if ExecCmd != nil { 648 return ExecCmd 649 } 650 ExecCmd = []string{} // avoid work the second time 651 if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH { 652 return ExecCmd 653 } 654 path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch)) 655 if err == nil { 656 ExecCmd = []string{path} 657 } 658 return ExecCmd 659} 660