Commit b2aab72d authored by Matthew Dempsky's avatar Matthew Dempsky Committed by Ian Lance Taylor

cmd/cgo: remove obsolete -cdefs flag

Now that there's no 6c compiler anymore, there's no need for cgo to
generate C headers that are compatible with it.

Fixes #9528

Change-Id: I43f53869719eb9a6065f1b39f66f060e604cbee0
Reviewed-on: https://go-review.googlesource.com/2482Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent f7e43f14
// Copyright 2013 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 "runtime.h"
#include "cdefstest.h"
struct CdefsTest test;
struct PackedTest packed;
// Copyright 2013 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.
//
// +build ignore
package cgotest
/*
// This file tests a bug found in the cgo -cdefs tool that incorrectly
// translated Go pointer arrays generated by the cgo godefs tool back into C
// pointer arrays.
//
// The comments below show how the type is translated from gcc-style C into Go
// and back into C for both the buggy version and the correct version
struct cdefsTest {
// This was already being handled correctly
// Correct: -> Array [20]int8 -> int8 array[20]
char array1[20];
// Buggy: -> Array [20][20]int8 -> [20]int8 array[20]
// Correct: -> Array [20][20]int8 -> int8 array[20][20]
char array2[20][20];
// Buggy: -> Array [20]*int8 -> *int8 array[20]
// Correct: -> Array [20]*int8 -> int8 *array[20]
char *array3[20];
// Buggy: -> Array [20][20]*int8 -> [20]*int8 array[20]
// Correct: -> Array [20]**int8 -> int8 *array[20][20]
char *array4[20][20];
// Buggy: -> Array [20][20]**int8 -> [20]**int8 array[20]
// Correct: -> Array [20][20]**int8 -> int8 **array[20][20]
char **array5[20][20];
};
// Test that packed structures can be translated to C correctly too.
// See issue 8477.
struct packedTest {
char first;
int second;
long long third;
} __attribute__((packed));
// Test that conflicting type definitions don't cause problems with cgo.
// See issue 8477.
typedef struct timespec {
double bogus;
} pid_t;
*/
import "C"
type CdefsTest C.struct_cdefsTest
//type PackedTest C.struct_packedTest
// Copyright 2013 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 "runtime.h"
#include "cdefstest.h"
void runtime·printf(int8*, ...);
// From cdefstest.go.
typedef struct CdefsOrig CdefsOrig;
struct CdefsOrig {
int8 array1[20];
int8 array2[20][20];
int8 *array3[20];
int8 *array4[20][20];
int8 **array5[20][20];
};
// Packed structs are no longer supported for -cdefs.
/*
typedef struct PackedOrig PackedOrig;
#pragma pack on
struct PackedOrig {
int8 first;
int32 second;
int64 third;
};
#pragma pack off
*/
void
main·test(int32 ret)
{
CdefsOrig o;
CdefsTest t;
// PackedOrig po;
// PackedTest pt;
ret = 0;
if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
ret = 1;
}
if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
ret = 1;
}
if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
ret = 1;
}
if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
ret = 1;
}
if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
ret = 1;
}
/*
if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
ret = 1;
}
if(sizeof(pt.second) != sizeof(po.second) || offsetof(PackedTest, second) != offsetof(PackedOrig, second)) {
runtime·printf("second: size, offset = %d, %d, want %d, %d\n", sizeof(pt.second), offsetof(PackedTest, second), sizeof(po.second), offsetof(PackedOrig, second));
ret = 1;
}
if(sizeof(pt.third) != sizeof(po.third) || offsetof(PackedTest, third) != offsetof(PackedOrig, third)) {
runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
ret = 1;
}
*/
FLUSH(&ret); // flush return value
}
// Copyright 2013 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 "os"
func test() int32 // in main.c
func main() {
os.Exit(int(test()))
}
# Copyright 2013 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.
# Just add issue file prefixes to this list if more issues come up
FILE_PREFIXES="cdefstest"
for FP in $FILE_PREFIXES
do
go tool cgo -cdefs ${FP}.go > ${FP}.h
done
go build . && ./testcdefs
EXIT=$?
rm -rf _obj testcdefs *.h
exit $EXIT
...@@ -237,10 +237,6 @@ The following options are available when running cgo directly: ...@@ -237,10 +237,6 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the names with real values. Used to generate files in the
syscall package when bootstrapping a new target. syscall package when bootstrapping a new target.
-cdefs
Like -godefs, but write file in C syntax.
Used to generate files in the runtime package when
bootstrapping a new target.
-objdir directory -objdir directory
Put all generated files in directory. Put all generated files in directory.
-gccgo -gccgo
......
...@@ -582,7 +582,7 @@ func (p *Package) mangleName(n *Name) { ...@@ -582,7 +582,7 @@ func (p *Package) mangleName(n *Name) {
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the // 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 // Go equivalents, now that we have figured out the meaning of all
// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names // the xxx. In *godefs mode, rewriteRef replaces the names
// with full definitions instead of mangled names. // with full definitions instead of mangled names.
func (p *Package) rewriteRef(f *File) { func (p *Package) rewriteRef(f *File) {
// Keep a list of all the functions, to remove the ones // Keep a list of all the functions, to remove the ones
...@@ -688,7 +688,7 @@ func (p *Package) rewriteRef(f *File) { ...@@ -688,7 +688,7 @@ func (p *Package) rewriteRef(f *File) {
error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
} }
} }
if *godefs || *cdefs { if *godefs {
// Substitute definition for mangled type name. // Substitute definition for mangled type name.
if id, ok := expr.(*ast.Ident); ok { if id, ok := expr.(*ast.Ident); ok {
if t := typedef[id.Name]; t != nil { if t := typedef[id.Name]; t != nil {
...@@ -992,8 +992,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) { ...@@ -992,8 +992,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.goVoid = c.Ident("_Ctype_void") c.goVoid = c.Ident("_Ctype_void")
// Normally cgo translates void* to unsafe.Pointer, // Normally cgo translates void* to unsafe.Pointer,
// but for historical reasons -cdefs and -godefs use *byte instead. // but for historical reasons -godefs uses *byte instead.
if *cdefs || *godefs { if *godefs {
c.goVoidPtr = &ast.StarExpr{X: c.byte} c.goVoidPtr = &ast.StarExpr{X: c.byte}
} else { } else {
c.goVoidPtr = c.Ident("unsafe.Pointer") c.goVoidPtr = c.Ident("unsafe.Pointer")
...@@ -1334,8 +1334,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { ...@@ -1334,8 +1334,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", // 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 // use that as the Go form for this typedef too, so that the typedef will be interchangeable
// with the base type. // with the base type.
// In -godefs and -cdefs mode, do this for all typedefs. // In -godefs mode, do this for all typedefs.
if isStructUnionClass(sub.Go) || *godefs || *cdefs { if isStructUnionClass(sub.Go) || *godefs {
t.Go = sub.Go t.Go = sub.Go
if isStructUnionClass(sub.Go) { if isStructUnionClass(sub.Go) {
...@@ -1397,7 +1397,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { ...@@ -1397,7 +1397,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
name := c.Ident("_Ctype_" + s) name := c.Ident("_Ctype_" + s)
tt := *t tt := *t
typedef[name.Name] = &tt typedef[name.Name] = &tt
if !*godefs && !*cdefs { if !*godefs {
t.Go = name t.Go = name
} }
} }
...@@ -1573,7 +1573,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct ...@@ -1573,7 +1573,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
used[f.Name] = true used[f.Name] = true
} }
if !*godefs && !*cdefs { if !*godefs {
for cid, goid := range ident { for cid, goid := range ident {
if token.Lookup(goid).IsKeyword() { if token.Lookup(goid).IsKeyword() {
// Avoid keyword // Avoid keyword
...@@ -1600,12 +1600,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct ...@@ -1600,12 +1600,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
name := f.Name name := f.Name
ft := f.Type ft := f.Type
// In godefs or cdefs mode, if this field is a C11 // In godefs mode, if this field is a C11
// anonymous union then treat the first field in the // anonymous union then treat the first field in the
// union as the field in the struct. This handles // union as the field in the struct. This handles
// cases like the glibc <sys/resource.h> file; see // cases like the glibc <sys/resource.h> file; see
// issue 6677. // issue 6677.
if *godefs || *cdefs { if *godefs {
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] { if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
name = st.Field[0].Name name = st.Field[0].Name
ident[name] = name ident[name] = name
...@@ -1635,14 +1635,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct ...@@ -1635,14 +1635,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
talign = size talign = size
} }
if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs { if talign > 0 && f.ByteOffset%talign != 0 {
// Drop misaligned fields, the same way we drop integer bit fields. // Drop misaligned fields, the same way we drop integer bit fields.
// The goal is to make available what can be made available. // The goal is to make available what can be made available.
// Otherwise one bad and unneeded field in an otherwise okay struct // Otherwise one bad and unneeded field in an otherwise okay struct
// makes the whole program not compile. Much of the time these // makes the whole program not compile. Much of the time these
// structs are in system headers that cannot be corrected. // structs are in system headers that cannot be corrected.
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
// fields should still work.
continue continue
} }
n := len(fld) n := len(fld)
...@@ -1672,7 +1670,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct ...@@ -1672,7 +1670,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
buf.WriteString("}") buf.WriteString("}")
csyntax = buf.String() csyntax = buf.String()
if *godefs || *cdefs { if *godefs {
godefsFields(fld) godefsFields(fld)
} }
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
...@@ -1707,9 +1705,7 @@ func godefsFields(fld []*ast.Field) { ...@@ -1707,9 +1705,7 @@ func godefsFields(fld []*ast.Field) {
n.Name = "Pad_cgo_" + strconv.Itoa(npad) n.Name = "Pad_cgo_" + strconv.Itoa(npad)
npad++ npad++
} }
if !*cdefs { n.Name = upper(n.Name)
n.Name = upper(n.Name)
}
} }
} }
} }
...@@ -1721,9 +1717,6 @@ func godefsFields(fld []*ast.Field) { ...@@ -1721,9 +1717,6 @@ func godefsFields(fld []*ast.Field) {
// package syscall's data structures, we drop a common prefix // package syscall's data structures, we drop a common prefix
// (so sec, usec, which will get turned into Sec, Usec for exporting). // (so sec, usec, which will get turned into Sec, Usec for exporting).
func fieldPrefix(fld []*ast.Field) string { func fieldPrefix(fld []*ast.Field) string {
if *cdefs {
return ""
}
prefix := "" prefix := ""
for _, f := range fld { for _, f := range fld {
for _, n := range f.Names { for _, n := range f.Names {
......
...@@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string { ...@@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string {
return buf.String() return buf.String()
} }
// cdefs returns the output for -cdefs mode.
// The easiest way to do this is to translate the godefs Go to C.
func (p *Package) cdefs(f *File, srcfile string) string {
godefsOutput := p.godefs(f, srcfile)
lines := strings.Split(godefsOutput, "\n")
lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
for i, line := range lines {
lines[i] = strings.TrimSpace(line)
}
var out bytes.Buffer
printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
didTypedef := false
for i := 0; i < len(lines); i++ {
line := lines[i]
// Delete
// package x
if strings.HasPrefix(line, "package ") {
continue
}
// Convert
// const (
// A = 1
// B = 2
// )
//
// to
//
// enum {
// A = 1,
// B = 2,
// };
if line == "const (" {
printf("enum {\n")
for i++; i < len(lines) && lines[i] != ")"; i++ {
line = lines[i]
if line != "" {
printf("\t%s,", line)
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// const A = 1
// to
// enum { A = 1 };
if strings.HasPrefix(line, "const ") {
printf("enum { %s };\n", line[len("const "):])
continue
}
// On first type definition, typedef all the structs
// in case there are dependencies between them.
if !didTypedef && strings.HasPrefix(line, "type ") {
didTypedef = true
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
printf("typedef struct %s %s;\n", s, s)
}
}
printf("\n")
printf("#pragma pack on\n")
printf("\n")
}
// Convert
// type T struct {
// X int64
// Y *int32
// Z [4]byte
// }
//
// to
//
// struct T {
// int64 X;
// int32 *Y;
// byte Z[4];
// }
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
if len(lines) > i+1 && lines[i+1] == "}" {
// do not output empty struct
i++
continue
}
s := line[len("type ") : len(line)-len(" struct {")]
printf("struct %s {\n", s)
for i++; i < len(lines) && lines[i] != "}"; i++ {
line := lines[i]
if line != "" {
f := strings.Fields(line)
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
nerrors++
continue
}
printf("\t%s;", cdecl(f[0], f[1]))
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// type T int
// to
// typedef int T;
if strings.HasPrefix(line, "type ") {
f := strings.Fields(line[len("type "):])
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
nerrors++
continue
}
printf("typedef\t%s;\n", cdecl(f[0], f[1]))
continue
}
printf("%s\n", line)
}
if didTypedef {
printf("\n")
printf("#pragma pack off\n")
}
return out.String()
}
// cdecl returns the C declaration for the given Go name and type.
// It only handles the specific cases necessary for converting godefs output.
func cdecl(name, typ string) string {
// X *[0]byte -> X *void
if strings.HasPrefix(typ, "*[0]") {
typ = "*void"
}
// X [4]byte -> X[4] byte
for strings.HasPrefix(typ, "[") {
i := strings.Index(typ, "]") + 1
name = name + typ[:i]
typ = typ[i:]
}
// X *byte -> *X byte
for strings.HasPrefix(typ, "*") {
name = "*" + name
typ = typ[1:]
}
// X T -> T X
// Handle the special case: 'unsafe.Pointer' is 'void *'
if typ == "unsafe.Pointer" {
typ = "void"
name = "*" + name
}
return typ + "\t" + name
}
var gofmtBuf bytes.Buffer var gofmtBuf bytes.Buffer
// gofmt returns the gofmt-formatted string for an AST node. // gofmt returns the gofmt-formatted string for an AST node.
......
...@@ -155,10 +155,9 @@ var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimpor ...@@ -155,10 +155,9 @@ var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimpor
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode") var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
// These flags are for bootstrapping a new Go implementation, // These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and // to generate Go types that match the data layout and
// constant values used in the host's C libraries and system calls. // constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output") var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
var objDir = flag.String("objdir", "", "object directory") var objDir = flag.String("objdir", "", "object directory")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
...@@ -185,12 +184,7 @@ func main() { ...@@ -185,12 +184,7 @@ func main() {
return return
} }
if *godefs && *cdefs { if *godefs {
fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
os.Exit(2)
}
if *godefs || *cdefs {
// Generating definitions pulled from header files, // Generating definitions pulled from header files,
// to be checked into Go repositories. // to be checked into Go repositories.
// Line numbers are just noise. // Line numbers are just noise.
...@@ -282,14 +276,12 @@ func main() { ...@@ -282,14 +276,12 @@ func main() {
p.Record(f) p.Record(f)
if *godefs { if *godefs {
os.Stdout.WriteString(p.godefs(f, input)) os.Stdout.WriteString(p.godefs(f, input))
} else if *cdefs {
os.Stdout.WriteString(p.cdefs(f, input))
} else { } else {
p.writeOutput(f, input) p.writeOutput(f, input)
} }
} }
if !*godefs && !*cdefs { if !*godefs {
p.writeDefs() p.writeDefs()
} }
if nerrors > 0 { if nerrors > 0 {
......
...@@ -181,17 +181,6 @@ linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) ...@@ -181,17 +181,6 @@ linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
fi fi
esac esac
# This tests cgo -cdefs. That mode is not supported,
# so it's okay if it doesn't work on some systems.
# In particular, it works badly with clang on OS X.
# It doesn't work at all now that we disallow C code
# outside runtime. Once runtime has no C code it won't
# even be necessary.
# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
# (xcd ../misc/cgo/testcdefs
# ./test.bash || exit 1
# ) || exit $?
[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
(xcd ../misc/cgo/testgodefs (xcd ../misc/cgo/testgodefs
./test.bash || exit 1 ./test.bash || exit 1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment