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");
|
||||
}
|
||||
|
||||
extern int go_callback_not_use_in_go(int);
|
||||
|
||||
static void run_callback() {
|
||||
test_callback(c_callback);
|
||||
test_callback(go_callback_not_use_in_go);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
@@ -107,6 +110,11 @@ import (
|
||||
"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
|
||||
func go_callback(i C.int) C.int {
|
||||
return i + 1
|
||||
|
||||
@@ -113,7 +113,8 @@ type context struct {
|
||||
cgoCalled bool
|
||||
cgoArgs []llssa.Expr
|
||||
cgoRet llssa.Expr
|
||||
cgoFuncs map[string][]string
|
||||
cgoSymbols []string
|
||||
cgoExports map[string]string
|
||||
}
|
||||
|
||||
type pkgState byte
|
||||
@@ -415,14 +416,6 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
|
||||
callRuntimeInit(b, pkg)
|
||||
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()
|
||||
cgoReturned := false
|
||||
isCgoCfunc := isCgoCfunc(fnName)
|
||||
@@ -442,8 +435,7 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, do
|
||||
// load cgo function pointer
|
||||
varName := instr.X.Name()
|
||||
if instr.Op == token.MUL && strings.HasPrefix(varName, "_cgo_") {
|
||||
cgoFuncs = append(cgoFuncs, varName)
|
||||
p.cgoFuncs[fname] = cgoFuncs
|
||||
p.cgoSymbols = append(p.cgoSymbols, varName)
|
||||
p.compileInstr(b, instr)
|
||||
}
|
||||
case *ssa.Call:
|
||||
@@ -925,13 +917,7 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
||||
varName := v.Name()
|
||||
val := p.varOf(b, v)
|
||||
if isCgoVar(varName) {
|
||||
fname := p.fset.Position(v.Pos()).Filename
|
||||
funcs, ok := p.cgoFuncs[fname]
|
||||
if !ok {
|
||||
funcs = make([]string, 0, 1)
|
||||
}
|
||||
funcs = append(funcs, val.Name())
|
||||
p.cgoFuncs[fname] = funcs
|
||||
p.cgoSymbols = append(p.cgoSymbols, val.Name())
|
||||
}
|
||||
if debugSymbols {
|
||||
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.
|
||||
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
|
||||
pkgTypes := pkg.Pkg
|
||||
oldTypes := pkgTypes
|
||||
@@ -1033,6 +1019,8 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [
|
||||
loaded: map[*types.Package]*pkgInfo{
|
||||
types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly?
|
||||
},
|
||||
cgoExports: make(map[string]string),
|
||||
cgoSymbols: make([]string, 0, 128),
|
||||
}
|
||||
ctx.initPyModule()
|
||||
ctx.initFiles(pkgPath, files)
|
||||
@@ -1066,25 +1054,11 @@ func NewPackageEx(prog llssa.Program, patches Patches, pkg *ssa.Package, files [
|
||||
ctx.initAfter = nil
|
||||
fn()
|
||||
}
|
||||
externs = ctx.cgoFuncs
|
||||
// TODO(lijie): read export name
|
||||
for _, funcs := range externs {
|
||||
for _, funcName := range funcs {
|
||||
if strings.Contains(funcName, ".__cgo_") {
|
||||
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)
|
||||
}
|
||||
}
|
||||
externs = ctx.cgoSymbols
|
||||
for fnName, exportName := range ctx.cgoExports {
|
||||
fn := ret.FuncOf(fnName)
|
||||
if fn != nil {
|
||||
fn.SetName(exportName)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
10
cl/import.go
10
cl/import.go
@@ -249,6 +249,7 @@ func (p *context) initLinkname(line string, f func(inPkgName string) (fullName s
|
||||
linkname = "//go:linkname "
|
||||
llgolink = "//llgo:link "
|
||||
llgolink2 = "// llgo:link "
|
||||
exportName = "//export "
|
||||
)
|
||||
if strings.HasPrefix(line, linkname) {
|
||||
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)
|
||||
} else if strings.HasPrefix(line, llgolink) {
|
||||
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)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -93,8 +93,7 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string
|
||||
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
|
||||
cgoSymbols := make(map[string]string)
|
||||
mallocFix := false
|
||||
for _, symbols := range externs {
|
||||
for _, symbolName := range symbols {
|
||||
for _, symbolName := range externs {
|
||||
lastPart := symbolName
|
||||
lastDot := strings.LastIndex(symbolName, ".")
|
||||
if lastDot != -1 {
|
||||
@@ -115,7 +114,6 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, preamble := range preambles {
|
||||
tmpFile, err := os.CreateTemp("", "-cgo-*.c")
|
||||
if err != nil {
|
||||
@@ -170,10 +168,16 @@ func genExternDeclsByClang(pkg *aPackage, src string, cflags []string, cgoSymbol
|
||||
var toRemove []string
|
||||
for cgoName, symbolName := range cgoSymbols {
|
||||
if strings.HasPrefix(symbolName, "__cgo_") {
|
||||
cfuncName := symbolName[len("__cgo_"):]
|
||||
cfn := pkg.LPkg.NewFunc(cfuncName, types.NewSignature(nil, nil, nil, false), llssa.InC)
|
||||
gofuncName := strings.Replace(cgoName, ".__cgo_", ".", 1)
|
||||
gofn := pkg.LPkg.FuncOf(gofuncName)
|
||||
cgoVar := pkg.LPkg.VarOf(cgoName)
|
||||
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)
|
||||
} else {
|
||||
usePtr := ""
|
||||
|
||||
Reference in New Issue
Block a user