summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/doc.go14
-rw-r--r--src/cmd/cgo/gcc.go94
-rw-r--r--src/cmd/cgo/out.go2
3 files changed, 93 insertions, 17 deletions
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index b3aa9aded..064725c1d 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -35,9 +35,17 @@ systems. For example:
// #include <png.h>
import "C"
-C identifiers or 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.
+Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
+tool using a '#cgo pkg-config:' directive followed by the package names.
+For example:
+
+ // #cgo pkg-config: png cairo
+ // #include <png.h>
+ import "C"
+
+Within the Go file, C identifiers or 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.
The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index ac6561345..fa7602cf2 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.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 2ce4e9752..dbc7bcf69 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -142,7 +142,7 @@ func dynimport(obj string) {
if f, err := pe.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
- fatalf("cannot load imported symbols from PE file %s: v", obj, err)
+ fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
}
for _, s := range sym {
ss := strings.Split(s, ":", -1)