mirror of
https://github.com/golang/go
synced 2024-11-23 22:00:11 -07:00
cmd/go: handle escapes in pkg-config output
This commit also adds a test for pkg-config usage in cgo. Fixes #16455. Change-Id: I95fb6a288a4d19093c4613c93878017d95cbe4a2 Reviewed-on: https://go-review.googlesource.com/32735 Run-TryBot: Quentin Smith <quentin@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
47d1c42aff
commit
c2917af628
@ -1635,6 +1635,39 @@ func (b *builder) pkgconfigCmd() string {
|
||||
return envList("PKG_CONFIG", defaultPkgConfig)[0]
|
||||
}
|
||||
|
||||
// splitPkgConfigOutput parses the pkg-config output into a slice of
|
||||
// flags. pkg-config always uses \ to escape special characters.
|
||||
func splitPkgConfigOutput(out []byte) []string {
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
var flags []string
|
||||
flag := make([]byte, len(out))
|
||||
r, w := 0, 0
|
||||
for r < len(out) {
|
||||
switch out[r] {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
if w > 0 {
|
||||
flags = append(flags, string(flag[:w]))
|
||||
}
|
||||
w = 0
|
||||
case '\\':
|
||||
r++
|
||||
fallthrough
|
||||
default:
|
||||
if r < len(out) {
|
||||
flag[w] = out[r]
|
||||
w++
|
||||
}
|
||||
}
|
||||
r++
|
||||
}
|
||||
if w > 0 {
|
||||
flags = append(flags, string(flag[:w]))
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
|
||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||
@ -1647,7 +1680,7 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e
|
||||
return
|
||||
}
|
||||
if len(out) > 0 {
|
||||
cflags = strings.Fields(string(out))
|
||||
cflags = splitPkgConfigOutput(out)
|
||||
}
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
|
||||
if err != nil {
|
||||
|
@ -6,6 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -23,3 +24,21 @@ func TestRemoveDevNull(t *testing.T) {
|
||||
t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitPkgConfigOutput(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in []byte
|
||||
want []string
|
||||
}{
|
||||
{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
|
||||
{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
|
||||
{[]byte(`broken flag\`), []string{"broken", "flag"}},
|
||||
{[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
|
||||
{[]byte(" \r\n "), nil},
|
||||
} {
|
||||
got := splitPkgConfigOutput(test.in)
|
||||
if !reflect.DeepEqual(got, test.want) {
|
||||
t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2201,6 +2201,51 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
tg.run("build", "origin")
|
||||
}
|
||||
|
||||
func TestCgoPkgConfig(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
|
||||
tg.run("env", "PKG_CONFIG")
|
||||
if _, err := exec.LookPath(strings.TrimSpace(tg.getStdout())); err != nil {
|
||||
t.Skip("skipping because pkg-config could not be found")
|
||||
}
|
||||
|
||||
// OpenBSD's pkg-config is strict about whitespace and only
|
||||
// supports backslash-escaped whitespace. It does not support
|
||||
// quotes, which the normal freedesktop.org pkg-config does
|
||||
// support. See http://man.openbsd.org/pkg-config.1
|
||||
tg.tempFile("foo.pc", `
|
||||
Name: foo
|
||||
Description: The foo library
|
||||
Version: 1.0.0
|
||||
Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
|
||||
`)
|
||||
tg.tempFile("foo.go", `package main
|
||||
|
||||
/*
|
||||
#cgo pkg-config: foo
|
||||
int value() {
|
||||
return DEFINED_FROM_PKG_CONFIG;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
if C.value() != 42 {
|
||||
println("value() =", C.value(), "wanted 42")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
`)
|
||||
tg.setenv("PKG_CONFIG_PATH", tg.path("."))
|
||||
tg.run("run", tg.path("foo.go"))
|
||||
}
|
||||
|
||||
// "go test -c -test.bench=XXX errors" should not hang
|
||||
func TestIssue6480(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
|
Loading…
Reference in New Issue
Block a user