return s
}
-// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
-// preamble. Multiple occurrences are concatenated with a separating space,
-// even across files.
-func (p *Package) ParseFlags(f *File, srcfile string) {
+// DiscardCgoDirectives processes the import C preamble, and discards
+// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
+// way into _cgo_export.h.
+func (f *File) DiscardCgoDirectives() {
linesIn := strings.Split(f.Preamble, "\n")
linesOut := make([]string, 0, len(linesIn))
-
-NextLine:
for _, line := range linesIn {
l := strings.TrimSpace(line)
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
linesOut = append(linesOut, line)
- continue
- }
-
- l = strings.TrimSpace(l[4:])
- fields := strings.SplitN(l, ":", 2)
- if len(fields) != 2 {
- fatalf("%s: bad #cgo line: %s", srcfile, line)
- }
-
- var k string
- kf := strings.Fields(fields[0])
- switch len(kf) {
- case 1:
- k = kf[0]
- case 2:
- k = kf[1]
- switch kf[0] {
- case goos:
- case goarch:
- case goos + "/" + goarch:
- default:
- continue NextLine
- }
- default:
- fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
- }
-
- args, err := splitQuoted(fields[1])
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- for _, arg := range args {
- if !safeName(arg) {
- fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
- }
- }
-
- switch k {
-
- case "CFLAGS", "LDFLAGS":
- p.addToFlag(k, args)
-
- case "pkg-config":
- cflags, ldflags, err := pkgConfig(args)
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- p.addToFlag("CFLAGS", cflags)
- p.addToFlag("LDFLAGS", ldflags)
-
- default:
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
-
}
}
f.Preamble = strings.Join(linesOut, "\n")
}
}
-// pkgConfig runs pkg-config and extracts --libs and --cflags information
-// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err error) {
- for _, name := range packages {
- if len(name) == 0 || name[0] == '-' {
- return nil, nil, errors.New(fmt.Sprintf("invalid name: %q", name))
- }
- }
-
- args := append([]string{"pkg-config", "--cflags"}, packages...)
- stdout, stderr, ok := run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- cflags, err = splitQuoted(string(stdout))
- if err != nil {
- return
- }
-
- args = append([]string{"pkg-config", "--libs"}, packages...)
- stdout, stderr, ok = run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- ldflags, err = splitQuoted(string(stdout))
- return
-}
-
// splitQuoted splits the string s around each instance of one or more consecutive
// white space characters while taking into account quotes and escaping, and
// returns an array of substrings of s or an empty list if s contains only white space.
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"sync"
"time"
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
// and returns a non-nil error.
-func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {
- out, err := b.runOut(dir, desc, cmdargs...)
+func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
+ out, err := b.runOut(dir, desc, env, cmdargs...)
if len(out) > 0 {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
// runOut runs the command given by cmdline in the directory dir.
// It returns the command output and any errors that occurred.
-func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byte, error) {
+func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
b.showcmd(dir, "%s", strings.Join(cmdline, " "))
cmd.Stdout = &buf
cmd.Stderr = &buf
cmd.Dir = dir
- cmd.Env = envForDir(cmd.Dir)
+ cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
err := cmd.Run()
// cmd.Run will fail on Unix if some other process has the binary
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, args)
+ output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
swigDirs[sd] = true
}
}
- return b.run(".", p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, swigArg, buildLdflags, mainpkg)
+ return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, buildLdflags, mainpkg)
}
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", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
- return b.run(p.Dir, p.ImportPath, args)
+ return b.run(p.Dir, p.ImportPath, nil, args)
}
// The Gccgo toolchain.
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, args)
+ output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
defs = append(defs, b.gccArchArgs()...)
- return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
}
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
}
- return b.run(".", p.ImportPath, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+ return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
}
func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
// TODO: Support using clang here (during gccgo build)?
- return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
+ return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
}
return fmt.Fprint(&buf, a...)
}
}
- f, err := b.runOut(p.Dir, p.ImportPath, gccCmd, "-print-libgcc-file-name")
+ f, err := b.runOut(p.Dir, p.ImportPath, nil, gccCmd, "-print-libgcc-file-name")
if err != nil {
return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
}
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
cfile = mkAbs(p.Dir, cfile)
- return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
+ return b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
}
// gccld runs the gcc linker to create an executable from a set of object files
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
- return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
+ return b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", out, obj, flags)
}
// gccCmd returns a gcc command line prefix
cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
- out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs)
+ 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")
if len(out) > 0 {
cgoCFLAGS = append(cgoCFLAGS, strings.Fields(string(out))...)
}
- out, err = b.runOut(p.Dir, p.ImportPath, "pkg-config", "--libs", pkgs)
+ 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")
cgoflags = append(cgoflags, "-import_syscall=false")
}
+ // Update $CGO_LDFLAGS with p.CgoLDFLAGS.
+ var cgoenv []string
+ if len(cgoLDFLAGS) > 0 {
+ flags := make([]string, len(cgoLDFLAGS))
+ for i, f := range cgoLDFLAGS {
+ flags[i] = strconv.Quote(f)
+ }
+ cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
+ }
+
if _, ok := buildToolchain.(gccgoToolchain); ok {
cgoflags = append(cgoflags, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
}
objExt = "o"
}
- if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
}
- if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
return nil, nil, err
}
args = append(args, "-c++")
}
- if out, err := b.runOut(p.Dir, p.ImportPath, "swig", args, file); err != nil {
+ if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
return "", "", errors.New("must have SWIG version >= 2.0.9\n")
cxxlib = []string{"-lstdc++"}
}
ldflags := stringList(osldflags[goos], cxxlib)
- b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", soname, gccObj, ldflags)
+ b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", soname, gccObj, ldflags)
return obj + goFile, cObj, nil
}