summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:11:55 +0200
commit80f18fc933cf3f3e829c5455a1023d69f7b86e52 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/cmd/cgo
parent28592ee1ea1f5cdffcf85472f9de0285d928cf12 (diff)
downloadgolang-80f18fc933cf3f3e829c5455a1023d69f7b86e52.tar.gz
Imported Upstream version 60
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/Makefile15
-rw-r--r--src/cmd/cgo/ast.go410
-rw-r--r--src/cmd/cgo/doc.go80
-rw-r--r--src/cmd/cgo/gcc.go1367
-rw-r--r--src/cmd/cgo/main.go268
-rw-r--r--src/cmd/cgo/out.go730
-rw-r--r--src/cmd/cgo/util.go110
7 files changed, 0 insertions, 2980 deletions
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
deleted file mode 100644
index 5458c3e4f..000000000
--- a/src/cmd/cgo/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=cgo
-GOFILES=\
- ast.go\
- gcc.go\
- main.go\
- out.go\
- util.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
deleted file mode 100644
index 46e33686d..000000000
--- a/src/cmd/cgo/ast.go
+++ /dev/null
@@ -1,410 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Parse input AST and prepare Prog structure.
-
-package main
-
-import (
- "fmt"
- "go/ast"
- "go/doc"
- "go/parser"
- "go/scanner"
- "go/token"
- "os"
- "strings"
-)
-
-func parse(name string, flags uint) *ast.File {
- ast1, err := parser.ParseFile(fset, name, nil, flags)
- if err != nil {
- if list, ok := err.(scanner.ErrorList); ok {
- // If err is a scanner.ErrorList, its String will print just
- // the first error and then (+n more errors).
- // Instead, turn it into a new Error that will return
- // details for all the errors.
- for _, e := range list {
- fmt.Fprintln(os.Stderr, e)
- }
- os.Exit(2)
- }
- fatalf("parsing %s: %s", name, err)
- }
- return ast1
-}
-
-func sourceLine(n ast.Node) int {
- return fset.Position(n.Pos()).Line
-}
-
-// ReadGo populates f with information learned from reading the
-// Go source file with the given file name. It gathers the C preamble
-// attached to the import "C" comment, a list of references to C.xxx,
-// a list of exported functions, and the actual AST, to be rewritten and
-// printed.
-func (f *File) ReadGo(name string) {
- // Two different parses: once with comments, once without.
- // The printer is not good enough at printing comments in the
- // right place when we start editing the AST behind its back,
- // so we use ast1 to look for the doc comments on import "C"
- // and on exported functions, and we use ast2 for translating
- // and reprinting.
- ast1 := parse(name, parser.ParseComments)
- ast2 := parse(name, 0)
-
- f.Package = ast1.Name.Name
- f.Name = make(map[string]*Name)
-
- // In ast1, find the import "C" line and get any extra C preamble.
- sawC := false
- for _, decl := range ast1.Decls {
- d, ok := decl.(*ast.GenDecl)
- if !ok {
- continue
- }
- for _, spec := range d.Specs {
- s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
- continue
- }
- sawC = true
- if s.Name != nil {
- error(s.Path.Pos(), `cannot rename import "C"`)
- }
- cg := s.Doc
- if cg == nil && len(d.Specs) == 1 {
- cg = d.Doc
- }
- if cg != nil {
- f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
- f.Preamble += doc.CommentText(cg) + "\n"
- }
- }
- }
- if !sawC {
- error(token.NoPos, `cannot find import "C"`)
- }
-
- // In ast2, strip the import "C" line.
- w := 0
- for _, decl := range ast2.Decls {
- d, ok := decl.(*ast.GenDecl)
- if !ok {
- ast2.Decls[w] = decl
- w++
- continue
- }
- ws := 0
- for _, spec := range d.Specs {
- s, ok := spec.(*ast.ImportSpec)
- if !ok || string(s.Path.Value) != `"C"` {
- d.Specs[ws] = spec
- ws++
- }
- }
- if ws == 0 {
- continue
- }
- d.Specs = d.Specs[0:ws]
- ast2.Decls[w] = d
- w++
- }
- ast2.Decls = ast2.Decls[0:w]
-
- // Accumulate pointers to uses of C.x.
- if f.Ref == nil {
- f.Ref = make([]*Ref, 0, 8)
- }
- f.walk(ast2, "prog", (*File).saveRef)
-
- // Accumulate exported functions.
- // The comments are only on ast1 but we need to
- // save the function bodies from ast2.
- // The first walk fills in ExpFunc, and the
- // second walk changes the entries to
- // refer to ast2 instead.
- f.walk(ast1, "prog", (*File).saveExport)
- f.walk(ast2, "prog", (*File).saveExport2)
-
- f.AST = ast2
-}
-
-// Save references to C.xxx for later processing.
-func (f *File) saveRef(x interface{}, context string) {
- n, ok := x.(*ast.Expr)
- if !ok {
- return
- }
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
- if context == "as2" {
- context = "expr"
- }
- goname := sel.Sel.Name
- if goname == "errno" {
- error(sel.Pos(), "cannot refer to errno directly; see documentation")
- return
- }
- name := f.Name[goname]
- if name == nil {
- name = &Name{
- Go: goname,
- }
- f.Name[goname] = name
- }
- f.Ref = append(f.Ref, &Ref{
- Name: name,
- Expr: n,
- Context: context,
- })
- return
- }
- }
-}
-
-// If a function should be exported add it to ExpFunc.
-func (f *File) saveExport(x interface{}, context string) {
- n, ok := x.(*ast.FuncDecl)
- if !ok {
- return
- }
-
- if n.Doc == nil {
- return
- }
- for _, c := range n.Doc.List {
- if !strings.HasPrefix(string(c.Text), "//export ") {
- continue
- }
-
- name := strings.TrimSpace(string(c.Text[9:]))
- if name == "" {
- error(c.Pos(), "export missing name")
- }
-
- f.ExpFunc = append(f.ExpFunc, &ExpFunc{
- Func: n,
- ExpName: name,
- })
- break
- }
-}
-
-// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
-func (f *File) saveExport2(x interface{}, context string) {
- n, ok := x.(*ast.FuncDecl)
- if !ok {
- return
- }
-
- for _, exp := range f.ExpFunc {
- if exp.Func.Name.Name == n.Name.Name {
- exp.Func = n
- break
- }
- }
-}
-
-// walk walks the AST x, calling visit(f, x, context) for each node.
-func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
- visit(f, x, context)
- switch n := x.(type) {
- case *ast.Expr:
- f.walk(*n, context, visit)
-
- // everything else just recurs
- default:
- error(token.NoPos, "unexpected type %T in walk", x, visit)
- panic("unexpected type")
-
- case nil:
-
- // These are ordered and grouped to match ../../pkg/go/ast/ast.go
- case *ast.Field:
- f.walk(&n.Type, "type", visit)
- case *ast.FieldList:
- for _, field := range n.List {
- f.walk(field, context, visit)
- }
- case *ast.BadExpr:
- case *ast.Ident:
- case *ast.Ellipsis:
- case *ast.BasicLit:
- case *ast.FuncLit:
- f.walk(n.Type, "type", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.CompositeLit:
- f.walk(&n.Type, "type", visit)
- f.walk(n.Elts, "expr", visit)
- case *ast.ParenExpr:
- f.walk(&n.X, context, visit)
- case *ast.SelectorExpr:
- f.walk(&n.X, "selector", visit)
- case *ast.IndexExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Index, "expr", visit)
- case *ast.SliceExpr:
- f.walk(&n.X, "expr", visit)
- if n.Low != nil {
- f.walk(&n.Low, "expr", visit)
- }
- if n.High != nil {
- f.walk(&n.High, "expr", visit)
- }
- case *ast.TypeAssertExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Type, "type", visit)
- case *ast.CallExpr:
- if context == "as2" {
- f.walk(&n.Fun, "call2", visit)
- } else {
- f.walk(&n.Fun, "call", visit)
- }
- f.walk(n.Args, "expr", visit)
- case *ast.StarExpr:
- f.walk(&n.X, context, visit)
- case *ast.UnaryExpr:
- f.walk(&n.X, "expr", visit)
- case *ast.BinaryExpr:
- f.walk(&n.X, "expr", visit)
- f.walk(&n.Y, "expr", visit)
- case *ast.KeyValueExpr:
- f.walk(&n.Key, "expr", visit)
- f.walk(&n.Value, "expr", visit)
-
- case *ast.ArrayType:
- f.walk(&n.Len, "expr", visit)
- f.walk(&n.Elt, "type", visit)
- case *ast.StructType:
- f.walk(n.Fields, "field", visit)
- case *ast.FuncType:
- f.walk(n.Params, "field", visit)
- if n.Results != nil {
- f.walk(n.Results, "field", visit)
- }
- case *ast.InterfaceType:
- f.walk(n.Methods, "field", visit)
- case *ast.MapType:
- f.walk(&n.Key, "type", visit)
- f.walk(&n.Value, "type", visit)
- case *ast.ChanType:
- f.walk(&n.Value, "type", visit)
-
- case *ast.BadStmt:
- case *ast.DeclStmt:
- f.walk(n.Decl, "decl", visit)
- case *ast.EmptyStmt:
- case *ast.LabeledStmt:
- f.walk(n.Stmt, "stmt", visit)
- case *ast.ExprStmt:
- f.walk(&n.X, "expr", visit)
- case *ast.SendStmt:
- f.walk(&n.Chan, "expr", visit)
- f.walk(&n.Value, "expr", visit)
- case *ast.IncDecStmt:
- f.walk(&n.X, "expr", visit)
- case *ast.AssignStmt:
- f.walk(n.Lhs, "expr", visit)
- if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
- f.walk(n.Rhs, "as2", visit)
- } else {
- f.walk(n.Rhs, "expr", visit)
- }
- case *ast.GoStmt:
- f.walk(n.Call, "expr", visit)
- case *ast.DeferStmt:
- f.walk(n.Call, "expr", visit)
- case *ast.ReturnStmt:
- f.walk(n.Results, "expr", visit)
- case *ast.BranchStmt:
- case *ast.BlockStmt:
- f.walk(n.List, context, visit)
- case *ast.IfStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Cond, "expr", visit)
- f.walk(n.Body, "stmt", visit)
- f.walk(n.Else, "stmt", visit)
- case *ast.CaseClause:
- if context == "typeswitch" {
- context = "type"
- } else {
- context = "expr"
- }
- f.walk(n.List, context, visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.SwitchStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Tag, "expr", visit)
- f.walk(n.Body, "switch", visit)
- case *ast.TypeSwitchStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(n.Assign, "stmt", visit)
- f.walk(n.Body, "typeswitch", visit)
- case *ast.CommClause:
- f.walk(n.Comm, "stmt", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.SelectStmt:
- f.walk(n.Body, "stmt", visit)
- case *ast.ForStmt:
- f.walk(n.Init, "stmt", visit)
- f.walk(&n.Cond, "expr", visit)
- f.walk(n.Post, "stmt", visit)
- f.walk(n.Body, "stmt", visit)
- case *ast.RangeStmt:
- f.walk(&n.Key, "expr", visit)
- f.walk(&n.Value, "expr", visit)
- f.walk(&n.X, "expr", visit)
- f.walk(n.Body, "stmt", visit)
-
- case *ast.ImportSpec:
- case *ast.ValueSpec:
- f.walk(&n.Type, "type", visit)
- f.walk(n.Values, "expr", visit)
- case *ast.TypeSpec:
- f.walk(&n.Type, "type", visit)
-
- case *ast.BadDecl:
- case *ast.GenDecl:
- f.walk(n.Specs, "spec", visit)
- case *ast.FuncDecl:
- if n.Recv != nil {
- f.walk(n.Recv, "field", visit)
- }
- f.walk(n.Type, "type", visit)
- if n.Body != nil {
- f.walk(n.Body, "stmt", visit)
- }
-
- case *ast.File:
- f.walk(n.Decls, "decl", visit)
-
- case *ast.Package:
- for _, file := range n.Files {
- f.walk(file, "file", visit)
- }
-
- case []ast.Decl:
- for _, d := range n {
- f.walk(d, context, visit)
- }
- case []ast.Expr:
- for i := range n {
- f.walk(&n[i], context, visit)
- }
- case []ast.Stmt:
- for _, s := range n {
- f.walk(s, context, visit)
- }
- case []ast.Spec:
- for _, s := range n {
- f.walk(s, context, visit)
- }
- }
-}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
deleted file mode 100644
index 064725c1d..000000000
--- a/src/cmd/cgo/doc.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-
-Cgo enables the creation of Go packages that call C code.
-
-Usage: cgo [compiler options] file.go
-
-The compiler options are passed through uninterpreted when
-invoking gcc to compile the C parts of the package.
-
-The input file.go is a syntactically valid Go source file that imports
-the pseudo-package "C" and then refers to types such as C.size_t,
-variables such as C.stdout, or functions such as C.putchar.
-
-If the import of "C" is immediately preceded by a comment, that
-comment is used as a header when compiling the C parts of
-the package. For example:
-
- // #include <stdio.h>
- // #include <errno.h>
- import "C"
-
-CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
-within these comments to tweak the behavior of gcc. Values defined
-in multiple directives are concatenated together. Options prefixed
-by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
-systems. For example:
-
- // #cgo CFLAGS: -DPNG_DEBUG=1
- // #cgo linux CFLAGS: -DLINUX=1
- // #cgo LDFLAGS: -lpng
- // #include <png.h>
- import "C"
-
-Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
-tool using a '#cgo pkg-config:' directive followed by the package names.
-For example:
-
- // #cgo pkg-config: png cairo
- // #include <png.h>
- import "C"
-
-Within the Go file, C identifiers or field names that are keywords in Go
-can be accessed by prefixing them with an underscore: if x points at a C
-struct with a field named "type", x._type accesses the field.
-
-The standard C numeric types are available under the names
-C.char, C.schar (signed char), C.uchar (unsigned char),
-C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
-C.long, C.ulong (unsigned long), C.longlong (long long),
-C.ulonglong (unsigned long long), C.float, C.double.
-
-To access a struct, union, or enum type directly, prefix it with
-struct_, union_, or enum_, as in C.struct_stat.
-
-Any C function that returns a value may be called in a multiple
-assignment context to retrieve both the return value and the
-C errno variable as an os.Error. For example:
-
- n, err := C.atoi("abc")
-
-In C, a function argument written as a fixed size array
-actually requires a pointer to the first element of the array.
-C compilers are aware of this calling convention and adjust
-the call accordingly, but Go cannot. In Go, you must pass
-the pointer to the first element explicitly: C.f(&x[0]).
-
-Cgo transforms the input file into four output files: two Go source
-files, a C file for 6c (or 8c or 5c), and a C file for gcc.
-
-The standard package makefile rules in Make.pkg automate the
-process of using cgo. See $GOROOT/misc/cgo/stdio and
-$GOROOT/misc/cgo/gmp for examples.
-
-Cgo does not yet work with gccgo.
-*/
-package documentation
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
deleted file mode 100644
index a4d83f1e7..000000000
--- a/src/cmd/cgo/gcc.go
+++ /dev/null
@@ -1,1367 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Annotate Ref in Prog with C types by parsing gcc debug output.
-// Conversion of debug output to Go types.
-
-package main
-
-import (
- "bytes"
- "debug/dwarf"
- "debug/elf"
- "debug/macho"
- "debug/pe"
- "encoding/binary"
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "os"
- "runtime"
- "strconv"
- "strings"
- "unicode"
-)
-
-var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
-var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
-
-var nameToC = map[string]string{
- "schar": "signed char",
- "uchar": "unsigned char",
- "ushort": "unsigned short",
- "uint": "unsigned int",
- "ulong": "unsigned long",
- "longlong": "long long",
- "ulonglong": "unsigned long long",
- "complexfloat": "float complex",
- "complexdouble": "double complex",
-}
-
-// cname returns the C name to use for C.s.
-// The expansions are listed in nameToC and also
-// struct_foo becomes "struct foo", and similarly for
-// union and enum.
-func cname(s string) string {
- if t, ok := nameToC[s]; ok {
- return t
- }
-
- if strings.HasPrefix(s, "struct_") {
- return "struct " + s[len("struct_"):]
- }
- if strings.HasPrefix(s, "union_") {
- return "union " + s[len("union_"):]
- }
- if strings.HasPrefix(s, "enum_") {
- return "enum " + s[len("enum_"):]
- }
- return s
-}
-
-// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
-// preamble. Multiple occurrences are concatenated with a separating space,
-// even across files.
-func (p *Package) ParseFlags(f *File, srcfile string) {
- linesIn := strings.Split(f.Preamble, "\n")
- linesOut := make([]string, 0, len(linesIn))
-
-NextLine:
- for _, line := range linesIn {
- l := strings.TrimSpace(line)
- if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
- linesOut = append(linesOut, line)
- continue
- }
-
- l = strings.TrimSpace(l[4:])
- fields := strings.SplitN(l, ":", 2)
- if len(fields) != 2 {
- fatalf("%s: bad #cgo line: %s", srcfile, line)
- }
-
- var k string
- kf := strings.Fields(fields[0])
- switch len(kf) {
- case 1:
- k = kf[0]
- case 2:
- k = kf[1]
- switch kf[0] {
- case runtime.GOOS:
- case runtime.GOARCH:
- case runtime.GOOS + "/" + runtime.GOARCH:
- default:
- continue NextLine
- }
- default:
- fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
- }
-
- args, err := splitQuoted(fields[1])
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- for _, arg := range args {
- if !safeName(arg) {
- fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
- }
- }
-
- switch k {
-
- case "CFLAGS", "LDFLAGS":
- p.addToFlag(k, args)
-
- case "pkg-config":
- cflags, ldflags, err := pkgConfig(args)
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- p.addToFlag("CFLAGS", cflags)
- p.addToFlag("LDFLAGS", ldflags)
-
- default:
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
-
- }
- }
- f.Preamble = strings.Join(linesOut, "\n")
-}
-
-// addToFlag appends args to flag. All flags are later written out onto the
-// _cgo_flags file for the build system to use.
-func (p *Package) addToFlag(flag string, args []string) {
- if oldv, ok := p.CgoFlags[flag]; ok {
- p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
- } else {
- p.CgoFlags[flag] = strings.Join(args, " ")
- }
- if flag == "CFLAGS" {
- // We'll also need these when preprocessing for dwarf information.
- p.GccOptions = append(p.GccOptions, args...)
- }
-}
-
-// pkgConfig runs pkg-config and extracts --libs and --cflags information
-// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
- for _, name := range packages {
- if len(name) == 0 || name[0] == '-' {
- return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name))
- }
- }
-
- args := append([]string{"pkg-config", "--cflags"}, packages...)
- stdout, stderr, ok := run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
- }
- cflags, err = splitQuoted(string(stdout))
- if err != nil {
- return
- }
-
- args = append([]string{"pkg-config", "--libs"}, packages...)
- stdout, stderr, ok = run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
- }
- ldflags, err = splitQuoted(string(stdout))
- return
-}
-
-// splitQuoted splits the string s around each instance of one or more consecutive
-// white space characters while taking into account quotes and escaping, and
-// returns an array of substrings of s or an empty list if s contains only white space.
-// Single quotes and double quotes are recognized to prevent splitting within the
-// quoted region, and are removed from the resulting substrings. If a quote in s
-// isn't closed err will be set and r will have the unclosed argument as the
-// last element. The backslash is used for escaping.
-//
-// For example, the following string:
-//
-// `a b:"c d" 'e''f' "g\""`
-//
-// Would be parsed as:
-//
-// []string{"a", "b:c d", "ef", `g"`}
-//
-func splitQuoted(s string) (r []string, err os.Error) {
- var args []string
- arg := make([]int, len(s))
- escaped := false
- quoted := false
- quote := 0
- i := 0
- for _, rune := range s {
- switch {
- case escaped:
- escaped = false
- case rune == '\\':
- escaped = true
- continue
- case quote != 0:
- if rune == quote {
- quote = 0
- continue
- }
- case rune == '"' || rune == '\'':
- quoted = true
- quote = rune
- continue
- case unicode.IsSpace(rune):
- if quoted || i > 0 {
- quoted = false
- args = append(args, string(arg[:i]))
- i = 0
- }
- continue
- }
- arg[i] = rune
- i++
- }
- if quoted || i > 0 {
- args = append(args, string(arg[:i]))
- }
- if quote != 0 {
- err = os.NewError("unclosed quote")
- } else if escaped {
- err = os.NewError("unfinished escaping")
- }
- return args, err
-}
-
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
-
-func safeName(s string) bool {
- if s == "" {
- return false
- }
- for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
- return false
- }
- }
- return true
-}
-
-// Translate rewrites f.AST, the original Go input, to remove
-// references to the imported package C, replacing them with
-// references to the equivalent Go types, functions, and variables.
-func (p *Package) Translate(f *File) {
- for _, cref := range f.Ref {
- // Convert C.ulong to C.unsigned long, etc.
- cref.Name.C = cname(cref.Name.Go)
- }
- p.loadDefines(f)
- needType := p.guessKinds(f)
- if len(needType) > 0 {
- p.loadDWARF(f, needType)
- }
- p.rewriteRef(f)
-}
-
-// loadDefines coerces gcc into spitting out the #defines in use
-// in the file f and saves relevant renamings in f.Name[name].Define.
-func (p *Package) loadDefines(f *File) {
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- stdout := p.gccDefines(b.Bytes())
-
- for _, line := range strings.Split(stdout, "\n") {
- 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:])
- }
-
- if n := f.Name[key]; n != nil {
- if *debugDefine {
- fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
- }
- n.Define = val
- }
- }
-}
-
-// guessKinds tricks gcc into revealing the kind of each
-// name xxx for the references C.xxx in the Go input.
-// The kind is either a constant, type, or variable.
-func (p *Package) guessKinds(f *File) []*Name {
- // Coerce gcc into telling us whether each name is
- // a type, a value, or undeclared. We compile a function
- // containing the line:
- // name;
- // If name is a type, gcc will print:
- // cgo-test:2: warning: useless type name in empty declaration
- // If name is a value, gcc will print
- // cgo-test:2: warning: statement with no effect
- // If name is undeclared, gcc will print
- // cgo-test:2: error: 'name' undeclared (first use in this function)
- // A line number directive causes the line number to
- // correspond to the index in the names array.
- //
- // The line also has an enum declaration:
- // name; enum { _cgo_enum_1 = name };
- // If name is not a constant, gcc will print:
- // cgo-test:4: error: enumerator value for '_cgo_enum_4' is not an integer constant
- // we assume lines without that error are constants.
-
- // Make list of names that need sniffing, type lookup.
- toSniff := make([]*Name, 0, len(f.Name))
- needType := make([]*Name, 0, len(f.Name))
-
- for _, n := range f.Name {
- // If we've already found this name as a #define
- // and we can translate it as a constant value, do so.
- if n.Define != "" {
- ok := false
- if _, err := strconv.Atoi(n.Define); err == nil {
- ok = true
- } else if n.Define[0] == '"' || n.Define[0] == '\'' {
- _, err := parser.ParseExpr(fset, "", n.Define)
- if err == nil {
- ok = true
- }
- }
- if ok {
- n.Kind = "const"
- n.Const = n.Define
- continue
- }
-
- if isName(n.Define) {
- n.C = n.Define
- }
- }
-
- // If this is a struct, union, or enum type name,
- // record the kind but also that we need type information.
- if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
- n.Kind = "type"
- i := len(needType)
- needType = needType[0 : i+1]
- needType[i] = n
- continue
- }
-
- i := len(toSniff)
- toSniff = toSniff[0 : i+1]
- toSniff[i] = n
- }
-
- if len(toSniff) == 0 {
- return needType
- }
-
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- b.WriteString("void __cgo__f__(void) {\n")
- b.WriteString("#line 0 \"cgo-test\"\n")
- for i, n := range toSniff {
- fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
- }
- b.WriteString("}\n")
- stderr := p.gccErrors(b.Bytes())
- if stderr == "" {
- fatalf("gcc produced no output\non input:\n%s", b.Bytes())
- }
-
- names := make([]*Name, len(toSniff))
- copy(names, toSniff)
-
- isConst := make([]bool, len(toSniff))
- for i := range isConst {
- isConst[i] = true // until proven otherwise
- }
-
- for _, line := range strings.Split(stderr, "\n") {
- if len(line) < 9 || line[0:9] != "cgo-test:" {
- // the user will see any compiler errors when the code is compiled later.
- continue
- }
- line = line[9:]
- colon := strings.Index(line, ":")
- if colon < 0 {
- continue
- }
- i, err := strconv.Atoi(line[0:colon])
- if err != nil {
- continue
- }
- what := ""
- switch {
- default:
- continue
- case strings.Contains(line, ": useless type name in empty declaration"):
- what = "type"
- isConst[i] = false
- case strings.Contains(line, ": statement with no effect"):
- what = "not-type" // const or func or var
- case strings.Contains(line, "undeclared"):
- error(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
- case strings.Contains(line, "is not an integer constant"):
- isConst[i] = false
- continue
- }
- n := toSniff[i]
- if n == nil {
- continue
- }
- toSniff[i] = nil
- n.Kind = what
-
- j := len(needType)
- needType = needType[0 : j+1]
- needType[j] = n
- }
- for i, b := range isConst {
- if b {
- names[i].Kind = "const"
- }
- }
- for _, n := range toSniff {
- if n == nil {
- continue
- }
- if n.Kind != "" {
- continue
- }
- error(token.NoPos, "could not determine kind of name for C.%s", n.Go)
- }
- if nerrors > 0 {
- fatalf("unresolved names")
- }
- return needType
-}
-
-// loadDWARF parses the DWARF debug information generated
-// by gcc to learn the details of the constants, variables, and types
-// being referred to as C.xxx.
-func (p *Package) loadDWARF(f *File, names []*Name) {
- // Extract the types from the DWARF section of an object
- // from a well-formed C program. Gcc only generates DWARF info
- // for symbols in the object file, so it is not enough to print the
- // preamble and hope the symbols we care about will be there.
- // Instead, emit
- // typeof(names[i]) *__cgo__i;
- // for each entry in names and then dereference the type we
- // learn for __cgo__i.
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- for i, n := range names {
- fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i)
- if n.Kind == "const" {
- fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
- }
- }
-
- // Apple's LLVM-based gcc does not include the enumeration
- // names and values in its DWARF debug output. In case we're
- // using such a gcc, create a data block initialized with the values.
- // We can read them out of the object file.
- fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
- for _, n := range names {
- if n.Kind == "const" {
- fmt.Fprintf(&b, "\t%s,\n", n.C)
- } else {
- fmt.Fprintf(&b, "\t0,\n")
- }
- }
- fmt.Fprintf(&b, "\t0\n")
- fmt.Fprintf(&b, "};\n")
-
- d, bo, debugData := p.gccDebug(b.Bytes())
- enumVal := make([]int64, len(debugData)/8)
- for i := range enumVal {
- enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
- }
-
- // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
- types := make([]dwarf.Type, len(names))
- enums := make([]dwarf.Offset, len(names))
- nameToIndex := make(map[*Name]int)
- for i, n := range names {
- nameToIndex[n] = i
- }
- r := d.Reader()
- for {
- e, err := r.Next()
- if err != nil {
- fatalf("reading DWARF entry: %s", err)
- }
- if e == nil {
- break
- }
- switch e.Tag {
- case dwarf.TagEnumerationType:
- offset := e.Offset
- for {
- e, err := r.Next()
- if err != nil {
- fatalf("reading DWARF entry: %s", err)
- }
- if e.Tag == 0 {
- break
- }
- if e.Tag == dwarf.TagEnumerator {
- entryName := e.Val(dwarf.AttrName).(string)
- if strings.HasPrefix(entryName, "__cgo_enum__") {
- n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
- if 0 <= n && n < len(names) {
- enums[n] = offset
- }
- }
- }
- }
- case dwarf.TagVariable:
- name, _ := e.Val(dwarf.AttrName).(string)
- typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
- if name == "" || typOff == 0 {
- fatalf("malformed DWARF TagVariable entry")
- }
- if !strings.HasPrefix(name, "__cgo__") {
- break
- }
- typ, err := d.Type(typOff)
- if err != nil {
- fatalf("loading DWARF type: %s", err)
- }
- t, ok := typ.(*dwarf.PtrType)
- if !ok || t == nil {
- fatalf("internal error: %s has non-pointer type", name)
- }
- i, err := strconv.Atoi(name[7:])
- if err != nil {
- fatalf("malformed __cgo__ name: %s", name)
- }
- if enums[i] != 0 {
- t, err := d.Type(enums[i])
- if err != nil {
- fatalf("loading DWARF type: %s", err)
- }
- types[i] = t
- } else {
- types[i] = t.Type
- }
- }
- if e.Tag != dwarf.TagCompileUnit {
- r.SkipChildren()
- }
- }
-
- // Record types and typedef information.
- var conv typeConv
- conv.Init(p.PtrSize)
- for i, n := range names {
- f, fok := types[i].(*dwarf.FuncType)
- if n.Kind != "type" && fok {
- n.Kind = "func"
- n.FuncType = conv.FuncType(f)
- } else {
- n.Type = conv.Type(types[i])
- if enums[i] != 0 && n.Type.EnumValues != nil {
- k := fmt.Sprintf("__cgo_enum__%d", i)
- n.Kind = "const"
- n.Const = strconv.Itoa64(n.Type.EnumValues[k])
- // Remove injected enum to ensure the value will deep-compare
- // equally in future loads of the same constant.
- n.Type.EnumValues[k] = 0, false
- } else if n.Kind == "const" && i < len(enumVal) {
- n.Const = strconv.Itoa64(enumVal[i])
- }
- }
- }
-
-}
-
-// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
-// Go equivalents, now that we have figured out the meaning of all
-// the xxx.
-func (p *Package) rewriteRef(f *File) {
- // Assign mangled names.
- for _, n := range f.Name {
- if n.Kind == "not-type" {
- n.Kind = "var"
- }
- if n.Mangle == "" {
- n.Mangle = "_C" + n.Kind + "_" + n.Go
- }
- }
-
- // Now that we have all the name types filled in,
- // scan through the Refs to identify the ones that
- // are trying to do a ,err call. Also check that
- // functions are only used in calls.
- for _, r := range f.Ref {
- if r.Name.Kind == "const" && r.Name.Const == "" {
- error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
- }
- var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
- switch r.Context {
- case "call", "call2":
- if r.Name.Kind != "func" {
- if r.Name.Kind == "type" {
- r.Context = "type"
- expr = r.Name.Type.Go
- break
- }
- error(r.Pos(), "call of non-function C.%s", r.Name.Go)
- break
- }
- if r.Context == "call2" {
- if r.Name.FuncType.Result == nil {
- error(r.Pos(), "assignment count mismatch: 2 = 0")
- }
- // Invent new Name for the two-result function.
- n := f.Name["2"+r.Name.Go]
- if n == nil {
- n = new(Name)
- *n = *r.Name
- n.AddError = true
- n.Mangle = "_C2func_" + n.Go
- f.Name["2"+r.Name.Go] = n
- }
- expr = ast.NewIdent(n.Mangle)
- r.Name = n
- break
- }
- case "expr":
- if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
- }
- if r.Name.Kind == "type" {
- // Okay - might be new(T)
- expr = r.Name.Type.Go
- }
- if r.Name.Kind == "var" {
- expr = &ast.StarExpr{X: expr}
- }
-
- case "type":
- if r.Name.Kind != "type" {
- error(r.Pos(), "expression C.%s used as type", r.Name.Go)
- } else {
- expr = r.Name.Type.Go
- }
- default:
- if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
- }
- }
- *r.Expr = expr
- }
-}
-
-// gccName returns the name of the compiler to run. Use $GCC if set in
-// the environment, otherwise just "gcc".
-
-func (p *Package) gccName() (ret string) {
- if ret = os.Getenv("GCC"); ret == "" {
- ret = "gcc"
- }
- return
-}
-
-// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
-func (p *Package) gccMachine() []string {
- switch runtime.GOARCH {
- case "amd64":
- return []string{"-m64"}
- case "386":
- return []string{"-m32"}
- }
- return nil
-}
-
-var gccTmp = objDir + "_cgo_.o"
-
-// gccCmd returns the gcc command line to use for compiling
-// the input.
-func (p *Package) gccCmd() []string {
- c := []string{
- p.gccName(),
- "-Wall", // many warnings
- "-Werror", // warnings are errors
- "-o" + gccTmp, // write object to tmp
- "-gdwarf-2", // generate DWARF v2 debugging symbols
- "-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
- "-c", // do not link
- "-xc", // input language is C
- }
- c = append(c, p.GccOptions...)
- c = append(c, p.gccMachine()...)
- c = append(c, "-") //read input from standard input
- return c
-}
-
-// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and, if present, debug data block.
-func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
- runGcc(stdin, p.gccCmd())
-
- if f, err := macho.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- var data []byte
- if f.Symtab != nil {
- for i := range f.Symtab.Syms {
- s := &f.Symtab.Syms[i]
- // Mach-O still uses a leading _ to denote non-assembly symbols.
- if s.Name == "_"+"__cgodebug_data" {
- // Found it. Now find data section.
- if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
- sect := f.Sections[i]
- if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
- if sdat, err := sect.Data(); err == nil {
- data = sdat[s.Value-sect.Addr:]
- }
- }
- }
- }
- }
- }
- return d, f.ByteOrder, data
- }
-
- // Can skip debug data block in ELF and PE for now.
- // The DWARF information is complete.
-
- if f, err := elf.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- return d, f.ByteOrder, nil
- }
-
- if f, err := pe.Open(gccTmp); err == nil {
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
- }
- return d, binary.LittleEndian, nil
- }
-
- fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
- panic("not reached")
-}
-
-// gccDefines runs gcc -E -dM -xc - over the C program stdin
-// and returns the corresponding standard output, which is the
-// #defines that gcc encountered while processing the input
-// and its included files.
-func (p *Package) gccDefines(stdin []byte) string {
- base := []string{p.gccName(), "-E", "-dM", "-xc"}
- base = append(base, p.gccMachine()...)
- stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
- return stdout
-}
-
-// gccErrors runs gcc over the C program stdin and returns
-// the errors that gcc prints. That is, this function expects
-// gcc to fail.
-func (p *Package) gccErrors(stdin []byte) string {
- // TODO(rsc): require failure
- args := p.gccCmd()
- if *debugGcc {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
- }
- stdout, stderr, _ := run(stdin, args)
- if *debugGcc {
- os.Stderr.Write(stdout)
- os.Stderr.Write(stderr)
- }
- return string(stderr)
-}
-
-// runGcc runs the gcc command line args with stdin on standard input.
-// If the command exits with a non-zero exit status, runGcc prints
-// details about what was run and exits.
-// Otherwise runGcc returns the data written to standard output and standard error.
-// Note that for some of the uses we expect useful data back
-// on standard error, but for those uses gcc must still exit 0.
-func runGcc(stdin []byte, args []string) (string, string) {
- if *debugGcc {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
- }
- stdout, stderr, ok := run(stdin, args)
- if *debugGcc {
- os.Stderr.Write(stdout)
- os.Stderr.Write(stderr)
- }
- if !ok {
- os.Stderr.Write(stderr)
- os.Exit(2)
- }
- return string(stdout), string(stderr)
-}
-
-// A typeConv is a translator from dwarf types to Go types
-// with equivalent memory layout.
-type typeConv struct {
- // Cache of already-translated or in-progress types.
- m map[dwarf.Type]*Type
- typedef map[string]ast.Expr
-
- // Predeclared types.
- bool ast.Expr
- byte ast.Expr // denotes padding
- int8, int16, int32, int64 ast.Expr
- uint8, uint16, uint32, uint64, uintptr ast.Expr
- float32, float64 ast.Expr
- complex64, complex128 ast.Expr
- void ast.Expr
- unsafePointer ast.Expr
- string ast.Expr
-
- ptrSize int64
-}
-
-var tagGen int
-var typedef = make(map[string]ast.Expr)
-
-func (c *typeConv) Init(ptrSize int64) {
- c.ptrSize = ptrSize
- c.m = make(map[dwarf.Type]*Type)
- c.bool = c.Ident("bool")
- c.byte = c.Ident("byte")
- c.int8 = c.Ident("int8")
- c.int16 = c.Ident("int16")
- c.int32 = c.Ident("int32")
- c.int64 = c.Ident("int64")
- c.uint8 = c.Ident("uint8")
- c.uint16 = c.Ident("uint16")
- c.uint32 = c.Ident("uint32")
- c.uint64 = c.Ident("uint64")
- c.uintptr = c.Ident("uintptr")
- c.float32 = c.Ident("float32")
- c.float64 = c.Ident("float64")
- c.complex64 = c.Ident("complex64")
- c.complex128 = c.Ident("complex128")
- c.unsafePointer = c.Ident("unsafe.Pointer")
- c.void = c.Ident("void")
- c.string = c.Ident("string")
-}
-
-// base strips away qualifiers and typedefs to get the underlying type
-func base(dt dwarf.Type) dwarf.Type {
- for {
- if d, ok := dt.(*dwarf.QualType); ok {
- dt = d.Type
- continue
- }
- if d, ok := dt.(*dwarf.TypedefType); ok {
- dt = d.Type
- continue
- }
- break
- }
- return dt
-}
-
-// Map from dwarf text names to aliases we use in package "C".
-var dwarfToName = map[string]string{
- "long int": "long",
- "long unsigned int": "ulong",
- "unsigned int": "uint",
- "short unsigned int": "ushort",
- "short int": "short",
- "long long int": "longlong",
- "long long unsigned int": "ulonglong",
- "signed char": "schar",
- "float complex": "complexfloat",
- "double complex": "complexdouble",
-}
-
-const signedDelta = 64
-
-// String returns the current type representation. Format arguments
-// are assembled within this method so that any changes in mutable
-// values are taken into account.
-func (tr *TypeRepr) String() string {
- if len(tr.Repr) == 0 {
- return ""
- }
- if len(tr.FormatArgs) == 0 {
- return tr.Repr
- }
- return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
-}
-
-// Empty returns true if the result of String would be "".
-func (tr *TypeRepr) Empty() bool {
- return len(tr.Repr) == 0
-}
-
-// Set modifies the type representation.
-// If fargs are provided, repr is used as a format for fmt.Sprintf.
-// Otherwise, repr is used unprocessed as the type representation.
-func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
- tr.Repr = repr
- tr.FormatArgs = fargs
-}
-
-// Type returns a *Type with the same memory layout as
-// dtype when used as the type of a variable or a struct field.
-func (c *typeConv) Type(dtype dwarf.Type) *Type {
- if t, ok := c.m[dtype]; ok {
- if t.Go == nil {
- fatalf("type conversion loop at %s", dtype)
- }
- return t
- }
-
- t := new(Type)
- t.Size = dtype.Size()
- t.Align = -1
- t.C = &TypeRepr{Repr: dtype.Common().Name}
- c.m[dtype] = t
-
- if t.Size < 0 {
- // Unsized types are [0]byte
- t.Size = 0
- t.Go = c.Opaque(0)
- if t.C.Empty() {
- t.C.Set("void")
- }
- return t
- }
-
- switch dt := dtype.(type) {
- default:
- fatalf("unexpected type: %s", dtype)
-
- case *dwarf.AddrType:
- if t.Size != c.ptrSize {
- fatalf("unexpected: %d-byte address type - %s", t.Size, dtype)
- }
- t.Go = c.uintptr
- t.Align = t.Size
-
- case *dwarf.ArrayType:
- if dt.StrideBitSize > 0 {
- // Cannot represent bit-sized elements in Go.
- t.Go = c.Opaque(t.Size)
- break
- }
- gt := &ast.ArrayType{
- Len: c.intExpr(dt.Count),
- }
- t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
- t.Align = sub.Align
- gt.Elt = sub.Go
- t.C.Set("typeof(%s[%d])", sub.C, dt.Count)
-
- case *dwarf.BoolType:
- t.Go = c.bool
- t.Align = c.ptrSize
-
- case *dwarf.CharType:
- if t.Size != 1 {
- fatalf("unexpected: %d-byte char type - %s", t.Size, dtype)
- }
- t.Go = c.int8
- t.Align = 1
-
- case *dwarf.EnumType:
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- t.C.Set("enum " + dt.EnumName)
- signed := 0
- t.EnumValues = make(map[string]int64)
- for _, ev := range dt.Val {
- t.EnumValues[ev.Name] = ev.Val
- if ev.Val < 0 {
- signed = signedDelta
- }
- }
- switch t.Size + int64(signed) {
- default:
- fatalf("unexpected: %d-byte enum type - %s", t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- case 1 + signedDelta:
- t.Go = c.int8
- case 2 + signedDelta:
- t.Go = c.int16
- case 4 + signedDelta:
- t.Go = c.int32
- case 8 + signedDelta:
- t.Go = c.int64
- }
-
- case *dwarf.FloatType:
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte float type - %s", t.Size, dtype)
- case 4:
- t.Go = c.float32
- case 8:
- t.Go = c.float64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.ComplexType:
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte complex type - %s", t.Size, dtype)
- case 8:
- t.Go = c.complex64
- case 16:
- t.Go = c.complex128
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.FuncType:
- // No attempt at translation: would enable calls
- // directly between worlds, but we need to moderate those.
- t.Go = c.uintptr
- t.Align = c.ptrSize
-
- case *dwarf.IntType:
- if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit int type - %s", dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte int type - %s", t.Size, dtype)
- case 1:
- t.Go = c.int8
- case 2:
- t.Go = c.int16
- case 4:
- t.Go = c.int32
- case 8:
- t.Go = c.int64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.PtrType:
- t.Align = c.ptrSize
-
- // Translate void* as unsafe.Pointer
- if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
- t.Go = c.unsafePointer
- t.C.Set("void*")
- break
- }
-
- gt := &ast.StarExpr{}
- t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
- gt.X = sub.Go
- t.C.Set("%s*", sub.C)
-
- case *dwarf.QualType:
- // Ignore qualifier.
- t = c.Type(dt.Type)
- c.m[dtype] = t
- return t
-
- case *dwarf.StructType:
- // Convert to Go struct, being careful about alignment.
- // Have to give it a name to simulate C "struct foo" references.
- tag := dt.StructName
- if tag == "" {
- tag = "__" + strconv.Itoa(tagGen)
- tagGen++
- } else if t.C.Empty() {
- t.C.Set(dt.Kind + " " + tag)
- }
- name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
- t.Go = name // publish before recursive calls
- switch dt.Kind {
- case "union", "class":
- typedef[name.Name] = c.Opaque(t.Size)
- if t.C.Empty() {
- t.C.Set("typeof(unsigned char[%d])", t.Size)
- }
- case "struct":
- g, csyntax, align := c.Struct(dt)
- if t.C.Empty() {
- t.C.Set(csyntax)
- }
- t.Align = align
- typedef[name.Name] = g
- }
-
- case *dwarf.TypedefType:
- // Record typedef for printing.
- if dt.Name == "_GoString_" {
- // Special C name for Go string type.
- // Knows string layout used by compilers: pointer plus length,
- // which rounds up to 2 pointers after alignment.
- t.Go = c.string
- t.Size = c.ptrSize * 2
- t.Align = c.ptrSize
- break
- }
- name := c.Ident("_Ctypedef_" + dt.Name)
- t.Go = name // publish before recursive call
- sub := c.Type(dt.Type)
- t.Size = sub.Size
- t.Align = sub.Align
- if _, ok := typedef[name.Name]; !ok {
- typedef[name.Name] = sub.Go
- }
-
- case *dwarf.UcharType:
- if t.Size != 1 {
- fatalf("unexpected: %d-byte uchar type - %s", t.Size, dtype)
- }
- t.Go = c.uint8
- t.Align = 1
-
- case *dwarf.UintType:
- if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit uint type - %s", dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("unexpected: %d-byte uint type - %s", t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
-
- case *dwarf.VoidType:
- t.Go = c.void
- t.C.Set("void")
- }
-
- switch dtype.(type) {
- case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
- s := dtype.Common().Name
- if s != "" {
- if ss, ok := dwarfToName[s]; ok {
- s = ss
- }
- s = strings.Join(strings.Split(s, " "), "") // strip spaces
- name := c.Ident("_Ctype_" + s)
- typedef[name.Name] = t.Go
- t.Go = name
- }
- }
-
- if t.C.Empty() {
- fatalf("internal error: did not create C name for %s", dtype)
- }
-
- return t
-}
-
-// FuncArg returns a Go type with the same memory layout as
-// dtype when used as the type of a C function argument.
-func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
- t := c.Type(dtype)
- switch dt := dtype.(type) {
- case *dwarf.ArrayType:
- // Arrays are passed implicitly as pointers in C.
- // In Go, we must be explicit.
- tr := &TypeRepr{}
- tr.Set("%s*", t.C)
- return &Type{
- Size: c.ptrSize,
- Align: c.ptrSize,
- Go: &ast.StarExpr{X: t.Go},
- C: tr,
- }
- case *dwarf.TypedefType:
- // C has much more relaxed rules than Go for
- // implicit type conversions. When the parameter
- // is type T defined as *X, simulate a little of the
- // laxness of C by making the argument *X instead of T.
- if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
- // Unless the typedef happens to point to void* since
- // Go has special rules around using unsafe.Pointer.
- if _, void := base(ptr.Type).(*dwarf.VoidType); !void {
- return c.Type(ptr)
- }
- }
- }
- return t
-}
-
-// FuncType returns the Go type analogous to dtype.
-// There is no guarantee about matching memory layout.
-func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
- p := make([]*Type, len(dtype.ParamType))
- gp := make([]*ast.Field, len(dtype.ParamType))
- for i, f := range dtype.ParamType {
- // gcc's DWARF generator outputs a single DotDotDotType parameter for
- // function pointers that specify no parameters (e.g. void
- // (*__cgo_0)()). Treat this special case as void. This case is
- // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
- // legal).
- if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
- p, gp = nil, nil
- break
- }
- p[i] = c.FuncArg(f)
- gp[i] = &ast.Field{Type: p[i].Go}
- }
- var r *Type
- var gr []*ast.Field
- if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType)
- gr = []*ast.Field{&ast.Field{Type: r.Go}}
- }
- return &FuncType{
- Params: p,
- Result: r,
- Go: &ast.FuncType{
- Params: &ast.FieldList{List: gp},
- Results: &ast.FieldList{List: gr},
- },
- }
-}
-
-// Identifier
-func (c *typeConv) Ident(s string) *ast.Ident {
- return ast.NewIdent(s)
-}
-
-// Opaque type of n bytes.
-func (c *typeConv) Opaque(n int64) ast.Expr {
- return &ast.ArrayType{
- Len: c.intExpr(n),
- Elt: c.byte,
- }
-}
-
-// Expr for integer n.
-func (c *typeConv) intExpr(n int64) ast.Expr {
- return &ast.BasicLit{
- Kind: token.INT,
- Value: strconv.Itoa64(n),
- }
-}
-
-// Add padding of given size to fld.
-func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
- n := len(fld)
- fld = fld[0 : n+1]
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
- return fld
-}
-
-// Struct conversion: return Go and (6g) C syntax for type.
-func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
- var buf bytes.Buffer
- buf.WriteString("struct {")
- fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
- off := int64(0)
-
- // Rename struct fields that happen to be named Go keywords into
- // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
- // be mangled. Any existing identifier that already has the same name on
- // the C-side will cause the Go-mangled version to be prefixed with _.
- // (e.g. in a struct with fields '_type' and 'type', the latter would be
- // rendered as '__type' in Go).
- ident := make(map[string]string)
- used := make(map[string]bool)
- for _, f := range dt.Field {
- ident[f.Name] = f.Name
- used[f.Name] = true
- }
- for cid, goid := range ident {
- if token.Lookup([]byte(goid)).IsKeyword() {
- // Avoid keyword
- goid = "_" + goid
-
- // Also avoid existing fields
- for _, exist := used[goid]; exist; _, exist = used[goid] {
- goid = "_" + goid
- }
-
- used[goid] = true
- ident[cid] = goid
- }
- }
-
- for _, f := range dt.Field {
- if f.BitSize > 0 && f.BitSize != f.ByteSize*8 {
- continue
- }
- if f.ByteOffset > off {
- fld = c.pad(fld, f.ByteOffset-off)
- off = f.ByteOffset
- }
- t := c.Type(f.Type)
- n := len(fld)
- fld = fld[0 : n+1]
-
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
- off += t.Size
- buf.WriteString(t.C.String())
- buf.WriteString(" ")
- buf.WriteString(f.Name)
- buf.WriteString("; ")
- if t.Align > align {
- align = t.Align
- }
- }
- if off < dt.ByteSize {
- fld = c.pad(fld, dt.ByteSize-off)
- off = dt.ByteSize
- }
- if off != dt.ByteSize {
- fatalf("struct size calculation error")
- }
- buf.WriteString("}")
- csyntax = buf.String()
- expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
- return
-}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
deleted file mode 100644
index be9c2bc4f..000000000
--- a/src/cmd/cgo/main.go
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Cgo; see gmp.go for an overview.
-
-// TODO(rsc):
-// Emit correct line number annotations.
-// Make 6g understand the annotations.
-
-package main
-
-import (
- "crypto/md5"
- "flag"
- "fmt"
- "go/ast"
- "go/token"
- "io"
- "os"
- "path/filepath"
- "reflect"
- "strings"
-)
-
-// A Package collects information about the package we're going to write.
-type Package struct {
- PackageName string // name of package
- PackagePath string
- PtrSize int64
- GccOptions []string
- CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
- Written map[string]bool
- Name map[string]*Name // accumulated Name from Files
- Typedef map[string]ast.Expr // accumulated Typedef from Files
- ExpFunc []*ExpFunc // accumulated ExpFunc from Files
- Decl []ast.Decl
- GoFiles []string // list of Go files
- GccFiles []string // list of gcc output files
-}
-
-// A File collects information about a single Go input file.
-type File struct {
- AST *ast.File // parsed AST
- Package string // Package name
- Preamble string // C preamble (doc comment on import "C")
- Ref []*Ref // all references to C.xxx in AST
- ExpFunc []*ExpFunc // exported functions for this file
- Name map[string]*Name // map from Go name to Name
- Typedef map[string]ast.Expr // translations of all necessary types from C
-}
-
-// A Ref refers to an expression of the form C.xxx in the AST.
-type Ref struct {
- Name *Name
- Expr *ast.Expr
- Context string // "type", "expr", "call", or "call2"
-}
-
-func (r *Ref) Pos() token.Pos {
- return (*r.Expr).Pos()
-}
-
-// A Name collects information about C.xxx.
-type Name struct {
- Go string // name used in Go referring to package C
- Mangle string // name used in generated Go
- C string // name used in C
- Define string // #define expansion
- Kind string // "const", "type", "var", "func", "not-type"
- Type *Type // the type of xxx
- FuncType *FuncType
- AddError bool
- Const string // constant definition
-}
-
-// A ExpFunc is an exported function, callable from C.
-// Such functions are identified in the Go input file
-// by doc comments containing the line //export ExpName
-type ExpFunc struct {
- Func *ast.FuncDecl
- ExpName string // name to use from C
-}
-
-// A TypeRepr contains the string representation of a type.
-type TypeRepr struct {
- Repr string
- FormatArgs []interface{}
-}
-
-// A Type collects information about a type in both the C and Go worlds.
-type Type struct {
- Size int64
- Align int64
- C *TypeRepr
- Go ast.Expr
- EnumValues map[string]int64
-}
-
-// A FuncType collects information about a function type in both the C and Go worlds.
-type FuncType struct {
- Params []*Type
- Result *Type
- Go *ast.FuncType
-}
-
-func usage() {
- fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-var ptrSizeMap = map[string]int64{
- "386": 4,
- "amd64": 8,
- "arm": 4,
-}
-
-var cPrefix string
-
-var fset = token.NewFileSet()
-
-var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if *dynobj != "" {
- // 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
- // 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
- // symbols and which ones to use.
- dynimport(*dynobj)
- return
- }
-
- args := flag.Args()
- if len(args) < 1 {
- usage()
- }
-
- // Find first arg that looks like a go file and assume everything before
- // that are options to pass to gcc.
- var i int
- for i = len(args); i > 0; i-- {
- if !strings.HasSuffix(args[i-1], ".go") {
- break
- }
- }
- if i == len(args) {
- 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),
- }
-
- // Need a unique prefix for the global C symbols that
- // we use to coordinate between gcc and ourselves.
- // We already put _cgo_ at the beginning, so the main
- // concern is other cgo wrappers for the same functions.
- // Use the beginning of the md5 of the input to disambiguate.
- h := md5.New()
- for _, input := range goFiles {
- f, err := os.Open(input)
- if err != nil {
- fatalf("%s", err)
- }
- io.Copy(h, f)
- f.Close()
- }
- cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
-
- fs := make([]*File, len(goFiles))
- for i, input := range goFiles {
- // Parse flags for all files before translating due to CFLAGS.
- f := new(File)
- f.ReadGo(input)
- p.ParseFlags(f, input)
- fs[i] = f
- }
-
- // make sure that _obj directory exists, so that we can write
- // all the output files there.
- os.Mkdir("_obj", 0777)
-
- for i, input := range goFiles {
- f := fs[i]
- p.Translate(f)
- for _, cref := range f.Ref {
- switch cref.Context {
- case "call", "call2":
- if cref.Name.Kind != "type" {
- break
- }
- *cref.Expr = cref.Name.Type.Go
- }
- }
- if nerrors > 0 {
- os.Exit(2)
- }
- pkg := f.Package
- if dir := os.Getenv("CGOPKGPATH"); dir != "" {
- pkg = filepath.Join(dir, pkg)
- }
- p.PackagePath = pkg
- p.writeOutput(f, input)
-
- p.Record(f)
- }
-
- p.writeDefs()
- if nerrors > 0 {
- os.Exit(2)
- }
-}
-
-// 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)
- }
-
- if p.Name == nil {
- p.Name = f.Name
- } else {
- for k, v := range f.Name {
- 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)
- }
- }
- }
-
- p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
- p.Decl = append(p.Decl, f.AST.Decls...)
-}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
deleted file mode 100644
index 6802dd1cf..000000000
--- a/src/cmd/cgo/out.go
+++ /dev/null
@@ -1,730 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "debug/elf"
- "debug/macho"
- "debug/pe"
- "fmt"
- "go/ast"
- "go/printer"
- "go/token"
- "os"
- "path/filepath"
- "strings"
-)
-
-var objDir = "_obj" + string(filepath.Separator)
-
-// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
-// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Package) writeDefs() {
- fgo2 := creat(objDir + "_cgo_gotypes.go")
- fc := creat(objDir + "_cgo_defun.c")
- fm := creat(objDir + "_cgo_main.c")
-
- fflg := creat(objDir + "_cgo_flags")
- for k, v := range p.CgoFlags {
- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
- }
- fflg.Close()
-
- // Write C main file for using gcc to resolve imports.
- fmt.Fprintf(fm, "int main() { return 0; }\n")
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
- fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
- fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
-
- // Write second Go output: definitions of _C_xxx.
- // In a separate file so that the import of "unsafe" does not
- // pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
- fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- fmt.Fprintf(fgo2, "import \"os\"\n\n")
- fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
- fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
- fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n")
-
- for name, def := range typedef {
- fmt.Fprintf(fgo2, "type %s ", name)
- printer.Fprint(fgo2, fset, def)
- fmt.Fprintf(fgo2, "\n")
- }
- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
-
- fmt.Fprintf(fc, cProlog)
-
- var cVars []string
- for _, n := range p.Name {
- if n.Kind != "var" {
- continue
- }
- cVars = append(cVars, n.C)
-
- fmt.Fprintf(fm, "extern char %s[];\n", n.C)
- fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
-
- fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
- fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
- fmt.Fprintf(fc, "\n")
-
- fmt.Fprintf(fgo2, "var %s ", n.Mangle)
- printer.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
- fmt.Fprintf(fgo2, "\n")
- }
- fmt.Fprintf(fc, "\n")
-
- for _, n := range p.Name {
- if n.Const != "" {
- fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
- }
- }
- fmt.Fprintf(fgo2, "\n")
-
- for _, n := range p.Name {
- if n.FuncType != nil {
- p.writeDefsFunc(fc, fgo2, n)
- }
- }
-
- p.writeExports(fgo2, fc, fm)
-
- fgo2.Close()
- fc.Close()
-}
-
-func dynimport(obj string) {
- if f, err := elf.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
- }
- for _, s := range sym {
- targ := s.Name
- if s.Version != "" {
- targ += "@" + s.Version
- }
- fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
- }
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
- }
- for _, l := range lib {
- fmt.Printf("#pragma dynimport _ _ %q\n", l)
- }
- return
- }
-
- if f, err := macho.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
- }
- for _, s := range sym {
- if len(s) > 0 && s[0] == '_' {
- s = s[1:]
- }
- fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
- }
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
- }
- for _, l := range lib {
- fmt.Printf("#pragma dynimport _ _ %q\n", l)
- }
- return
- }
-
- if f, err := pe.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
- }
- for _, s := range sym {
- ss := strings.Split(s, ":")
- fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
- }
- return
- }
-
- fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
-}
-
-// Construct a gcc struct matching the 6c argument frame.
-// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
-// These assumptions are checked by the gccProlog.
-// Also assumes that 6c convention is to word-align the
-// input and output parameters.
-func (p *Package) structType(n *Name) (string, int64) {
- var buf bytes.Buffer
- fmt.Fprint(&buf, "struct {\n")
- off := int64(0)
- for i, t := range n.FuncType.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- fmt.Fprintf(&buf, "\t\t%s p%d;\n", t.C, i)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- if t := n.FuncType.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- qual := ""
- if c := t.C.String(); c[len(c)-1] == '*' {
- qual = "const "
- }
- fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
- off += pad
- }
- if n.AddError {
- fmt.Fprint(&buf, "\t\tvoid *e[2]; /* os.Error */\n")
- off += 2 * p.PtrSize
- }
- if off == 0 {
- fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
- }
- fmt.Fprintf(&buf, "\t}")
- return buf.String(), off
-}
-
-func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
- name := n.Go
- gtype := n.FuncType.Go
- if n.AddError {
- // Add "os.Error" to return type list.
- // Type list is known to be 0 or 1 element - it's a C function.
- err := &ast.Field{Type: ast.NewIdent("os.Error")}
- l := gtype.Results.List
- if len(l) == 0 {
- l = []*ast.Field{err}
- } else {
- l = []*ast.Field{l[0], err}
- }
- t := new(ast.FuncType)
- *t = *gtype
- t.Results = &ast.FieldList{List: l}
- gtype = t
- }
-
- // Go func declaration.
- d := &ast.FuncDecl{
- Name: ast.NewIdent(n.Mangle),
- Type: gtype,
- }
- printer.Fprint(fgo2, fset, d)
- fmt.Fprintf(fgo2, "\n")
-
- if name == "CString" || name == "GoString" || name == "GoStringN" {
- // The builtins are already defined in the C prolog.
- return
- }
-
- var argSize int64
- _, argSize = p.structType(n)
-
- // C wrapper calls into gcc, passing a pointer to the argument frame.
- fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- if argSize == 0 {
- argSize++
- }
- fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
- if n.AddError {
- // gcc leaves errno in first word of interface at end of p.
- // check whether it is zero; if so, turn interface into nil.
- // if not, turn interface into errno.
- // Go init function initializes ·_Cerrno with an os.Errno
- // for us to copy.
- fmt.Fprintln(fc, ` {
- int32 e;
- void **v;
- v = (void**)(&p+1) - 2; /* v = final two void* of p */
- e = *(int32*)v;
- v[0] = (void*)0xdeadbeef;
- v[1] = (void*)0xdeadbeef;
- if(e == 0) {
- /* nil interface */
- v[0] = 0;
- v[1] = 0;
- } else {
- ·_Cerrno(v, e); /* fill in v as os.Error for errno e */
- }
- }`)
- }
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
-}
-
-// writeOutput creates stubs for a specific source file to be compiled by 6g
-// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Package) writeOutput(f *File, srcfile string) {
- base := srcfile
- if strings.HasSuffix(base, ".go") {
- base = base[0 : len(base)-3]
- }
- base = strings.Map(slashToUnderscore, base)
- fgo1 := creat(objDir + base + ".cgo1.go")
- fgcc := creat(objDir + base + ".cgo2.c")
-
- p.GoFiles = append(p.GoFiles, base+".cgo1.go")
- p.GccFiles = append(p.GccFiles, base+".cgo2.c")
-
- // Write Go output: Go input with rewrites of C.xxx to _C_xxx.
- fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
- printer.Fprint(fgo1, fset, f.AST)
-
- // While we process the vars and funcs, also write 6c and gcc output.
- // Gcc output starts with the preamble.
- fmt.Fprintf(fgcc, "%s\n", f.Preamble)
- fmt.Fprintf(fgcc, "%s\n", gccProlog)
-
- for _, n := range f.Name {
- if n.FuncType != nil {
- p.writeOutputFunc(fgcc, n)
- }
- }
-
- fgo1.Close()
- fgcc.Close()
-}
-
-func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
- name := n.Mangle
- if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] {
- // The builtins are already defined in the C prolog, and we don't
- // want to duplicate function definitions we've already done.
- return
- }
- p.Written[name] = true
-
- ctype, _ := p.structType(n)
-
- // Gcc wrapper unpacks the C argument struct
- // and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
- fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
- fmt.Fprintf(fgcc, "{\n")
- if n.AddError {
- fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
- fmt.Fprintf(fgcc, "\terrno = 0;\n")
- }
- // We're trying to write a gcc struct that matches 6c/8c/5c's layout.
- // Use packed attribute to force no padding in this struct in case
- // gcc has different packing requirements. For example,
- // on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
- fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype)
- fmt.Fprintf(fgcc, "\t")
- if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "a->r = ")
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(const %s) ", t.C)
- }
- }
- fmt.Fprintf(fgcc, "%s(", n.C)
- for i := range n.FuncType.Params {
- if i > 0 {
- fmt.Fprintf(fgcc, ", ")
- }
- fmt.Fprintf(fgcc, "a->p%d", i)
- }
- fmt.Fprintf(fgcc, ");\n")
- if n.AddError {
- fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
- }
- fmt.Fprintf(fgcc, "}\n")
- fmt.Fprintf(fgcc, "\n")
-}
-
-// Write out the various stubs we need to support functions exported
-// from Go so that they are callable from C.
-func (p *Package) writeExports(fgo2, fc, fm *os.File) {
- fgcc := creat(objDir + "_cgo_export.c")
- fgcch := creat("_cgo_export.h")
-
- fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
- fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
-
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
- fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
-
- for _, exp := range p.ExpFunc {
- fn := exp.Func
-
- // Construct a gcc struct matching the 6c argument and
- // result frame. The gcc struct will be compiled with
- // __attribute__((packed)) so all padding must be accounted
- // for explicitly.
- ctype := "struct {\n"
- off := int64(0)
- npad := 0
- if fn.Recv != nil {
- t := p.cgoType(fn.Recv.List[0].Type)
- ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
- off += t.Size
- }
- fntype := fn.Type
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
- })
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
- off += t.Size
- })
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if ctype == "struct {\n" {
- ctype += "\t\tchar unused;\n" // avoid empty struct
- }
- ctype += "\t}"
-
- // Get the return type of the wrapper function
- // compiled by gcc.
- gccResult := ""
- if fntype.Results == nil || len(fntype.Results.List) == 0 {
- gccResult = "void"
- } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
- gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
- } else {
- fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
- fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
- })
- fmt.Fprintf(fgcch, "};\n")
- gccResult = "struct " + exp.ExpName + "_return"
- }
-
- // Build the wrapper function compiled by gcc.
- s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
- if fn.Recv != nil {
- s += p.cgoType(fn.Recv.List[0].Type).C.String()
- s += " recv"
- }
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- if i > 0 || fn.Recv != nil {
- s += ", "
- }
- s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
- })
- s += ")"
- fmt.Fprintf(fgcch, "\nextern %s;\n", s)
-
- fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fgcc, "\n%s\n", s)
- fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
- if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
- fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
- }
- if fn.Recv != nil {
- fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
- }
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
- })
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
- if gccResult != "void" {
- if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
- fmt.Fprintf(fgcc, "\treturn a.r0;\n")
- } else {
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
- })
- fmt.Fprintf(fgcc, "\treturn r;\n")
- }
- }
- fmt.Fprintf(fgcc, "}\n")
-
- // Build the wrapper function compiled by 6c/8c
- goname := exp.Func.Name.Name
- if fn.Recv != nil {
- goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
- }
- fmt.Fprintf(fc, "extern void ·%s();\n", goname)
- fmt.Fprintf(fc, "\nvoid\n")
- fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
- fmt.Fprintf(fc, "}\n")
-
- fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
-
- // Calling a function with a receiver from C requires
- // a Go wrapper function.
- if fn.Recv != nil {
- fmt.Fprintf(fgo2, "func %s(recv ", goname)
- printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- fmt.Fprintf(fgo2, ", p%d ", i)
- printer.Fprint(fgo2, fset, atype)
- })
- fmt.Fprintf(fgo2, ")")
- if gccResult != "void" {
- fmt.Fprint(fgo2, " (")
- forFieldList(fntype.Results,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- printer.Fprint(fgo2, fset, atype)
- })
- fmt.Fprint(fgo2, ")")
- }
- fmt.Fprint(fgo2, " {\n")
- fmt.Fprint(fgo2, "\t")
- if gccResult != "void" {
- fmt.Fprint(fgo2, "return ")
- }
- fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
- forFieldList(fntype.Params,
- func(i int, atype ast.Expr) {
- if i > 0 {
- fmt.Fprint(fgo2, ", ")
- }
- fmt.Fprintf(fgo2, "p%d", i)
- })
- fmt.Fprint(fgo2, ")\n")
- fmt.Fprint(fgo2, "}\n")
- }
- }
-}
-
-// Call a function for each entry in an ast.FieldList, passing the
-// index into the list and the type.
-func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
- if fl == nil {
- return
- }
- i := 0
- for _, r := range fl.List {
- if r.Names == nil {
- fn(i, r.Type)
- i++
- } else {
- for _ = range r.Names {
- fn(i, r.Type)
- i++
- }
- }
- }
-}
-
-func c(repr string, args ...interface{}) *TypeRepr {
- return &TypeRepr{repr, args}
-}
-
-// Map predeclared Go types to Type.
-var goTypes = map[string]*Type{
- "int": &Type{Size: 4, Align: 4, C: c("int")},
- "uint": &Type{Size: 4, Align: 4, C: c("uint")},
- "int8": &Type{Size: 1, Align: 1, C: c("schar")},
- "uint8": &Type{Size: 1, Align: 1, C: c("uchar")},
- "int16": &Type{Size: 2, Align: 2, C: c("short")},
- "uint16": &Type{Size: 2, Align: 2, C: c("ushort")},
- "int32": &Type{Size: 4, Align: 4, C: c("int")},
- "uint32": &Type{Size: 4, Align: 4, C: c("uint")},
- "int64": &Type{Size: 8, Align: 8, C: c("int64")},
- "uint64": &Type{Size: 8, Align: 8, C: c("uint64")},
- "float": &Type{Size: 4, Align: 4, C: c("float")},
- "float32": &Type{Size: 4, Align: 4, C: c("float")},
- "float64": &Type{Size: 8, Align: 8, C: c("double")},
- "complex": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex64": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex128": &Type{Size: 16, Align: 16, C: c("__complex double")},
-}
-
-// Map an ast type to a Type.
-func (p *Package) cgoType(e ast.Expr) *Type {
- switch t := e.(type) {
- case *ast.StarExpr:
- x := p.cgoType(t.X)
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
- case *ast.ArrayType:
- if t.Len == nil {
- return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")}
- }
- case *ast.StructType:
- // TODO
- case *ast.FuncType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
- case *ast.InterfaceType:
- return &Type{Size: 3 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
- case *ast.MapType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
- case *ast.ChanType:
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
- case *ast.Ident:
- // Look up the type in the top level declarations.
- // TODO: Handle types defined within a function.
- for _, d := range p.Decl {
- gd, ok := d.(*ast.GenDecl)
- if !ok || gd.Tok != token.TYPE {
- continue
- }
- for _, spec := range gd.Specs {
- ts, ok := spec.(*ast.TypeSpec)
- if !ok {
- continue
- }
- if ts.Name.Name == t.Name {
- return p.cgoType(ts.Type)
- }
- }
- }
- for name, def := range typedef {
- if name == t.Name {
- return p.cgoType(def)
- }
- }
- if t.Name == "uintptr" {
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("uintptr")}
- }
- if t.Name == "string" {
- return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: c("GoString")}
- }
- if r, ok := goTypes[t.Name]; ok {
- if r.Align > p.PtrSize {
- r.Align = p.PtrSize
- }
- return r
- }
- case *ast.SelectorExpr:
- id, ok := t.X.(*ast.Ident)
- if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
- return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
- }
- }
- error(e.Pos(), "unrecognized Go type %T", e)
- return &Type{Size: 4, Align: 4, C: c("int")}
-}
-
-const gccProlog = `
-// Usual nonsense: if x and y are not equal, the type will be invalid
-// (have a negative array count) and an inscrutable error will come
-// out of the compiler and hopefully mention "name".
-#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
-
-// Check at compile time that the sizes we use match our expectations.
-#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
-
-__cgo_size_assert(char, 1)
-__cgo_size_assert(short, 2)
-__cgo_size_assert(int, 4)
-typedef long long __cgo_long_long;
-__cgo_size_assert(__cgo_long_long, 8)
-__cgo_size_assert(float, 4)
-__cgo_size_assert(double, 8)
-
-#include <errno.h>
-#include <string.h>
-`
-
-const builtinProlog = `
-typedef struct { char *p; int n; } _GoString_;
-_GoString_ GoString(char *p);
-_GoString_ GoStringN(char *p, int l);
-char *CString(_GoString_);
-`
-
-const cProlog = `
-#include "runtime.h"
-#include "cgocall.h"
-
-void ·_Cerrno(void*, int32);
-
-void
-·_Cfunc_GoString(int8 *p, String s)
-{
- s = runtime·gostring((byte*)p);
- FLUSH(&s);
-}
-
-void
-·_Cfunc_GoStringN(int8 *p, int32 l, String s)
-{
- s = runtime·gostringn((byte*)p, l);
- FLUSH(&s);
-}
-
-void
-·_Cfunc_CString(String s, int8 *p)
-{
- p = runtime·cmalloc(s.len+1);
- runtime·mcpy((byte*)p, s.str, s.len);
- p[s.len] = 0;
- FLUSH(&p);
-}
-`
-
-const gccExportHeaderProlog = `
-typedef unsigned int uint;
-typedef signed char schar;
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef long long int64;
-typedef unsigned long long uint64;
-typedef __SIZE_TYPE__ uintptr;
-
-typedef struct { char *p; int n; } GoString;
-typedef void *GoMap;
-typedef void *GoChan;
-typedef struct { void *t; void *v; } GoInterface;
-`
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
deleted file mode 100644
index e79b0e1bf..000000000
--- a/src/cmd/cgo/util.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "exec"
- "fmt"
- "go/token"
- "io/ioutil"
- "os"
-)
-
-// run runs the command argv, feeding in stdin on standard input.
-// It returns the output to standard output and standard error.
-// ok indicates whether the command exited successfully.
-func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
- cmd, err := exec.LookPath(argv[0])
- if err != nil {
- fatalf("exec %s: %s", argv[0], err)
- }
- r0, w0, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r1, w1, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r2, w2, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- p, err := os.StartProcess(cmd, argv, &os.ProcAttr{Files: []*os.File{r0, w1, w2}})
- if err != nil {
- fatalf("%s", err)
- }
- defer p.Release()
- r0.Close()
- w1.Close()
- w2.Close()
- c := make(chan bool)
- go func() {
- w0.Write(stdin)
- w0.Close()
- c <- true
- }()
- go func() {
- stdout, _ = ioutil.ReadAll(r1)
- r1.Close()
- c <- true
- }()
- stderr, _ = ioutil.ReadAll(r2)
- r2.Close()
- <-c
- <-c
-
- w, err := p.Wait(0)
- if err != nil {
- fatalf("%s", err)
- }
- ok = w.Exited() && w.ExitStatus() == 0
- return
-}
-
-// Die with an error message.
-func fatalf(msg string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, msg+"\n", args...)
- os.Exit(2)
-}
-
-var nerrors int
-
-func error(pos token.Pos, msg string, args ...interface{}) {
- nerrors++
- if pos.IsValid() {
- fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
- }
- fmt.Fprintf(os.Stderr, msg, args...)
- fmt.Fprintf(os.Stderr, "\n")
-}
-
-// isName returns true if s is a valid C identifier
-func isName(s string) bool {
- for i, v := range s {
- if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
- return false
- }
- if i == 0 && '0' <= v && v <= '9' {
- return false
- }
- }
- return s != ""
-}
-
-func creat(name string) *os.File {
- f, err := os.Create(name)
- if err != nil {
- fatalf("%s", err)
- }
- return f
-}
-
-func slashToUnderscore(c int) int {
- if c == '/' || c == '\\' || c == ':' {
- c = '_'
- }
- return c
-}