mirror of
https://github.com/golang/go
synced 2024-11-22 01:34:41 -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>
|
// #include <png.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
C identifiers or field names that are keywords in Go can be
|
Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
|
||||||
accessed by prefixing them with an underscore: if x points at
|
tool using a '#cgo pkg-config:' directive followed by the package names.
|
||||||
a C struct with a field named "type", x._type accesses the field.
|
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
|
The standard C numeric types are available under the names
|
||||||
C.char, C.schar (signed char), C.uchar (unsigned char),
|
C.char, C.schar (signed char), C.uchar (unsigned char),
|
||||||
|
@ -100,27 +100,76 @@ NextLine:
|
|||||||
fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
|
fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if k != "CFLAGS" && k != "LDFLAGS" {
|
args, err := splitQuoted(fields[1])
|
||||||
fatalf("%s: unsupported #cgo option %s", srcfile, k)
|
if err != nil {
|
||||||
|
fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := strings.TrimSpace(fields[1])
|
switch k {
|
||||||
args, err := splitQuoted(v)
|
|
||||||
if err != nil {
|
case "CFLAGS", "LDFLAGS":
|
||||||
fatalf("%s: bad #cgo option %s: %s", srcfile, k, err.String())
|
p.addToFlag(k, args)
|
||||||
}
|
|
||||||
if oldv, ok := p.CgoFlags[k]; ok {
|
case "pkg-config":
|
||||||
p.CgoFlags[k] = oldv + " " + v
|
cflags, ldflags, err := pkgConfig(args)
|
||||||
} else {
|
if err != nil {
|
||||||
p.CgoFlags[k] = v
|
fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
|
||||||
}
|
}
|
||||||
if k == "CFLAGS" {
|
p.addToFlag("CFLAGS", cflags)
|
||||||
p.GccOptions = append(p.GccOptions, args...)
|
p.addToFlag("LDFLAGS", ldflags)
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatalf("%s: unsupported #cgo option %s", srcfile, k)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Preamble = strings.Join(linesOut, "\n")
|
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
|
// splitQuoted splits the string s around each instance of one or more consecutive
|
||||||
// white space characters while taking into account quotes and escaping, and
|
// 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.
|
// 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
|
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
|
// Translate rewrites f.AST, the original Go input, to remove
|
||||||
// references to the imported package C, replacing them with
|
// references to the imported package C, replacing them with
|
||||||
// references to the equivalent Go types, functions, and variables.
|
// references to the equivalent Go types, functions, and variables.
|
||||||
|
Loading…
Reference in New Issue
Block a user