mirror of
https://github.com/golang/go
synced 2024-11-25 09:57:57 -07:00
cgo: Make constants #define'd in C available to Go (as consts)
Fixes #435 R=rsc CC=golang-dev https://golang.org/cl/181161
This commit is contained in:
parent
d668d4fbbd
commit
bc82aaddb6
@ -19,7 +19,7 @@ import (
|
|||||||
type Cref struct {
|
type Cref struct {
|
||||||
Name string
|
Name string
|
||||||
Expr *ast.Expr
|
Expr *ast.Expr
|
||||||
Context string // "type", "expr", or "call"
|
Context string // "type", "expr", "const", or "call"
|
||||||
TypeName bool // whether xxx is a C type name
|
TypeName bool // whether xxx is a C type name
|
||||||
Type *Type // the type of xxx
|
Type *Type // the type of xxx
|
||||||
FuncType *FuncType
|
FuncType *FuncType
|
||||||
@ -36,6 +36,7 @@ type Prog struct {
|
|||||||
Vardef map[string]*Type
|
Vardef map[string]*Type
|
||||||
Funcdef map[string]*FuncType
|
Funcdef map[string]*FuncType
|
||||||
Enumdef map[string]int64
|
Enumdef map[string]int64
|
||||||
|
Constdef map[string]string
|
||||||
PtrSize int64
|
PtrSize int64
|
||||||
GccOptions []string
|
GccOptions []string
|
||||||
OutDefs map[string]bool
|
OutDefs map[string]bool
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"debug/macho"
|
"debug/macho"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -21,9 +22,51 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (p *Prog) loadDebugInfo() {
|
func (p *Prog) loadDebugInfo() {
|
||||||
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
b.WriteString(p.Preamble)
|
||||||
|
stdout := p.gccPostProc(b.Bytes())
|
||||||
|
defines := make(map[string]string)
|
||||||
|
for _, line := range strings.Split(stdout, "\n", 0) {
|
||||||
|
if len(line) < 9 || line[0:7] != "#define" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimSpace(line[8:])
|
||||||
|
|
||||||
|
var key, val string
|
||||||
|
spaceIndex := strings.Index(line, " ")
|
||||||
|
tabIndex := strings.Index(line, "\t")
|
||||||
|
|
||||||
|
if spaceIndex == -1 && tabIndex == -1 {
|
||||||
|
continue
|
||||||
|
} else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
|
||||||
|
key = line[0:spaceIndex]
|
||||||
|
val = strings.TrimSpace(line[spaceIndex:])
|
||||||
|
} else {
|
||||||
|
key = line[0:tabIndex]
|
||||||
|
val = strings.TrimSpace(line[tabIndex:])
|
||||||
|
}
|
||||||
|
|
||||||
|
defines[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
// Construct a slice of unique names from p.Crefs.
|
// Construct a slice of unique names from p.Crefs.
|
||||||
m := make(map[string]int)
|
m := make(map[string]int)
|
||||||
for _, c := range p.Crefs {
|
for _, c := range p.Crefs {
|
||||||
|
// If we've already found this name as a define, it is not a Cref.
|
||||||
|
if val, ok := defines[c.Name]; ok {
|
||||||
|
_, err := parser.ParseExpr("", val)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "The value in C.%s does not parse as a Go expression; cannot use.\n", c.Name)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Context = "const"
|
||||||
|
c.TypeName = false
|
||||||
|
p.Constdef[c.Name] = val
|
||||||
|
continue
|
||||||
|
}
|
||||||
m[c.Name] = -1
|
m[c.Name] = -1
|
||||||
}
|
}
|
||||||
names := make([]string, 0, len(m))
|
names := make([]string, 0, len(m))
|
||||||
@ -46,7 +89,7 @@ func (p *Prog) loadDebugInfo() {
|
|||||||
// x.c:2: error: 'name' undeclared (first use in this function)
|
// x.c:2: error: 'name' undeclared (first use in this function)
|
||||||
// A line number directive causes the line number to
|
// A line number directive causes the line number to
|
||||||
// correspond to the index in the names array.
|
// correspond to the index in the names array.
|
||||||
var b bytes.Buffer
|
b.Reset()
|
||||||
b.WriteString(p.Preamble)
|
b.WriteString(p.Preamble)
|
||||||
b.WriteString("void f(void) {\n")
|
b.WriteString("void f(void) {\n")
|
||||||
b.WriteString("#line 0 \"cgo-test\"\n")
|
b.WriteString("#line 0 \"cgo-test\"\n")
|
||||||
@ -189,7 +232,13 @@ func (p *Prog) loadDebugInfo() {
|
|||||||
var conv typeConv
|
var conv typeConv
|
||||||
conv.Init(p.PtrSize)
|
conv.Init(p.PtrSize)
|
||||||
for _, c := range p.Crefs {
|
for _, c := range p.Crefs {
|
||||||
i := m[c.Name]
|
i, ok := m[c.Name]
|
||||||
|
if !ok {
|
||||||
|
if _, ok := p.Constdef[c.Name]; !ok {
|
||||||
|
fatal("Cref %s is no longer around", c.Name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
c.TypeName = kind[c.Name] == "type"
|
c.TypeName = kind[c.Name] == "type"
|
||||||
f, fok := types[i].(*dwarf.FuncType)
|
f, fok := types[i].(*dwarf.FuncType)
|
||||||
if c.Context == "call" && !c.TypeName && fok {
|
if c.Context == "call" && !c.TypeName && fok {
|
||||||
@ -257,6 +306,21 @@ func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) {
|
|||||||
return d, ""
|
return d, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Prog) gccPostProc(stdin []byte) string {
|
||||||
|
machine := "-m32"
|
||||||
|
if p.PtrSize == 8 {
|
||||||
|
machine = "-m64"
|
||||||
|
}
|
||||||
|
|
||||||
|
base := []string{"gcc", machine, "-E", "-dM", "-xc", "-"}
|
||||||
|
stdout, stderr, ok := run(stdin, concat(base, p.GccOptions))
|
||||||
|
if !ok {
|
||||||
|
return string(stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(stdout)
|
||||||
|
}
|
||||||
|
|
||||||
// A typeConv is a translator from dwarf types to Go types
|
// A typeConv is a translator from dwarf types to Go types
|
||||||
// with equivalent memory layout.
|
// with equivalent memory layout.
|
||||||
type typeConv struct {
|
type typeConv struct {
|
||||||
|
@ -76,6 +76,7 @@ func main() {
|
|||||||
p.Vardef = make(map[string]*Type)
|
p.Vardef = make(map[string]*Type)
|
||||||
p.Funcdef = make(map[string]*FuncType)
|
p.Funcdef = make(map[string]*FuncType)
|
||||||
p.Enumdef = make(map[string]int64)
|
p.Enumdef = make(map[string]int64)
|
||||||
|
p.Constdef = make(map[string]string)
|
||||||
p.OutDefs = make(map[string]bool)
|
p.OutDefs = make(map[string]bool)
|
||||||
|
|
||||||
for _, input := range goFiles {
|
for _, input := range goFiles {
|
||||||
@ -91,6 +92,10 @@ func main() {
|
|||||||
p.loadDebugInfo()
|
p.loadDebugInfo()
|
||||||
for _, cref := range p.Crefs {
|
for _, cref := range p.Crefs {
|
||||||
switch cref.Context {
|
switch cref.Context {
|
||||||
|
case "const":
|
||||||
|
// This came from a #define and we'll output it later.
|
||||||
|
*cref.Expr = &ast.Ident{Value: cref.Name}
|
||||||
|
break
|
||||||
case "call":
|
case "call":
|
||||||
if !cref.TypeName {
|
if !cref.TypeName {
|
||||||
// Is an actual function call.
|
// Is an actual function call.
|
||||||
|
@ -57,6 +57,10 @@ func (p *Prog) writeDefs() {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(fc, "\n")
|
fmt.Fprintf(fc, "\n")
|
||||||
|
|
||||||
|
for name, value := range p.Constdef {
|
||||||
|
fmt.Fprintf(fgo2, "const %s = %s\n", name, value)
|
||||||
|
}
|
||||||
|
|
||||||
for name, value := range p.Enumdef {
|
for name, value := range p.Enumdef {
|
||||||
fmt.Fprintf(fgo2, "const %s = %d\n", name, value)
|
fmt.Fprintf(fgo2, "const %s = %d\n", name, value)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user