diff options
Diffstat (limited to 'src/cmd/cgo/gcc.go')
-rw-r--r-- | src/cmd/cgo/gcc.go | 144 |
1 files changed, 130 insertions, 14 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index be3b8fe64..cadc6fae9 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -21,19 +21,22 @@ import ( "os" "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", + "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. @@ -57,6 +60,107 @@ func cname(s string) string { 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", -1) + linesOut := make([]string, 0, len(linesIn)) + 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.Split(l, ":", 2) + if len(fields) != 2 { + fatal("%s: bad #cgo line: %s", srcfile, line) + } + + k := fields[0] + v := strings.TrimSpace(fields[1]) + if k != "CFLAGS" && k != "LDFLAGS" { + fatal("%s: unsupported #cgo option %s", srcfile, k) + } + args, err := splitQuoted(v) + if err != nil { + fatal("%s: bad #cgo option %s: %s", srcfile, k, err.String()) + } + if oldv, ok := p.CgoFlags[k]; ok { + p.CgoFlags[k] = oldv + " " + v + } else { + p.CgoFlags[k] = v + } + if k == "CFLAGS" { + p.GccOptions = append(p.GccOptions, args...) + } + } + f.Preamble = strings.Join(linesOut, "\n") +} + +// 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.ErrorString("unclosed quote") + } else if escaped { + err = os.ErrorString("unfinished escaping") + } + return args, err +} + // 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. @@ -205,9 +309,7 @@ func (p *Package) guessKinds(f *File) []*Name { for _, line := range strings.Split(stderr, "\n", -1) { if len(line) < 9 || line[0:9] != "cgo-test:" { - if len(line) > 8 && line[0:8] == "<stdin>:" { - fatal("gcc produced unexpected output:\n%s\non input:\n%s", line, b.Bytes()) - } + // the user will see any compiler errors when the code is compiled later. continue } line = line[9:] @@ -568,10 +670,6 @@ func runGcc(stdin []byte, args []string) (string, string) { os.Stderr.Write(stderr) } if !ok { - fmt.Fprint(os.Stderr, "Error running gcc:\n") - fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) - os.Stderr.Write(stdin) - fmt.Fprint(os.Stderr, "EOF\n") os.Stderr.Write(stderr) os.Exit(2) } @@ -591,6 +689,7 @@ type typeConv struct { 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 @@ -617,6 +716,8 @@ func (c *typeConv) Init(ptrSize int64) { 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") @@ -648,6 +749,8 @@ var dwarfToName = map[string]string{ "long long int": "longlong", "long long unsigned int": "ulonglong", "signed char": "schar", + "float complex": "complexfloat", + "double complex": "complexdouble", } // Type returns a *Type with the same memory layout as @@ -749,6 +852,19 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { t.Align = c.ptrSize } + case *dwarf.ComplexType: + switch t.Size { + default: + fatal("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. |