1
0
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:
Quentin Smith 2016-11-03 18:45:01 -04:00
parent 47d1c42aff
commit c2917af628
3 changed files with 98 additions and 1 deletions

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -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)