]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: add support for function export for gccgo.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 15 Mar 2012 22:50:25 +0000 (23:50 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 15 Mar 2012 22:50:25 +0000 (23:50 +0100)
A "gccgoprefix" flag is added and used by the go tool,
to mirror the -fgo-prefix flag for gccgo, whose value
is required to know how to access functions from C.

Trying to export Go methods or unexported Go functions
will not work.

Also fix go test on "main" packages.

Updates #2313.
Fixes #3262.

R=mpimenov, rsc, iant
CC=golang-dev
https://golang.org/cl/5797046

src/cmd/cgo/main.go
src/cmd/cgo/out.go
src/cmd/go/build.go
src/cmd/go/pkg.go
src/cmd/go/test.go

index 5f307607ba3655101f02b1e3f98270dd9a91b44f..7449f04c4c8a2a01f28e4d37bd111802cf25917d 100644 (file)
@@ -136,6 +136,7 @@ var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C
 var objDir = flag.String("objdir", "", "object directory")
 
 var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "go", "prefix of symbols generated by gccgo")
 var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
 var goarch, goos string
 
index bbadad1bed97c28225fda5a17d448edc8e15d6cf..933d7e6cabfd0b5bca2a00a871eda8d09e0eb4b1 100644 (file)
@@ -107,7 +107,11 @@ func (p *Package) writeDefs() {
                }
        }
 
-       p.writeExports(fgo2, fc, fm)
+       if *gccgo {
+               p.writeGccgoExports(fgo2, fc, fm)
+       } else {
+               p.writeExports(fgo2, fc, fm)
+       }
 
        fgo2.Close()
        fc.Close()
@@ -624,6 +628,83 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
        }
 }
 
+// Write out the C header allowing C code to call exported gccgo functions.
+func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+       fgcc := creat(*objDir + "_cgo_export.c")
+       fgcch := creat(*objDir + "_cgo_export.h")
+       _ = fgcc
+
+       fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+       fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+       fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
+       fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
+
+       clean := func(r rune) rune {
+               switch {
+               case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+                       '0' <= r && r <= '9':
+                       return r
+               }
+               return '_'
+       }
+       gccgoSymbolPrefix := strings.Map(clean, *gccgoprefix)
+
+       for _, exp := range p.ExpFunc {
+               // TODO: support functions with receivers.
+               fn := exp.Func
+               fntype := fn.Type
+
+               if !ast.IsExported(fn.Name.Name) {
+                       fatalf("cannot export unexported function %s with gccgo", fn.Name)
+               }
+
+               cdeclBuf := new(bytes.Buffer)
+               resultCount := 0
+               forFieldList(fntype.Results,
+                       func(i int, atype ast.Expr) { resultCount++ })
+               switch resultCount {
+               case 0:
+                       fmt.Fprintf(cdeclBuf, "void")
+               case 1:
+                       forFieldList(fntype.Results,
+                               func(i int, atype ast.Expr) {
+                                       t := p.cgoType(atype)
+                                       fmt.Fprintf(cdeclBuf, "%s", t.C)
+                               })
+               default:
+                       // Declare a result struct.
+                       fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
+                       forFieldList(fntype.Results,
+                               func(i int, atype ast.Expr) {
+                                       t := p.cgoType(atype)
+                                       fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+                               })
+                       fmt.Fprintf(fgcch, "};\n")
+                       fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
+               }
+
+               // The function name.
+               fmt.Fprintf(cdeclBuf, " "+exp.ExpName)
+               gccgoSymbol := fmt.Sprintf("%s.%s.%s", gccgoSymbolPrefix, p.PackageName, exp.Func.Name)
+               fmt.Fprintf(cdeclBuf, " (")
+               // Function parameters.
+               forFieldList(fntype.Params,
+                       func(i int, atype ast.Expr) {
+                               if i > 0 {
+                                       fmt.Fprintf(cdeclBuf, ", ")
+                               }
+                               t := p.cgoType(atype)
+                               fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
+                       })
+               fmt.Fprintf(cdeclBuf, ")")
+               cdecl := cdeclBuf.String()
+
+               fmt.Fprintf(fgcch, "extern %s __asm__(\"%s\");\n", cdecl, gccgoSymbol)
+               // Dummy declaration for _cgo_main.c
+               fmt.Fprintf(fm, "%s {}\n", cdecl)
+       }
+}
+
 // Call a function for each entry in an ast.FieldList, passing the
 // index into the list and the type.
 func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
