1
0
mirror of https://github.com/golang/go synced 2024-11-19 21:54:40 -07:00

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
This commit is contained in:
Rémy Oudompheng 2012-03-15 23:50:25 +01:00
parent 86c7bc6e8b
commit 3211b2cca9
5 changed files with 112 additions and 19 deletions

View 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

View 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)) {

View 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

View 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) {

View 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,
}