1
0
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:
Devon H. O'Dell 2010-01-11 13:05:26 -08:00 committed by Russ Cox
parent d668d4fbbd
commit bc82aaddb6
4 changed files with 77 additions and 3 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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.

View File

@ -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)
} }