mirror of https://github.com/go-python/gopy.git
gopy: load from export data, not source
This CL, inspired from https://golang.org/cl/16911, drops the use of `x/tools/go/loader` (importing from sources) and replaces it with the stdlib `go/importer`, working off the (binary) exported data under $GOPATH/pkg/pkgname.a. This allows us: - to rely completely on the stdlib-1.5, - to support cgo-based packages (which are not supported by `x/tools/go/loader`) Fixes #28 Fixes #36 Fixes #68 Fixes #70 Change-Id: I0321645dfeec8738687a675a7e80283053c89123
This commit is contained in:
parent
6403bdc659
commit
90f5fcd36e
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2015 The go-python Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cgo tests bindings of CGo-based packages.
|
||||
package cgo
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <string.h>
|
||||
//#include <stdlib.h>
|
||||
//const char* cpkg_sprintf(const char *str) {
|
||||
// char *o = (char*)malloc(strlen(str));
|
||||
// sprintf(o, "%s", str);
|
||||
// return o;
|
||||
//}
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Hi returns a string from Go (via C's stdio)
|
||||
func Hi() string {
|
||||
cstr := C.CString("hi from go\n")
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
cout := C.cpkg_sprintf(cstr)
|
||||
defer C.free(unsafe.Pointer(cout))
|
||||
return C.GoString(cout)
|
||||
}
|
||||
|
||||
// Hello returns a string via C's stdio
|
||||
func Hello(s string) string {
|
||||
if s == "" {
|
||||
s = "you"
|
||||
}
|
||||
cstr := C.CString(fmt.Sprintf("hello %s from go\n", s))
|
||||
defer C.free(unsafe.Pointer(cstr))
|
||||
cout := C.cpkg_sprintf(cstr)
|
||||
defer C.free(unsafe.Pointer(cout))
|
||||
return C.GoString(cout)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2015 The go-python Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
## py2/py3 compat
|
||||
from __future__ import print_function
|
||||
|
||||
import cgo
|
||||
|
||||
print("cgo.doc: %r" % (cgo.__doc__,))
|
||||
print("cgo.Hi()= %r" % (cgo.Hi(),))
|
||||
print("cgo.Hello(you)= %r" % (cgo.Hello("you"),))
|
55
gen.go
55
gen.go
|
@ -9,6 +9,7 @@ import (
|
|||
"go/ast"
|
||||
"go/build"
|
||||
"go/doc"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
|
@ -20,7 +21,6 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/go-python/gopy/bind"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -160,24 +160,40 @@ func newPackage(path string) (*bind.Package, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pkg, err := build.Import(path, cwd, 0)
|
||||
pkgfiles := make([]string, 0, len(pkg.GoFiles)+len(pkg.CgoFiles))
|
||||
pkgfiles = append(pkgfiles, pkg.GoFiles...)
|
||||
pkgfiles = append(pkgfiles, pkg.CgoFiles...)
|
||||
files, err := parseFiles(pkg.Dir, pkgfiles)
|
||||
cmd := exec.Command("go", "install", path)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = cwd
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("error installing [%s]: %v\n",
|
||||
path,
|
||||
err,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf := loader.Config{
|
||||
Fset: fset,
|
||||
}
|
||||
conf.TypeChecker.Error = func(e error) {
|
||||
log.Printf("%v\n", e)
|
||||
err = e
|
||||
bpkg, err := build.Import(path, cwd, 0)
|
||||
if err != nil {
|
||||
log.Printf("error resolving import path [%s]: %v\n",
|
||||
path,
|
||||
err,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, err := newPackageFrom(files, &conf, pkg)
|
||||
pkg, err := importer.Default().Import(bpkg.ImportPath)
|
||||
if err != nil {
|
||||
log.Printf("error importing package [%v]: %v\n",
|
||||
bpkg.ImportPath,
|
||||
err,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, err := newPackageFrom(bpkg, pkg)
|
||||
if err != nil {
|
||||
log.Printf("%v\n", err)
|
||||
return nil, err
|
||||
|
@ -186,17 +202,10 @@ func newPackage(path string) (*bind.Package, error) {
|
|||
return p, err
|
||||
}
|
||||
|
||||
func newPackageFrom(files []*ast.File, conf *loader.Config, pkg *build.Package) (*bind.Package, error) {
|
||||
|
||||
conf.CreateFromFiles(pkg.ImportPath, files...)
|
||||
program, err := conf.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := program.Created[0].Pkg
|
||||
func newPackageFrom(bpkg *build.Package, p *types.Package) (*bind.Package, error) {
|
||||
|
||||
var pkgast *ast.Package
|
||||
pkgs, err := parser.ParseDir(fset, pkg.Dir, nil, parser.ParseComments)
|
||||
pkgs, err := parser.ParseDir(fset, bpkg.Dir, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -205,7 +214,7 @@ func newPackageFrom(files []*ast.File, conf *loader.Config, pkg *build.Package)
|
|||
return nil, fmt.Errorf("gopy: could not find AST for package %q", p.Name())
|
||||
}
|
||||
|
||||
pkgdoc := doc.New(pkgast, pkg.ImportPath, 0)
|
||||
pkgdoc := doc.New(pkgast, bpkg.ImportPath, 0)
|
||||
|
||||
return bind.NewPackage(p, pkgdoc)
|
||||
}
|
||||
|
|
11
main_test.go
11
main_test.go
|
@ -453,3 +453,14 @@ func TestBindInterfaces(t *testing.T) {
|
|||
`),
|
||||
})
|
||||
}
|
||||
|
||||
func TestBindCgoPackage(t *testing.T) {
|
||||
t.Parallel()
|
||||
testPkg(t, pkg{
|
||||
path: "_examples/cgo",
|
||||
want: []byte(`cgo.doc: 'Package cgo tests bindings of CGo-based packages.\n'
|
||||
cgo.Hi()= 'hi from go\n'
|
||||
cgo.Hello(you)= 'hello you from go\n'
|
||||
`),
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue