]> Cypherpunks repositories - gostls13.git/commitdiff
go: introduce support for "go build" with gccgo.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Fri, 27 Jan 2012 22:05:51 +0000 (17:05 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 27 Jan 2012 22:05:51 +0000 (17:05 -0500)
The use of gccgo is triggered by GC=gccgo in environment. It
still needs the standard distribution to behave properly, but
allows using the test, build, run, install subcommands with
gccgo.

R=rsc, iant, fullung
CC=golang-dev, remy
https://golang.org/cl/5562045

src/cmd/go/build.go
src/cmd/go/pkg.go
src/cmd/go/test.go

index cbe36f52e9f1e4b3b3cd957a57ac6898ec14151e..8a895b41e28a265692918af4851913b790a67045 100644 (file)
@@ -354,7 +354,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
        }
 
        a.objdir = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_obj")) + string(filepath.Separator)
-       a.objpkg = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+".a"))
+       a.objpkg = buildToolchain.pkgpath(b.work, a.p)
        a.link = p.Name == "main"
 
        switch mode {
@@ -557,17 +557,11 @@ func (b *builder) build(a *action) error {
 
        // Compile Go.
        if len(gofiles) > 0 {
-               out := "_go_." + b.arch
-               gcargs := []string{"-p", a.p.ImportPath}
-               if a.p.Standard && a.p.ImportPath == "runtime" {
-                       // runtime compiles with a special 6g flag to emit
-                       // additional reflect type data.
-                       gcargs = append(gcargs, "-+")
-               }
-               if err := b.gc(a.p, obj+out, gcargs, inc, gofiles); err != nil {
+               if out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles); err != nil {
                        return err
+               } else {
+                       objects = append(objects, out)
                }
-               objects = append(objects, out)
        }
 
        // Copy .h files named for goos or goarch or goos_goarch
@@ -598,7 +592,7 @@ func (b *builder) build(a *action) error {
 
        for _, file := range cfiles {
                out := file[:len(file)-len(".c")] + "." + b.arch
-               if err := b.cc(a.p, obj, obj+out, file); err != nil {
+               if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
                        return err
                }
                objects = append(objects, out)
@@ -607,7 +601,7 @@ func (b *builder) build(a *action) error {
        // Assemble .s files.
        for _, file := range sfiles {
                out := file[:len(file)-len(".s")] + "." + b.arch
-               if err := b.asm(a.p, obj, obj+out, file); err != nil {
+               if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
                        return err
                }
                objects = append(objects, out)
@@ -620,7 +614,7 @@ func (b *builder) build(a *action) error {
        objects = append(objects, cgoObjects...)
 
        // Pack into archive in obj directory
-       if err := b.gopack(a.p, obj, a.objpkg, objects); err != nil {
+       if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
                return err
        }
 
@@ -630,8 +624,7 @@ func (b *builder) build(a *action) error {
                // linker needs the whole dependency tree.
                all := actionList(a)
                all = all[:len(all)-1] // drop a
-               inc := b.includeArgs("-L", all)
-               if err := b.ld(a.p, a.target, inc, a.objpkg); err != nil {
+               if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
                        return err
                }
        }
@@ -685,6 +678,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
        // Finally, look in the installed package directories for each action.
        for _, a1 := range all {
                if dir := a1.pkgdir; dir == a1.p.t.PkgDir() && !incMap[dir] {
+                       if _, ok := buildToolchain.(gccgoToolchain); ok {
+                               dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
+                       }
                        incMap[dir] = true
                        inc = append(inc, flag, dir)
                }
@@ -935,27 +931,68 @@ func mkAbs(dir, f string) string {
        return filepath.Join(dir, f)
 }
 
-// gc runs the Go compiler in a specific directory on a set of files
-// to generate the named output file. 
-func (b *builder) gc(p *Package, ofile string, gcargs, importArgs []string, gofiles []string) error {
+type toolchain interface {
+       // gc runs the compiler in a specific directory on a set of files
+       // and returns the name of the generated output file. 
+       gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
+       // 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
+       // pkgpath creates the appropriate destination path for a package file.
+       pkgpath(basedir string, p *Package) string
+       // pack runs the archive packer in a specific directory to create
+       // an archive from a set of object files.
+       // typically it is run in the object directory.
+       pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
+       // ld runs the linker to create a package starting at mainpkg.
+       ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
+}
+
+type goToolchain struct{}
+type gccgoToolchain struct{}
+
+var buildToolchain toolchain
+
+func init() {
+       if os.Getenv("GC") == "gccgo" {
+               buildToolchain = gccgoToolchain{}
+       } else {
+               buildToolchain = goToolchain{}
+       }
+}
+
+// The Go toolchain.
+
+func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+       out := "_go_." + b.arch
+       ofile = obj + out
+       gcargs := []string{"-p", p.ImportPath}
+       if p.Standard && p.ImportPath == "runtime" {
+               // runtime compiles with a special 6g flag to emit
+               // additional reflect type data.
+               gcargs = append(gcargs, "-+")
+       }
+
        args := stringList(b.arch+"g", "-o", ofile, b.gcflags, gcargs, importArgs)
        for _, f := range gofiles {
                args = append(args, mkAbs(p.Dir, f))
        }
-       return b.run(p.Dir, p.ImportPath, args)
+       return ofile, b.run(p.Dir, p.ImportPath, args)
 }
 
-// asm runs the assembler in a specific directory on a specific file
-// to generate the named output file. 
-func (b *builder) asm(p *Package, obj, ofile, sfile string) error {
+func (goToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
        sfile = mkAbs(p.Dir, sfile)
        return b.run(p.Dir, p.ImportPath, b.arch+"a", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
 }
 
-// gopack runs the assembler in a specific directory to create
-// an archive from a set of object files.
-// typically it is run in the object directory.
-func (b *builder) gopack(p *Package, objDir, afile string, ofiles []string) error {
+func (goToolchain) pkgpath(basedir string, p *Package) string {
+       return filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a"))
+}
+
+func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
        var absOfiles []string
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objDir, f))
@@ -963,14 +1000,12 @@ func (b *builder) gopack(p *Package, objDir, afile string, ofiles []string) erro
        return b.run(p.Dir, p.ImportPath, "gopack", "grc", mkAbs(objDir, afile), absOfiles)
 }
 
-// ld runs the linker to create a package starting at mainpkg.
-func (b *builder) ld(p *Package, out string, importArgs []string, mainpkg string) error {
+func (goToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+       importArgs := b.includeArgs("-L", allactions)
        return b.run(p.Dir, p.ImportPath, b.arch+"l", "-o", out, importArgs, mainpkg)
 }
 
-// cc runs the gc-toolchain C compiler in a directory on a C file
-// to produce an output file.
-func (b *builder) cc(p *Package, objdir, ofile, cfile string) error {
+func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
        inc := filepath.Join(b.goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch))
        cfile = mkAbs(p.Dir, cfile)
        return b.run(p.Dir, p.ImportPath, b.arch+"c", "-FVw",
@@ -978,6 +1013,71 @@ func (b *builder) cc(p *Package, objdir, ofile, cfile string) error {
                "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile)
 }
 
+// The Gccgo toolchain.
+
+func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+       out := p.Name + ".o"
+       ofile = obj + out
+       gcargs := []string{"-g"}
+       if p.Name != "main" {
+               if p.fake {
+                       gcargs = append(gcargs, "-fgo-prefix=fake_"+p.ImportPath)
+               } else {
+                       gcargs = append(gcargs, "-fgo-prefix=go_"+p.ImportPath)
+               }
+       }
+       args := stringList("gccgo", importArgs, "-c", b.gcflags, gcargs, "-o", ofile)
+       for _, f := range gofiles {
+               args = append(args, mkAbs(p.Dir, f))
+       }
+       return ofile, b.run(p.Dir, p.ImportPath, args)
+}
+
+func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+       sfile = mkAbs(p.Dir, sfile)
+       return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
+}
+
+func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
+       afile := filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a"))
+       // prepend "lib" to the basename
+       return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
+}
+
+func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+       var absOfiles []string
+       for _, f := range ofiles {
+               absOfiles = append(absOfiles, mkAbs(objDir, f))
+       }
+       return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+}
+
+func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+       // gccgo needs explicit linking with all package dependencies,
+       // and all LDFLAGS from cgo dependencies
+       afiles := []string{}
+       ldflags := []string{}
+       seen := map[*Package]bool{}
+       for _, a := range allactions {
+               if a.p != nil && !seen[a.p] {
+                       seen[a.p] = true
+                       if !a.p.Standard {
+                               afiles = append(afiles, a.target)
+                       }
+                       ldflags = append(ldflags, a.p.CgoLDFLAGS...)
+               }
+       }
+       return b.run(p.Dir, p.ImportPath, "gccgo", "-o", out, ofiles, "-Wl,-(", afiles, ldflags, "-Wl,-)")
+}
+
+func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+       inc := filepath.Join(b.goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch))
+       cfile = mkAbs(p.Dir, cfile)
+       return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
+               "-I", objdir, "-I", inc, "-o", ofile,
+               "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, "-c", cfile)
+}
+
 // 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)
@@ -1056,19 +1156,24 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
                cfiles = append(cfiles, f+"cgo2.c")
        }
        defunC := obj + "_cgo_defun.c"
+
+       cgoflags := []string{}
        // TODO: make cgo not depend on $GOARCH?
-       var runtimeFlag []string
+
        if p.Standard && p.ImportPath == "runtime/cgo" {
-               runtimeFlag = []string{"-import_runtime_cgo=false"}
+               cgoflags = append(cgoflags, "-import_runtime_cgo=false")
+       }
+       if _, ok := buildToolchain.(gccgoToolchain); ok {
+               cgoflags = append(cgoflags, "-gccgo")
        }
-       if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, runtimeFlag, "--", p.CgoFiles); err != nil {
+       if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", p.CgoFiles); err != nil {
                return nil, nil, err
        }
        outGo = append(outGo, gofiles...)
 
        // cc _cgo_defun.c
        defunObj := obj + "_cgo_defun." + b.arch
-       if err := b.cc(p, obj, defunObj, defunC); err != nil {
+       if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
                return nil, nil, err
        }
        outObj = append(outObj, defunObj)
@@ -1106,7 +1211,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
 
        // cc _cgo_import.ARCH
        importObj := obj + "_cgo_import." + b.arch
-       if err := b.cc(p, obj, importObj, importC); err != nil {
+       if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
                return nil, nil, err
        }
 
index 09fa67127951e695090151f25e0f99410e6eac8f..bbfcfa26a76ee0ce9b40d58b3928ec060675b40e 100644 (file)
@@ -270,6 +270,16 @@ func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string
                p.target = filepath.Join(t.PkgDir(), filepath.FromSlash(importPath)+".a")
        }
 
+       // For gccgo, rewrite p.target with the expected library name. We won't do
+       // that for the standard library for the moment.
+       if !p.Standard {
+               dir := t.PkgDir()
+               if _, ok := buildToolchain.(gccgoToolchain); ok {
+                       dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
+               }
+               p.target = buildToolchain.pkgpath(dir, p)
+       }
+
        var built time.Time
        if fi, err := os.Stat(p.target); err == nil {
                built = fi.ModTime()
index 6cd49fe5a67ca335a11b681544c6dfed39523f3c..95fe62d35a59e417119758c702abb717522e9638 100644 (file)
@@ -330,8 +330,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
        // We write the external test package archive to
        // $WORK/unicode/utf8/_test/unicode/utf8_test.a.
        testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
-       ptestObj := filepath.Join(testDir, filepath.FromSlash(p.ImportPath+".a"))
-       pxtestObj := filepath.Join(testDir, filepath.FromSlash(p.ImportPath+"_test.a"))
+       ptestObj := buildToolchain.pkgpath(testDir, p)
 
        // Create the directory for the .a files.
        ptestDir, _ := filepath.Split(ptestObj)
@@ -380,8 +379,8 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
                pxtest.imports = append(pxtest.imports, ptest)
                a := b.action(modeBuild, modeBuild, pxtest)
                a.objdir = testDir + string(filepath.Separator)
-               a.objpkg = pxtestObj
-               a.target = pxtestObj
+               a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
+               a.target = a.objpkg
        }
 
        // Action for building test.out.