summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/doc.go28
-rw-r--r--src/cmd/cgo/gcc.go84
-rw-r--r--src/cmd/cgo/out.go47
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) {