mirror of
https://github.com/golang/go
synced 2024-11-21 19:14:44 -07:00
cgo: support pkg-config for flags and libs
Fixes issue #1853. R=golang-dev, mattn.jp, adg CC=golang-dev https://golang.org/cl/4550084
This commit is contained in:
parent
12376c93ef
commit
bddb75127f
@ -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),
|
||||
|
@ -100,27 +100,76 @@ NextLine:
|
||||
fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
|
||||
}
|
||||
|
||||
if k != "CFLAGS" && k != "LDFLAGS" {
|
||||
fatalf("%s: unsupported #cgo option %s", srcfile, k)
|
||||
args, err := splitQuoted(fields[1])
|
||||
if err != nil {
|
||||
fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
|
||||
}
|
||||
|
||||
v := strings.TrimSpace(fields[1])
|
||||
args, err := splitQuoted(v)
|
||||
if err != nil {
|
||||
fatalf("%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...)
|
||||
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 || !safeName(name) || 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 +231,20 @@ func splitQuoted(s string) (r []string, err os.Error) {
|
||||
return args, err
|
||||
}
|
||||
|
||||
var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_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.
|
||||
|
Loading…
Reference in New Issue
Block a user