diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/cmd/go/build.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/cmd/go/build.go')
-rw-r--r-- | src/cmd/go/build.go | 226 |
1 files changed, 157 insertions, 69 deletions
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 3645f1c2d..1dd4314da 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -57,6 +57,7 @@ and test commands: -a force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. -n print the commands but do not run them. -p n @@ -64,7 +65,7 @@ and test commands: The default is the number of CPUs available. -race enable data race detection. - Supported only on linux/amd64, darwin/amd64 and windows/amd64. + Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. -v print the names of packages as they are compiled. -work @@ -284,23 +285,26 @@ func runBuild(cmd *Command, args []string) { } } + depMode := modeBuild + if buildI { + depMode = modeInstall + } + if *buildO != "" { if len(pkgs) > 1 { fatalf("go build: cannot use -o with multiple packages") + } else if len(pkgs) == 0 { + fatalf("no packages to build") } p := pkgs[0] p.target = "" // must build - not up to date - a := b.action(modeInstall, modeBuild, p) + a := b.action(modeInstall, depMode, p) a.target = *buildO b.do(a) return } a := &action{} - depMode := modeBuild - if buildI { - depMode = modeInstall - } for _, p := range packages(args) { a.deps = append(a.deps, b.action(modeBuild, depMode, p)) } @@ -431,12 +435,11 @@ const ( ) var ( - goroot = filepath.Clean(runtime.GOROOT()) - gobin = os.Getenv("GOBIN") - gorootBin = filepath.Join(goroot, "bin") - gorootSrcPkg = filepath.Join(goroot, "src/pkg") - gorootPkg = filepath.Join(goroot, "pkg") - gorootSrc = filepath.Join(goroot, "src") + goroot = filepath.Clean(runtime.GOROOT()) + gobin = os.Getenv("GOBIN") + gorootBin = filepath.Join(goroot, "bin") + gorootPkg = filepath.Join(goroot, "pkg") + gorootSrc = filepath.Join(goroot, "src") ) func (b *builder) init() { @@ -503,8 +506,13 @@ func goFilesPackage(gofiles []string) *Package { } ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil } - if !filepath.IsAbs(dir) { - dir = filepath.Join(cwd, dir) + var err error + if dir == "" { + dir = cwd + } + dir, err = filepath.Abs(dir) + if err != nil { + fatalf("%s", err) } bp, err := ctxt.ImportDir(dir, 0) @@ -823,12 +831,17 @@ func (b *builder) build(a *action) (err error) { } } - var gofiles, cfiles, sfiles, objects, cgoObjects []string + var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.p.GoFiles...) cfiles = append(cfiles, a.p.CFiles...) sfiles = append(sfiles, a.p.SFiles...) + if a.p.usesCgo() || a.p.usesSwig() { + if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { + return + } + } // Run cgo. if a.p.usesCgo() { // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. @@ -859,7 +872,7 @@ func (b *builder) build(a *action) (err error) { if a.cgo != nil && a.cgo.target != "" { cgoExe = a.cgo.target } - outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles) if err != nil { return err } @@ -872,9 +885,18 @@ func (b *builder) build(a *action) (err error) { // In a package using SWIG, any .c or .s files are // compiled with gcc. gccfiles := append(cfiles, sfiles...) + cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles cfiles = nil sfiles = nil - outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + + // Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config). + if a.p.usesCgo() { + cxxfiles = nil + gccfiles = nil + mfiles = nil + } + + outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles) if err != nil { return err } @@ -883,7 +905,7 @@ func (b *builder) build(a *action) (err error) { } if len(gofiles) == 0 { - return &build.NoGoError{a.p.Dir} + return &build.NoGoError{Dir: a.p.Dir} } // If we're doing coverage, preprocess the .go files and put them in the work directory @@ -1018,6 +1040,34 @@ func (b *builder) build(a *action) (err error) { return nil } +// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. +func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) { + if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { + var out []byte + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + cflags = strings.Fields(string(out)) + } + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + ldflags = strings.Fields(string(out)) + } + } + return +} + // install is the action for installing a single package or executable. func (b *builder) install(a *action) (err error) { defer func() { @@ -1253,7 +1303,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { // the source directory for the package that has failed to build. // showOutput rewrites mentions of dir with a relative path to dir // when the relative path is shorter. This is usually more pleasant. -// For example, if fmt doesn't compile and we are in src/pkg/html, +// For example, if fmt doesn't compile and we are in src/html, // the output is // // $ go build @@ -1265,7 +1315,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { // // $ go build // # fmt -// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf +// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf // $ // // showOutput also replaces references to the work directory with $WORK. @@ -1425,6 +1475,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter continue } + // err can be something like 'exit status 1'. + // Add information about what program was running. + // Note that if buf.Bytes() is non-empty, the caller usually + // shows buf.Bytes() and does not print err at all, so the + // prefix here does not make most output any more verbose. + if err != nil { + err = errors.New(cmdline[0] + ": " + err.Error()) + } return buf.Bytes(), err } } @@ -1587,7 +1645,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) if p.Standard { switch p.ImportPath { - case "os", "runtime/pprof", "sync", "time": + case "bytes", "net", "os", "runtime/pprof", "sync", "time": extFiles++ } } @@ -1611,8 +1669,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] } func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { + // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. + inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) sfile = mkAbs(p.Dir, sfile) - return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) + return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) } func (gcToolchain) pkgpath(basedir string, p *Package) string { @@ -1706,7 +1766,7 @@ func packInternal(b *builder, afile string, ofiles []string) error { func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { importArgs := b.includeArgs("-L", allactions) - cxx := false + cxx := len(p.CXXFiles) > 0 for _, a := range allactions { if a.p != nil && len(a.p.CXXFiles) > 0 { cxx = true @@ -1766,14 +1826,30 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) cfile = mkAbs(p.Dir, cfile) - args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) + warn := []string{"-w"} + if p.usesSwig() { + // When using SWIG, this compiler is only used to + // compile the C files generated by SWIG. + // We don't want warnings. + // See issue 9065 for details. + warn = nil + } + args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) return b.run(p.Dir, p.ImportPath, nil, args) } // The Gccgo toolchain. type gccgoToolchain struct{} -var gccgoBin, _ = exec.LookPath("gccgo") +var gccgoName, gccgoBin string + +func init() { + gccgoName = os.Getenv("GCCGO") + if gccgoName == "" { + gccgoName = "gccgo" + } + gccgoBin, _ = exec.LookPath(gccgoName) +} func (gccgoToolchain) compiler() string { return gccgoBin @@ -1784,7 +1860,7 @@ func (gccgoToolchain) linker() string { } func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - out := p.Name + ".o" + out := "_go_.o" ofile = obj + out gcargs := []string{"-g"} gcargs = append(gcargs, b.gccArchArgs()...) @@ -1794,7 +1870,7 @@ func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs if p.localPrefix != "" { gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix) } - args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) + args := stringList(gccgoName, importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) for _, f := range gofiles { args = append(args, mkAbs(p.Dir, f)) } @@ -1810,7 +1886,7 @@ func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) erro defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } defs = append(defs, b.gccArchArgs()...) - return b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile) + return b.run(p.Dir, p.ImportPath, nil, gccgoName, "-I", obj, "-o", ofile, defs, sfile) } func (gccgoToolchain) pkgpath(basedir string, p *Package) string { @@ -1836,8 +1912,8 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] ldflags := b.gccArchArgs() cgoldflags := []string{} usesCgo := false - cxx := false - objc := false + cxx := len(p.CXXFiles) > 0 + objc := len(p.MFiles) > 0 // Prefer the output of an install action to the output of a build action, // because the install action will delete the output of the build action. @@ -1877,6 +1953,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] } ldflags = append(ldflags, afiles...) ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) ldflags = append(ldflags, p.CgoLDFLAGS...) if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") @@ -1887,7 +1964,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] if objc { ldflags = append(ldflags, "-lobjc") } - return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) + return b.run(".", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) } func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { @@ -1898,8 +1975,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } - // TODO: Support using clang here (during gccgo build)? - return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g", + return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g", "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) } @@ -1950,9 +2026,9 @@ func (b *builder) libgcc(p *Package) (string, error) { return "$LIBGCC", nil } - // clang might not be able to find libgcc, and in that case, + // The compiler might not be able to find libgcc, and in that case, // it will simply return "libgcc.a", which is of no use to us. - if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) { + if !filepath.IsAbs(string(f)) { return "", nil } @@ -2090,36 +2166,16 @@ var ( cgoLibGccFileOnce sync.Once ) -func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true) _, cgoexeCFLAGS, _, _ := b.cflags(p, false) - + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) + cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc if len(mfiles) > 0 { cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") } - if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { - out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...) - } - out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...) - } - } - // Allows including _cgo_export.h from .[ch] files in the package. cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) @@ -2196,6 +2252,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles strings.HasSuffix(f, ".so"), strings.HasSuffix(f, ".dll"): continue + // Remove any -fsanitize=foo flags. + // Otherwise the compiler driver thinks that we are doing final link + // and links sanitizer runtime into the object file. But we are not doing + // the final link, we will link the resulting object file again. And + // so the program ends up with two copies of sanitizer runtime. + // See issue 8788 for details. + case strings.HasPrefix(f, "-fsanitize="): + continue default: bareLDFLAGS = append(bareLDFLAGS, f) } @@ -2262,13 +2326,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles linkobj = append(linkobj, p.SysoFiles...) dynobj := obj + "_cgo_.o" - if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym + pie := goarch == "arm" && (goos == "linux" || goos == "android") + if pie { // we need to use -pie for Linux/ARM to get accurate imported sym cgoLDFLAGS = append(cgoLDFLAGS, "-pie") } if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil { return nil, nil, err } - if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs + if pie { // but we don't need -pie for normal cgo programs cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1] } @@ -2302,7 +2367,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles nonGccObjs = append(nonGccObjs, f) } } - if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil { + ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) + + // Some systems, such as Ubuntu, always add --build-id to + // every link, but we don't want a build ID since we are + // producing an object file. On some of those system a plain + // -r (not -Wl,-r) will turn off --build-id, but clang 3.0 + // doesn't support a plain -r. I don't know how to turn off + // --build-id when using clang other than passing a trailing + // --build-id=none. So that is what we do, but only on + // systems likely to support it, which is to say, systems that + // normally use gold or the GNU linker. + switch goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + + if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil { return nil, nil, err } @@ -2317,7 +2398,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) @@ -2358,7 +2439,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } for _, f := range p.SwigFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) if err != nil { return nil, nil, err } @@ -2373,7 +2454,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } } for _, f := range p.SwigCXXFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) if err != nil { return nil, nil, err } @@ -2452,13 +2533,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { +func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) var cflags []string if cxx { - cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) } else { - cflags = stringList(cgoCPPFLAGS, cgoCFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) } n := 5 // length of ".swig" @@ -2484,6 +2565,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri "-o", obj + gccBase + gccExt, "-outdir", obj, } + + for _, f := range cflags { + if len(f) > 3 && f[:2] == "-I" { + args = append(args, f) + } + } + if gccgo { args = append(args, "-gccgo") if pkgpath := gccgoPkgpath(p); pkgpath != "" { @@ -2556,8 +2644,8 @@ func raceInit() { if !buildRace { return } - if goarch != "amd64" || goos != "linux" && goos != "darwin" && goos != "windows" { - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" { + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) os.Exit(2) } buildGcflags = append(buildGcflags, "-race") |