From ccea2b367771831e9877ec31e0656d153818bf3f Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 14 Jan 2017 00:05:42 +0000 Subject: libgo: update to Go 1.8 release candidate 1 Compiler changes: * Change map assignment to use mapassign and assign value directly. * Change string iteration to use decoderune, faster for ASCII strings. * Change makeslice to take int, and use makeslice64 for larger values. * Add new noverflow field to hmap struct used for maps. Unresolved problems, to be fixed later: * Commented out test in go/types/sizes_test.go that doesn't compile. * Commented out reflect.TestStructOf test for padding after zero-sized field. Reviewed-on: https://go-review.googlesource.com/35231 gotools/: Updates for Go 1.8rc1. * Makefile.am (go_cmd_go_files): Add bug.go. (s-zdefaultcc): Write defaultPkgConfig. * Makefile.in: Rebuild. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244456 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgo/go/cmd/go/build.go | 455 +++++++++++++++++++++++++++++------------------ 1 file changed, 286 insertions(+), 169 deletions(-) (limited to 'libgo/go/cmd/go/build.go') diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go index 10116f282f0..a8f90344c30 100644 --- a/libgo/go/cmd/go/build.go +++ b/libgo/go/cmd/go/build.go @@ -346,6 +346,13 @@ func buildModeInit() { case "darwin/arm", "darwin/arm64": codegenArg = "-shared" default: + switch goos { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + // Use -shared so that the result is + // suitable for inclusion in a PIE or + // shared library. + codegenArg = "-shared" + } } exeSuffix = ".a" ldBuildmode = "c-archive" @@ -407,6 +414,21 @@ func buildModeInit() { fatalf("-buildmode=shared and -o not supported together") } ldBuildmode = "shared" + case "plugin": + pkgsFilter = pkgsMain + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", + "android/amd64", "android/arm", "android/arm64", "android/386": + default: + fatalf("-buildmode=plugin not supported on %s\n", platform) + } + codegenArg = "-dynlink" + } + exeSuffix = ".so" + ldBuildmode = "plugin" default: fatalf("buildmode=%s not supported", buildBuildmode) } @@ -432,10 +454,13 @@ func buildModeInit() { buildAsmflags = append(buildAsmflags, codegenArg) buildGcflags = append(buildGcflags, codegenArg) } - if buildContext.InstallSuffix != "" { - buildContext.InstallSuffix += "_" + // Don't alter InstallSuffix when modifying default codegen args. + if buildBuildmode != "default" || buildLinkshared { + if buildContext.InstallSuffix != "" { + buildContext.InstallSuffix += "_" + } + buildContext.InstallSuffix += codegenArg[1:] } - buildContext.InstallSuffix += codegenArg[1:] } } @@ -452,6 +477,11 @@ func runBuild(cmd *Command, args []string) { *buildO += exeSuffix } + // Special case -o /dev/null by not writing at all. + if *buildO == os.DevNull { + *buildO = "" + } + // sanity check some often mis-used options switch buildContext.Compiler { case "gccgo": @@ -580,6 +610,10 @@ func libname(args []string, pkgs []*Package) (string, error) { } func runInstall(cmd *Command, args []string) { + installPackages(args, false) +} + +func installPackages(args []string, forGet bool) { if gobin != "" && !filepath.IsAbs(gobin) { fatalf("cannot install, GOBIN must be an absolute path") } @@ -599,7 +633,7 @@ func runInstall(cmd *Command, args []string) { errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir) default: errorf("go install: no install location for directory %s outside GOPATH\n"+ - "\tFor more details see: go help gopath", p.Dir) + "\tFor more details see: 'go help gopath'", p.Dir) } } } @@ -607,6 +641,8 @@ func runInstall(cmd *Command, args []string) { var b builder b.init() + // Set the behavior for `go get` to not error on packages with test files only. + b.testFilesOnlyOK = forGet var a *action if buildBuildmode == "shared" { if libName, err := libname(args, pkgs); err != nil { @@ -697,6 +733,8 @@ type builder struct { flagCache map[string]bool // a cache of supported compiler flags print func(args ...interface{}) (int, error) + testFilesOnlyOK bool // do not error if the packages only have test files + output sync.Mutex scriptDir string // current directory in printed script @@ -1283,6 +1321,8 @@ func (b *builder) do(root *action) { if err != nil { if err == errPrintedOutput { setExitStatus(2) + } else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK { + // Ignore the "no buildable Go source files" error for a package with only test files. } else { errorf("%s", err) } @@ -1369,7 +1409,7 @@ func (b *builder) build(a *action) (err error) { } defer func() { - if err != nil && err != errPrintedOutput { + if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.p.TestGoFiles) > 0) { err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err) } }() @@ -1400,7 +1440,7 @@ func (b *builder) build(a *action) (err error) { } } - var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string + var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.p.GoFiles...) cgofiles = append(cgofiles, a.p.CgoFiles...) @@ -1422,7 +1462,7 @@ func (b *builder) build(a *action) (err error) { if err != nil { return err } - cgofiles = append(cgofiles, outGo...) + objdirCgofiles = append(objdirCgofiles, outGo...) cfiles = append(cfiles, outC...) cxxfiles = append(cxxfiles, outCXX...) } @@ -1457,7 +1497,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, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles) + outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles) if err != nil { return err } @@ -1555,12 +1595,12 @@ func (b *builder) build(a *action) (err error) { } // Assemble .s files. - for _, file := range sfiles { - out := file[:len(file)-len(".s")] + ".o" - if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil { + if len(sfiles) > 0 { + ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles) + if err != nil { return err } - objects = append(objects, out) + objects = append(objects, ofiles...) } // NOTE(rsc): On Windows, it is critically important that the @@ -1599,23 +1639,62 @@ func (b *builder) build(a *action) (err error) { return nil } +// pkgconfigCmd returns a pkg-config binary name +// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. +func (b *builder) pkgconfigCmd() string { + return envList("PKG_CONFIG", defaultPkgConfig)[0] +} + +// splitPkgConfigOutput parses the pkg-config output into a slice of +// flags. pkg-config always uses \ to escape special characters. +func splitPkgConfigOutput(out []byte) []string { + if len(out) == 0 { + return nil + } + var flags []string + flag := make([]byte, len(out)) + r, w := 0, 0 + for r < len(out) { + switch out[r] { + case ' ', '\t', '\r', '\n': + if w > 0 { + flags = append(flags, string(flag[:w])) + } + w = 0 + case '\\': + r++ + fallthrough + default: + if r < len(out) { + flag[w] = out[r] + w++ + } + } + r++ + } + if w > 0 { + flags = append(flags, string(flag[:w])) + } + return flags +} + // 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) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs) if err != nil { - b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) + b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) b.print(err.Error() + "\n") err = errPrintedOutput return } if len(out) > 0 { - cflags = strings.Fields(string(out)) + cflags = splitPkgConfigOutput(out) } - out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs) if err != nil { - b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) + b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) b.print(err.Error() + "\n") err = errPrintedOutput return @@ -1656,7 +1735,7 @@ func (b *builder) install(a *action) (err error) { perm := os.FileMode(0666) if a1.link { switch buildBuildmode { - case "c-archive", "c-shared": + case "c-archive", "c-shared", "plugin": default: perm = 0777 } @@ -2197,9 +2276,9 @@ type toolchain interface { // cc runs the toolchain's C compiler in a directory on a C file // to produce an output file. cc(b *builder, p *Package, objdir, ofile, cfile string) error - // asm runs the assembler in a specific directory on a specific file - // to generate the named output file. - asm(b *builder, p *Package, obj, ofile, sfile string) error + // asm runs the assembler in a specific directory on specific files + // and returns a list of named output files. + asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) // pkgpath builds an appropriate path for a temporary package file. pkgpath(basedir string, p *Package) string // pack runs the archive packer in a specific directory to create @@ -2236,8 +2315,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, return "", nil, noCompiler() } -func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { - return noCompiler() +func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { + return nil, noCompiler() } func (noToolchain) pkgpath(basedir string, p *Package) string { @@ -2342,11 +2421,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, return ofile, output, err } -func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { +func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. inc := filepath.Join(goroot, "pkg", "include") - sfile = mkAbs(p.Dir, sfile) - args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags} + args := []interface{}{buildToolExec, tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags} if p.ImportPath == "runtime" && goarch == "386" { for _, arg := range buildAsmflags { if arg == "-dynlink" { @@ -2354,11 +2432,16 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { } } } - args = append(args, sfile) - if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil { - return err + var ofiles []string + for _, sfile := range sfiles { + ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + a := append(args, "-o", ofile, mkAbs(p.Dir, sfile)) + if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil { + return nil, err + } } - return nil + return ofiles, nil } // toolVerify checks that the command line args writes the same output file @@ -2516,6 +2599,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action if root.p.omitDWARF { ldflags = append(ldflags, "-w") } + if buildBuildmode == "plugin" { + pluginpath := root.p.ImportPath + if pluginpath == "command-line-arguments" { + pluginpath = "plugin/unnamed-" + root.p.buildID + } + ldflags = append(ldflags, "-pluginpath", pluginpath) + } // If the user has not specified the -extld option, then specify the // appropriate linker. In case of C++ code, use the compiler named @@ -2625,15 +2715,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh return ofile, output, err } -func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { - sfile = mkAbs(p.Dir, sfile) - defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch} - if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { - defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath) +func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { + var ofiles []string + for _, sfile := range sfiles { + ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + sfile = mkAbs(p.Dir, sfile) + defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch} + if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { + defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath) + } + defs = tools.maybePIC(defs) + defs = append(defs, b.gccArchArgs()...) + err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile) + if err != nil { + return nil, err + } } - defs = tools.maybePIC(defs) - defs = append(defs, b.gccArchArgs()...) - return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile) + return ofiles, nil } func (gccgoToolchain) pkgpath(basedir string, p *Package) string { @@ -2755,7 +2854,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction if !apackagePathsSeen[a.p.ImportPath] { apackagePathsSeen[a.p.ImportPath] = true target := a.target - if len(a.p.CgoFiles) > 0 { + if len(a.p.CgoFiles) > 0 || a.p.usesSwig() { target, err = readAndRemoveCgoFlags(target) if err != nil { return @@ -2947,7 +3046,7 @@ func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile stri // maybePIC adds -fPIC to the list of arguments if needed. func (tools gccgoToolchain) maybePIC(args []string) []string { switch buildBuildmode { - case "c-shared", "shared": + case "c-shared", "shared", "plugin": args = append(args, "-fPIC") } return args @@ -2988,9 +3087,19 @@ func (b *builder) gfortran(p *Package, out string, flags []string, ffile string) } // ccompile runs the given C or C++ compiler and creates an object from a single source file. -func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error { +func (b *builder) ccompile(p *Package, outfile string, flags []string, file string, compiler []string) error { file = mkAbs(p.Dir, file) - return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file) + desc := p.ImportPath + output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file) + if len(output) > 0 { + b.showOutput(p.Dir, desc, b.processOutput(output)) + if err != nil { + err = errPrintedOutput + } else if os.Getenv("GO_BUILDER_NAME") != "" { + return errors.New("C compiler warning promoted to error on Go builders") + } + } + return err } // gccld runs the gcc linker to create an executable from a set of object files. @@ -3129,6 +3238,8 @@ func (b *builder) gccArchArgs() []string { return []string{"-m64", "-march=z196"} case "mips64", "mips64le": return []string{"-mabi=64"} + case "mips", "mipsle": + return []string{"-mabi=32", "-march=mips32"} } return nil } @@ -3144,11 +3255,8 @@ func envList(key, def string) []string { } // Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo. -func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, fflags, ldflags []string) { - var defaults string - if def { - defaults = "-g -O2" - } +func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { + defaults := "-g -O2" cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) @@ -3160,9 +3268,9 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ffla var cgoRe = regexp.MustCompile(`[/\\:]`) -func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p, true) - _, cgoexeCFLAGS, _, _, _ := b.cflags(p, false) +func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { + p := a.p + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p) cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc @@ -3183,7 +3291,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi } } - if buildMSan && p.ImportPath != "runtime/cgo" { + if buildMSan { cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) } @@ -3191,20 +3299,33 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi // Allows including _cgo_export.h from .[ch] files in the package. cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) + // If we have cgo files in the object directory, then copy any + // other cgo files into the object directory, and pass a + // -srcdir option to cgo. + var srcdirarg []string + if len(objdirCgofiles) > 0 { + for _, fn := range cgofiles { + if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil { + return nil, nil, err + } + } + cgofiles = append(cgofiles, objdirCgofiles...) + srcdirarg = []string{"-srcdir", obj} + } + // cgo // TODO: CGO_FLAGS? gofiles := []string{obj + "_cgo_gotypes.go"} - cfiles := []string{"_cgo_main.c", "_cgo_export.c"} + cfiles := []string{"_cgo_export.c"} for _, fn := range cgofiles { f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_") gofiles = append(gofiles, obj+f+"cgo1.go") cfiles = append(cfiles, f+"cgo2.c") } - defunC := obj + "_cgo_defun.c" - cgoflags := []string{} // TODO: make cgo not depend on $GOARCH? + cgoflags := []string{} if p.Standard && p.ImportPath == "runtime/cgo" { cgoflags = append(cgoflags, "-import_runtime_cgo=false") } @@ -3241,165 +3362,166 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h") } - if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil { + if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil { return nil, nil, err } outGo = append(outGo, gofiles...) - // cc _cgo_defun.c - _, gccgo := buildToolchain.(gccgoToolchain) - if gccgo { - defunObj := obj + "_cgo_defun.o" - if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { - return nil, nil, err - } - outObj = append(outObj, defunObj) - } - // gcc - var linkobj []string - - var bareLDFLAGS []string - // When linking relocatable objects, various flags need to be - // filtered out as they are inapplicable and can cause some linkers - // to fail. - for i := 0; i < len(cgoLDFLAGS); i++ { - f := cgoLDFLAGS[i] - switch { - // skip "-lc" or "-l somelib" - case strings.HasPrefix(f, "-l"): - if f == "-l" { - i++ - } - // skip "-framework X" on Darwin - case goos == "darwin" && f == "-framework": - i++ - // skip "*.{dylib,so,dll}" - case strings.HasSuffix(f, ".dylib"), - strings.HasSuffix(f, ".so"), - strings.HasSuffix(f, ".dll"): - // 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 - // runpath flags not applicable unless building a shared - // object or executable; see issue 12115 for details. This - // is necessary as Go currently does not offer a way to - // specify the set of LDFLAGS that only apply to shared - // objects. - case strings.HasPrefix(f, "-Wl,-rpath"): - if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" { - // Skip following argument to -rpath* too. - i++ - } - default: - bareLDFLAGS = append(bareLDFLAGS, f) - } - } - - var staticLibs []string - if goos == "windows" { - // libmingw32 and libmingwex have some inter-dependencies, - // so must use linker groups. - staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"} - } - cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) for _, cfile := range cfiles { ofile := obj + cfile[:len(cfile)-1] + "o" if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil { return nil, nil, err } - linkobj = append(linkobj, ofile) - if !strings.HasSuffix(ofile, "_cgo_main.o") { - outObj = append(outObj, ofile) - } + outObj = append(outObj, ofile) } for _, file := range gccfiles { - ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o" + base := filepath.Base(file) + ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o" if err := b.gcc(p, ofile, cflags, file); err != nil { return nil, nil, err } - linkobj = append(linkobj, ofile) outObj = append(outObj, ofile) } cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) for _, file := range gxxfiles { // Append .o to the file, just in case the pkg has file.c and file.cpp - ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" + ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" if err := b.gxx(p, ofile, cxxflags, file); err != nil { return nil, nil, err } - linkobj = append(linkobj, ofile) outObj = append(outObj, ofile) } for _, file := range mfiles { // Append .o to the file, just in case the pkg has file.c and file.m - ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" + ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" if err := b.gcc(p, ofile, cflags, file); err != nil { return nil, nil, err } - linkobj = append(linkobj, ofile) outObj = append(outObj, ofile) } fflags := stringList(cgoCPPFLAGS, cgoFFLAGS) for _, file := range ffiles { // Append .o to the file, just in case the pkg has file.c and file.f - ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" + ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" if err := b.gfortran(p, ofile, fflags, file); err != nil { return nil, nil, err } - linkobj = append(linkobj, ofile) outObj = append(outObj, ofile) } - linkobj = append(linkobj, p.SysoFiles...) - dynobj := obj + "_cgo_.o" - 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 + switch buildToolchain.(type) { + case gcToolchain: + importGo := obj + "_cgo_import.go" + if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil { + return nil, nil, err + } + outGo = append(outGo, importGo) + + ofile := obj + "_all.o" + if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil { + return nil, nil, err + } + outObj = []string{ofile} + + case gccgoToolchain: + defunC := obj + "_cgo_defun.c" + defunObj := obj + "_cgo_defun.o" + if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { + return nil, nil, err + } + outObj = append(outObj, defunObj) + + default: + noCompiler() } - if pie { // but we don't need -pie for normal cgo programs - cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1] + + return outGo, outObj, nil +} + +// dynimport creates a Go source file named importGo containing +// //go:cgo_import_dynamic directives for each symbol or library +// dynamically imported by the object files outObj. +func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { + cfile := obj + "_cgo_main.c" + ofile := obj + "_cgo_main.o" + if err := b.gcc(p, ofile, cflags, cfile); err != nil { + return err } - if _, ok := buildToolchain.(gccgoToolchain); ok { - // we don't use dynimport when using gccgo. - return outGo, outObj, nil + linkobj := stringList(ofile, outObj, p.SysoFiles) + dynobj := obj + "_cgo_.o" + + // we need to use -pie for Linux/ARM to get accurate imported sym + ldflags := cgoLDFLAGS + if (goarch == "arm" && goos == "linux") || goos == "android" { + ldflags = append(ldflags, "-pie") + } + if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil { + return err } // cgo -dynimport - importGo := obj + "_cgo_import.go" - cgoflags = []string{} + var cgoflags []string if p.Standard && p.ImportPath == "runtime/cgo" { - cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker - } - if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil { - return nil, nil, err + cgoflags = []string{"-dynlinker"} // record path to dynamic linker } - outGo = append(outGo, importGo) + return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) +} - ofile := obj + "_all.o" - var gccObjs, nonGccObjs []string - for _, f := range outObj { - if strings.HasSuffix(f, ".o") { - gccObjs = append(gccObjs, f) - } else { - nonGccObjs = append(nonGccObjs, f) +// collect partially links the object files outObj into a single +// relocatable object file named ofile. +func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []string) error { + // When linking relocatable objects, various flags need to be + // filtered out as they are inapplicable and can cause some linkers + // to fail. + var ldflags []string + for i := 0; i < len(cgoLDFLAGS); i++ { + f := cgoLDFLAGS[i] + switch { + // skip "-lc" or "-l somelib" + case strings.HasPrefix(f, "-l"): + if f == "-l" { + i++ + } + // skip "-framework X" on Darwin + case goos == "darwin" && f == "-framework": + i++ + // skip "*.{dylib,so,dll,o,a}" + case strings.HasSuffix(f, ".dylib"), + strings.HasSuffix(f, ".so"), + strings.HasSuffix(f, ".dll"), + strings.HasSuffix(f, ".o"), + strings.HasSuffix(f, ".a"): + // 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 + // runpath flags not applicable unless building a shared + // object or executable; see issue 12115 for details. This + // is necessary as Go currently does not offer a way to + // specify the set of LDFLAGS that only apply to shared + // objects. + case strings.HasPrefix(f, "-Wl,-rpath"): + if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" { + // Skip following argument to -rpath* too. + i++ + } + default: + ldflags = append(ldflags, f) } } - ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) + + ldflags = append(ldflags, "-Wl,-r", "-nostdlib") if b.gccSupportsNoPie() { ldflags = append(ldflags, "-no-pie") @@ -3408,16 +3530,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi // We are creating an object file, so we don't want a build ID. ldflags = b.disableBuildID(ldflags) - if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil { - return nil, nil, err - } - - // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows - // must be processed before the gcc-generated objects. - // Put it first. https://golang.org/issue/2601 - outObj = stringList(nonGccObjs, ofile) - - return outGo, outObj, nil + return b.gccld(p, ofile, ldflags, outObj) } // Run SWIG on all SWIG input files. @@ -3570,7 +3683,7 @@ 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, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p, true) + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p) var cflags []string if cxx { cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) @@ -3633,7 +3746,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning } - return obj + goFile, obj + gccBase + gccExt, nil + return goFile, obj + gccBase + gccExt, nil } // disableBuildID adjusts a linker command line to avoid creating a @@ -3682,7 +3795,11 @@ func instrumentInit() { return } if buildRace && buildMSan { - fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously", flag.Args()[0]) + fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) + os.Exit(2) + } + if buildMSan && (goos != "linux" || goarch != "amd64") { + fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", goos, goarch) os.Exit(2) } if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" { -- cgit v1.2.1