From 505c19580e0f43fe5224431459cacb7c21edd93d Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Fri, 6 Apr 2012 15:14:11 +0200 Subject: Imported Upstream version 1 --- src/cmd/cgo/main.go | 125 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 35 deletions(-) (limited to 'src/cmd/cgo/main.go') 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...) } -- cgit v1.2.3