cgo: supports //export functions only calls in C
This commit is contained in:
@@ -94,8 +94,11 @@ static void test_callback(Cb cb) {
|
|||||||
printf("done\n");
|
printf("done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int go_callback_not_use_in_go(int);
|
||||||
|
|
||||||
static void run_callback() {
|
static void run_callback() {
|
||||||
test_callback(c_callback);
|
test_callback(c_callback);
|
||||||
|
test_callback(go_callback_not_use_in_go);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
@@ -107,6 +110,11 @@ import (
|
|||||||
"github.com/goplus/llgo/cl/_testgo/cgofull/pymod2"
|
"github.com/goplus/llgo/cl/_testgo/cgofull/pymod2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//export go_callback_not_use_in_go
|
||||||
|
func go_callback_not_use_in_go(i C.int) C.int {
|
||||||
|
return i + 1
|
||||||
|
}
|
||||||
|
|
||||||
//export go_callback
|
//export go_callback
|
||||||
func go_callback(i C.int) C.int {
|
func go_callback(i C.int) C.int {
|
||||||
return i + 1
|
return i + 1
|
||||||
|
|||||||
@@ -110,10 +110,11 @@ type context struct {
|
|||||||
inCFunc bool
|
inCFunc bool
|
||||||
skipall bool
|
skipall bool
|
||||||
|
|
||||||
cgoCalled bool
|
cgoCalled bool
|
||||||
cgoArgs []llssa.Expr
|
cgoArgs []llssa.Expr
|
||||||
cgoRet llssa.Expr
|
cgoRet llssa.Expr
|
||||||
cgoFuncs map[string][]string
|
cgoSymbols []string
|
||||||
|
cgoExports map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type pkgState byte
|
type pkgState byte
|
||||||
@@ -415,14 +416,6 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
|
|||||||
callRuntimeInit(b, pkg)
|
callRuntimeInit(b, pkg)
|
||||||
b.Call(pkg.FuncOf("main.init").Expr)
|
b.Call(pkg.FuncOf("main.init").Expr)
|
||||||
}
|
}
|
||||||
fname := p.goProg.Fset.Position(block.Parent().Pos()).Filename
|
|
||||||
if p.cgoFuncs == nil {
|
|
||||||
p.cgoFuncs = make(map[string][]string)
|
|
||||||
}
|
|
||||||
var cgoFuncs []string
|
|
||||||
if funcs, ok := p.cgoFuncs[fname]; ok {
|
|
||||||
cgoFuncs = funcs
|
|
||||||
}
|
|
||||||
fnName := block.Parent().Name()
|
fnName := block.Parent().Name()
|
||||||
cgoReturned := false
|
cgoReturned := false
|
||||||
isCgoCfunc := isCgoCfunc(fnName)
|
isCgoCfunc := isCgoCfunc(fnName)
|
||||||
@@ -442,8 +435,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
|
|||||||
// load cgo function pointer
|
// load cgo function pointer
|
||||||
varName := instr.X.Name()
|
varName := instr.X.Name()
|
||||||
if instr.Op == token.MUL && strings.HasPrefix(varName, "_cgo_") {
|
if instr.Op == token.MUL && strings.HasPrefix(varName, "_cgo_") {
|
||||||
cgoFuncs = append(cgoFuncs, varName)
|
p.cgoSymbols = append(p.cgoSymbols, varName)
|
||||||
p.cgoFuncs[fname] = cgoFuncs
|
|
||||||
p.compileInstr(b, instr)
|
p.compileInstr(b, instr)
|
||||||
}
|
}
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
@@ -925,13 +917,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
varName := v.Name()
|
varName := v.Name()
|
||||||
val := p.varOf(b, v)
|
val := p.varOf(b, v)
|
||||||
if isCgoVar(varName) {
|
if isCgoVar(varName) {
|
||||||
fname := p.fset.Position(v.Pos()).Filename
|
p.cgoSymbols = append(p.cgoSymbols, val.Name())
|
||||||
funcs, ok := p.cgoFuncs[fname]
|
|
||||||
if !ok {
|
|
||||||
funcs = make([]string, 0, 1)
|
|
||||||
}
|
|
||||||
funcs = append(funcs, val.Name())
|
|
||||||
p.cgoFuncs[fname] = funcs
|
|
||||||
}
|
}
|
||||||
if debugSymbols {
|
if debugSymbols {
|
||||||
pos := p.fset.Position(v.Pos())
|
pos := p.fset.Position(v.Pos())
|
||||||
@@ -1001,7 +987,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPackageEx compiles a Go package to LLVM IR package.
|
// NewPackageEx compiles a Go package to LLVM IR package.
|
||||||
func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, externs map[string][]string, err error) {
|
func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, externs []string, err error) {
|
||||||
pkgProg := pkg.Prog
|
pkgProg := pkg.Prog
|
||||||
pkgTypes := pkg.Pkg
|
pkgTypes := pkg.Pkg
|
||||||
oldTypes := pkgTypes
|
oldTypes := pkgTypes
|
||||||
@@ -1033,6 +1019,8 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [
|
|||||||
loaded: map[*types.Package]*pkgInfo{
|
loaded: map[*types.Package]*pkgInfo{
|
||||||
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||||
},
|
},
|
||||||
|
cgoExports: make(map[string]string),
|
||||||
|
cgoSymbols: make([]string, 0, 128),
|
||||||
}
|
}
|
||||||
ctx.initPyModule()
|
ctx.initPyModule()
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
@@ -1066,25 +1054,11 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [
|
|||||||
ctx.initAfter = nil
|
ctx.initAfter = nil
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
externs = ctx.cgoFuncs
|
externs = ctx.cgoSymbols
|
||||||
// TODO(lijie): read export name
|
for fnName, exportName := range ctx.cgoExports {
|
||||||
for _, funcs := range externs {
|
fn := ret.FuncOf(fnName)
|
||||||
for _, funcName := range funcs {
|
if fn != nil {
|
||||||
if strings.Contains(funcName, ".__cgo_") {
|
fn.SetName(exportName)
|
||||||
goFnName := strings.Replace(funcName, ".__cgo_", ".", 1)
|
|
||||||
idx := strings.LastIndex(funcName, ".__cgo_")
|
|
||||||
cfuncName := funcName[idx+len(".__cgo_"):]
|
|
||||||
v := ret.VarOf(funcName)
|
|
||||||
if fn := ret.FuncOf(goFnName); fn != nil {
|
|
||||||
// TODO(lijie): naive go:export, need better way from comment
|
|
||||||
fn.SetName(cfuncName)
|
|
||||||
// Replace symbol instead of static linking
|
|
||||||
v.ReplaceAllUsesWith(fn.Expr)
|
|
||||||
} else if fn := ret.FuncOf(cfuncName); fn != nil {
|
|
||||||
// Replace symbol instead of static linking
|
|
||||||
v.ReplaceAllUsesWith(fn.Expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
16
cl/import.go
16
cl/import.go
@@ -246,9 +246,10 @@ func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName s
|
|||||||
|
|
||||||
func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) {
|
func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) {
|
||||||
const (
|
const (
|
||||||
linkname = "//go:linkname "
|
linkname = "//go:linkname "
|
||||||
llgolink = "//llgo:link "
|
llgolink = "//llgo:link "
|
||||||
llgolink2 = "// llgo:link "
|
llgolink2 = "// llgo:link "
|
||||||
|
exportName = "//export "
|
||||||
)
|
)
|
||||||
if strings.HasPrefix(line, linkname) {
|
if strings.HasPrefix(line, linkname) {
|
||||||
p.initLink(line, len(linkname), f)
|
p.initLink(line, len(linkname), f)
|
||||||
@@ -256,6 +257,15 @@ func (p *context) initLinkname(line string, f func(inPkgName string) (fullName s
|
|||||||
p.initLink(line, len(llgolink2), f)
|
p.initLink(line, len(llgolink2), f)
|
||||||
} else if strings.HasPrefix(line, llgolink) {
|
} else if strings.HasPrefix(line, llgolink) {
|
||||||
p.initLink(line, len(llgolink), f)
|
p.initLink(line, len(llgolink), f)
|
||||||
|
} else if strings.HasPrefix(line, exportName) {
|
||||||
|
p.initCgoExport(line, len(exportName), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) initCgoExport(line string, prefix int, f func(inPkgName string) (fullName string, isVar, ok bool)) {
|
||||||
|
name := strings.TrimSpace(line[prefix:])
|
||||||
|
if fullName, _, ok := f(name); ok {
|
||||||
|
p.cgoExports[fullName] = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ static void* _Cmalloc(size_t size) {
|
|||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string][]string, verbose bool) (cgoLdflags []string, err error) {
|
func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string, verbose bool) (cgoLdflags []string, err error) {
|
||||||
cfiles, preambles, cdecls, err := parseCgo_(pkg, files)
|
cfiles, preambles, cdecls, err := parseCgo_(pkg, files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -93,26 +93,24 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string
|
|||||||
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
|
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
|
||||||
cgoSymbols := make(map[string]string)
|
cgoSymbols := make(map[string]string)
|
||||||
mallocFix := false
|
mallocFix := false
|
||||||
for _, symbols := range externs {
|
for _, symbolName := range externs {
|
||||||
for _, symbolName := range symbols {
|
lastPart := symbolName
|
||||||
lastPart := symbolName
|
lastDot := strings.LastIndex(symbolName, ".")
|
||||||
lastDot := strings.LastIndex(symbolName, ".")
|
if lastDot != -1 {
|
||||||
if lastDot != -1 {
|
lastPart = symbolName[lastDot+1:]
|
||||||
lastPart = symbolName[lastDot+1:]
|
}
|
||||||
}
|
if strings.HasPrefix(lastPart, "__cgo_") {
|
||||||
if strings.HasPrefix(lastPart, "__cgo_") {
|
// func ptr var: main.__cgo_func_name
|
||||||
// func ptr var: main.__cgo_func_name
|
cgoSymbols[symbolName] = lastPart
|
||||||
cgoSymbols[symbolName] = lastPart
|
} else if m := re.FindStringSubmatch(symbolName); len(m) > 0 {
|
||||||
} else if m := re.FindStringSubmatch(symbolName); len(m) > 0 {
|
prefix := m[1] // _cgo_hash_(Cfunc|Cmacro)_
|
||||||
prefix := m[1] // _cgo_hash_(Cfunc|Cmacro)_
|
name := m[3] // remaining part
|
||||||
name := m[3] // remaining part
|
cgoSymbols[symbolName] = name
|
||||||
cgoSymbols[symbolName] = name
|
// fix missing _cgo_9113e32b6599_Cfunc__Cmalloc
|
||||||
// fix missing _cgo_9113e32b6599_Cfunc__Cmalloc
|
if !mallocFix && m[2] == "Cfunc" {
|
||||||
if !mallocFix && m[2] == "Cfunc" {
|
mallocName := prefix + "_Cmalloc"
|
||||||
mallocName := prefix + "_Cmalloc"
|
cgoSymbols[mallocName] = "_Cmalloc"
|
||||||
cgoSymbols[mallocName] = "_Cmalloc"
|
mallocFix = true
|
||||||
mallocFix = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,10 +168,16 @@ func genExternDeclsByClang(pkg *aPackage, src string, cflags []string, cgoSymbol
|
|||||||
var toRemove []string
|
var toRemove []string
|
||||||
for cgoName, symbolName := range cgoSymbols {
|
for cgoName, symbolName := range cgoSymbols {
|
||||||
if strings.HasPrefix(symbolName, "__cgo_") {
|
if strings.HasPrefix(symbolName, "__cgo_") {
|
||||||
cfuncName := symbolName[len("__cgo_"):]
|
gofuncName := strings.Replace(cgoName, ".__cgo_", ".", 1)
|
||||||
cfn := pkg.LPkg.NewFunc(cfuncName, types.NewSignature(nil, nil, nil, false), llssa.InC)
|
gofn := pkg.LPkg.FuncOf(gofuncName)
|
||||||
cgoVar := pkg.LPkg.VarOf(cgoName)
|
cgoVar := pkg.LPkg.VarOf(cgoName)
|
||||||
cgoVar.ReplaceAllUsesWith(cfn.Expr)
|
if gofn != nil {
|
||||||
|
cgoVar.ReplaceAllUsesWith(gofn.Expr)
|
||||||
|
} else {
|
||||||
|
cfuncName := symbolName[len("__cgo_"):]
|
||||||
|
cfn := pkg.LPkg.NewFunc(cfuncName, types.NewSignatureType(nil, nil, nil, nil, nil, false), llssa.InC)
|
||||||
|
cgoVar.ReplaceAllUsesWith(cfn.Expr)
|
||||||
|
}
|
||||||
toRemove = append(toRemove, cgoName)
|
toRemove = append(toRemove, cgoName)
|
||||||
} else {
|
} else {
|
||||||
usePtr := ""
|
usePtr := ""
|
||||||
|
|||||||
Reference in New Issue
Block a user