If the arguments to build are a list of .go files, build treats
them as a list of source files specifying a single package.
-When the command line specifies a single main package,
-build writes the resulting executable to output.
-Otherwise build compiles the packages but discards the results,
+When compiling a single main package, build writes
+the resulting executable to an output file named after
+the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
+or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
+The '.exe' suffix is added when writing a Windows executable.
+
+When compiling multiple packages or a single non-main package,
+build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
-The -o flag specifies the output file name. If not specified, the
-output file name depends on the arguments and derives from the name
-of the package, such as p.a for package p, unless p is 'main'. If
-the package is main and file names are provided, the file name
-derives from the first file name mentioned, such as f1 for 'go build
-f1.go f2.go'; with no files provided ('go build'), the output file
-name is the base name of the containing directory.
+The -o flag, only allowed when compiling a single package,
+forces build to write the resulting executable or object
+to the named output file, instead of the default behavior described
+in the last two paragraphs.
The -i flag installs the packages that are dependencies of the target.
If the arguments to build are a list of .go files, build treats
them as a list of source files specifying a single package.
-When the command line specifies a single main package,
-build writes the resulting executable to output.
-Otherwise build compiles the packages but discards the results,
+When compiling a single main package, build writes
+the resulting executable to an output file named after
+the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
+or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
+The '.exe' suffix is added when writing a Windows executable.
+
+When compiling multiple packages or a single non-main package,
+build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
-The -o flag specifies the output file name. If not specified, the
-output file name depends on the arguments and derives from the name
-of the package, such as p.a for package p, unless p is 'main'. If
-the package is main and file names are provided, the file name
-derives from the first file name mentioned, such as f1 for 'go build
-f1.go f2.go'; with no files provided ('go build'), the output file
-name is the base name of the containing directory.
+The -o flag, only allowed when compiling a single package,
+forces build to write the resulting executable or object
+to the named output file, instead of the default behavior described
+in the last two paragraphs.
The -i flag installs the packages that are dependencies of the target.
fatalf("no packages to build")
}
p := pkgs[0]
- p.target = "" // must build - not up to date
+ p.target = *buildO
+ p.Stale = true // must build - not up to date
a := b.action(modeInstall, depMode, p)
- a.target = *buildO
- if p.local {
- // If p.local, then b.action did not really install,
- // so install the header file now if necessary.
- a = b.maybeAddHeaderAction(a, false)
- }
b.do(a)
return
}
if gobin != "" {
pkg.target = filepath.Join(gobin, exe)
}
- } else {
- if *buildO == "" {
- *buildO = pkg.Name + ".a"
- }
}
+
pkg.Target = pkg.target
pkg.Stale = true
name := "a.out"
if p.exeName != "" {
name = p.exeName
+ } else if goos == "darwin" && buildBuildmode == "c-shared" && p.target != "" {
+ // On OS X, the linker output name gets recorded in the
+ // shared library's LC_ID_DYLIB load command.
+ // The code invoking the linker knows to pass only the final
+ // path element. Arrange that the path element matches what
+ // we'll install it as; otherwise the library is only loadable as "a.out".
+ _, name = filepath.Split(p.target)
}
a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
}
ldflags = append(ldflags, "-buildid="+root.p.buildID)
}
ldflags = append(ldflags, buildLdflags...)
- return b.run(".", root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+
+ // On OS X when using external linking to build a shared library,
+ // the argument passed here to -o ends up recorded in the final
+ // shared library in the LC_ID_DYLIB load command.
+ // To avoid putting the temporary output directory name there
+ // (and making the resulting shared library useless),
+ // run the link in the output directory so that -o can name
+ // just the final path element.
+ dir := "."
+ if goos == "darwin" && buildBuildmode == "c-shared" {
+ dir, out = filepath.Split(out)
+ }
+
+ return b.run(dir, root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
}
func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
"go/build"
"go/format"
"internal/testenv"
+ "io"
"io/ioutil"
"os"
"os/exec"
return filepath.Join(tg.tempdir, name)
}
+// mustNotExist fails if path exists.
+func (tg *testgoData) mustNotExist(path string) {
+ if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
+ tg.t.Fatalf("%s exists but should not (%v)", path, err)
+ }
+}
+
// wantExecutable fails with msg if path is not executable.
func (tg *testgoData) wantExecutable(path, msg string) {
if st, err := os.Stat(path); err != nil {
}
}
+// wantArchive fails if path is not an archive.
+func (tg *testgoData) wantArchive(path string) {
+ f, err := os.Open(path)
+ if err != nil {
+ tg.t.Fatal(err)
+ }
+ buf := make([]byte, 100)
+ io.ReadFull(f, buf)
+ f.Close()
+ if !bytes.HasPrefix(buf, []byte("!<arch>\n")) {
+ tg.t.Fatalf("file %s exists but is not an archive", path)
+ }
+}
+
// isStale returns whether pkg is stale.
func (tg *testgoData) isStale(pkg string) bool {
tg.run("list", "-f", "{{.Stale}}", pkg)
tg.unsetenv("TERM")
tg.run("run", tg.path("run.go"))
}
+
+func TestGoBuildOutput(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.makeTempdir()
+ tg.cd(tg.path("."))
+
+ nonExeSuffix := ".exe"
+ if exeSuffix == ".exe" {
+ nonExeSuffix = ""
+ }
+
+ tg.tempFile("x.go", "package main\nfunc main(){}\n")
+ tg.run("build", "x.go")
+ tg.wantExecutable("x"+exeSuffix, "go build x.go did not write x"+exeSuffix)
+ tg.must(os.Remove(tg.path("x" + exeSuffix)))
+ tg.mustNotExist("x" + nonExeSuffix)
+
+ tg.run("build", "-o", "myprog", "x.go")
+ tg.mustNotExist("x")
+ tg.mustNotExist("x.exe")
+ tg.wantExecutable("myprog", "go build -o myprog x.go did not write myprog")
+ tg.mustNotExist("myprog.exe")
+
+ tg.tempFile("p.go", "package p\n")
+ tg.run("build", "p.go")
+ tg.mustNotExist("p")
+ tg.mustNotExist("p.a")
+ tg.mustNotExist("p.o")
+ tg.mustNotExist("p.exe")
+
+ tg.run("build", "-o", "p.a", "p.go")
+ tg.wantArchive("p.a")
+
+ tg.run("build", "cmd/gofmt")
+ tg.wantExecutable("gofmt"+exeSuffix, "go build cmd/gofmt did not write gofmt"+exeSuffix)
+ tg.must(os.Remove(tg.path("gofmt" + exeSuffix)))
+ tg.mustNotExist("gofmt" + nonExeSuffix)
+
+ tg.run("build", "-o", "mygofmt", "cmd/gofmt")
+ tg.wantExecutable("mygofmt", "go build -o mygofmt cmd/gofmt did not write mygofmt")
+ tg.mustNotExist("mygofmt.exe")
+ tg.mustNotExist("gofmt")
+ tg.mustNotExist("gofmt.exe")
+
+ tg.run("build", "sync/atomic")
+ tg.mustNotExist("atomic")
+ tg.mustNotExist("atomic.exe")
+
+ tg.run("build", "-o", "myatomic.a", "sync/atomic")
+ tg.wantArchive("myatomic.a")
+ tg.mustNotExist("atomic")
+ tg.mustNotExist("atomic.a")
+ tg.mustNotExist("atomic.exe")
+
+ tg.runFail("build", "-o", "whatever", "cmd/gofmt", "sync/atomic")
+ tg.grepStderr("multiple packages", "did not reject -o with multiple packages")
+}