...

Source file src/pkg/cmd/go/internal/work/build.go

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

View as plain text