diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
commit | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch) | |
tree | 4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/cmd/cgo | |
parent | c8bf49ef8a92e2337b69c14b9b88396efe498600 (diff) | |
download | golang-upstream/1.3.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r-- | src/cmd/cgo/doc.go | 28 | ||||
-rw-r--r-- | src/cmd/cgo/gcc.go | 84 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 47 |
3 files changed, 137 insertions, 22 deletions
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 605bab6d2..69c7ce893 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -52,6 +52,14 @@ these directives. Package-specific flags should be set using the directives, not the environment variables, so that builds work in unmodified environments. +All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and +used to compile C files in that package. All the CPPFLAGS and CXXFLAGS +directives in a package are concatenated and used to compile C++ files in that +package. All the LDFLAGS directives in any package in the program are +concatenated and used at link time. All the pkg-config directives are +concatenated and sent to pkg-config simultaneously to add to each appropriate +set of command-line flags. + When the Go tool sees that one or more Go files use the special import "C", it will look for other non-Go files in the directory and compile them as part of the Go package. Any .c, .s, or .S files will be @@ -63,11 +71,26 @@ compilers may be changed by the CC and CXX environment variables, respectively; those environment variables may include command line options. +To enable cgo during cross compiling builds, set the CGO_ENABLED +environment variable to 1 when building the Go tools with make.bash. +Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will +be used for compiling for the host. + +After the Go tools are built, when running the go command, CC_FOR_TARGET is +ignored. The value of CC_FOR_TARGET when running make.bash is the default +compiler. However, you can set the environment variable CC, not CC_FOR_TARGET, +to control the compiler when running the go tool. + +CXX_FOR_TARGET works in a similar way for C++ code. + Go references to C Within the Go file, C's struct 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. +C struct fields that cannot be expressed in Go, such as bit fields +or misaligned data, are omitted in the Go struct, replaced by +appropriate padding to reach the next field or the end of the struct. The standard C numeric types are available under the names C.char, C.schar (signed char), C.uchar (unsigned char), @@ -84,6 +107,11 @@ C's union types are represented as a Go byte array with the same length. Go structs cannot embed fields with C types. +Cgo translates C types into equivalent unexported Go types. +Because the translations are unexported, a Go package should not +expose C types in its exported API: a C type used in one Go package +is different from the same C type used in another. + Any C function (even void functions) may be called in a multiple assignment context to retrieve both the return value (if any) and the C errno variable as an error (use _ to skip the result value if the diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 3e1837ebf..7a802102d 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1197,12 +1197,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t case *dwarf.StructType: - if dt.ByteSize < 0 { // opaque struct - break - } // Convert to Go struct, being careful about alignment. // Have to give it a name to simulate C "struct foo" references. tag := dt.StructName + if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible + break + } if tag == "" { tag = "__" + strconv.Itoa(tagGen) tagGen++ @@ -1212,6 +1212,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) t.Go = name // publish before recursive calls goIdent[name.Name] = name + if dt.ByteSize < 0 { + // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown), + // so execute the basic things that the struct case would do + // other than try to determine a Go representation. + tt := *t + tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} + tt.Go = c.Ident("struct{}") + typedef[name.Name] = &tt + break + } switch dt.Kind { case "class", "union": t.Go = c.Opaque(t.Size) @@ -1259,13 +1269,33 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { sub := c.Type(dt.Type, pos) t.Size = sub.Size t.Align = sub.Align - if _, ok := typedef[name.Name]; !ok { + oldType := typedef[name.Name] + if oldType == nil { tt := *t tt.Go = sub.Go typedef[name.Name] = &tt } - if *godefs || *cdefs { + + // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", + // use that as the Go form for this typedef too, so that the typedef will be interchangeable + // with the base type. + // In -godefs and -cdefs mode, do this for all typedefs. + if isStructUnionClass(sub.Go) || *godefs || *cdefs { t.Go = sub.Go + + if isStructUnionClass(sub.Go) { + // Use the typedef name for C code. + typedef[sub.Go.(*ast.Ident).Name].C = t.C + } + + // If we've seen this typedef before, and it + // was an anonymous struct/union/class before + // too, use the old definition. + // TODO: it would be safer to only do this if + // we verify that the types are the same. + if oldType != nil && isStructUnionClass(oldType.Go) { + t.Go = oldType.Go + } } case *dwarf.UcharType: @@ -1327,9 +1357,21 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { // be correct, so calling dtype.Size again will produce the correct value. t.Size = dtype.Size() if t.Size < 0 { - // Unsized types are [0]byte + // Unsized types are [0]byte, unless they're typedefs of other types + // or structs with tags. + // if so, use the name we've already defined. t.Size = 0 - t.Go = c.Opaque(0) + switch dt := dtype.(type) { + case *dwarf.TypedefType: + // ok + case *dwarf.StructType: + if dt.StructName != "" { + break + } + t.Go = c.Opaque(0) + default: + t.Go = c.Opaque(0) + } if t.C.Empty() { t.C.Set("void") } @@ -1344,6 +1386,19 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t } +// isStructUnionClass reports whether the type described by the Go syntax x +// is a struct, union, or class with a tag. +func isStructUnionClass(x ast.Expr) bool { + id, ok := x.(*ast.Ident) + if !ok { + return false + } + name := id.Name + return strings.HasPrefix(name, "_Ctype_struct_") || + strings.HasPrefix(name, "_Ctype_union_") || + strings.HasPrefix(name, "_Ctype_class_") +} + // 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, pos token.Pos) *Type { @@ -1496,7 +1551,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct t := c.Type(f.Type, pos) tgo := t.Go size := t.Size - + talign := t.Align if f.BitSize > 0 { if f.BitSize%8 != 0 { continue @@ -1509,8 +1564,17 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct name = "uint" } tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize)) + talign = size } + if talign > 0 && f.ByteOffset%talign != 0 { + // Drop misaligned fields, the same way we drop integer bit fields. + // The goal is to make available what can be made available. + // Otherwise one bad and unneeded field in an otherwise okay struct + // makes the whole program not compile. Much of the time these + // structs are in system headers that cannot be corrected. + continue + } n := len(fld) fld = fld[0 : n+1] name := f.Name @@ -1525,8 +1589,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct buf.WriteString(" ") buf.WriteString(name) buf.WriteString("; ") - if t.Align > align { - align = t.Align + if talign > align { + align = talign } } if off < dt.ByteSize { diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 83ab95251..76c7247af 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -485,7 +485,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { fgcc.Close() } -// fixGo convers the internal Name.Go field into the name we should show +// fixGo converts the internal Name.Go field into the name we should show // to users in error messages. There's only one for now: on input we rewrite // C.malloc into C._CMalloc, so change it back here. func fixGo(name string) string { @@ -529,15 +529,8 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { } // 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. - // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, - // and http://golang.org/issue/5603. - extraAttr := "" - if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { - extraAttr = ", __gcc_struct__" - } - fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__%v)) *a = v;\n", ctype, extraAttr) + // gcc has different packing requirements. + fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { fmt.Fprintf(fgcc, "a->r = ") @@ -618,6 +611,19 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "\n") } +// packedAttribute returns host compiler struct attribute that will be +// used to match 6c/8c/5c's struct layout. For example, on 386 Windows, +// gcc wants to 8-align int64s, but 8c does not. +// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, +// and http://golang.org/issue/5603. +func (p *Package) packedAttribute() string { + s := "__attribute__((__packed__" + if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { + s += ", __gcc_struct__" + } + return s + "))" +} + // 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) { @@ -727,7 +733,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { fmt.Fprintf(fgcc, "extern void _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) + fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute()) if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) } @@ -874,10 +880,24 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprintf(cdeclBuf, ")") cParams := cdeclBuf.String() + // We need to use a name that will be exported by the + // Go code; otherwise gccgo will make it static and we + // will not be able to link against it from the C + // code. goName := "Cgoexp_" + exp.ExpName fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) fmt.Fprint(fgcch, "\n") + // Use a #define so that the C code that includes + // cgo_export.h will be able to refer to the Go + // function using the expected name. + fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName) + + // Use a #undef in _cgo_export.c so that we ignore the + // #define from cgo_export.h, since here we are + // defining the real function. + fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName) + fmt.Fprint(fgcc, "\n") fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) fmt.Fprint(fgcc, "\t") @@ -1219,7 +1239,10 @@ struct __go_string __go_byte_array_to_string(const void* p, intgo len); struct __go_open_array __go_string_to_byte_array (struct __go_string str); const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) { - return strndup((const char*)s.__data, s.__length); + char *p = malloc(s.__length+1); + memmove(p, s.__data, s.__length); + p[s.__length] = 0; + return p; } struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) { |