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:
parent
86c7bc6e8b
commit
3211b2cca9
@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user