Skip to content

Commit

Permalink
Add support for cgo pkg-config
Browse files Browse the repository at this point in the history
Signed-off-by: Odin Ugedal <odin@ugedal.com>
  • Loading branch information
odinuge committed Jun 21, 2019
1 parent 221457a commit c118745
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .travis.yml
Expand Up @@ -11,6 +11,8 @@ addons:
packages:
- wget
- pkg-config
- libjpeg-dev
- libpng-dev

before_install:
- |
Expand Down
31 changes: 30 additions & 1 deletion language/go/fileinfo.go
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/bazelbuild/bazel-gazelle/config"
"github.com/bazelbuild/bazel-gazelle/language/proto"
"github.com/bazelbuild/bazel-gazelle/rule"
"os/exec"
)

// fileInfo holds information used to decide how to build a file. This
Expand Down Expand Up @@ -333,6 +334,29 @@ func goFileInfo(path, rel string) fileInfo {
return info
}

func resolvePkgConfig(pkgs []string) (clinkopts, copts string, err error) {
clinkopts, err = resolvePkgConfigForMode("--libs", pkgs)
if err != nil {
return
}
copts, err = resolvePkgConfigForMode("--cflags", pkgs)
return
}

// resolvePkgConfigForMode runs pkg-config for with the given mode for the given set of packages
func resolvePkgConfigForMode(mode string, pkgs []string) (string, error) {
cmd := exec.Command("pkg-config", append([]string{mode}, pkgs...)...)
out, err := cmd.CombinedOutput()
if err != nil {
s := fmt.Sprintf("%s failed: %v", strings.Join(cmd.Args, " "), err)
if len(out) > 0 {
s = fmt.Sprintf("%s: %s", s, out)
}
return "", errors.New(s)
}
return strings.TrimSpace(string(out)), nil
}

// saveCgo extracts CFLAGS, CPPFLAGS, CXXFLAGS, and LDFLAGS directives
// from a comment above a "C" import. This is intended to match logic in
// go/build.Context.saveCgo.
Expand Down Expand Up @@ -386,7 +410,12 @@ func saveCgo(info *fileInfo, rel string, cg *ast.CommentGroup) error {
case "LDFLAGS":
info.clinkopts = append(info.clinkopts, taggedOpts{tags, joinedStr})
case "pkg-config":
return fmt.Errorf("%s: pkg-config not supported: %s", info.path, orig)
clinkopts, copts, err := resolvePkgConfig(opts)
if err != nil {
return fmt.Errorf("%s: error when resolving pkg-config: %s", info.path, orig)
}
info.clinkopts = append(info.clinkopts, taggedOpts{tags, clinkopts})
info.copts = append(info.copts, taggedOpts{tags, copts})
default:
return fmt.Errorf("%s: invalid #cgo verb: %s", info.path, orig)
}
Expand Down
54 changes: 54 additions & 0 deletions language/go/fileinfo_go_test.go
Expand Up @@ -18,6 +18,7 @@ package golang
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"reflect"
"strings"
Expand Down Expand Up @@ -191,6 +192,12 @@ func TestGoFileInfoFailure(t *testing.T) {
}

func TestCgo(t *testing.T) {

pkgOutput, err := exec.Command("pkg-config", "--cflags", "libpng").Output()
if err != nil {
t.Fatal("Unable to find libpng.")
}
libpngCopts := strings.TrimSpace(string(pkgOutput))
for _, tc := range []struct {
desc, source string
want fileInfo
Expand Down Expand Up @@ -283,6 +290,53 @@ import ("C")
},
},
},
{
"pkg-config works",
`package foo
/*
#cgo pkg-config: libpng
#cgo pkg-config: libpng libjpeg
*/
import ("C")
`,
fileInfo{
isCgo: true,
copts: []taggedOpts{
{opts: libpngCopts},
{opts: libpngCopts},
},
clinkopts: []taggedOpts{
{opts: "-lpng16 -lz"},
{opts: "-lpng16 -lz -ljpeg"},
},
},
},
{
"pkg-config with conditions",
`package foo
/*
#cgo foo bar,!baz pkg-config: libpng
*/
import "C"
`,
fileInfo{
isCgo: true,
copts: []taggedOpts{
{
tags: tagLine{{"foo"}, {"bar", "!baz"}},
opts: libpngCopts,
},
},
clinkopts: []taggedOpts{
{
tags: tagLine{{"foo"}, {"bar", "!baz"}},
opts: "-lpng16 -lz",
},
},
},
},
} {
t.Run(tc.desc, func(t *testing.T) {
dir, err := ioutil.TempDir(os.Getenv("TEST_TEMPDIR"), "TestCgo")
Expand Down

0 comments on commit c118745

Please sign in to comment.