summaryrefslogtreecommitdiff
path: root/src/cmd/cgo/gcc.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo/gcc.go')
-rw-r--r--src/cmd/cgo/gcc.go144
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.