cgo: refactor; support multiple cgo files in a single package
This is a big commit that does a few things: * It moves CGo processing into a separate package. It never really belonged in the loader package, and certainly not now that the loader package may be refactored into a driver package. * It adds support for multiple CGo files (files that import package "C") in a single package. Previously, this led to multiple definition errors in the Go typecheck phase because certain C symbols were defined multiple times in all the files. Now it generates a new fake AST that defines these, to avoid multiple definition errors. * It improves debug info in a few edge cases that are probably not relevant outside of bugs in cgo itself.
Этот коммит содержится в:
родитель
4619207f99
коммит
11567c62d4
8 изменённых файлов: 320 добавлений и 244 удалений
2
Makefile
2
Makefile
|
@ -32,7 +32,7 @@ CGO_LDFLAGS=-L$(LLVM_BUILDDIR)/lib $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUIL
|
||||||
clean:
|
clean:
|
||||||
@rm -rf build
|
@rm -rf build
|
||||||
|
|
||||||
FMT_PATHS = ./*.go compiler interp ir loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall
|
FMT_PATHS = ./*.go cgo compiler interp ir loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall
|
||||||
fmt:
|
fmt:
|
||||||
@gofmt -l -w $(FMT_PATHS)
|
@gofmt -l -w $(FMT_PATHS)
|
||||||
fmt-check:
|
fmt-check:
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
package loader
|
// Package cgo implements CGo by modifying a loaded AST. It does this by parsing
|
||||||
|
// the `import "C"` statements found in the source code with libclang and
|
||||||
|
// generating stub function and global declarations.
|
||||||
|
//
|
||||||
|
// There are a few advantages to modifying the AST directly instead of doing CGo
|
||||||
|
// as a preprocessing step, with the main advantage being that debug information
|
||||||
|
// is kept intact as much as possible.
|
||||||
|
package cgo
|
||||||
|
|
||||||
// This file extracts the `import "C"` statement from the source and modifies
|
// This file extracts the `import "C"` statement from the source and modifies
|
||||||
// the AST for Cgo. It does not use libclang directly (see libclang.go).
|
// the AST for CCo. It does not use libclang directly: see libclang.go for the C
|
||||||
|
// source file parsing.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
@ -13,25 +21,35 @@ import (
|
||||||
"golang.org/x/tools/go/ast/astutil"
|
"golang.org/x/tools/go/ast/astutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileInfo holds all Cgo-related information of a given *ast.File.
|
// cgoPackage holds all CCo-related information of a package.
|
||||||
type fileInfo struct {
|
type cgoPackage struct {
|
||||||
*ast.File
|
generated *ast.File
|
||||||
*Package
|
generatedPos token.Pos
|
||||||
filename string
|
errors []error
|
||||||
constants map[string]*ast.BasicLit
|
dir string
|
||||||
functions map[string]*functionInfo
|
fset *token.FileSet
|
||||||
globals map[string]*globalInfo
|
tokenFiles map[string]*token.File
|
||||||
typedefs map[string]*typedefInfo
|
|
||||||
elaboratedTypes map[string]ast.Expr
|
|
||||||
importCPos token.Pos
|
|
||||||
missingSymbols map[string]struct{}
|
missingSymbols map[string]struct{}
|
||||||
|
constants map[string]constantInfo
|
||||||
|
functions map[string]*functionInfo
|
||||||
|
globals map[string]globalInfo
|
||||||
|
typedefs map[string]*typedefInfo
|
||||||
|
elaboratedTypes map[string]*elaboratedTypeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// functionInfo stores some information about a Cgo function found by libclang
|
// constantInfo stores some information about a CGo constant found by libclang
|
||||||
|
// and declared in the Go AST.
|
||||||
|
type constantInfo struct {
|
||||||
|
expr *ast.BasicLit
|
||||||
|
pos token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// functionInfo stores some information about a CCo function found by libclang
|
||||||
// and declared in the AST.
|
// and declared in the AST.
|
||||||
type functionInfo struct {
|
type functionInfo struct {
|
||||||
args []paramInfo
|
args []paramInfo
|
||||||
results *ast.FieldList
|
results *ast.FieldList
|
||||||
|
pos token.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
// paramInfo is a parameter of a Cgo function (see functionInfo).
|
// paramInfo is a parameter of a Cgo function (see functionInfo).
|
||||||
|
@ -43,11 +61,20 @@ type paramInfo struct {
|
||||||
// typedefInfo contains information about a single typedef in C.
|
// typedefInfo contains information about a single typedef in C.
|
||||||
type typedefInfo struct {
|
type typedefInfo struct {
|
||||||
typeExpr ast.Expr
|
typeExpr ast.Expr
|
||||||
|
pos token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// elaboratedTypeInfo contains some information about an elaborated type
|
||||||
|
// (struct, union) found in the C AST.
|
||||||
|
type elaboratedTypeInfo struct {
|
||||||
|
typeExpr ast.Expr
|
||||||
|
pos token.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
// globalInfo contains information about a declared global variable in C.
|
// globalInfo contains information about a declared global variable in C.
|
||||||
type globalInfo struct {
|
type globalInfo struct {
|
||||||
typeExpr ast.Expr
|
typeExpr ast.Expr
|
||||||
|
pos token.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgoAliases list type aliases between Go and C, for types that are equivalent
|
// cgoAliases list type aliases between Go and C, for types that are equivalent
|
||||||
|
@ -64,9 +91,9 @@ var cgoAliases = map[string]string{
|
||||||
"C.uintptr_t": "uintptr",
|
"C.uintptr_t": "uintptr",
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgoBuiltinAliases are handled specially because they only exist on the Go
|
// builtinAliases are handled specially because they only exist on the Go side
|
||||||
// side of CGo, not on the CGo (they're prefixed with "_Cgo_" there).
|
// of CGo, not on the CGo side (they're prefixed with "_Cgo_" there).
|
||||||
var cgoBuiltinAliases = map[string]struct{}{
|
var builtinAliases = map[string]struct{}{
|
||||||
"char": struct{}{},
|
"char": struct{}{},
|
||||||
"schar": struct{}{},
|
"schar": struct{}{},
|
||||||
"uchar": struct{}{},
|
"uchar": struct{}{},
|
||||||
|
@ -97,111 +124,146 @@ typedef long long _Cgo_longlong;
|
||||||
typedef unsigned long long _Cgo_ulonglong;
|
typedef unsigned long long _Cgo_ulonglong;
|
||||||
`
|
`
|
||||||
|
|
||||||
// processCgo extracts the `import "C"` statement from the AST, parses the
|
// Process extracts `import "C"` statements from the AST, parses the comment
|
||||||
// comment with libclang, and modifies the AST to use this information.
|
// with libclang, and modifies the AST to use this information. It returns a
|
||||||
func (p *Package) processCgo(filename string, f *ast.File, cflags []string) []error {
|
// newly created *ast.File that should be added to the list of to-be-parsed
|
||||||
info := &fileInfo{
|
// files. If there is one or more error, it returns these in the []error slice
|
||||||
File: f,
|
// but still modifies the AST.
|
||||||
Package: p,
|
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []error) {
|
||||||
filename: filename,
|
p := &cgoPackage{
|
||||||
constants: map[string]*ast.BasicLit{},
|
dir: dir,
|
||||||
functions: map[string]*functionInfo{},
|
fset: fset,
|
||||||
globals: map[string]*globalInfo{},
|
tokenFiles: map[string]*token.File{},
|
||||||
typedefs: map[string]*typedefInfo{},
|
|
||||||
elaboratedTypes: map[string]ast.Expr{},
|
|
||||||
missingSymbols: map[string]struct{}{},
|
missingSymbols: map[string]struct{}{},
|
||||||
|
constants: map[string]constantInfo{},
|
||||||
|
functions: map[string]*functionInfo{},
|
||||||
|
globals: map[string]globalInfo{},
|
||||||
|
typedefs: map[string]*typedefInfo{},
|
||||||
|
elaboratedTypes: map[string]*elaboratedTypeInfo{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new location for the following file.
|
||||||
|
generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0)
|
||||||
|
generatedTokenPos.SetLines([]int{0})
|
||||||
|
p.generatedPos = generatedTokenPos.Pos(0)
|
||||||
|
|
||||||
|
// Construct a new in-memory AST for CGo declarations of this package.
|
||||||
|
unsafeImport := &ast.ImportSpec{
|
||||||
|
Path: &ast.BasicLit{
|
||||||
|
ValuePos: p.generatedPos,
|
||||||
|
Kind: token.STRING,
|
||||||
|
Value: "\"unsafe\"",
|
||||||
|
},
|
||||||
|
EndPos: p.generatedPos,
|
||||||
|
}
|
||||||
|
p.generated = &ast.File{
|
||||||
|
Package: p.generatedPos,
|
||||||
|
Name: &ast.Ident{
|
||||||
|
NamePos: p.generatedPos,
|
||||||
|
Name: files[0].Name.Name,
|
||||||
|
},
|
||||||
|
Decls: []ast.Decl{
|
||||||
|
&ast.GenDecl{
|
||||||
|
TokPos: p.generatedPos,
|
||||||
|
Tok: token.IMPORT,
|
||||||
|
Specs: []ast.Spec{
|
||||||
|
unsafeImport,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Imports: []*ast.ImportSpec{unsafeImport},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all C.* symbols.
|
// Find all C.* symbols.
|
||||||
f = astutil.Apply(f, info.findMissingCGoNames, nil).(*ast.File)
|
for _, f := range files {
|
||||||
for name := range cgoBuiltinAliases {
|
astutil.Apply(f, p.findMissingCGoNames, nil)
|
||||||
info.missingSymbols["_Cgo_"+name] = struct{}{}
|
}
|
||||||
|
for name := range builtinAliases {
|
||||||
|
p.missingSymbols["_Cgo_"+name] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find `import "C"` statements in the file.
|
// Find `import "C"` statements in the file.
|
||||||
for i := 0; i < len(f.Decls); i++ {
|
for _, f := range files {
|
||||||
decl := f.Decls[i]
|
for i := 0; i < len(f.Decls); i++ {
|
||||||
genDecl, ok := decl.(*ast.GenDecl)
|
decl := f.Decls[i]
|
||||||
if !ok {
|
genDecl, ok := decl.(*ast.GenDecl)
|
||||||
continue
|
if !ok {
|
||||||
}
|
continue
|
||||||
if len(genDecl.Specs) != 1 {
|
}
|
||||||
continue
|
if len(genDecl.Specs) != 1 {
|
||||||
}
|
continue
|
||||||
spec, ok := genDecl.Specs[0].(*ast.ImportSpec)
|
}
|
||||||
if !ok {
|
spec, ok := genDecl.Specs[0].(*ast.ImportSpec)
|
||||||
continue
|
if !ok {
|
||||||
}
|
continue
|
||||||
path, err := strconv.Unquote(spec.Path.Value)
|
}
|
||||||
if err != nil {
|
path, err := strconv.Unquote(spec.Path.Value)
|
||||||
panic("could not parse import path: " + err.Error())
|
if err != nil {
|
||||||
}
|
panic("could not parse import path: " + err.Error())
|
||||||
if path != "C" {
|
}
|
||||||
continue
|
if path != "C" {
|
||||||
}
|
continue
|
||||||
cgoComment := genDecl.Doc.Text()
|
}
|
||||||
|
cgoComment := genDecl.Doc.Text()
|
||||||
|
|
||||||
// Stored for later use by generated functions, to use a somewhat sane
|
pos := genDecl.Pos()
|
||||||
// source location.
|
if genDecl.Doc != nil {
|
||||||
info.importCPos = spec.Path.ValuePos
|
pos = genDecl.Doc.Pos()
|
||||||
|
}
|
||||||
|
position := fset.PositionFor(pos, true)
|
||||||
|
p.parseFragment(cgoComment+cgoTypes, cflags, position.Filename, position.Line)
|
||||||
|
|
||||||
pos := genDecl.Pos()
|
// Remove this import declaration.
|
||||||
if genDecl.Doc != nil {
|
f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
|
||||||
pos = genDecl.Doc.Pos()
|
i--
|
||||||
}
|
|
||||||
position := info.fset.PositionFor(pos, true)
|
|
||||||
errs := info.parseFragment(cgoComment+cgoTypes, cflags, position.Filename, position.Line)
|
|
||||||
if errs != nil {
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove this import declaration.
|
// Print the AST, for debugging.
|
||||||
f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
|
//ast.Print(fset, f)
|
||||||
i--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the AST, for debugging.
|
|
||||||
//ast.Print(p.fset, f)
|
|
||||||
|
|
||||||
// Declare functions found by libclang.
|
// Declare functions found by libclang.
|
||||||
info.addFuncDecls()
|
p.addFuncDecls()
|
||||||
|
|
||||||
// Declare stub function pointer values found by libclang.
|
// Declare stub function pointer values found by libclang.
|
||||||
info.addFuncPtrDecls()
|
p.addFuncPtrDecls()
|
||||||
|
|
||||||
// Declare globals found by libclang.
|
// Declare globals found by libclang.
|
||||||
info.addConstDecls()
|
p.addConstDecls()
|
||||||
|
|
||||||
// Declare globals found by libclang.
|
// Declare globals found by libclang.
|
||||||
info.addVarDecls()
|
p.addVarDecls()
|
||||||
|
|
||||||
// Forward C types to Go types (like C.uint32_t -> uint32).
|
// Forward C types to Go types (like C.uint32_t -> uint32).
|
||||||
info.addTypeAliases()
|
p.addTypeAliases()
|
||||||
|
|
||||||
// Add type declarations for C types, declared using typedef in C.
|
// Add type declarations for C types, declared using typedef in C.
|
||||||
info.addTypedefs()
|
p.addTypedefs()
|
||||||
|
|
||||||
// Add elaborated types for C structs and unions.
|
// Add elaborated types for C structs and unions.
|
||||||
info.addElaboratedTypes()
|
p.addElaboratedTypes()
|
||||||
|
|
||||||
// Patch the AST to use the declared types and functions.
|
// Patch the AST to use the declared types and functions.
|
||||||
f = astutil.Apply(f, info.walker, nil).(*ast.File)
|
for _, f := range files {
|
||||||
|
astutil.Apply(f, p.walker, nil)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
|
//ast.Print(fset, p.generated)
|
||||||
|
|
||||||
|
return p.generated, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// addFuncDecls adds the C function declarations found by libclang in the
|
// addFuncDecls adds the C function declarations found by libclang in the
|
||||||
// comment above the `import "C"` statement.
|
// comment above the `import "C"` statement.
|
||||||
func (info *fileInfo) addFuncDecls() {
|
func (p *cgoPackage) addFuncDecls() {
|
||||||
// TODO: replace all uses of importCPos with the real locations from
|
names := make([]string, 0, len(p.functions))
|
||||||
// libclang.
|
for name := range p.functions {
|
||||||
names := make([]string, 0, len(info.functions))
|
|
||||||
for name := range info.functions {
|
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
fn := info.functions[name]
|
fn := p.functions[name]
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Fun,
|
Kind: ast.Fun,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
|
@ -209,16 +271,16 @@ func (info *fileInfo) addFuncDecls() {
|
||||||
args := make([]*ast.Field, len(fn.args))
|
args := make([]*ast.Field, len(fn.args))
|
||||||
decl := &ast.FuncDecl{
|
decl := &ast.FuncDecl{
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: fn.pos,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
},
|
},
|
||||||
Type: &ast.FuncType{
|
Type: &ast.FuncType{
|
||||||
Func: info.importCPos,
|
Func: fn.pos,
|
||||||
Params: &ast.FieldList{
|
Params: &ast.FieldList{
|
||||||
Opening: info.importCPos,
|
Opening: fn.pos,
|
||||||
List: args,
|
List: args,
|
||||||
Closing: info.importCPos,
|
Closing: fn.pos,
|
||||||
},
|
},
|
||||||
Results: fn.results,
|
Results: fn.results,
|
||||||
},
|
},
|
||||||
|
@ -228,7 +290,7 @@ func (info *fileInfo) addFuncDecls() {
|
||||||
args[i] = &ast.Field{
|
args[i] = &ast.Field{
|
||||||
Names: []*ast.Ident{
|
Names: []*ast.Ident{
|
||||||
&ast.Ident{
|
&ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: fn.pos,
|
||||||
Name: arg.name,
|
Name: arg.name,
|
||||||
Obj: &ast.Object{
|
Obj: &ast.Object{
|
||||||
Kind: ast.Var,
|
Kind: ast.Var,
|
||||||
|
@ -240,7 +302,7 @@ func (info *fileInfo) addFuncDecls() {
|
||||||
Type: arg.typeExpr,
|
Type: arg.typeExpr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, decl)
|
p.generated.Decls = append(p.generated.Decls, decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,39 +315,40 @@ func (info *fileInfo) addFuncDecls() {
|
||||||
// C.mul unsafe.Pointer
|
// C.mul unsafe.Pointer
|
||||||
// // ...
|
// // ...
|
||||||
// )
|
// )
|
||||||
func (info *fileInfo) addFuncPtrDecls() {
|
func (p *cgoPackage) addFuncPtrDecls() {
|
||||||
if len(info.functions) == 0 {
|
if len(p.functions) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.VAR,
|
Tok: token.VAR,
|
||||||
Lparen: info.importCPos,
|
Lparen: token.NoPos,
|
||||||
Rparen: info.importCPos,
|
Rparen: token.NoPos,
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(info.functions))
|
names := make([]string, 0, len(p.functions))
|
||||||
for name := range info.functions {
|
for name := range p.functions {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
|
fn := p.functions[name]
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Typ,
|
Kind: ast.Typ,
|
||||||
Name: "C." + name + "$funcaddr",
|
Name: "C." + name + "$funcaddr",
|
||||||
}
|
}
|
||||||
valueSpec := &ast.ValueSpec{
|
valueSpec := &ast.ValueSpec{
|
||||||
Names: []*ast.Ident{&ast.Ident{
|
Names: []*ast.Ident{&ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: fn.pos,
|
||||||
Name: "C." + name + "$funcaddr",
|
Name: "C." + name + "$funcaddr",
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
}},
|
}},
|
||||||
Type: &ast.SelectorExpr{
|
Type: &ast.SelectorExpr{
|
||||||
X: &ast.Ident{
|
X: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: fn.pos,
|
||||||
Name: "unsafe",
|
Name: "unsafe",
|
||||||
},
|
},
|
||||||
Sel: &ast.Ident{
|
Sel: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: fn.pos,
|
||||||
Name: "Pointer",
|
Name: "Pointer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -293,7 +356,7 @@ func (info *fileInfo) addFuncPtrDecls() {
|
||||||
obj.Decl = valueSpec
|
obj.Decl = valueSpec
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
gen.Specs = append(gen.Specs, valueSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addConstDecls declares external C constants in the Go source.
|
// addConstDecls declares external C constants in the Go source.
|
||||||
|
@ -304,39 +367,39 @@ func (info *fileInfo) addFuncPtrDecls() {
|
||||||
// C.CONST_FLOAT = 5.8
|
// C.CONST_FLOAT = 5.8
|
||||||
// // ...
|
// // ...
|
||||||
// )
|
// )
|
||||||
func (info *fileInfo) addConstDecls() {
|
func (p *cgoPackage) addConstDecls() {
|
||||||
if len(info.constants) == 0 {
|
if len(p.constants) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.CONST,
|
Tok: token.CONST,
|
||||||
Lparen: info.importCPos,
|
Lparen: token.NoPos,
|
||||||
Rparen: info.importCPos,
|
Rparen: token.NoPos,
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(info.constants))
|
names := make([]string, 0, len(p.constants))
|
||||||
for name := range info.constants {
|
for name := range p.constants {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
constVal := info.constants[name]
|
constVal := p.constants[name]
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Con,
|
Kind: ast.Con,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
}
|
}
|
||||||
valueSpec := &ast.ValueSpec{
|
valueSpec := &ast.ValueSpec{
|
||||||
Names: []*ast.Ident{&ast.Ident{
|
Names: []*ast.Ident{&ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: constVal.pos,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
}},
|
}},
|
||||||
Values: []ast.Expr{constVal},
|
Values: []ast.Expr{constVal.expr},
|
||||||
}
|
}
|
||||||
obj.Decl = valueSpec
|
obj.Decl = valueSpec
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
gen.Specs = append(gen.Specs, valueSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addVarDecls declares external C globals in the Go source.
|
// addVarDecls declares external C globals in the Go source.
|
||||||
|
@ -347,30 +410,30 @@ func (info *fileInfo) addConstDecls() {
|
||||||
// C.globalBool bool
|
// C.globalBool bool
|
||||||
// // ...
|
// // ...
|
||||||
// )
|
// )
|
||||||
func (info *fileInfo) addVarDecls() {
|
func (p *cgoPackage) addVarDecls() {
|
||||||
if len(info.globals) == 0 {
|
if len(p.globals) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.VAR,
|
Tok: token.VAR,
|
||||||
Lparen: info.importCPos,
|
Lparen: token.NoPos,
|
||||||
Rparen: info.importCPos,
|
Rparen: token.NoPos,
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(info.globals))
|
names := make([]string, 0, len(p.globals))
|
||||||
for name := range info.globals {
|
for name := range p.globals {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
global := info.globals[name]
|
global := p.globals[name]
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Var,
|
Kind: ast.Var,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
}
|
}
|
||||||
valueSpec := &ast.ValueSpec{
|
valueSpec := &ast.ValueSpec{
|
||||||
Names: []*ast.Ident{&ast.Ident{
|
Names: []*ast.Ident{&ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: global.pos,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
}},
|
}},
|
||||||
|
@ -379,7 +442,7 @@ func (info *fileInfo) addVarDecls() {
|
||||||
obj.Decl = valueSpec
|
obj.Decl = valueSpec
|
||||||
gen.Specs = append(gen.Specs, valueSpec)
|
gen.Specs = append(gen.Specs, valueSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addTypeAliases aliases some built-in Go types with their equivalent C types.
|
// addTypeAliases aliases some built-in Go types with their equivalent C types.
|
||||||
|
@ -390,17 +453,17 @@ func (info *fileInfo) addVarDecls() {
|
||||||
// C.int16_t = int16
|
// C.int16_t = int16
|
||||||
// // ...
|
// // ...
|
||||||
// )
|
// )
|
||||||
func (info *fileInfo) addTypeAliases() {
|
func (p *cgoPackage) addTypeAliases() {
|
||||||
aliasKeys := make([]string, 0, len(cgoAliases))
|
aliasKeys := make([]string, 0, len(cgoAliases))
|
||||||
for key := range cgoAliases {
|
for key := range cgoAliases {
|
||||||
aliasKeys = append(aliasKeys, key)
|
aliasKeys = append(aliasKeys, key)
|
||||||
}
|
}
|
||||||
sort.Strings(aliasKeys)
|
sort.Strings(aliasKeys)
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.TYPE,
|
Tok: token.TYPE,
|
||||||
Lparen: info.importCPos,
|
Lparen: token.NoPos,
|
||||||
Rparen: info.importCPos,
|
Rparen: token.NoPos,
|
||||||
}
|
}
|
||||||
for _, typeName := range aliasKeys {
|
for _, typeName := range aliasKeys {
|
||||||
goTypeName := cgoAliases[typeName]
|
goTypeName := cgoAliases[typeName]
|
||||||
|
@ -410,37 +473,37 @@ func (info *fileInfo) addTypeAliases() {
|
||||||
}
|
}
|
||||||
typeSpec := &ast.TypeSpec{
|
typeSpec := &ast.TypeSpec{
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: token.NoPos,
|
||||||
Name: typeName,
|
Name: typeName,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
},
|
},
|
||||||
Assign: info.importCPos,
|
Assign: p.generatedPos,
|
||||||
Type: &ast.Ident{
|
Type: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: token.NoPos,
|
||||||
Name: goTypeName,
|
Name: goTypeName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
obj.Decl = typeSpec
|
obj.Decl = typeSpec
|
||||||
gen.Specs = append(gen.Specs, typeSpec)
|
gen.Specs = append(gen.Specs, typeSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *fileInfo) addTypedefs() {
|
func (p *cgoPackage) addTypedefs() {
|
||||||
if len(info.typedefs) == 0 {
|
if len(p.typedefs) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.TYPE,
|
Tok: token.TYPE,
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(info.typedefs))
|
names := make([]string, 0, len(p.typedefs))
|
||||||
for name := range info.typedefs {
|
for name := range p.typedefs {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
typedef := info.typedefs[name]
|
typedef := p.typedefs[name]
|
||||||
typeName := "C." + name
|
typeName := "C." + name
|
||||||
isAlias := true
|
isAlias := true
|
||||||
if strings.HasPrefix(name, "_Cgo_") {
|
if strings.HasPrefix(name, "_Cgo_") {
|
||||||
|
@ -457,19 +520,19 @@ func (info *fileInfo) addTypedefs() {
|
||||||
}
|
}
|
||||||
typeSpec := &ast.TypeSpec{
|
typeSpec := &ast.TypeSpec{
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: typedef.pos,
|
||||||
Name: typeName,
|
Name: typeName,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
},
|
},
|
||||||
Type: typedef.typeExpr,
|
Type: typedef.typeExpr,
|
||||||
}
|
}
|
||||||
if isAlias {
|
if isAlias {
|
||||||
typeSpec.Assign = info.importCPos
|
typeSpec.Assign = typedef.pos
|
||||||
}
|
}
|
||||||
obj.Decl = typeSpec
|
obj.Decl = typeSpec
|
||||||
gen.Specs = append(gen.Specs, typeSpec)
|
gen.Specs = append(gen.Specs, typeSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addElaboratedTypes adds C elaborated types as aliases. These are the "struct
|
// addElaboratedTypes adds C elaborated types as aliases. These are the "struct
|
||||||
|
@ -477,21 +540,21 @@ func (info *fileInfo) addTypedefs() {
|
||||||
//
|
//
|
||||||
// See also:
|
// See also:
|
||||||
// https://en.cppreference.com/w/cpp/language/elaborated_type_specifier
|
// https://en.cppreference.com/w/cpp/language/elaborated_type_specifier
|
||||||
func (info *fileInfo) addElaboratedTypes() {
|
func (p *cgoPackage) addElaboratedTypes() {
|
||||||
if len(info.elaboratedTypes) == 0 {
|
if len(p.elaboratedTypes) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: info.importCPos,
|
TokPos: token.NoPos,
|
||||||
Tok: token.TYPE,
|
Tok: token.TYPE,
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(info.elaboratedTypes))
|
names := make([]string, 0, len(p.elaboratedTypes))
|
||||||
for name := range info.elaboratedTypes {
|
for name := range p.elaboratedTypes {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
typ := info.elaboratedTypes[name]
|
typ := p.elaboratedTypes[name]
|
||||||
typeName := "C." + name
|
typeName := "C." + name
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Typ,
|
Kind: ast.Typ,
|
||||||
|
@ -499,22 +562,22 @@ func (info *fileInfo) addElaboratedTypes() {
|
||||||
}
|
}
|
||||||
typeSpec := &ast.TypeSpec{
|
typeSpec := &ast.TypeSpec{
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: info.importCPos,
|
NamePos: typ.pos,
|
||||||
Name: typeName,
|
Name: typeName,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
},
|
},
|
||||||
Type: typ,
|
Type: typ.typeExpr,
|
||||||
}
|
}
|
||||||
obj.Decl = typeSpec
|
obj.Decl = typeSpec
|
||||||
gen.Specs = append(gen.Specs, typeSpec)
|
gen.Specs = append(gen.Specs, typeSpec)
|
||||||
}
|
}
|
||||||
info.Decls = append(info.Decls, gen)
|
p.generated.Decls = append(p.generated.Decls, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// findMissingCGoNames traverses the AST and finds all C.something names. Only
|
// findMissingCGoNames traverses the AST and finds all C.something names. Only
|
||||||
// these symbols are extracted from the parsed C AST and converted to the Go
|
// these symbols are extracted from the parsed C AST and converted to the Go
|
||||||
// equivalent.
|
// equivalent.
|
||||||
func (info *fileInfo) findMissingCGoNames(cursor *astutil.Cursor) bool {
|
func (p *cgoPackage) findMissingCGoNames(cursor *astutil.Cursor) bool {
|
||||||
switch node := cursor.Node().(type) {
|
switch node := cursor.Node().(type) {
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
x, ok := node.X.(*ast.Ident)
|
x, ok := node.X.(*ast.Ident)
|
||||||
|
@ -523,10 +586,10 @@ func (info *fileInfo) findMissingCGoNames(cursor *astutil.Cursor) bool {
|
||||||
}
|
}
|
||||||
if x.Name == "C" {
|
if x.Name == "C" {
|
||||||
name := node.Sel.Name
|
name := node.Sel.Name
|
||||||
if _, ok := cgoBuiltinAliases[name]; ok {
|
if _, ok := builtinAliases[name]; ok {
|
||||||
name = "_Cgo_" + name
|
name = "_Cgo_" + name
|
||||||
}
|
}
|
||||||
info.missingSymbols[name] = struct{}{}
|
p.missingSymbols[name] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -536,7 +599,7 @@ func (info *fileInfo) findMissingCGoNames(cursor *astutil.Cursor) bool {
|
||||||
// expressions. Such expressions are impossible to write in Go (a dot cannot be
|
// expressions. Such expressions are impossible to write in Go (a dot cannot be
|
||||||
// used in the middle of a name) so in practice all C identifiers live in a
|
// used in the middle of a name) so in practice all C identifiers live in a
|
||||||
// separate namespace (no _Cgo_ hacks like in gc).
|
// separate namespace (no _Cgo_ hacks like in gc).
|
||||||
func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
|
func (p *cgoPackage) walker(cursor *astutil.Cursor) bool {
|
||||||
switch node := cursor.Node().(type) {
|
switch node := cursor.Node().(type) {
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
fun, ok := node.Fun.(*ast.SelectorExpr)
|
fun, ok := node.Fun.(*ast.SelectorExpr)
|
||||||
|
@ -547,7 +610,7 @@ func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
|
||||||
if !ok {
|
if !ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if _, ok := info.functions[fun.Sel.Name]; ok && x.Name == "C" {
|
if _, ok := p.functions[fun.Sel.Name]; ok && x.Name == "C" {
|
||||||
node.Fun = &ast.Ident{
|
node.Fun = &ast.Ident{
|
||||||
NamePos: x.NamePos,
|
NamePos: x.NamePos,
|
||||||
Name: "C." + fun.Sel.Name,
|
Name: "C." + fun.Sel.Name,
|
||||||
|
@ -560,7 +623,7 @@ func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
|
||||||
}
|
}
|
||||||
if x.Name == "C" {
|
if x.Name == "C" {
|
||||||
name := "C." + node.Sel.Name
|
name := "C." + node.Sel.Name
|
||||||
if _, ok := info.functions[node.Sel.Name]; ok {
|
if _, ok := p.functions[node.Sel.Name]; ok {
|
||||||
name += "$funcaddr"
|
name += "$funcaddr"
|
||||||
}
|
}
|
||||||
cursor.Replace(&ast.Ident{
|
cursor.Replace(&ast.Ident{
|
|
@ -1,4 +1,4 @@
|
||||||
package loader
|
package cgo
|
||||||
|
|
||||||
// This file parses a fragment of C with libclang and stores the result for AST
|
// This file parses a fragment of C with libclang and stores the result for AST
|
||||||
// modification. It does not touch the AST itself.
|
// modification. It does not touch the AST itself.
|
||||||
|
@ -55,8 +55,8 @@ int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData cl
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// refMap stores references to types, used for clang_visitChildren.
|
// storedRefs stores references to types, used for clang_visitChildren.
|
||||||
var refMap RefMap
|
var storedRefs refMap
|
||||||
|
|
||||||
var diagnosticSeverity = [...]string{
|
var diagnosticSeverity = [...]string{
|
||||||
C.CXDiagnostic_Ignored: "ignored",
|
C.CXDiagnostic_Ignored: "ignored",
|
||||||
|
@ -66,7 +66,7 @@ var diagnosticSeverity = [...]string{
|
||||||
C.CXDiagnostic_Fatal: "fatal",
|
C.CXDiagnostic_Fatal: "fatal",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *fileInfo) parseFragment(fragment string, cflags []string, posFilename string, posLine int) []error {
|
func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename string, posLine int) {
|
||||||
index := C.clang_createIndex(0, 0)
|
index := C.clang_createIndex(0, 0)
|
||||||
defer C.clang_disposeIndex(index)
|
defer C.clang_disposeIndex(index)
|
||||||
|
|
||||||
|
@ -110,7 +110,6 @@ func (info *fileInfo) parseFragment(fragment string, cflags []string, posFilenam
|
||||||
defer C.clang_disposeTranslationUnit(unit)
|
defer C.clang_disposeTranslationUnit(unit)
|
||||||
|
|
||||||
if numDiagnostics := int(C.clang_getNumDiagnostics(unit)); numDiagnostics != 0 {
|
if numDiagnostics := int(C.clang_getNumDiagnostics(unit)); numDiagnostics != 0 {
|
||||||
errs := []error{}
|
|
||||||
addDiagnostic := func(diagnostic C.CXDiagnostic) {
|
addDiagnostic := func(diagnostic C.CXDiagnostic) {
|
||||||
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
|
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
|
||||||
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
|
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
|
||||||
|
@ -122,12 +121,12 @@ func (info *fileInfo) parseFragment(fragment string, cflags []string, posFilenam
|
||||||
filename := getString(libclangFilename)
|
filename := getString(libclangFilename)
|
||||||
if filepath.IsAbs(filename) {
|
if filepath.IsAbs(filename) {
|
||||||
// Relative paths for readability, like other Go parser errors.
|
// Relative paths for readability, like other Go parser errors.
|
||||||
relpath, err := filepath.Rel(info.Program.Dir, filename)
|
relpath, err := filepath.Rel(p.dir, filename)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
filename = relpath
|
filename = relpath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errs = append(errs, &scanner.Error{
|
p.errors = append(p.errors, &scanner.Error{
|
||||||
Pos: token.Position{
|
Pos: token.Position{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Offset: 0, // not provided by clang_getPresumedLocation
|
Offset: 0, // not provided by clang_getPresumedLocation
|
||||||
|
@ -147,26 +146,24 @@ func (info *fileInfo) parseFragment(fragment string, cflags []string, posFilenam
|
||||||
addDiagnostic(C.clang_getDiagnosticInSet(diagnostics, C.uint(j)))
|
addDiagnostic(C.clang_getDiagnosticInSet(diagnostics, C.uint(j)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errs
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ref := refMap.Put(info)
|
ref := storedRefs.Put(p)
|
||||||
defer refMap.Remove(ref)
|
defer storedRefs.Remove(ref)
|
||||||
cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
|
cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
|
||||||
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tinygo_clang_globals_visitor
|
//export tinygo_clang_globals_visitor
|
||||||
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
info := refMap.Get(unsafe.Pointer(client_data)).(*fileInfo)
|
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
|
||||||
kind := C.tinygo_clang_getCursorKind(c)
|
kind := C.tinygo_clang_getCursorKind(c)
|
||||||
pos := info.getCursorPosition(c)
|
pos := p.getCursorPosition(c)
|
||||||
switch kind {
|
switch kind {
|
||||||
case C.CXCursor_FunctionDecl:
|
case C.CXCursor_FunctionDecl:
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
if _, required := info.missingSymbols[name]; !required {
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
cursorType := C.tinygo_clang_getCursorType(c)
|
cursorType := C.tinygo_clang_getCursorType(c)
|
||||||
|
@ -174,8 +171,10 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
return C.CXChildVisit_Continue // not supported
|
return C.CXChildVisit_Continue // not supported
|
||||||
}
|
}
|
||||||
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
||||||
fn := &functionInfo{}
|
fn := &functionInfo{
|
||||||
info.functions[name] = fn
|
pos: pos,
|
||||||
|
}
|
||||||
|
p.functions[name] = fn
|
||||||
for i := 0; i < numArgs; i++ {
|
for i := 0; i < numArgs; i++ {
|
||||||
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
|
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
|
||||||
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
|
argName := getString(C.tinygo_clang_getCursorSpelling(arg))
|
||||||
|
@ -185,7 +184,7 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
}
|
}
|
||||||
fn.args = append(fn.args, paramInfo{
|
fn.args = append(fn.args, paramInfo{
|
||||||
name: argName,
|
name: argName,
|
||||||
typeExpr: info.makeASTType(argType, pos),
|
typeExpr: p.makeASTType(argType, pos),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
resultType := C.tinygo_clang_getCursorResultType(c)
|
resultType := C.tinygo_clang_getCursorResultType(c)
|
||||||
|
@ -193,7 +192,7 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
fn.results = &ast.FieldList{
|
fn.results = &ast.FieldList{
|
||||||
List: []*ast.Field{
|
List: []*ast.Field{
|
||||||
&ast.Field{
|
&ast.Field{
|
||||||
Type: info.makeASTType(resultType, pos),
|
Type: p.makeASTType(resultType, pos),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -201,29 +200,30 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
case C.CXCursor_StructDecl:
|
case C.CXCursor_StructDecl:
|
||||||
typ := C.tinygo_clang_getCursorType(c)
|
typ := C.tinygo_clang_getCursorType(c)
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
if _, required := info.missingSymbols["struct_"+name]; !required {
|
if _, required := p.missingSymbols["struct_"+name]; !required {
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
info.makeASTType(typ, pos)
|
p.makeASTType(typ, pos)
|
||||||
case C.CXCursor_TypedefDecl:
|
case C.CXCursor_TypedefDecl:
|
||||||
typedefType := C.tinygo_clang_getCursorType(c)
|
typedefType := C.tinygo_clang_getCursorType(c)
|
||||||
name := getString(C.clang_getTypedefName(typedefType))
|
name := getString(C.clang_getTypedefName(typedefType))
|
||||||
if _, required := info.missingSymbols[name]; !required {
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
info.makeASTType(typedefType, pos)
|
p.makeASTType(typedefType, pos)
|
||||||
case C.CXCursor_VarDecl:
|
case C.CXCursor_VarDecl:
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
if _, required := info.missingSymbols[name]; !required {
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
cursorType := C.tinygo_clang_getCursorType(c)
|
cursorType := C.tinygo_clang_getCursorType(c)
|
||||||
info.globals[name] = &globalInfo{
|
p.globals[name] = globalInfo{
|
||||||
typeExpr: info.makeASTType(cursorType, pos),
|
typeExpr: p.makeASTType(cursorType, pos),
|
||||||
|
pos: pos,
|
||||||
}
|
}
|
||||||
case C.CXCursor_MacroDefinition:
|
case C.CXCursor_MacroDefinition:
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
if _, required := info.missingSymbols[name]; !required {
|
if _, required := p.missingSymbols[name]; !required {
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
sourceRange := C.tinygo_clang_getCursorExtent(c)
|
sourceRange := C.tinygo_clang_getCursorExtent(c)
|
||||||
|
@ -266,12 +266,12 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
// https://en.cppreference.com/w/cpp/language/integer_literal
|
// https://en.cppreference.com/w/cpp/language/integer_literal
|
||||||
if value[0] == '"' {
|
if value[0] == '"' {
|
||||||
// string constant
|
// string constant
|
||||||
info.constants[name] = &ast.BasicLit{pos, token.STRING, value}
|
p.constants[name] = constantInfo{&ast.BasicLit{pos, token.STRING, value}, pos}
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
if value[0] == '\'' {
|
if value[0] == '\'' {
|
||||||
// char constant
|
// char constant
|
||||||
info.constants[name] = &ast.BasicLit{pos, token.CHAR, value}
|
p.constants[name] = constantInfo{&ast.BasicLit{pos, token.CHAR, value}, pos}
|
||||||
return C.CXChildVisit_Continue
|
return C.CXChildVisit_Continue
|
||||||
}
|
}
|
||||||
// assume it's a number (int or float)
|
// assume it's a number (int or float)
|
||||||
|
@ -289,15 +289,15 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||||
switch nonnum {
|
switch nonnum {
|
||||||
case 0:
|
case 0:
|
||||||
// no non-number found, must be an integer
|
// no non-number found, must be an integer
|
||||||
info.constants[name] = &ast.BasicLit{pos, token.INT, value}
|
p.constants[name] = constantInfo{&ast.BasicLit{pos, token.INT, value}, pos}
|
||||||
case 'x', 'X':
|
case 'x', 'X':
|
||||||
// hex integer constant
|
// hex integer constant
|
||||||
// TODO: may also be a floating point number per C++17.
|
// TODO: may also be a floating point number per C++17.
|
||||||
info.constants[name] = &ast.BasicLit{pos, token.INT, value}
|
p.constants[name] = constantInfo{&ast.BasicLit{pos, token.INT, value}, pos}
|
||||||
case '.', 'e':
|
case '.', 'e':
|
||||||
// float constant
|
// float constant
|
||||||
value = strings.TrimRight(value, "fFlL")
|
value = strings.TrimRight(value, "fFlL")
|
||||||
info.constants[name] = &ast.BasicLit{pos, token.FLOAT, value}
|
p.constants[name] = constantInfo{&ast.BasicLit{pos, token.FLOAT, value}, pos}
|
||||||
default:
|
default:
|
||||||
// unknown type, ignore
|
// unknown type, ignore
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ func getString(clangString C.CXString) (s string) {
|
||||||
// getCursorPosition returns a usable token.Pos from a libclang cursor. If the
|
// getCursorPosition returns a usable token.Pos from a libclang cursor. If the
|
||||||
// file for this cursor has not been seen before, it is read from libclang
|
// file for this cursor has not been seen before, it is read from libclang
|
||||||
// (which already has the file in memory) and added to the token.FileSet.
|
// (which already has the file in memory) and added to the token.FileSet.
|
||||||
func (info *fileInfo) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
||||||
location := C.tinygo_clang_getCursorLocation(cursor)
|
location := C.tinygo_clang_getCursorLocation(cursor)
|
||||||
var file C.CXFile
|
var file C.CXFile
|
||||||
var line C.unsigned
|
var line C.unsigned
|
||||||
|
@ -327,7 +327,7 @@ func (info *fileInfo) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
||||||
return token.NoPos
|
return token.NoPos
|
||||||
}
|
}
|
||||||
filename := getString(C.clang_getFileName(file))
|
filename := getString(C.clang_getFileName(file))
|
||||||
if _, ok := info.tokenFiles[filename]; !ok {
|
if _, ok := p.tokenFiles[filename]; !ok {
|
||||||
// File has not been seen before in this package, add line information
|
// File has not been seen before in this package, add line information
|
||||||
// now by reading the file from libclang.
|
// now by reading the file from libclang.
|
||||||
tu := C.tinygo_clang_Cursor_getTranslationUnit(cursor)
|
tu := C.tinygo_clang_Cursor_getTranslationUnit(cursor)
|
||||||
|
@ -340,16 +340,16 @@ func (info *fileInfo) getCursorPosition(cursor C.GoCXCursor) token.Pos {
|
||||||
lines = append(lines, i+1)
|
lines = append(lines, i+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f := info.fset.AddFile(filename, -1, int(size))
|
f := p.fset.AddFile(filename, -1, int(size))
|
||||||
f.SetLines(lines)
|
f.SetLines(lines)
|
||||||
info.tokenFiles[filename] = f
|
p.tokenFiles[filename] = f
|
||||||
}
|
}
|
||||||
return info.tokenFiles[filename].Pos(int(offset))
|
return p.tokenFiles[filename].Pos(int(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeASTType return the ast.Expr for the given libclang type. In other words,
|
// makeASTType return the ast.Expr for the given libclang type. In other words,
|
||||||
// it converts a libclang type to a type in the Go AST.
|
// it converts a libclang type to a type in the Go AST.
|
||||||
func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
var typeName string
|
var typeName string
|
||||||
switch typ.kind {
|
switch typ.kind {
|
||||||
case C.CXType_Char_S, C.CXType_Char_U:
|
case C.CXType_Char_S, C.CXType_Char_U:
|
||||||
|
@ -410,7 +410,7 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
}
|
}
|
||||||
return &ast.StarExpr{
|
return &ast.StarExpr{
|
||||||
Star: pos,
|
Star: pos,
|
||||||
X: info.makeASTType(pointeeType, pos),
|
X: p.makeASTType(pointeeType, pos),
|
||||||
}
|
}
|
||||||
case C.CXType_ConstantArray:
|
case C.CXType_ConstantArray:
|
||||||
return &ast.ArrayType{
|
return &ast.ArrayType{
|
||||||
|
@ -420,7 +420,7 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
Kind: token.INT,
|
Kind: token.INT,
|
||||||
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
|
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
|
||||||
},
|
},
|
||||||
Elt: info.makeASTType(C.clang_getElementType(typ), pos),
|
Elt: p.makeASTType(C.clang_getElementType(typ), pos),
|
||||||
}
|
}
|
||||||
case C.CXType_FunctionProto:
|
case C.CXType_FunctionProto:
|
||||||
// Be compatible with gc, which uses the *[0]byte type for function
|
// Be compatible with gc, which uses the *[0]byte type for function
|
||||||
|
@ -441,11 +441,11 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
}
|
}
|
||||||
case C.CXType_Typedef:
|
case C.CXType_Typedef:
|
||||||
name := getString(C.clang_getTypedefName(typ))
|
name := getString(C.clang_getTypedefName(typ))
|
||||||
if _, ok := info.typedefs[name]; !ok {
|
if _, ok := p.typedefs[name]; !ok {
|
||||||
info.typedefs[name] = nil // don't recurse
|
p.typedefs[name] = nil // don't recurse
|
||||||
c := C.tinygo_clang_getTypeDeclaration(typ)
|
c := C.tinygo_clang_getTypeDeclaration(typ)
|
||||||
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
||||||
expr := info.makeASTType(underlyingType, pos)
|
expr := p.makeASTType(underlyingType, pos)
|
||||||
if strings.HasPrefix(name, "_Cgo_") {
|
if strings.HasPrefix(name, "_Cgo_") {
|
||||||
expr := expr.(*ast.Ident)
|
expr := expr.(*ast.Ident)
|
||||||
typeSize := C.clang_Type_getSizeOf(underlyingType)
|
typeSize := C.clang_Type_getSizeOf(underlyingType)
|
||||||
|
@ -487,8 +487,9 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.typedefs[name] = &typedefInfo{
|
p.typedefs[name] = &typedefInfo{
|
||||||
typeExpr: expr,
|
typeExpr: expr,
|
||||||
|
pos: pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ast.Ident{
|
return &ast.Ident{
|
||||||
|
@ -499,7 +500,7 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
underlying := C.clang_Type_getNamedType(typ)
|
underlying := C.clang_Type_getNamedType(typ)
|
||||||
switch underlying.kind {
|
switch underlying.kind {
|
||||||
case C.CXType_Record:
|
case C.CXType_Record:
|
||||||
return info.makeASTType(underlying, pos)
|
return p.makeASTType(underlying, pos)
|
||||||
default:
|
default:
|
||||||
panic("unknown elaborated type")
|
panic("unknown elaborated type")
|
||||||
}
|
}
|
||||||
|
@ -515,23 +516,26 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
default:
|
default:
|
||||||
panic("unknown record declaration")
|
panic("unknown record declaration")
|
||||||
}
|
}
|
||||||
if _, ok := info.elaboratedTypes[cgoName]; !ok {
|
if _, ok := p.elaboratedTypes[cgoName]; !ok {
|
||||||
info.elaboratedTypes[cgoName] = nil // predeclare (to avoid endless recursion)
|
p.elaboratedTypes[cgoName] = nil // predeclare (to avoid endless recursion)
|
||||||
fieldList := &ast.FieldList{
|
fieldList := &ast.FieldList{
|
||||||
Opening: pos,
|
Opening: pos,
|
||||||
Closing: pos,
|
Closing: pos,
|
||||||
}
|
}
|
||||||
ref := refMap.Put(struct {
|
ref := storedRefs.Put(struct {
|
||||||
fieldList *ast.FieldList
|
fieldList *ast.FieldList
|
||||||
info *fileInfo
|
pkg *cgoPackage
|
||||||
}{fieldList, info})
|
}{fieldList, p})
|
||||||
defer refMap.Remove(ref)
|
defer storedRefs.Remove(ref)
|
||||||
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
|
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
|
||||||
switch C.tinygo_clang_getCursorKind(cursor) {
|
switch C.tinygo_clang_getCursorKind(cursor) {
|
||||||
case C.CXCursor_StructDecl:
|
case C.CXCursor_StructDecl:
|
||||||
info.elaboratedTypes[cgoName] = &ast.StructType{
|
p.elaboratedTypes[cgoName] = &elaboratedTypeInfo{
|
||||||
Struct: pos,
|
typeExpr: &ast.StructType{
|
||||||
Fields: fieldList,
|
Struct: pos,
|
||||||
|
Fields: fieldList,
|
||||||
|
},
|
||||||
|
pos: pos,
|
||||||
}
|
}
|
||||||
case C.CXCursor_UnionDecl:
|
case C.CXCursor_UnionDecl:
|
||||||
if len(fieldList.List) > 1 {
|
if len(fieldList.List) > 1 {
|
||||||
|
@ -561,9 +565,12 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
}
|
}
|
||||||
fieldList.List = append([]*ast.Field{unionMarker}, fieldList.List...)
|
fieldList.List = append([]*ast.Field{unionMarker}, fieldList.List...)
|
||||||
}
|
}
|
||||||
info.elaboratedTypes[cgoName] = &ast.StructType{
|
p.elaboratedTypes[cgoName] = &elaboratedTypeInfo{
|
||||||
Struct: pos,
|
typeExpr: &ast.StructType{
|
||||||
Fields: fieldList,
|
Struct: pos,
|
||||||
|
Fields: fieldList,
|
||||||
|
},
|
||||||
|
pos: pos,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
|
@ -587,23 +594,23 @@ func (info *fileInfo) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||||
|
|
||||||
//export tinygo_clang_struct_visitor
|
//export tinygo_clang_struct_visitor
|
||||||
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
|
||||||
passed := refMap.Get(unsafe.Pointer(client_data)).(struct {
|
passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
|
||||||
fieldList *ast.FieldList
|
fieldList *ast.FieldList
|
||||||
info *fileInfo
|
pkg *cgoPackage
|
||||||
})
|
})
|
||||||
fieldList := passed.fieldList
|
fieldList := passed.fieldList
|
||||||
info := passed.info
|
p := passed.pkg
|
||||||
if C.tinygo_clang_getCursorKind(c) != C.CXCursor_FieldDecl {
|
if C.tinygo_clang_getCursorKind(c) != C.CXCursor_FieldDecl {
|
||||||
panic("expected field inside cursor")
|
panic("expected field inside cursor")
|
||||||
}
|
}
|
||||||
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
name := getString(C.tinygo_clang_getCursorSpelling(c))
|
||||||
typ := C.tinygo_clang_getCursorType(c)
|
typ := C.tinygo_clang_getCursorType(c)
|
||||||
field := &ast.Field{
|
field := &ast.Field{
|
||||||
Type: info.makeASTType(typ, info.getCursorPosition(c)),
|
Type: p.makeASTType(typ, p.getCursorPosition(c)),
|
||||||
}
|
}
|
||||||
field.Names = []*ast.Ident{
|
field.Names = []*ast.Ident{
|
||||||
&ast.Ident{
|
&ast.Ident{
|
||||||
NamePos: info.getCursorPosition(c),
|
NamePos: p.getCursorPosition(c),
|
||||||
Name: name,
|
Name: name,
|
||||||
Obj: &ast.Object{
|
Obj: &ast.Object{
|
||||||
Kind: ast.Var,
|
Kind: ast.Var,
|
|
@ -1,6 +1,6 @@
|
||||||
// +build !byollvm
|
// +build !byollvm
|
||||||
|
|
||||||
package loader
|
package cgo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo linux CFLAGS: -I/usr/lib/llvm-8/include
|
#cgo linux CFLAGS: -I/usr/lib/llvm-8/include
|
|
@ -1,4 +1,4 @@
|
||||||
package loader
|
package cgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -8,17 +8,17 @@ import (
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// RefMap is a convenient way to store opaque references that can be passed to
|
// refMap is a convenient way to store opaque references that can be passed to
|
||||||
// C. It is useful if an API uses function pointers and you cannot pass a Go
|
// C. It is useful if an API uses function pointers and you cannot pass a Go
|
||||||
// pointer but only a C pointer.
|
// pointer but only a C pointer.
|
||||||
type RefMap struct {
|
type refMap struct {
|
||||||
refs map[unsafe.Pointer]interface{}
|
refs map[unsafe.Pointer]interface{}
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put stores a value in the map. It can later be retrieved using Get. It must
|
// Put stores a value in the map. It can later be retrieved using Get. It must
|
||||||
// be removed using Remove to avoid memory leaks.
|
// be removed using Remove to avoid memory leaks.
|
||||||
func (m *RefMap) Put(v interface{}) unsafe.Pointer {
|
func (m *refMap) Put(v interface{}) unsafe.Pointer {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
if m.refs == nil {
|
if m.refs == nil {
|
||||||
|
@ -31,14 +31,14 @@ func (m *RefMap) Put(v interface{}) unsafe.Pointer {
|
||||||
|
|
||||||
// Get returns a stored value previously inserted with Put. Use the same
|
// Get returns a stored value previously inserted with Put. Use the same
|
||||||
// reference as you got from Put.
|
// reference as you got from Put.
|
||||||
func (m *RefMap) Get(ref unsafe.Pointer) interface{} {
|
func (m *refMap) Get(ref unsafe.Pointer) interface{} {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
return m.refs[ref]
|
return m.refs[ref]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove deletes a single reference from the map.
|
// Remove deletes a single reference from the map.
|
||||||
func (m *RefMap) Remove(ref unsafe.Pointer) {
|
func (m *refMap) Remove(ref unsafe.Pointer) {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
defer m.lock.Unlock()
|
defer m.lock.Unlock()
|
||||||
delete(m.refs, ref)
|
delete(m.refs, ref)
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/cgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Program holds all packages and some metadata about the program as a whole.
|
// Program holds all packages and some metadata about the program as a whole.
|
||||||
|
@ -30,11 +32,10 @@ type Program struct {
|
||||||
type Package struct {
|
type Package struct {
|
||||||
*Program
|
*Program
|
||||||
*build.Package
|
*build.Package
|
||||||
Imports map[string]*Package
|
Imports map[string]*Package
|
||||||
Importing bool
|
Importing bool
|
||||||
Files []*ast.File
|
Files []*ast.File
|
||||||
tokenFiles map[string]*token.File
|
Pkg *types.Package
|
||||||
Pkg *types.Package
|
|
||||||
types.Info
|
types.Info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +108,6 @@ func (p *Program) newPackage(pkg *build.Package) *Package {
|
||||||
Scopes: make(map[ast.Node]*types.Scope),
|
Scopes: make(map[ast.Node]*types.Scope),
|
||||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||||
},
|
},
|
||||||
tokenFiles: map[string]*token.File{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,16 +295,6 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||||
}
|
}
|
||||||
files = append(files, f)
|
files = append(files, f)
|
||||||
}
|
}
|
||||||
clangIncludes := ""
|
|
||||||
if len(p.CgoFiles) != 0 {
|
|
||||||
if _, err := os.Stat(filepath.Join(p.TINYGOROOT, "llvm", "tools", "clang", "lib", "Headers")); !os.IsNotExist(err) {
|
|
||||||
// Running from the source directory.
|
|
||||||
clangIncludes = filepath.Join(p.TINYGOROOT, "llvm", "tools", "clang", "lib", "Headers")
|
|
||||||
} else {
|
|
||||||
// Running from the installation directory.
|
|
||||||
clangIncludes = filepath.Join(p.TINYGOROOT, "lib", "clang", "include")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, file := range p.CgoFiles {
|
for _, file := range p.CgoFiles {
|
||||||
path := filepath.Join(p.Package.Dir, file)
|
path := filepath.Join(p.Package.Dir, file)
|
||||||
f, err := p.parseFile(path, parser.ParseComments)
|
f, err := p.parseFile(path, parser.ParseComments)
|
||||||
|
@ -312,12 +302,22 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||||
fileErrs = append(fileErrs, err)
|
fileErrs = append(fileErrs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
errs := p.processCgo(path, f, append(p.CFlags, "-I"+p.Package.Dir, "-I"+clangIncludes))
|
files = append(files, f)
|
||||||
|
}
|
||||||
|
if len(p.CgoFiles) != 0 {
|
||||||
|
clangIncludes := ""
|
||||||
|
if _, err := os.Stat(filepath.Join(p.TINYGOROOT, "llvm", "tools", "clang", "lib", "Headers")); !os.IsNotExist(err) {
|
||||||
|
// Running from the source directory.
|
||||||
|
clangIncludes = filepath.Join(p.TINYGOROOT, "llvm", "tools", "clang", "lib", "Headers")
|
||||||
|
} else {
|
||||||
|
// Running from the installation directory.
|
||||||
|
clangIncludes = filepath.Join(p.TINYGOROOT, "lib", "clang", "include")
|
||||||
|
}
|
||||||
|
generated, errs := cgo.Process(files, p.Program.Dir, p.fset, append(p.CFlags, "-I"+p.Package.Dir, "-I"+clangIncludes))
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
fileErrs = append(fileErrs, errs...)
|
fileErrs = append(fileErrs, errs...)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
files = append(files, f)
|
files = append(files, generated)
|
||||||
}
|
}
|
||||||
if len(fileErrs) != 0 {
|
if len(fileErrs) != 0 {
|
||||||
return nil, Errors{p, fileErrs}
|
return nil, Errors{p, fileErrs}
|
||||||
|
|
6
testdata/cgo/extra.go
предоставленный
Обычный файл
6
testdata/cgo/extra.go
предоставленный
Обычный файл
|
@ -0,0 +1,6 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Make sure CGo supports multiple files.
|
||||||
|
|
||||||
|
// int fortytwo(void);
|
||||||
|
import "C"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче