finally got windows working -- fixed issues with library path by grabbing include dir which seems more reliable. adds an extra sed to fix generated .c file to do stupid windows __declspec(dllexport).. argh.

This commit is contained in:
Randall C. O'Reilly 2021-08-29 22:32:08 -07:00
parent c428d23650
commit d0c78b69e9
7 changed files with 86 additions and 35 deletions

View File

@ -33,6 +33,18 @@ To [install python modules](https://packaging.python.org/tutorials/packaging-pro
python3 -m pip install --upgrade setuptools wheel
```
### Windows
As of version 0.4.0, windows is now better supported, and is passing tests (on at least one developers machine). You may still need to set some environment variables depending on your python installation, but a vanilla standard install is working.
Install Python from the main Python distribution: https://www.python.org/downloads/windows/ -- *do not under any circumstances install from the Microsoft Store app!* while that is very convenient, it creates symbolic links to access the python executables, which is incompatible with go exec.Command to run it, despite too many hours of trying to get around that.
The standard python install does not create a `python3.exe` which gopy looks for -- follow instructions here:
https://stackoverflow.com/questions/39910730/python3-is-not-recognized-as-an-internal-or-external-command-operable-program/41492852
(just make a copy of python.exe to python3.exe in the relevant installed location).
If you get a bunch of errors during linking in the build process, set `LIBDIR` or `GOPY_LIBDIR` to path to python libraries, and `LIBRARY` or `GOPY_PYLIB` to name of python library (e.g., python39 for 3.9).
## Community
The `go-python` community can be reached out at [go-python@googlegroups.com](mailto:go-python@googlegroups.com) or via the web forum: [go-python group](https://groups.google.com/forum/#!forum/go-python).

View File

@ -33,6 +33,9 @@ const (
ModePkg = "pkg"
)
// set this to true if OS is windows
var WindowsOS = false
// for all preambles: 1 = name of package (outname), 2 = cmdstr
// 3 = libcfg, 4 = GoHandle, 5 = CGoHandle, 6 = all imports, 7 = mainstr, 8 = exe pre C, 9 = exe pre go
@ -332,7 +335,8 @@ def Init():
`
// 3 = gencmd, 4 = vm, 5 = libext 6 = extraGccArgs
// 3 = gencmd, 4 = vm, 5 = libext 6 = extraGccArgs, 7 = CFLAGS, 8 = LDLFAGS,
// 9 = windows special declspec hack
MakefileTemplate = `# Makefile for python interface for package %[1]s.
# File is generated by gopy. Do not edit.
# %[2]s
@ -366,6 +370,7 @@ build:
$(PYTHON) build.py
# build the _%[1]s$(LIBEXT) library that contains the cgo and CPython wrappers
# generated %[1]s.py python wrapper imports this c-code package
%[9]s
$(GCC) %[1]s.c %[6]s %[1]s_go$(LIBEXT) -o _%[1]s$(LIBEXT) $(CFLAGS) $(LDFLAGS) -fPIC --shared -w
`
@ -695,7 +700,12 @@ func (g *pyGen) genMakefile() {
if g.mode == ModeExe {
g.makefile.Printf(MakefileExeTemplate, g.cfg.Name, g.cfg.Cmd, gencmd, g.cfg.VM, g.libext, pycfg.CFlags, pycfg.LdFlags)
} else {
g.makefile.Printf(MakefileTemplate, g.cfg.Name, g.cfg.Cmd, gencmd, g.cfg.VM, g.libext, g.extraGccArgs, pycfg.CFlags, pycfg.LdFlags)
winhack := ""
if WindowsOS {
winhack = fmt.Sprintf(`# windows-only sed hack here to fix pybindgen declaration of PyInit
sed -i "s/ PyInit_/ __declspec(dllexport) PyInit_/g" %s.c`, g.cfg.Name)
}
g.makefile.Printf(MakefileTemplate, g.cfg.Name, g.cfg.Cmd, gencmd, g.cfg.VM, g.libext, g.extraGccArgs, pycfg.CFlags, pycfg.LdFlags, winhack)
}
}

View File

@ -110,6 +110,7 @@ version=sys.version_info.major
if "GOPY_INCLUDE" in os.environ and "GOPY_LIBDIR" in os.environ and "GOPY_PYLIB" in os.environ:
print(json.dumps({
"version": version,
"minor": sys.version_info.minor,
"incdir": os.environ["GOPY_INCLUDE"],
"libdir": os.environ["GOPY_LIBDIR"],
"libpy": os.environ["GOPY_PYLIB"],
@ -121,6 +122,7 @@ if "GOPY_INCLUDE" in os.environ and "GOPY_LIBDIR" in os.environ and "GOPY_PYLIB"
else:
print(json.dumps({
"version": sys.version_info.major,
"minor": sys.version_info.minor,
"incdir": ds.get_python_inc(),
"libdir": ds.get_config_var("LIBDIR"),
"libpy": ds.get_config_var("LIBRARY"),
@ -149,6 +151,7 @@ else:
var raw struct {
Version int `json:"version"`
Minor int `json:"minor"`
IncDir string `json:"incdir"`
LibDir string `json:"libdir"`
LibPy string `json:"libpy"`
@ -164,6 +167,20 @@ else:
raw.IncDir = filepath.ToSlash(raw.IncDir)
raw.LibDir = filepath.ToSlash(raw.LibDir)
// on windows these can be empty -- use include dir which is usu good
if raw.LibDir == "" && raw.IncDir != "" {
raw.LibDir = raw.IncDir
if strings.HasSuffix(raw.LibDir, "include") {
raw.LibDir = raw.LibDir[:len(raw.LibDir)-len("include")] + "libs"
}
fmt.Printf("no LibDir -- copy from IncDir: %s\n", raw.LibDir)
}
if raw.LibPy == "" {
raw.LibPy = fmt.Sprintf("python%d%d", raw.Version, raw.Minor)
fmt.Printf("no LibPy -- set to: %s\n", raw.LibPy)
}
if strings.HasSuffix(raw.LibPy, ".a") {
raw.LibPy = raw.LibPy[:len(raw.LibPy)-len(".a")]
}

View File

@ -197,6 +197,16 @@ func runBuild(mode bind.BuildMode, cfg *BuildCfg) error {
return err
}
if bind.WindowsOS {
fmt.Printf("Doing windows sed hack to fix declspec for PyInit\n")
cmd = exec.Command("sed", "-i", "s/ PyInit_/ __declspec(dllexport) PyInit_/g", cfg.Name+".c")
cmdout, err = cmd.CombinedOutput()
if err != nil {
fmt.Printf("cmd had error: %v output:\no%v\n", err, string(cmdout))
return err
}
}
cflags := strings.Fields(strings.TrimSpace(pycfg.CFlags))
cflags = append(cflags, "-fPIC", "-Ofast")
if include, exists := os.LookupEnv("GOPY_INCLUDE"); exists {

View File

@ -937,7 +937,7 @@ func writeGoMod(t *testing.T, pkgDir, tstDir string) {
module dummy
require github.com/go-python/gopy v0.0.0
replace github.com/go-python/gopy => "%s"
replace github.com/go-python/gopy => %s
`
contents := fmt.Sprintf(template, pkgDir)
if err := ioutil.WriteFile(filepath.Join(tstDir, "go.mod"), []byte(contents), 0666); err != nil {

View File

@ -2,11 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build windows
// +build windows
package main
import "github.com/go-python/gopy/bind"
const (
libExt = ".dll"
libExt = ".pyd"
extraGccArgs = ""
)
func init() {
bind.WindowsOS = true
}

View File

@ -1,7 +1,7 @@
// 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.
//go:build windows
// +build windows
package main
@ -10,30 +10,22 @@ import (
"log"
"os"
"os/exec"
"path"
"strings"
)
func init() {
testEnvironment = os.Environ()
var (
py2 = "python2"
py3 = "python3"
pypy2 = "pypy"
pypy3 = "pypy3"
// py2 = "python2"
py3 = "python3"
// pypy2 = "pypy"
// pypy3 = "pypy3"
)
if os.Getenv("GOPY_APPVEYOR_CI") == "1" {
log.Printf("Running in appveyor CI")
var (
cpy2dir = os.Getenv("CPYTHON2DIR")
cpy3dir = os.Getenv("CPYTHON3DIR")
pypy2dir = os.Getenv("PYPY2DIR")
pypy3dir = os.Getenv("PYPY3DIR")
)
py2 = path.Join(cpy2dir, "python")
py3 = path.Join(cpy3dir, "python")
pypy2 = path.Join(pypy2dir, "pypy")
pypy3 = path.Join(pypy3dir, "pypy")
if os.Getenv("GOPY_TRAVIS_CI") == "1" {
log.Printf("Running in travis CI")
}
var (
@ -46,23 +38,26 @@ func init() {
module string
mandatory bool
}{
// {"py2", py2, "", true},
{"py2-cffi", py2, "cffi", true},
// {"py3", py3, "", true},
{"py3-cffi", py3, "cffi", true},
{"pypy2-cffi", pypy2, "cffi", false},
{"pypy3-cffi", pypy3, "cffi", false},
{"py3", py3, "", true},
// {"py2", py2, "", true},
} {
args := []string{"-c", ""}
if be.module != "" {
args[1] = "import " + be.module
}
log.Printf("checking testbackend: %q...", be.name)
cmd := exec.Command(be.vm, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
py, err := exec.LookPath(be.vm)
if err != nil {
log.Printf("gopy: could not locate 'python' executable (err: %v)", err)
} else {
log.Printf("python executable found at: %s\n", py)
cmd := exec.Command(py, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
}
if err != nil {
log.Printf("disabling testbackend: %q, error: '%s'", be.name, err.Error())
testBackends[be.name] = ""
@ -79,8 +74,8 @@ func init() {
if len(disabled) > 0 {
log.Printf("The following test backends are not available: %s",
strings.Join(disabled, ", "))
if os.Getenv("GOPY_APPVEYOR_CI") == "1" && missing > 0 {
log.Fatalf("Not all backends available in appveyor CI")
if os.Getenv("GOPY_TRAVIS_CI") == "1" && missing > 0 {
log.Fatalf("Not all backends available in travis CI")
}
}
}