cgo: add //go: pragmas to generated functions and globals
This patch adds //go: pragmas directly to declared functions and globals found during CGo processing. This simplifies the logic in the compiler: it no longer has to consider special "C." prefixed function names. It also makes the cgo pass more flexible in the pragmas it emits for functions and global variables.
Этот коммит содержится в:
родитель
a536ddcda8
коммит
1789570f52
8 изменённых файлов: 108 добавлений и 49 удалений
32
cgo/cgo.go
32
cgo/cgo.go
|
@ -496,6 +496,14 @@ func (p *cgoPackage) addFuncDecls() {
|
||||||
}
|
}
|
||||||
args := make([]*ast.Field, len(fn.args))
|
args := make([]*ast.Field, len(fn.args))
|
||||||
decl := &ast.FuncDecl{
|
decl := &ast.FuncDecl{
|
||||||
|
Doc: &ast.CommentGroup{
|
||||||
|
List: []*ast.Comment{
|
||||||
|
{
|
||||||
|
Slash: fn.pos - 1,
|
||||||
|
Text: "//export " + name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
Name: &ast.Ident{
|
Name: &ast.Ident{
|
||||||
NamePos: fn.pos,
|
NamePos: fn.pos,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
|
@ -512,14 +520,10 @@ func (p *cgoPackage) addFuncDecls() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if fn.variadic {
|
if fn.variadic {
|
||||||
decl.Doc = &ast.CommentGroup{
|
decl.Doc.List = append(decl.Doc.List, &ast.Comment{
|
||||||
List: []*ast.Comment{
|
Slash: fn.pos - 1,
|
||||||
{
|
Text: "//go:variadic",
|
||||||
Slash: fn.pos,
|
})
|
||||||
Text: "//go:variadic",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
obj.Decl = decl
|
obj.Decl = decl
|
||||||
for i, arg := range fn.args {
|
for i, arg := range fn.args {
|
||||||
|
@ -652,13 +656,21 @@ func (p *cgoPackage) addVarDecls() {
|
||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
|
global := p.globals[name]
|
||||||
gen := &ast.GenDecl{
|
gen := &ast.GenDecl{
|
||||||
TokPos: token.NoPos,
|
TokPos: global.pos,
|
||||||
Tok: token.VAR,
|
Tok: token.VAR,
|
||||||
Lparen: token.NoPos,
|
Lparen: token.NoPos,
|
||||||
Rparen: token.NoPos,
|
Rparen: token.NoPos,
|
||||||
|
Doc: &ast.CommentGroup{
|
||||||
|
List: []*ast.Comment{
|
||||||
|
{
|
||||||
|
Slash: global.pos - 1,
|
||||||
|
Text: "//go:extern " + name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
global := p.globals[name]
|
|
||||||
obj := &ast.Object{
|
obj := &ast.Object{
|
||||||
Kind: ast.Var,
|
Kind: ast.Var,
|
||||||
Name: "C." + name,
|
Name: "C." + name,
|
||||||
|
|
|
@ -30,7 +30,14 @@ func normalizeResult(result string) string {
|
||||||
func TestCGo(t *testing.T) {
|
func TestCGo(t *testing.T) {
|
||||||
var cflags = []string{"--target=armv6m-unknown-unknown-eabi"}
|
var cflags = []string{"--target=armv6m-unknown-unknown-eabi"}
|
||||||
|
|
||||||
for _, name := range []string{"basic", "errors", "types", "flags", "const"} {
|
for _, name := range []string{
|
||||||
|
"basic",
|
||||||
|
"errors",
|
||||||
|
"types",
|
||||||
|
"symbols",
|
||||||
|
"flags",
|
||||||
|
"const",
|
||||||
|
} {
|
||||||
name := name // avoid a race condition
|
name := name // avoid a race condition
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
// Skip tests that require specific Go version.
|
// Skip tests that require specific Go version.
|
||||||
|
|
23
cgo/testdata/symbols.go
предоставленный
Обычный файл
23
cgo/testdata/symbols.go
предоставленный
Обычный файл
|
@ -0,0 +1,23 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Function signatures.
|
||||||
|
int foo(int a, int b);
|
||||||
|
void variadic0();
|
||||||
|
void variadic2(int x, int y, ...);
|
||||||
|
|
||||||
|
// Global variable signatures.
|
||||||
|
extern int someValue;
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// Test function signatures.
|
||||||
|
func accessFunctions() {
|
||||||
|
C.foo(3, 4)
|
||||||
|
C.variadic0()
|
||||||
|
C.variadic2(3, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func accessGlobals() {
|
||||||
|
_ = C.someValue
|
||||||
|
}
|
44
cgo/testdata/symbols.out.go
предоставленный
Обычный файл
44
cgo/testdata/symbols.out.go
предоставленный
Обычный файл
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
//export foo
|
||||||
|
func C.foo(a C.int, b C.int) C.int
|
||||||
|
|
||||||
|
//export variadic0
|
||||||
|
//go:variadic
|
||||||
|
func C.variadic0()
|
||||||
|
|
||||||
|
//export variadic2
|
||||||
|
//go:variadic
|
||||||
|
func C.variadic2(x C.int, y C.int)
|
||||||
|
|
||||||
|
var C.foo$funcaddr unsafe.Pointer
|
||||||
|
var C.variadic0$funcaddr unsafe.Pointer
|
||||||
|
var C.variadic2$funcaddr unsafe.Pointer
|
||||||
|
|
||||||
|
//go:extern someValue
|
||||||
|
var C.someValue C.int
|
||||||
|
|
||||||
|
type C.int16_t = int16
|
||||||
|
type C.int32_t = int32
|
||||||
|
type C.int64_t = int64
|
||||||
|
type C.int8_t = int8
|
||||||
|
type C.uint16_t = uint16
|
||||||
|
type C.uint32_t = uint32
|
||||||
|
type C.uint64_t = uint64
|
||||||
|
type C.uint8_t = uint8
|
||||||
|
type C.uintptr_t = uintptr
|
||||||
|
type C.char uint8
|
||||||
|
type C.int int32
|
||||||
|
type C.long int32
|
||||||
|
type C.longlong int64
|
||||||
|
type C.schar int8
|
||||||
|
type C.short int16
|
||||||
|
type C.uchar uint8
|
||||||
|
type C.uint uint32
|
||||||
|
type C.ulong uint32
|
||||||
|
type C.ulonglong uint64
|
||||||
|
type C.ushort uint16
|
10
cgo/testdata/types.go
предоставленный
10
cgo/testdata/types.go
предоставленный
|
@ -104,10 +104,6 @@ typedef struct {
|
||||||
unsigned char e : 3;
|
unsigned char e : 3;
|
||||||
// Note that C++ allows bitfields bigger than the underlying type.
|
// Note that C++ allows bitfields bigger than the underlying type.
|
||||||
} bitfield_t;
|
} bitfield_t;
|
||||||
|
|
||||||
// Function signatures.
|
|
||||||
void variadic0();
|
|
||||||
void variadic2(int x, int y, ...);
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
@ -171,9 +167,3 @@ func accessUnion() {
|
||||||
var _ *C.int = union2d.unionfield_i()
|
var _ *C.int = union2d.unionfield_i()
|
||||||
var _ *[2]float64 = union2d.unionfield_d()
|
var _ *[2]float64 = union2d.unionfield_d()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test function signatures.
|
|
||||||
func accessFunctions() {
|
|
||||||
C.variadic0()
|
|
||||||
C.variadic2(3, 5)
|
|
||||||
}
|
|
||||||
|
|
5
cgo/testdata/types.out.go
предоставленный
5
cgo/testdata/types.out.go
предоставленный
|
@ -4,11 +4,6 @@ import "unsafe"
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
func C.variadic0() //go:variadic
|
|
||||||
func C.variadic2(x C.int, y C.int) //go:variadic
|
|
||||||
var C.variadic0$funcaddr unsafe.Pointer
|
|
||||||
var C.variadic2$funcaddr unsafe.Pointer
|
|
||||||
|
|
||||||
const C.option2A = 20
|
const C.option2A = 20
|
||||||
const C.optionA = 0
|
const C.optionA = 0
|
||||||
const C.optionB = 1
|
const C.optionB = 1
|
||||||
|
|
|
@ -2802,9 +2802,8 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
||||||
// var C.add unsafe.Pointer
|
// var C.add unsafe.Pointer
|
||||||
// Instead of a load from the global, create a bitcast of the
|
// Instead of a load from the global, create a bitcast of the
|
||||||
// function pointer itself.
|
// function pointer itself.
|
||||||
globalName := b.getGlobalInfo(unop.X.(*ssa.Global)).linkName
|
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
||||||
name := globalName[:len(globalName)-len("$funcaddr")]
|
fn := b.getFunction(b.fn.Pkg.Members[name].(*ssa.Function))
|
||||||
fn := b.getFunction(b.fn.Pkg.Members["C."+name].(*ssa.Function))
|
|
||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,14 +208,9 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
||||||
// present in *ssa.Function, such as the link name and whether it should be
|
// present in *ssa.Function, such as the link name and whether it should be
|
||||||
// exported.
|
// exported.
|
||||||
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||||
info := functionInfo{}
|
info := functionInfo{
|
||||||
if strings.HasPrefix(f.Name(), "C.") {
|
|
||||||
// Created by CGo: such a name cannot be created by regular C code.
|
|
||||||
info.linkName = f.Name()[2:]
|
|
||||||
info.exported = true
|
|
||||||
} else {
|
|
||||||
// Pick the default linkName.
|
// Pick the default linkName.
|
||||||
info.linkName = f.RelString(nil)
|
linkName: f.RelString(nil),
|
||||||
}
|
}
|
||||||
// Check for //go: pragmas, which may change the link name (among others).
|
// Check for //go: pragmas, which may change the link name (among others).
|
||||||
info.parsePragmas(f)
|
info.parsePragmas(f)
|
||||||
|
@ -460,20 +455,14 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||||
|
|
||||||
// getGlobalInfo returns some information about a specific global.
|
// getGlobalInfo returns some information about a specific global.
|
||||||
func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
|
func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
|
||||||
info := globalInfo{}
|
info := globalInfo{
|
||||||
if strings.HasPrefix(g.Name(), "C.") {
|
|
||||||
// Created by CGo: such a name cannot be created by regular C code.
|
|
||||||
info.linkName = g.Name()[2:]
|
|
||||||
info.extern = true
|
|
||||||
} else {
|
|
||||||
// Pick the default linkName.
|
// Pick the default linkName.
|
||||||
info.linkName = g.RelString(nil)
|
linkName: g.RelString(nil),
|
||||||
// Check for //go: pragmas, which may change the link name (among
|
}
|
||||||
// others).
|
// Check for //go: pragmas, which may change the link name (among others).
|
||||||
doc := c.astComments[info.linkName]
|
doc := c.astComments[info.linkName]
|
||||||
if doc != nil {
|
if doc != nil {
|
||||||
info.parsePragmas(doc)
|
info.parsePragmas(doc)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче