diff --git a/bind/gengo.go b/bind/gengo.go index 0d9486f..58fc740 100644 --- a/bind/gengo.go +++ b/bind/gengo.go @@ -8,10 +8,40 @@ import ( "fmt" "go/token" "go/types" + "runtime" "strings" ) const ( + checkGoVersionImport = `"strconv" + "strings" + "os" +` + checkGoVersion= "_cgopy_CheckGoVersion()" + checkGoVersionDef = ` +func _cgopy_CheckGoVersion() { + godebug := os.Getenv("GODEBUG") + cgocheck := -1 + var err error + if godebug != "" { + const prefix = "cgocheck=" + for _, option := range strings.Split(godebug, ",") { + if !strings.HasPrefix(option, prefix) { + continue + } + cgocheck, err = strconv.Atoi(option[len(prefix):]) + if err != nil { + cgocheck = -1 + fmt.Fprintf(os.Stderr, "gopy: invalid cgocheck value %q (expected an integer)\n", option) + } + } + } + + if cgocheck != 0 { + fmt.Fprintf(os.Stderr, "gopy: GODEBUG=cgocheck=0 should be set for Go>=1.6\n") + } +} +` goPreamble = `// Package main is an autogenerated binder stub for package %[1]s. // gopy gen -lang=go %[1]s // @@ -30,6 +60,8 @@ import ( "unsafe" %[3]s + + %[4]s ) var _ = unsafe.Pointer(nil) @@ -111,7 +143,10 @@ func cgopy_decref(ptr unsafe.Pointer) { refs.Unlock() } +%[5]s + func init() { + %[6]s refs.Lock() refs.next = -24 // Go objects get negative reference numbers. Arbitrary starting point. refs.refs = make(map[unsafe.Pointer]int32) @@ -969,7 +1004,13 @@ func (g *goGen) genPreamble() { panic(err) } - g.Printf(goPreamble, n, pkgcfg, pkgimport) + version := runtime.Version() + major, minor, _ := getGoVersion(version) + if major >= 1 && minor >= 6 { + g.Printf(goPreamble, n, pkgcfg, pkgimport, checkGoVersionImport, checkGoVersionDef, checkGoVersion) + } else { + g.Printf(goPreamble, n, pkgcfg, pkgimport, "", "", "") + } } func (g *goGen) tupleString(tuple []*Var) string { diff --git a/bind/utils.go b/bind/utils.go index be95231..de82064 100644 --- a/bind/utils.go +++ b/bind/utils.go @@ -13,6 +13,8 @@ import ( "os/exec" "regexp" "sort" + "strconv" + "strings" ) func isErrorType(typ types.Type) bool { @@ -148,3 +150,15 @@ func getPkgConfig(vers int) (string, error) { return pkgcfg, nil } + +func getGoVersion(version string) (int64, int64, error) { + version_regex := regexp.MustCompile(`^go((\d+)(\.(\d+))*)`) + match := version_regex.FindStringSubmatch(version) + if match == nil { + return -1, -1, fmt.Errorf("gopy: invalid Go version information: %q", version) + } + version_info := strings.Split(match[1], ".") + major, _ := strconv.ParseInt(version_info[0], 10, 0) + minor, _ := strconv.ParseInt(version_info[1], 10, 0) + return major, minor, nil + } diff --git a/bind/utils_test.go b/bind/utils_test.go new file mode 100644 index 0000000..151b474 --- /dev/null +++ b/bind/utils_test.go @@ -0,0 +1,40 @@ +// Copyright 2017 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 bind + +import ( + "errors" + "testing" +) + +func TestGetGoVersion(t *testing.T) { + for _, tt := range []struct { + info string + major int64 + minor int64 + err error + }{ + {"go1.5", 1, 5, nil}, + {"go1.6", 1, 6, nil}, + {"go1.7", 1, 7, nil}, + {"go1.8", 1, 8, nil}, + {"gcc4", -1, -1, errors.New("gopy: invalid Go version information: \"gcc4\"")}, + {"1.8go", -1, -1, errors.New("gopy: invalid Go version information: \"1.8go\"")}, + {"llvm", -1, -1, errors.New("gopy: invalid Go version information: \"llvm\"")}, + } { + major, minor, err := getGoVersion(tt.info) + if major != tt.major { + t.Errorf("getGoVersion(%s): expected major %d, actual %d", tt.info, tt.major, major) + } + + if minor != tt.minor { + t.Errorf("getGoVersion(%s): expected major %d, actual %d", tt.info, tt.minor, minor) + } + + if err != nil && err.Error() != tt.err.Error() { + t.Errorf("getGoVersion(%s): expected err %s, actual %s", tt.info, tt.err, err) + } + } +}