diff options
Diffstat (limited to 'src/cmd/cgo/gcc.go')
-rw-r--r-- | src/cmd/cgo/gcc.go | 122 |
1 files changed, 98 insertions, 24 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index ae5ca2c7d..10411e94f 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -100,27 +100,81 @@ NextLine: fatalf("%s: bad #cgo option: %s", srcfile, fields[0]) } - if k != "CFLAGS" && k != "LDFLAGS" { - fatalf("%s: unsupported #cgo option %s", srcfile, k) - } - - v := strings.TrimSpace(fields[1]) - args, err := splitQuoted(v) + args, err := splitQuoted(fields[1]) if err != nil { - fatalf("%s: bad #cgo option %s: %s", srcfile, k, err.String()) + fatalf("%s: bad #cgo option %s: %s", srcfile, k, err) } - if oldv, ok := p.CgoFlags[k]; ok { - p.CgoFlags[k] = oldv + " " + v - } else { - p.CgoFlags[k] = v + for _, arg := range args { + if !safeName(arg) { + fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg) + } } - if k == "CFLAGS" { - p.GccOptions = append(p.GccOptions, args...) + + switch k { + + case "CFLAGS", "LDFLAGS": + p.addToFlag(k, args) + + case "pkg-config": + cflags, ldflags, err := pkgConfig(args) + if err != nil { + fatalf("%s: bad #cgo option %s: %s", srcfile, k, err) + } + p.addToFlag("CFLAGS", cflags) + p.addToFlag("LDFLAGS", ldflags) + + default: + fatalf("%s: unsupported #cgo option %s", srcfile, k) + } } f.Preamble = strings.Join(linesOut, "\n") } +// addToFlag appends args to flag. All flags are later written out onto the +// _cgo_flags file for the build system to use. +func (p *Package) addToFlag(flag string, args []string) { + if oldv, ok := p.CgoFlags[flag]; ok { + p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ") + } else { + p.CgoFlags[flag] = strings.Join(args, " ") + } + if flag == "CFLAGS" { + // We'll also need these when preprocessing for dwarf information. + p.GccOptions = append(p.GccOptions, args...) + } +} + +// pkgConfig runs pkg-config and extracts --libs and --cflags information +// for packages. +func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) { + for _, name := range packages { + if len(name) == 0 || name[0] == '-' { + return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name)) + } + } + + args := append([]string{"pkg-config", "--cflags"}, packages...) + stdout, stderr, ok := run(nil, args) + if !ok { + os.Stderr.Write(stderr) + return nil, nil, os.NewError("pkg-config failed") + } + cflags, err = splitQuoted(string(stdout)) + if err != nil { + return + } + + args = append([]string{"pkg-config", "--libs"}, packages...) + stdout, stderr, ok = run(nil, args) + if !ok { + os.Stderr.Write(stderr) + return nil, nil, os.NewError("pkg-config failed") + } + ldflags, err = splitQuoted(string(stdout)) + return +} + // 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. @@ -182,6 +236,20 @@ func splitQuoted(s string) (r []string, err os.Error) { return args, err } +var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz") + +func safeName(s string) bool { + if s == "" { + return false + } + for i := 0; i < len(s); i++ { + if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { + return false + } + } + return true +} + // 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. @@ -592,11 +660,14 @@ func (p *Package) gccName() (ret string) { } // gccMachine returns the gcc -m flag to use, either "-m32" or "-m64". -func (p *Package) gccMachine() string { - if p.PtrSize == 8 { - return "-m64" +func (p *Package) gccMachine() []string { + switch runtime.GOARCH { + case "amd64": + return []string{"-m64"} + case "386": + return []string{"-m32"} } - return "-m32" + return nil } const gccTmp = "_obj/_cgo_.o" @@ -604,9 +675,8 @@ const gccTmp = "_obj/_cgo_.o" // gccCmd returns the gcc command line to use for compiling // the input. func (p *Package) gccCmd() []string { - return []string{ + c := []string{ p.gccName(), - p.gccMachine(), "-Wall", // many warnings "-Werror", // warnings are errors "-o" + gccTmp, // write object to tmp @@ -614,15 +684,18 @@ func (p *Package) gccCmd() []string { "-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise "-c", // do not link "-xc", // input language is C - "-", // read input from standard input } + c = append(c, p.GccOptions...) + c = append(c, p.gccMachine()...) + c = append(c, "-") //read input from standard input + return c } // gccDebug runs gcc -gdwarf-2 over the C program stdin and // returns the corresponding DWARF data and any messages // printed to standard error. func (p *Package) gccDebug(stdin []byte) *dwarf.Data { - runGcc(stdin, append(p.gccCmd(), p.GccOptions...)) + runGcc(stdin, p.gccCmd()) // Try to parse f as ELF and Mach-O and hope one works. var f interface { @@ -649,8 +722,9 @@ func (p *Package) gccDebug(stdin []byte) *dwarf.Data { // #defines that gcc encountered while processing the input // and its included files. func (p *Package) gccDefines(stdin []byte) string { - base := []string{p.gccName(), p.gccMachine(), "-E", "-dM", "-xc", "-"} - stdout, _ := runGcc(stdin, append(base, p.GccOptions...)) + base := []string{p.gccName(), "-E", "-dM", "-xc"} + base = append(base, p.gccMachine()...) + stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) return stdout } @@ -659,7 +733,7 @@ func (p *Package) gccDefines(stdin []byte) string { // gcc to fail. func (p *Package) gccErrors(stdin []byte) string { // TODO(rsc): require failure - args := append(p.gccCmd(), p.GccOptions...) + args := p.gccCmd() if *debugGcc { fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) os.Stderr.Write(stdin) |