diff --git a/bind/bind.go b/bind/bind.go index 2fab6a1..b00fe66 100644 --- a/bind/bind.go +++ b/bind/bind.go @@ -54,12 +54,13 @@ func GenCPython(w io.Writer, fset *token.FileSet, pkg *Package, lang int) error } // GenGo generates a cgo package from a Go package -func GenGo(w io.Writer, fset *token.FileSet, pkg *Package) error { +func GenGo(w io.Writer, fset *token.FileSet, pkg *Package, lang int) error { buf := new(bytes.Buffer) gen := &goGen{ printer: &printer{buf: buf, indentEach: []byte("\t")}, fset: fset, pkg: pkg, + lang: lang, } err := gen.gen() if err != nil { diff --git a/bind/gengo.go b/bind/gengo.go index a9a8ca1..f6deb32 100644 --- a/bind/gengo.go +++ b/bind/gengo.go @@ -7,7 +7,6 @@ package bind import ( "fmt" "go/token" - "path/filepath" "strings" "golang.org/x/tools/go/types" @@ -20,7 +19,7 @@ const ( // File is generated by gopy gen. Do not edit. package main -//#cgo pkg-config: python2 --cflags --libs +//#cgo pkg-config: %[3]s --cflags --libs //#include //#include //#include @@ -134,6 +133,7 @@ type goGen struct { fset *token.FileSet pkg *Package + lang int // python's version API (2 or 3) err ErrorList } @@ -952,7 +952,12 @@ func (g *goGen) genPreamble() { pkgimport = fmt.Sprintf("_ %q", g.pkg.pkg.Path()) } - g.Printf(goPreamble, n, pkgimport, filepath.Base(n)) + pkgcfg, err := getPkgConfig(g.lang) + if err != nil { + panic(err) + } + + g.Printf(goPreamble, n, pkgimport, pkgcfg) } func (g *goGen) tupleString(tuple []*Var) string { diff --git a/bind/utils.go b/bind/utils.go index c8cdf66..d9690e2 100644 --- a/bind/utils.go +++ b/bind/utils.go @@ -5,7 +5,13 @@ package bind import ( + "bufio" + "bytes" "fmt" + "io" + "os/exec" + "regexp" + "sort" "golang.org/x/tools/go/types" ) @@ -79,3 +85,67 @@ func isConstructor(sig *types.Signature) bool { //TODO(sbinet) return false } + +// getPkgConfig returns the name of the pkg-config python's pc file +func getPkgConfig(vers int) (string, error) { + bin, err := exec.LookPath("pkg-config") + if err != nil { + return "", fmt.Errorf( + "gopy: could not locate 'pkg-config' executable (err: %v)", + err, + ) + } + + out, err := exec.Command(bin, "--list-all").Output() + if err != nil { + return "", fmt.Errorf( + "gopy: error retrieving the list of packages known to pkg-config (err: %v)", + err, + ) + } + + pkgs := []string{} + re := regexp.MustCompile(fmt.Sprintf(`^python(\s|-|\.|)%d.*?`, vers)) + s := bufio.NewScanner(bytes.NewReader(out)) + for s.Scan() { + err = s.Err() + if err != nil { + if err == io.EOF { + err = nil + } + break + } + + line := s.Bytes() + if !bytes.HasPrefix(line, []byte("python")) { + continue + } + + if !re.Match(line) { + continue + } + + pkg := bytes.Split(line, []byte(" ")) + pkgs = append(pkgs, string(pkg[0])) + } + + if err != nil { + return "", fmt.Errorf( + "gopy: error scanning pkg-config output (err: %v)", + err, + ) + } + + if len(pkgs) <= 0 { + return "", fmt.Errorf( + "gopy: could not find pkg-config file (no python.pc installed?)", + ) + } + + sort.Strings(pkgs) + + // FIXME(sbinet): make sure we take the latest version? + pkgcfg := pkgs[0] + + return pkgcfg, nil +} diff --git a/gen.go b/gen.go index 9bfba33..8450688 100644 --- a/gen.go +++ b/gen.go @@ -40,6 +40,18 @@ func genPkg(odir string, p *bind.Package, lang string) error { // no-op } + pyvers := 2 + switch lang { + case "python2", "py2": + pyvers = 2 + case "python3", "py3": + pyvers = 3 + } + + if err != nil { + return err + } + switch lang { case "python2", "py2": o, err = os.Create(filepath.Join(odir, p.Name()+".c")) @@ -62,7 +74,7 @@ func genPkg(odir string, p *bind.Package, lang string) error { } defer o.Close() - err = bind.GenGo(o, fset, p) + err = bind.GenGo(o, fset, p, pyvers) if err != nil { return err }