Home | History | Annotate | Download | only in work
      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"
     14 	"path/filepath"
     15 	"runtime"
     16 	"strings"
     17 
     18 	"cmd/go/internal/base"
     19 	"cmd/go/internal/cfg"
     20 	"cmd/go/internal/load"
     21 )
     22 
     23 var CmdBuild = &base.Command{
     24 	UsageLine: "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, build treats
     31 them as a list of source files specifying a single package.
     32 
     33 When compiling a single main package, build writes
     34 the resulting executable to an output file named after
     35 the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
     36 or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
     37 The '.exe' suffix is added when writing a Windows executable.
     38 
     39 When compiling multiple packages or a single non-main package,
     40 build compiles the packages but discards the resulting object,
     41 serving only as a check that the packages can be built.
     42 
     43 When compiling packages, build ignores files that end in '_test.go'.
     44 
     45 The -o flag, only allowed when compiling a single package,
     46 forces build to write the resulting executable or object
     47 to the named output file, instead of the default behavior described
     48 in the last two paragraphs.
     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,
     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 	-pkgdir dir
    101 		install and load all packages from dir instead of the usual locations.
    102 		For example, when building with a non-standard configuration,
    103 		use -pkgdir to keep generated packages in a separate location.
    104 	-tags 'tag list'
    105 		a space-separated list of build tags to consider satisfied during the
    106 		build. For more information about build tags, see the description of
    107 		build constraints in the documentation for the go/build package.
    108 	-toolexec 'cmd args'
    109 		a program to use to invoke toolchain programs like vet and asm.
    110 		For example, instead of running asm, the go command will run
    111 		'cmd args /path/to/asm <arguments for asm>'.
    112 
    113 The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a
    114 space-separated list of arguments to pass to an underlying tool
    115 during the build. To embed spaces in an element in the list, surround
    116 it with either single or double quotes. The argument list may be
    117 preceded by a package pattern and an equal sign, which restricts
    118 the use of that argument list to the building of packages matching
    119 that pattern (see 'go help packages' for a description of package
    120 patterns). Without a pattern, the argument list applies only to the
    121 packages named on the command line. The flags may be repeated
    122 with different patterns in order to specify different arguments for
    123 different sets of packages. If a package matches patterns given in
    124 multiple flags, the latest match on the command line wins.
    125 For example, 'go build -gcflags=-S fmt' prints the disassembly
    126 only for package fmt, while 'go build -gcflags=all=-S fmt'
    127 prints the disassembly for fmt and all its dependencies.
    128 
    129 For more about specifying packages, see 'go help packages'.
    130 For more about where packages and binaries are installed,
    131 run 'go help gopath'.
    132 For more about calling between Go and C/C++, run 'go help c'.
    133 
    134 Note: Build adheres to certain conventions such as those described
    135 by 'go help gopath'. Not all projects can follow these conventions,
    136 however. Installations that have their own conventions or that use
    137 a separate software build system may choose to use lower-level
    138 invocations such as 'go tool compile' and 'go tool link' to avoid
    139 some of the overheads and design decisions of the build tool.
    140 
    141 See also: go install, go get, go clean.
    142 	`,
    143 }
    144 
    145 const concurrentGCBackendCompilationEnabledByDefault = true
    146 
    147 func init() {
    148 	// break init cycle
    149 	CmdBuild.Run = runBuild
    150 	CmdInstall.Run = runInstall
    151 
    152 	CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "")
    153 	CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file")
    154 
    155 	CmdInstall.Flag.BoolVar(&cfg.BuildI, "i", false, "")
    156 
    157 	AddBuildFlags(CmdBuild)
    158 	AddBuildFlags(CmdInstall)
    159 }
    160 
    161 // Note that flags consulted by other parts of the code
    162 // (for example, buildV) are in cmd/go/internal/cfg.
    163 
    164 var (
    165 	forcedAsmflags   []string // internally-forced flags for cmd/asm
    166 	forcedGcflags    []string // internally-forced flags for cmd/compile
    167 	forcedLdflags    []string // internally-forced flags for cmd/link
    168 	forcedGccgoflags []string // internally-forced flags for gccgo
    169 )
    170 
    171 var BuildToolchain toolchain = noToolchain{}
    172 var ldBuildmode string
    173 
    174 // buildCompiler implements flag.Var.
    175 // It implements Set by updating both
    176 // BuildToolchain and buildContext.Compiler.
    177 type buildCompiler struct{}
    178 
    179 func (c buildCompiler) Set(value string) error {
    180 	switch value {
    181 	case "gc":
    182 		BuildToolchain = gcToolchain{}
    183 	case "gccgo":
    184 		BuildToolchain = gccgoToolchain{}
    185 	default:
    186 		return fmt.Errorf("unknown compiler %q", value)
    187 	}
    188 	cfg.BuildToolchainName = value
    189 	cfg.BuildToolchainCompiler = BuildToolchain.compiler
    190 	cfg.BuildToolchainLinker = BuildToolchain.linker
    191 	cfg.BuildContext.Compiler = value
    192 	return nil
    193 }
    194 
    195 func (c buildCompiler) String() string {
    196 	return cfg.BuildContext.Compiler
    197 }
    198 
    199 func init() {
    200 	switch build.Default.Compiler {
    201 	case "gc", "gccgo":
    202 		buildCompiler{}.Set(build.Default.Compiler)
    203 	}
    204 }
    205 
    206 // addBuildFlags adds the flags common to the build, clean, get,
    207 // install, list, run, and test commands.
    208 func AddBuildFlags(cmd *base.Command) {
    209 	cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "")
    210 	cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "")
    211 	cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "")
    212 	cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "")
    213 	cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "")
    214 
    215 	cmd.Flag.Var(&load.BuildAsmflags, "asmflags", "")
    216 	cmd.Flag.Var(buildCompiler{}, "compiler", "")
    217 	cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "")
    218 	cmd.Flag.Var(&load.BuildGcflags, "gcflags", "")
    219 	cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "")
    220 	cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
    221 	cmd.Flag.Var(&load.BuildLdflags, "ldflags", "")
    222 	cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "")
    223 	cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
    224 	cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
    225 	cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")
    226 	cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
    227 	cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
    228 	cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
    229 
    230 	// Undocumented, unstable debugging flags.
    231 	cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
    232 	cmd.Flag.Var(&load.DebugDeprecatedImportcfg, "debug-deprecated-importcfg", "")
    233 }
    234 
    235 // fileExtSplit expects a filename and returns the name
    236 // and ext (without the dot). If the file has no
    237 // extension, ext will be empty.
    238 func fileExtSplit(file string) (name, ext string) {
    239 	dotExt := filepath.Ext(file)
    240 	name = file[:len(file)-len(dotExt)]
    241 	if dotExt != "" {
    242 		ext = dotExt[1:]
    243 	}
    244 	return
    245 }
    246 
    247 func pkgsMain(pkgs []*load.Package) (res []*load.Package) {
    248 	for _, p := range pkgs {
    249 		if p.Name == "main" {
    250 			res = append(res, p)
    251 		}
    252 	}
    253 	return res
    254 }
    255 
    256 func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) {
    257 	for _, p := range pkgs {
    258 		if p.Name != "main" {
    259 			res = append(res, p)
    260 		}
    261 	}
    262 	return res
    263 }
    264 
    265 func oneMainPkg(pkgs []*load.Package) []*load.Package {
    266 	if len(pkgs) != 1 || pkgs[0].Name != "main" {
    267 		base.Fatalf("-buildmode=%s requires exactly one main package", cfg.BuildBuildmode)
    268 	}
    269 	return pkgs
    270 }
    271 
    272 var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
    273 
    274 var runtimeVersion = runtime.Version()
    275 
    276 func runBuild(cmd *base.Command, args []string) {
    277 	BuildInit()
    278 	var b Builder
    279 	b.Init()
    280 
    281 	pkgs := load.PackagesForBuild(args)
    282 
    283 	if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
    284 		_, cfg.BuildO = path.Split(pkgs[0].ImportPath)
    285 		cfg.BuildO += cfg.ExeSuffix
    286 	}
    287 
    288 	// Special case -o /dev/null by not writing at all.
    289 	if cfg.BuildO == os.DevNull {
    290 		cfg.BuildO = ""
    291 	}
    292 
    293 	// sanity check some often mis-used options
    294 	switch cfg.BuildContext.Compiler {
    295 	case "gccgo":
    296 		if load.BuildGcflags.Present() {
    297 			fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags")
    298 		}
    299 		if load.BuildLdflags.Present() {
    300 			fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags")
    301 		}
    302 	case "gc":
    303 		if load.BuildGccgoflags.Present() {
    304 			fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags")
    305 		}
    306 	}
    307 
    308 	depMode := ModeBuild
    309 	if cfg.BuildI {
    310 		depMode = ModeInstall
    311 	}
    312 
    313 	pkgs = pkgsFilter(load.Packages(args))
    314 
    315 	if cfg.BuildO != "" {
    316 		if len(pkgs) > 1 {
    317 			base.Fatalf("go build: cannot use -o with multiple packages")
    318 		} else if len(pkgs) == 0 {
    319 			base.Fatalf("no packages to build")
    320 		}
    321 		p := pkgs[0]
    322 		p.Target = cfg.BuildO
    323 		p.Stale = true // must build - not up to date
    324 		p.StaleReason = "build -o flag in use"
    325 		a := b.AutoAction(ModeInstall, depMode, p)
    326 		b.Do(a)
    327 		return
    328 	}
    329 
    330 	a := &Action{Mode: "go build"}
    331 	for _, p := range pkgs {
    332 		a.Deps = append(a.Deps, b.AutoAction(ModeBuild, depMode, p))
    333 	}
    334 	if cfg.BuildBuildmode == "shared" {
    335 		a = b.buildmodeShared(ModeBuild, depMode, args, pkgs, a)
    336 	}
    337 	b.Do(a)
    338 }
    339 
    340 var CmdInstall = &base.Command{
    341 	UsageLine: "install [-i] [build flags] [packages]",
    342 	Short:     "compile and install packages and dependencies",
    343 	Long: `
    344 Install compiles and installs the packages named by the import paths.
    345 
    346 The -i flag installs the dependencies of the named packages as well.
    347 
    348 For more about the build flags, see 'go help build'.
    349 For more about specifying packages, see 'go help packages'.
    350 
    351 See also: go build, go get, go clean.
    352 	`,
    353 }
    354 
    355 // libname returns the filename to use for the shared library when using
    356 // -buildmode=shared. The rules we use are:
    357 // Use arguments for special 'meta' packages:
    358 //	std --> libstd.so
    359 //	std cmd --> libstd,cmd.so
    360 // A single non-meta argument with trailing "/..." is special cased:
    361 //	foo/... --> libfoo.so
    362 //	(A relative path like "./..."  expands the "." first)
    363 // Use import paths for other cases, changing '/' to '-':
    364 //	somelib --> libsubdir-somelib.so
    365 //	./ or ../ --> libsubdir-somelib.so
    366 //	gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
    367 //	a/... b/... ---> liba/c,b/d.so - all matching import paths
    368 // Name parts are joined with ','.
    369 func libname(args []string, pkgs []*load.Package) (string, error) {
    370 	var libname string
    371 	appendName := func(arg string) {
    372 		if libname == "" {
    373 			libname = arg
    374 		} else {
    375 			libname += "," + arg
    376 		}
    377 	}
    378 	var haveNonMeta bool
    379 	for _, arg := range args {
    380 		if load.IsMetaPackage(arg) {
    381 			appendName(arg)
    382 		} else {
    383 			haveNonMeta = true
    384 		}
    385 	}
    386 	if len(libname) == 0 { // non-meta packages only. use import paths
    387 		if len(args) == 1 && strings.HasSuffix(args[0], "/...") {
    388 			// Special case of "foo/..." as mentioned above.
    389 			arg := strings.TrimSuffix(args[0], "/...")
    390 			if build.IsLocalImport(arg) {
    391 				cwd, _ := os.Getwd()
    392 				bp, _ := cfg.BuildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
    393 				if bp.ImportPath != "" && bp.ImportPath != "." {
    394 					arg = bp.ImportPath
    395 				}
    396 			}
    397 			appendName(strings.Replace(arg, "/", "-", -1))
    398 		} else {
    399 			for _, pkg := range pkgs {
    400 				appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
    401 			}
    402 		}
    403 	} else if haveNonMeta { // have both meta package and a non-meta one
    404 		return "", errors.New("mixing of meta and non-meta packages is not allowed")
    405 	}
    406 	// TODO(mwhudson): Needs to change for platforms that use different naming
    407 	// conventions...
    408 	return "lib" + libname + ".so", nil
    409 }
    410 
    411 func runInstall(cmd *base.Command, args []string) {
    412 	BuildInit()
    413 	InstallPackages(args, false)
    414 }
    415 
    416 func InstallPackages(args []string, forGet bool) {
    417 	if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) {
    418 		base.Fatalf("cannot install, GOBIN must be an absolute path")
    419 	}
    420 
    421 	pkgs := pkgsFilter(load.PackagesForBuild(args))
    422 
    423 	for _, p := range pkgs {
    424 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
    425 			switch {
    426 			case p.Internal.GobinSubdir:
    427 				base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName)
    428 			case p.Internal.CmdlineFiles:
    429 				base.Errorf("go %s: no install location for .go files listed on command line (GOBIN not set)", cfg.CmdName)
    430 			case p.ConflictDir != "":
    431 				base.Errorf("go %s: no install location for %s: hidden by %s", cfg.CmdName, p.Dir, p.ConflictDir)
    432 			default:
    433 				base.Errorf("go %s: no install location for directory %s outside GOPATH\n"+
    434 					"\tFor more details see: 'go help gopath'", cfg.CmdName, p.Dir)
    435 			}
    436 		}
    437 	}
    438 	base.ExitIfErrors()
    439 
    440 	var b Builder
    441 	b.Init()
    442 	depMode := ModeBuild
    443 	if cfg.BuildI {
    444 		depMode = ModeInstall
    445 	}
    446 	a := &Action{Mode: "go install"}
    447 	var tools []*Action
    448 	for _, p := range pkgs {
    449 		// During 'go get', don't attempt (and fail) to install packages with only tests.
    450 		// TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760.
    451 		if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
    452 			continue
    453 		}
    454 		// If p is a tool, delay the installation until the end of the build.
    455 		// This avoids installing assemblers/compilers that are being executed
    456 		// by other steps in the build.
    457 		a1 := b.AutoAction(ModeInstall, depMode, p)
    458 		if load.InstallTargetDir(p) == load.ToTool {
    459 			a.Deps = append(a.Deps, a1.Deps...)
    460 			a1.Deps = append(a1.Deps, a)
    461 			tools = append(tools, a1)
    462 			continue
    463 		}
    464 		a.Deps = append(a.Deps, a1)
    465 	}
    466 	if len(tools) > 0 {
    467 		a = &Action{
    468 			Mode: "go install (tools)",
    469 			Deps: tools,
    470 		}
    471 	}
    472 
    473 	if cfg.BuildBuildmode == "shared" {
    474 		// Note: If buildmode=shared then only non-main packages
    475 		// are present in the pkgs list, so all the special case code about
    476 		// tools above did not apply, and a is just a simple Action
    477 		// with a list of Deps, one per package named in pkgs,
    478 		// the same as in runBuild.
    479 		a = b.buildmodeShared(ModeInstall, ModeInstall, args, pkgs, a)
    480 	}
    481 
    482 	b.Do(a)
    483 	base.ExitIfErrors()
    484 
    485 	// Success. If this command is 'go install' with no arguments
    486 	// and the current directory (the implicit argument) is a command,
    487 	// remove any leftover command binary from a previous 'go build'.
    488 	// The binary is installed; it's not needed here anymore.
    489 	// And worse it might be a stale copy, which you don't want to find
    490 	// instead of the installed one if $PATH contains dot.
    491 	// One way to view this behavior is that it is as if 'go install' first
    492 	// runs 'go build' and the moves the generated file to the install dir.
    493 	// See issue 9645.
    494 	if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
    495 		// Compute file 'go build' would have created.
    496 		// If it exists and is an executable file, remove it.
    497 		_, targ := filepath.Split(pkgs[0].ImportPath)
    498 		targ += cfg.ExeSuffix
    499 		if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
    500 			fi, err := os.Stat(targ)
    501 			if err == nil {
    502 				m := fi.Mode()
    503 				if m.IsRegular() {
    504 					if m&0111 != 0 || cfg.Goos == "windows" { // windows never sets executable bit
    505 						os.Remove(targ)
    506 					}
    507 				}
    508 			}
    509 		}
    510 	}
    511 }
    512 
    513 // ExecCmd is the command to use to run user binaries.
    514 // Normally it is empty, meaning run the binaries directly.
    515 // If cross-compiling and running on a remote system or
    516 // simulator, it is typically go_GOOS_GOARCH_exec, with
    517 // the target GOOS and GOARCH substituted.
    518 // The -exec flag overrides these defaults.
    519 var ExecCmd []string
    520 
    521 // FindExecCmd derives the value of ExecCmd to use.
    522 // It returns that value and leaves ExecCmd set for direct use.
    523 func FindExecCmd() []string {
    524 	if ExecCmd != nil {
    525 		return ExecCmd
    526 	}
    527 	ExecCmd = []string{} // avoid work the second time
    528 	if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH {
    529 		return ExecCmd
    530 	}
    531 	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch))
    532 	if err == nil {
    533 		ExecCmd = []string{path}
    534 	}
    535 	return ExecCmd
    536 }
    537