Commit 3211b2cc authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/cgo: add support for function export for gccgo.

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
parent 86c7bc6e
......@@ -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
......
......@@ -107,7 +107,11 @@ func (p *Package) writeDefs() {
}
}
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)) {
......
......@@ -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
......
......@@ -72,6 +72,7 @@ type Package struct {
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
}
......
......@@ -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,
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment