cgo: implement support for static functions
Этот коммит содержится в:
родитель
91104b2f27
коммит
5551ec7a1e
10 изменённых файлов: 131 добавлений и 22 удалений
73
cgo/cgo.go
73
cgo/cgo.go
|
@ -32,6 +32,7 @@ type cgoPackage struct {
|
||||||
errors []error
|
errors []error
|
||||||
currentDir string // current working directory
|
currentDir string // current working directory
|
||||||
packageDir string // full path to the package to process
|
packageDir string // full path to the package to process
|
||||||
|
importPath string
|
||||||
fset *token.FileSet
|
fset *token.FileSet
|
||||||
tokenFiles map[string]*token.File
|
tokenFiles map[string]*token.File
|
||||||
definedGlobally map[string]ast.Node
|
definedGlobally map[string]ast.Node
|
||||||
|
@ -39,12 +40,15 @@ type cgoPackage struct {
|
||||||
cflags []string // CFlags from #cgo lines
|
cflags []string // CFlags from #cgo lines
|
||||||
ldflags []string // LDFlags from #cgo lines
|
ldflags []string // LDFlags from #cgo lines
|
||||||
visitedFiles map[string][]byte
|
visitedFiles map[string][]byte
|
||||||
|
cgoHeaders []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgoFile holds information only for a single Go file (with one or more
|
// cgoFile holds information only for a single Go file (with one or more
|
||||||
// `import "C"` statements).
|
// `import "C"` statements).
|
||||||
type cgoFile struct {
|
type cgoFile struct {
|
||||||
*cgoPackage
|
*cgoPackage
|
||||||
|
file *ast.File
|
||||||
|
index int
|
||||||
defined map[string]ast.Node
|
defined map[string]ast.Node
|
||||||
names map[string]clangCursor
|
names map[string]clangCursor
|
||||||
}
|
}
|
||||||
|
@ -158,9 +162,10 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||||
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
||||||
// hashes of the accessed C header files. If there is one or more error, it
|
// hashes of the accessed C header files. If there is one or more error, it
|
||||||
// returns these in the []error slice but still modifies the AST.
|
// returns these in the []error slice but still modifies the AST.
|
||||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||||
p := &cgoPackage{
|
p := &cgoPackage{
|
||||||
currentDir: dir,
|
currentDir: dir,
|
||||||
|
importPath: importPath,
|
||||||
fset: fset,
|
fset: fset,
|
||||||
tokenFiles: map[string]*token.File{},
|
tokenFiles: map[string]*token.File{},
|
||||||
definedGlobally: map[string]ast.Node{},
|
definedGlobally: map[string]ast.Node{},
|
||||||
|
@ -210,13 +215,13 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Patch some types, for example *C.char in C.CString.
|
// Patch some types, for example *C.char in C.CString.
|
||||||
cf := p.newCGoFile()
|
cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
|
||||||
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
|
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
|
||||||
return cf.walker(cursor, nil)
|
return cf.walker(cursor, nil)
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
// Find `import "C"` C fragments in the file.
|
// Find `import "C"` C fragments in the file.
|
||||||
cgoHeaders := make([]string, len(files)) // combined CGo header fragment for each file
|
p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
var cgoHeader string
|
var cgoHeader string
|
||||||
for i := 0; i < len(f.Decls); i++ {
|
for i := 0; i < len(f.Decls); i++ {
|
||||||
|
@ -275,7 +280,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
cgoHeader += fragment
|
cgoHeader += fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
cgoHeaders[i] = cgoHeader
|
p.cgoHeaders[i] = cgoHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define CFlags that will be used while parsing the package.
|
// Define CFlags that will be used while parsing the package.
|
||||||
|
@ -289,7 +294,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve types such as C.int, C.longlong, etc from C.
|
// Retrieve types such as C.int, C.longlong, etc from C.
|
||||||
p.newCGoFile().readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: token.NoPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.TYPE,
|
Tok: token.TYPE,
|
||||||
|
@ -303,8 +308,8 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
|
|
||||||
// Process CGo imports for each file.
|
// Process CGo imports for each file.
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
cf := p.newCGoFile()
|
cf := p.newCGoFile(f, i)
|
||||||
cf.readNames(cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
||||||
for _, name := range builtinAliases {
|
for _, name := range builtinAliases {
|
||||||
// Names such as C.int should not be obtained from C.
|
// Names such as C.int should not be obtained from C.
|
||||||
// This works around an issue in picolibc that has `#define int`
|
// This works around an issue in picolibc that has `#define int`
|
||||||
|
@ -320,12 +325,14 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
// Print the newly generated in-memory AST, for debugging.
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
//ast.Print(fset, p.generated)
|
//ast.Print(fset, p.generated)
|
||||||
|
|
||||||
return p.generated, cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *cgoPackage) newCGoFile() *cgoFile {
|
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
||||||
return &cgoFile{
|
return &cgoFile{
|
||||||
cgoPackage: p,
|
cgoPackage: p,
|
||||||
|
file: file,
|
||||||
|
index: index,
|
||||||
defined: make(map[string]ast.Node),
|
defined: make(map[string]ast.Node),
|
||||||
names: make(map[string]clangCursor),
|
names: make(map[string]clangCursor),
|
||||||
}
|
}
|
||||||
|
@ -1117,8 +1124,11 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
|
||||||
return alias
|
return alias
|
||||||
}
|
}
|
||||||
node := f.getASTDeclNode(name, found, iscall)
|
node := f.getASTDeclNode(name, found, iscall)
|
||||||
if _, ok := node.(*ast.FuncDecl); ok && !iscall {
|
if node, ok := node.(*ast.FuncDecl); ok {
|
||||||
return "C." + name + "$funcaddr"
|
if !iscall {
|
||||||
|
return node.Name.Name + "$funcaddr"
|
||||||
|
}
|
||||||
|
return node.Name.Name
|
||||||
}
|
}
|
||||||
return "C." + name
|
return "C." + name
|
||||||
}
|
}
|
||||||
|
@ -1142,7 +1152,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||||
// Original cgo reports an error like
|
// Original cgo reports an error like
|
||||||
// cgo: inconsistent definitions for C.myint
|
// cgo: inconsistent definitions for C.myint
|
||||||
// which is far less helpful.
|
// which is far less helpful.
|
||||||
f.addError(getPos(node), "defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
|
f.addError(getPos(node), name+" defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
|
||||||
}
|
}
|
||||||
f.defined[name] = node
|
f.defined[name] = node
|
||||||
return node
|
return node
|
||||||
|
@ -1150,11 +1160,39 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||||
|
|
||||||
// The declaration has no AST node. Create it now.
|
// The declaration has no AST node. Create it now.
|
||||||
f.defined[name] = nil
|
f.defined[name] = nil
|
||||||
node, elaboratedType := f.createASTNode(name, found)
|
node, extra := f.createASTNode(name, found)
|
||||||
f.defined[name] = node
|
f.defined[name] = node
|
||||||
f.definedGlobally[name] = node
|
|
||||||
switch node := node.(type) {
|
switch node := node.(type) {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
|
if strings.HasPrefix(node.Doc.List[0].Text, "//export _Cgo_static_") {
|
||||||
|
// Static function. Only accessible in the current Go file.
|
||||||
|
globalName := strings.TrimPrefix(node.Doc.List[0].Text, "//export ")
|
||||||
|
// Make an alias. Normally this is done using the alias function
|
||||||
|
// attribute, but MacOS for some reason doesn't support this (even
|
||||||
|
// though the linker has support for aliases in the form of N_INDR).
|
||||||
|
// Therefore, create an actual function for MacOS.
|
||||||
|
var params []string
|
||||||
|
for _, param := range node.Type.Params.List {
|
||||||
|
params = append(params, param.Names[0].Name)
|
||||||
|
}
|
||||||
|
callInst := fmt.Sprintf("%s(%s);", name, strings.Join(params, ", "))
|
||||||
|
if node.Type.Results != nil {
|
||||||
|
callInst = "return " + callInst
|
||||||
|
}
|
||||||
|
aliasDeclaration := fmt.Sprintf(`
|
||||||
|
#ifdef __APPLE__
|
||||||
|
%s {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
extern __typeof(%s) %s __attribute__((alias(%#v)));
|
||||||
|
#endif
|
||||||
|
`, extra.(string), callInst, name, globalName, name)
|
||||||
|
f.cgoHeaders[f.index] += "\n\n" + aliasDeclaration
|
||||||
|
} else {
|
||||||
|
// Regular (non-static) function.
|
||||||
|
f.definedGlobally[name] = node
|
||||||
|
}
|
||||||
f.generated.Decls = append(f.generated.Decls, node)
|
f.generated.Decls = append(f.generated.Decls, node)
|
||||||
// Also add a declaration like the following:
|
// Also add a declaration like the following:
|
||||||
// var C.foo$funcaddr unsafe.Pointer
|
// var C.foo$funcaddr unsafe.Pointer
|
||||||
|
@ -1162,7 +1200,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||||
Tok: token.VAR,
|
Tok: token.VAR,
|
||||||
Specs: []ast.Spec{
|
Specs: []ast.Spec{
|
||||||
&ast.ValueSpec{
|
&ast.ValueSpec{
|
||||||
Names: []*ast.Ident{{Name: "C." + name + "$funcaddr"}},
|
Names: []*ast.Ident{{Name: node.Name.Name + "$funcaddr"}},
|
||||||
Type: &ast.SelectorExpr{
|
Type: &ast.SelectorExpr{
|
||||||
X: &ast.Ident{Name: "unsafe"},
|
X: &ast.Ident{Name: "unsafe"},
|
||||||
Sel: &ast.Ident{Name: "Pointer"},
|
Sel: &ast.Ident{Name: "Pointer"},
|
||||||
|
@ -1171,8 +1209,10 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
case *ast.GenDecl:
|
case *ast.GenDecl:
|
||||||
|
f.definedGlobally[name] = node
|
||||||
f.generated.Decls = append(f.generated.Decls, node)
|
f.generated.Decls = append(f.generated.Decls, node)
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
|
f.definedGlobally[name] = node
|
||||||
f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
|
f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
|
||||||
Tok: token.TYPE,
|
Tok: token.TYPE,
|
||||||
Specs: []ast.Spec{node},
|
Specs: []ast.Spec{node},
|
||||||
|
@ -1186,7 +1226,8 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||||
|
|
||||||
// If this is a struct or union it may need bitfields or union accessor
|
// If this is a struct or union it may need bitfields or union accessor
|
||||||
// methods.
|
// methods.
|
||||||
if elaboratedType != nil {
|
switch elaboratedType := extra.(type) {
|
||||||
|
case *elaboratedTypeInfo:
|
||||||
// Add struct bitfields.
|
// Add struct bitfields.
|
||||||
for _, bitfield := range elaboratedType.bitfields {
|
for _, bitfield := range elaboratedType.bitfields {
|
||||||
f.createBitfieldGetter(bitfield, "C."+name)
|
f.createBitfieldGetter(bitfield, "C."+name)
|
||||||
|
|
|
@ -48,7 +48,7 @@ func TestCGo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the AST with CGo.
|
// Process the AST with CGo.
|
||||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags, "")
|
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags, "")
|
||||||
|
|
||||||
// Check the AST for type errors.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
var typecheckErrors []error
|
||||||
|
|
|
@ -4,7 +4,9 @@ package cgo
|
||||||
// modification. It does not touch the AST itself.
|
// modification. It does not touch the AST itself.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
|
@ -43,6 +45,8 @@ typedef struct {
|
||||||
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
|
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
|
||||||
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
|
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
|
||||||
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
|
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
|
||||||
|
CXString tinygo_clang_getCursorPrettyPrinted(GoCXCursor c, CXPrintingPolicy Policy);
|
||||||
|
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(GoCXCursor c);
|
||||||
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
|
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
|
||||||
CXType tinygo_clang_getCursorType(GoCXCursor c);
|
CXType tinygo_clang_getCursorType(GoCXCursor c);
|
||||||
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
|
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
|
||||||
|
@ -50,6 +54,7 @@ CXType tinygo_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
|
||||||
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
|
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
|
||||||
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
|
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
|
||||||
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
||||||
|
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(GoCXCursor c);
|
||||||
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
||||||
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
||||||
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
||||||
|
@ -189,7 +194,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
||||||
|
|
||||||
// Convert the AST node under the given Clang cursor to a Go AST node and return
|
// Convert the AST node under the given Clang cursor to a Go AST node and return
|
||||||
// it.
|
// it.
|
||||||
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaboratedTypeInfo) {
|
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||||
kind := C.tinygo_clang_getCursorKind(c)
|
kind := C.tinygo_clang_getCursorKind(c)
|
||||||
pos := f.getCursorPosition(c)
|
pos := f.getCursorPosition(c)
|
||||||
switch kind {
|
switch kind {
|
||||||
|
@ -200,19 +205,43 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
|
||||||
Kind: ast.Fun,
|
Kind: ast.Fun,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
}
|
}
|
||||||
|
exportName := name
|
||||||
|
localName := name
|
||||||
|
var stringSignature string
|
||||||
|
if C.tinygo_clang_Cursor_getStorageClass(c) == C.CX_SC_Static {
|
||||||
|
// A static function is assigned a globally unique symbol name based
|
||||||
|
// on the file path (like _Cgo_static_2d09198adbf58f4f4655_foo) and
|
||||||
|
// has a different Go name in the form of C.foo!symbols.go instead
|
||||||
|
// of just C.foo.
|
||||||
|
path := f.importPath + "/" + filepath.Base(f.fset.File(f.file.Pos()).Name())
|
||||||
|
staticIDBuf := sha256.Sum256([]byte(path))
|
||||||
|
staticID := hex.EncodeToString(staticIDBuf[:10])
|
||||||
|
exportName = "_Cgo_static_" + staticID + "_" + name
|
||||||
|
localName = name + "!" + filepath.Base(path)
|
||||||
|
|
||||||
|
// Create a signature. This is necessary for MacOS to forward the
|
||||||
|
// call, because MacOS doesn't support aliases like ELF and PE do.
|
||||||
|
// (There is N_INDR but __attribute__((alias("..."))) doesn't work).
|
||||||
|
policy := C.tinygo_clang_getCursorPrintingPolicy(c)
|
||||||
|
defer C.clang_PrintingPolicy_dispose(policy)
|
||||||
|
C.clang_PrintingPolicy_setProperty(policy, C.CXPrintingPolicy_TerseOutput, 1)
|
||||||
|
stringSignature = getString(C.tinygo_clang_getCursorPrettyPrinted(c, policy))
|
||||||
|
stringSignature = strings.Replace(stringSignature, " "+name+"(", " "+exportName+"(", 1)
|
||||||
|
stringSignature = strings.TrimPrefix(stringSignature, "static ")
|
||||||
|
}
|
||||||
args := make([]*ast.Field, numArgs)
|
args := make([]*ast.Field, numArgs)
|
||||||
decl := &ast.FuncDecl{
|
decl := &ast.FuncDecl{
|
||||||
Doc: &ast.CommentGroup{
|
Doc: &ast.CommentGroup{
|
||||||
List: []*ast.Comment{
|
List: []*ast.Comment{
|
||||||
{
|
{
|
||||||
Slash: pos - 1,
|
Slash: pos - 1,
|
||||||
Text: "//export " + name,
|
Text: "//export " + exportName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: pos,
|
NamePos: pos,
|
||||||
Name: "C." + name,
|
Name: "C." + localName,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
},
|
},
|
||||||
Type: &ast.FuncType{
|
Type: &ast.FuncType{
|
||||||
|
@ -263,7 +292,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj.Decl = decl
|
obj.Decl = decl
|
||||||
return decl, nil
|
return decl, stringSignature
|
||||||
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
||||||
typ := f.makeASTRecordType(c, pos)
|
typ := f.makeASTRecordType(c, pos)
|
||||||
typeName := "C." + name
|
typeName := "C." + name
|
||||||
|
|
|
@ -17,6 +17,14 @@ CXString tinygo_clang_getCursorSpelling(CXCursor c) {
|
||||||
return clang_getCursorSpelling(c);
|
return clang_getCursorSpelling(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXString tinygo_clang_getCursorPrettyPrinted(CXCursor c, CXPrintingPolicy policy) {
|
||||||
|
return clang_getCursorPrettyPrinted(c, policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(CXCursor c) {
|
||||||
|
return clang_getCursorPrintingPolicy(c);
|
||||||
|
}
|
||||||
|
|
||||||
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
|
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
|
||||||
return clang_getCursorKind(c);
|
return clang_getCursorKind(c);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +53,10 @@ CXCursor tinygo_clang_Cursor_getArgument(CXCursor c, unsigned i) {
|
||||||
return clang_Cursor_getArgument(c, i);
|
return clang_Cursor_getArgument(c, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(CXCursor c) {
|
||||||
|
return clang_Cursor_getStorageClass(c);
|
||||||
|
}
|
||||||
|
|
||||||
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
|
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
|
||||||
return clang_getCursorLocation(c);
|
return clang_getCursorLocation(c);
|
||||||
}
|
}
|
||||||
|
|
2
cgo/testdata/symbols.go
предоставленный
2
cgo/testdata/symbols.go
предоставленный
|
@ -5,6 +5,7 @@ package main
|
||||||
int foo(int a, int b);
|
int foo(int a, int b);
|
||||||
void variadic0();
|
void variadic0();
|
||||||
void variadic2(int x, int y, ...);
|
void variadic2(int x, int y, ...);
|
||||||
|
static void staticfunc(int x);
|
||||||
|
|
||||||
// Global variable signatures.
|
// Global variable signatures.
|
||||||
extern int someValue;
|
extern int someValue;
|
||||||
|
@ -16,6 +17,7 @@ func accessFunctions() {
|
||||||
C.foo(3, 4)
|
C.foo(3, 4)
|
||||||
C.variadic0()
|
C.variadic0()
|
||||||
C.variadic2(3, 5)
|
C.variadic2(3, 5)
|
||||||
|
C.staticfunc(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func accessGlobals() {
|
func accessGlobals() {
|
||||||
|
|
5
cgo/testdata/symbols.out.go
предоставленный
5
cgo/testdata/symbols.out.go
предоставленный
|
@ -55,5 +55,10 @@ func C.variadic2(x C.int, y C.int)
|
||||||
|
|
||||||
var C.variadic2$funcaddr unsafe.Pointer
|
var C.variadic2$funcaddr unsafe.Pointer
|
||||||
|
|
||||||
|
//export _Cgo_static_173c95a79b6df1980521_staticfunc
|
||||||
|
func C.staticfunc!symbols.go(x C.int)
|
||||||
|
|
||||||
|
var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
|
||||||
|
|
||||||
//go:extern someValue
|
//go:extern someValue
|
||||||
var C.someValue C.int
|
var C.someValue C.int
|
||||||
|
|
|
@ -440,7 +440,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||||
var initialCFlags []string
|
var initialCFlags []string
|
||||||
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
|
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
|
||||||
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
||||||
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags, p.program.clangHeaders)
|
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.clangHeaders)
|
||||||
p.CFlags = append(initialCFlags, cflags...)
|
p.CFlags = append(initialCFlags, cflags...)
|
||||||
p.CGoHeaders = headerCode
|
p.CGoHeaders = headerCode
|
||||||
for path, hash := range accessedFiles {
|
for path, hash := range accessedFiles {
|
||||||
|
|
14
testdata/cgo/extra.go
предоставленный
14
testdata/cgo/extra.go
предоставленный
|
@ -3,4 +3,18 @@ package main
|
||||||
// Make sure CGo supports multiple files.
|
// Make sure CGo supports multiple files.
|
||||||
|
|
||||||
// int fortytwo(void);
|
// int fortytwo(void);
|
||||||
|
// static float headerfunc_static(float a) { return a - 1; }
|
||||||
|
// static void headerfunc_void(int a, int *ptr) { *ptr = a; }
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
func headerfunc_2() {
|
||||||
|
// Call headerfunc_static that is different from the headerfunc_static in
|
||||||
|
// the main.go file.
|
||||||
|
// The upstream CGo implementation does not handle this case correctly.
|
||||||
|
println("static headerfunc 2:", C.headerfunc_static(5))
|
||||||
|
|
||||||
|
// Test function without return value.
|
||||||
|
var n C.int
|
||||||
|
C.headerfunc_void(3, &n)
|
||||||
|
println("static headerfunc void:", n)
|
||||||
|
}
|
||||||
|
|
3
testdata/cgo/main.go
предоставленный
3
testdata/cgo/main.go
предоставленный
|
@ -12,6 +12,7 @@ int mul(int, int);
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// int headerfunc(int a) { return a + 1; }
|
// int headerfunc(int a) { return a + 1; }
|
||||||
|
// static int headerfunc_static(int a) { return a - 1; }
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
@ -47,6 +48,8 @@ func main() {
|
||||||
|
|
||||||
// functions in the header C snippet
|
// functions in the header C snippet
|
||||||
println("headerfunc:", C.headerfunc(5))
|
println("headerfunc:", C.headerfunc(5))
|
||||||
|
println("static headerfunc:", C.headerfunc_static(5))
|
||||||
|
headerfunc_2()
|
||||||
|
|
||||||
// equivalent types
|
// equivalent types
|
||||||
var goInt8 int8 = 5
|
var goInt8 int8 = 5
|
||||||
|
|
3
testdata/cgo/out.txt
предоставленный
3
testdata/cgo/out.txt
предоставленный
|
@ -16,6 +16,9 @@ callback 2: 600
|
||||||
variadic0: 1
|
variadic0: 1
|
||||||
variadic2: 15
|
variadic2: 15
|
||||||
headerfunc: 6
|
headerfunc: 6
|
||||||
|
static headerfunc: 4
|
||||||
|
static headerfunc 2: +4.000000e+000
|
||||||
|
static headerfunc void: 3
|
||||||
bool: true true
|
bool: true true
|
||||||
float: +3.100000e+000
|
float: +3.100000e+000
|
||||||
double: +3.200000e+000
|
double: +3.200000e+000
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче