summaryrefslogtreecommitdiff
path: root/src/cmd/cgo/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo/main.go')
-rw-r--r--src/cmd/cgo/main.go125
1 files changed, 90 insertions, 35 deletions
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index be9c2bc4f..7449f04c4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -15,11 +15,13 @@ import (
"flag"
"fmt"
"go/ast"
+ "go/printer"
"go/token"
"io"
"os"
"path/filepath"
"reflect"
+ "runtime"
"strings"
)
@@ -37,11 +39,13 @@ type Package struct {
Decl []ast.Decl
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
+ Preamble string // collected preamble for _cgo_export.h
}
// A File collects information about a single Go input file.
type File struct {
AST *ast.File // parsed AST
+ Comments []*ast.CommentGroup // comments from file
Package string // Package name
Preamble string // C preamble (doc comment on import "C")
Ref []*Ref // all references to C.xxx in AST
@@ -95,6 +99,7 @@ type Type struct {
C *TypeRepr
Go ast.Expr
EnumValues map[string]int64
+ Typedef string
}
// A FuncType collects information about a function type in both the C and Go worlds.
@@ -121,6 +126,19 @@ var cPrefix string
var fset = token.NewFileSet()
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
+var dynout = flag.String("dynout", "", "write -dynobj output to this file")
+
+// These flags are for bootstrapping a new Go implementation,
+// to generate Go and C headers that match the data layout and
+// constant values used in the host's C libraries and system calls.
+var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
+var objDir = flag.String("objdir", "", "object directory")
+
+var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "go", "prefix of symbols generated by gccgo")
+var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
+var goarch, goos string
func main() {
flag.Usage = usage
@@ -130,7 +148,7 @@ func main() {
// cgo -dynimport is essentially a separate helper command
// built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
- // imported libraries. The Make.pkg rules for cgo prepare an
+ // imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
@@ -139,6 +157,18 @@ func main() {
return
}
+ if *godefs && *cdefs {
+ fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
+ os.Exit(2)
+ }
+
+ if *godefs || *cdefs {
+ // Generating definitions pulled from header files,
+ // to be checked into Go repositories.
+ // Line numbers are just noise.
+ conf.Mode &^= printer.SourcePos
+ }
+
args := flag.Args()
if len(args) < 1 {
usage()
@@ -156,32 +186,9 @@ func main() {
usage()
}
- // Copy it to a new slice so it can grow.
- gccOptions := make([]string, i)
- copy(gccOptions, args[0:i])
-
goFiles := args[i:]
- arch := os.Getenv("GOARCH")
- if arch == "" {
- fatalf("$GOARCH is not set")
- }
- ptrSize := ptrSizeMap[arch]
- if ptrSize == 0 {
- fatalf("unknown $GOARCH %q", arch)
- }
-
- // Clear locale variables so gcc emits English errors [sic].
- os.Setenv("LANG", "en_US.UTF-8")
- os.Setenv("LC_ALL", "C")
- os.Setenv("LC_CTYPE", "C")
-
- p := &Package{
- PtrSize: ptrSize,
- GccOptions: gccOptions,
- CgoFlags: make(map[string]string),
- Written: make(map[string]bool),
- }
+ p := newPackage(args[:i])
// Need a unique prefix for the global C symbols that
// we use to coordinate between gcc and ourselves.
@@ -197,7 +204,7 @@ func main() {
io.Copy(h, f)
f.Close()
}
- cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
+ cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
@@ -208,9 +215,13 @@ func main() {
fs[i] = f
}
- // make sure that _obj directory exists, so that we can write
- // all the output files there.
- os.Mkdir("_obj", 0777)
+ if *objDir == "" {
+ // make sure that _obj directory exists, so that we can write
+ // all the output files there.
+ os.Mkdir("_obj", 0777)
+ *objDir = "_obj"
+ }
+ *objDir += string(filepath.Separator)
for i, input := range goFiles {
f := fs[i]
@@ -232,23 +243,64 @@ func main() {
pkg = filepath.Join(dir, pkg)
}
p.PackagePath = pkg
- p.writeOutput(f, input)
-
p.Record(f)
+ if *godefs {
+ os.Stdout.WriteString(p.godefs(f, input))
+ } else if *cdefs {
+ os.Stdout.WriteString(p.cdefs(f, input))
+ } else {
+ p.writeOutput(f, input)
+ }
}
- p.writeDefs()
+ if !*godefs && !*cdefs {
+ p.writeDefs()
+ }
if nerrors > 0 {
os.Exit(2)
}
}
+// newPackage returns a new Package that will invoke
+// gcc with the additional arguments specified in args.
+func newPackage(args []string) *Package {
+ // Copy the gcc options to a new slice so the list
+ // can grow without overwriting the slice that args is in.
+ gccOptions := make([]string, len(args))
+ copy(gccOptions, args)
+
+ goarch = runtime.GOARCH
+ if s := os.Getenv("GOARCH"); s != "" {
+ goarch = s
+ }
+ goos = runtime.GOOS
+ if s := os.Getenv("GOOS"); s != "" {
+ goos = s
+ }
+ ptrSize := ptrSizeMap[goarch]
+ if ptrSize == 0 {
+ fatalf("unknown $GOARCH %q", goarch)
+ }
+
+ // Reset locale variables so gcc emits English errors [sic].
+ os.Setenv("LANG", "en_US.UTF-8")
+ os.Setenv("LC_ALL", "C")
+
+ p := &Package{
+ PtrSize: ptrSize,
+ GccOptions: gccOptions,
+ CgoFlags: make(map[string]string),
+ Written: make(map[string]bool),
+ }
+ return p
+}
+
// Record what needs to be recorded about f.
func (p *Package) Record(f *File) {
if p.PackageName == "" {
p.PackageName = f.Package
} else if p.PackageName != f.Package {
- error(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
+ error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
}
if p.Name == nil {
@@ -258,11 +310,14 @@ func (p *Package) Record(f *File) {
if p.Name[k] == nil {
p.Name[k] = v
} else if !reflect.DeepEqual(p.Name[k], v) {
- error(token.NoPos, "inconsistent definitions for C.%s", k)
+ error_(token.NoPos, "inconsistent definitions for C.%s", k)
}
}
}
- p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ if f.ExpFunc != nil {
+ p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ p.Preamble += "\n" + f.Preamble
+ }
p.Decl = append(p.Decl, f.AST.Decls...)
}