Skip to content

Commit

Permalink
Refactor gcc/gxx cgo invocation in gccld
Browse files Browse the repository at this point in the history
  • Loading branch information
davecheney committed Sep 17, 2015
1 parent 1c4727a commit de34371
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 53 deletions.
155 changes: 103 additions & 52 deletions cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func cgo14(pkg *Package) (*Action, []string, []string, error) {
Name: "rungcc3: " + pkg.ImportPath,
Deps: []*Action{&runcgo2, &rundefun},
Task: TaskFn(func() error {
return rungcc3(pkg.Context, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
return rungcc3(pkg, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
}),
}
return &action, []string{defun, imports, allo}, cgofiles, nil
Expand Down Expand Up @@ -169,7 +169,7 @@ func cgo15(pkg *Package) (*Action, []string, []string, error) {
Name: "rungcc3: " + pkg.ImportPath,
Deps: []*Action{&runcgo2},
Task: TaskFn(func() error {
return rungcc3(pkg.Context, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
return rungcc3(pkg, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
}),
}

Expand Down Expand Up @@ -212,7 +212,7 @@ func cgocc(pkg *Package, cflags, cxxflags, cfiles, cxxfiles []string, deps ...*A

// rungcc1 invokes gcc to compile cfile into ofile
func rungcc1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
args := []string{"-g", "-O2", "-fPIC", "-pthread", "-fmessage-length=0",
args := []string{"-g", "-O2",
"-I", pkg.Dir,
"-I", filepath.Dir(ofile),
}
Expand All @@ -222,14 +222,15 @@ func rungcc1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
"-c", cfile,
)
t0 := time.Now()
err := run(pkg.Dir, nil, gcc(), args...)
pkg.Record("gcc1", time.Since(t0))
gcc := gccCmd(pkg, pkg.Dir)
err := run(pkg.Dir, nil, gcc[0], append(gcc[1:], args...)...)
pkg.Record(gcc[0], time.Since(t0))
return err
}

// rungpp1 invokes g++ to compile cfile into ofile
func rungpp1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
args := []string{"-g", "-O2", "-fPIC", "-pthread", "-fmessage-length=0",
args := []string{"-g", "-O2",
"-I", pkg.Dir,
"-I", filepath.Dir(ofile),
}
Expand All @@ -239,49 +240,53 @@ func rungpp1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
"-c", cfile,
)
t0 := time.Now()
err := run(pkg.Dir, nil, "g++", args...) // TODO(dfc) hack
pkg.Record("gcc1", time.Since(t0))
gxx := gxxCmd(pkg, pkg.Dir)
err := run(pkg.Dir, nil, gxx[0], append(gxx[1:], args...)...)
pkg.Record(gxx[0], time.Since(t0))
return err
}

// gccld links the o files from rungcc1 into a single _cgo_.o.
func gccld(pkg *Package, cgoCFLAGS, cgoLDFLAGS []string, ofile string, ofiles []string) error {
args := []string{
"-fPIC", "-fmessage-length=0",
}
if !isClang() {
args = append(args, "-pthread")
}
args := []string{}
args = append(args, "-o", ofile)
args = append(args, ofiles...)
args = append(args, cgoLDFLAGS...) // this has to go at the end, because reasons!
t0 := time.Now()
err := run(pkg.Dir, nil, gcc(), args...)

var cmd []string
if len(pkg.CXXFiles) > 0 || len(pkg.SwigCXXFiles) > 0 {
cmd = gxxCmd(pkg, pkg.Dir)
} else {
cmd = gccCmd(pkg, pkg.Dir)
}
err := run(pkg.Dir, nil, cmd[0], append(cmd[1:], args...)...)
pkg.Record("gccld", time.Since(t0))
return err
}

// rungcc3 links all previous ofiles together with libgcc into a single _all.o.
func rungcc3(ctx *Context, dir string, ofile string, ofiles []string) error {
args := []string{
"-fPIC", "-fmessage-length=0",
}
if !isClang() {
args = append(args, "-pthread")
}
args = append(args, "-g", "-O2", "-o", ofile)
func rungcc3(pkg *Package, dir string, ofile string, ofiles []string) error {
args := []string{}
args = append(args, "-o", ofile)
args = append(args, ofiles...)
args = append(args, "-Wl,-r", "-nostdlib")
if !isClang() {
libgcc, err := libgcc(ctx)
var cmd []string
if len(pkg.CXXFiles) > 0 || len(pkg.SwigCXXFiles) > 0 {
cmd = gxxCmd(pkg, dir)
} else {
cmd = gccCmd(pkg, dir)
}
if !strings.HasPrefix(cmd[0], "clang") {
libgcc, err := libgcc(pkg.Context)
if err != nil {
return nil
}
args = append(args, libgcc)
}
t0 := time.Now()
err := run(dir, nil, gcc(), args...)
ctx.Record("gcc3", time.Since(t0))
err := run(dir, nil, cmd[0], append(cmd[1:], args...)...)
pkg.Record("gcc3", time.Since(t0))
return err
}

Expand All @@ -291,7 +296,8 @@ func libgcc(ctx *Context) (string, error) {
"-print-libgcc-file-name",
}
var buf bytes.Buffer
err := runOut(&buf, ".", nil, gcc(), args...)
cmd := gccCmd(&Package{Context: ctx}, "") // TODO(dfc) hack
err := runOut(&buf, ".", nil, cmd[0], args...)
return strings.TrimSpace(buf.String()), err
}

Expand All @@ -300,29 +306,6 @@ func cgotool(ctx *Context) string {
return filepath.Join(ctx.Context.GOROOT, "pkg", "tool", ctx.gohostos+"_"+ctx.gohostarch, "cgo")
}

func gcc() string {
return gccBaseCmd()[0] // TODO(dfc) handle gcc wrappers properly
}

func isClang() bool {
return strings.HasPrefix(gcc(), "clang")
}

// gccBaseCmd returns the start of the compiler command line.
// It uses $CC if set, or else $GCC, or else the default
// compiler for the operating system is used.
func gccBaseCmd() []string {
// Use $CC if set, since that's what the build uses.
if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
return ret
}
// Try $GCC if set, since that's what we used to use.
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
return ret
}
return strings.Fields(defaultCC)
}

// envList returns the value of the given environment variable broken
// into fields, using the default value when the variable is empty.
func envList(key, def string) []string {
Expand Down Expand Up @@ -407,7 +390,7 @@ func runcgo1(pkg *Package, cflags, ldflags []string) error {
"-I", pkg.Dir,
)
default:
return fmt.Errorf("unsuppored Go version: %v", runtime.Version)
return fmt.Errorf("unsupported Go version: %v", runtime.Version)
}
args = append(args, cflags...)
args = append(args, pkg.CgoFiles...)
Expand Down Expand Up @@ -448,3 +431,71 @@ func runcgo2(pkg *Package, dynout, ofile string) error {
func cgoobjdir(pkg *Package) string {
return filepath.Join(pkg.Objdir(), pkg.Name, "_cgo")
}

// gccCmd returns a gcc command line prefix.
func gccCmd(pkg *Package, objdir string) []string {
return ccompilerCmd(pkg, "CC", defaultCC, objdir)
}

// gxxCmd returns a g++ command line prefix.
func gxxCmd(pkg *Package, objdir string) []string {
return ccompilerCmd(pkg, "CXX", defaultCXX, objdir)
}

// ccompilerCmd returns a command line prefix for the given environment
// variable and using the default command when the variable is empty.
func ccompilerCmd(pkg *Package, envvar, defcmd, objdir string) []string {
compiler := envList(envvar, defcmd)
a := []string{compiler[0]}
if objdir != "" {
a = append(a, "-I", objdir)
}
a = append(a, compiler[1:]...)

// Definitely want -fPIC but on Windows gcc complains
// "-fPIC ignored for target (all code is position independent)"
if pkg.gotargetos != "windows" {
a = append(a, "-fPIC")
}
a = append(a, gccArchArgs(pkg.gotargetarch)...)
// gcc-4.5 and beyond require explicit "-pthread" flag
// for multithreading with pthread library.
switch pkg.gotargetos {
case "windows":
a = append(a, "-mthreads")
default:
a = append(a, "-pthread")
}

if strings.Contains(a[0], "clang") {
// disable ASCII art in clang errors, if possible
a = append(a, "-fno-caret-diagnostics")
// clang is too smart about command-line arguments
a = append(a, "-Qunused-arguments")
}

// disable word wrapping in error messages
a = append(a, "-fmessage-length=0")

// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See https://golang.org/issue/3253.
if pkg.gotargetos == "darwin" {
a = append(a, "-fno-common")
}

return a
}

// gccArchArgs returns arguments to pass to gcc based on the architecture.
func gccArchArgs(goarch string) []string {
switch goarch {
case "386":
return []string{"-m32"}
case "amd64", "amd64p32":
return []string{"-m64"}
case "arm":
return []string{"-marm"} // not thumb
}
return nil
}
1 change: 1 addition & 0 deletions defaultcc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
package gb

const defaultCC = "gcc"
const defaultCXX = "g++"
1 change: 1 addition & 0 deletions defaultcc_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
package gb

const defaultCC = "clang"
const defaultCXX = "clang++"
1 change: 0 additions & 1 deletion gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ func (t *gcToolchain) Ld(pkg *Package, searchpaths []string, outfile, afile stri
for _, d := range searchpaths {
args = append(args, "-L", d)
}
args = append(args, "-extld="+gcc())
if gc15 {
args = append(args, "-buildmode", pkg.buildmode)
}
Expand Down

0 comments on commit de34371

Please sign in to comment.