summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/build.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/build.go')
-rw-r--r--libgo/go/cmd/go/build.go455
1 files changed, 286 insertions, 169 deletions
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" {