index 1cc2dc4ca456b4a01404a114a693729f4079aec0..eb51d2d789fbea73f55e360f0734931433468ae9 100644 (file)
@@ -661,7 +661,7 @@ func (b *builder) build(a *action) (err error) {
                }
 
                cgoExe := tool("cgo")
-               if a.cgo != nil {
+               if a.cgo != nil && a.cgo.target != "" {
                        cgoExe = a.cgo.target
                }
                outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles)
@@ -1239,12 +1239,8 @@ func (gccgcToolchain) gc(b *builder, p *Package, obj string, importArgs []string
        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)
-               }
+       if prefix := gccgoPrefix(p); prefix != "" {
+               gcargs = append(gcargs, "-fgo-prefix="+gccgoPrefix(p))
        }
        args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
        for _, f := range gofiles {
@@ -1304,6 +1300,16 @@ func (gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
                "-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
 }
 
+func gccgoPrefix(p *Package) string {
+       switch {
+       case p.build.IsCommand() && !p.forceLibrary:
+               return ""
+       case p.fake:
+               return "fake_" + p.ImportPath
+       }
+       return "go_" + p.ImportPath
+}
+
 // 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)
@@ -1404,6 +1410,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
        }
        if _, ok := buildToolchain.(gccgcToolchain); ok {
                cgoflags = append(cgoflags, "-gccgo")
+               if prefix := gccgoPrefix(p); prefix != "" {
+                       cgoflags = append(cgoflags, "-gccgoprefix="+gccgoPrefix(p))
+               }
        }
        if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
                return nil, nil, err
index 46ada4002b7598db2f3e468fc2e10873bc36f9dd..44dbd6798ab4f7efd3f6fab60ea287123bc635ed 100644 (file)
@@ -64,16 +64,17 @@ type Package struct {
        XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
 
        // Unexported fields are not part of the public API.
-       build       *build.Package
-       pkgdir      string // overrides build.PkgDir
-       imports     []*Package
-       deps        []*Package
-       gofiles     []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
-       target      string   // installed file for this package (may be executable)
-       fake        bool     // synthesized package
-       forceBuild  bool     // this package must be rebuilt
-       local       bool     // imported via local path (./ or ../)
-       localPrefix string   // interpret ./ and ../ imports relative to this prefix
+       build        *build.Package
+       pkgdir       string // overrides build.PkgDir
+       imports      []*Package
+       deps         []*Package
+       gofiles      []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+       target       string   // installed file for this package (may be executable)
+       fake         bool     // synthesized package
+       forceBuild   bool     // this package must be rebuilt
+       forceLibrary bool     // this package is a library (even if named "main")
+       local        bool     // imported via local path (./ or ../)
+       localPrefix  string   // interpret ./ and ../ imports relative to this prefix
 }
 
 func (p *Package) copyBuild(pp *build.Package) {
index 6aecbe7c06df147918298a7fe78cd48fe4f66610..870ab190fc41ed0490bf55612da01cfba0b9245c 100644 (file)
@@ -446,6 +446,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
                ptest.imports = append(append([]*Package{}, p.imports...), imports...)
                ptest.pkgdir = testDir
                ptest.fake = true
+               ptest.forceLibrary = true
                ptest.Stale = true
                ptest.build = new(build.Package)
                *ptest.build = *p.build
@@ -489,7 +490,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
                ImportPath: "testmain",
                Root:       p.Root,
                imports:    []*Package{ptest},
-               build:      &build.Package{},
+               build:      &build.Package{Name: "main"},
                fake:       true,
                Stale:      true,
        }