Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building on Windows #119

Closed
l1n3n01z opened this issue Nov 3, 2013 · 58 comments
Closed

Building on Windows #119

l1n3n01z opened this issue Nov 3, 2013 · 58 comments

Comments

@l1n3n01z
Copy link

l1n3n01z commented Nov 3, 2013

I am trying to build on Windows 64 and seem to be way out of my depth.

I have followed the build guide in the readme and I'm stuck on building gopy.

I have setup Mingw-w64, which seemed to be the most sensible way to get off the ground.
I have compiled libffi using it.
I have changed cgo.go to the following:

package py

// #cgo CFLAGS: -I C:\Python33\include
// #cgo LDFLAGS: -L C:\Python33\libs -ldl -lpython3.3
// #cgo pkg-config: libffi
import "C"

When running
[..]\libs\gopy> go test

I get the following output:

warning: building out-of-date packages:
        lime/3rdparty/libs/gopy/lib
installing these packages with 'go test -i' will speed future tests.

# lime/3rdparty/libs/gopy/lib
In file included from abstract.go:7:0:
utils.h:9:20: fatal error: Python.h: No such file or directory
 #include <Python.h>
                    ^
compilation terminated.
FAIL    lime/3rdparty/libs/gopy [build failed]

Which seems to suggest the I am doing something wrong in cgo.go.
Has anyone been able to build on Windows yet? Any pointers?

@adzenith
Copy link
Contributor

adzenith commented Nov 4, 2013

Can you compile other things using Python.h? Did you try taking out the spaces after -L and -I?

@jackielii
Copy link

Hi,

I've been trying this for a few days. here is how far I've got:
Install lime on windows 7 64bit

  • install mingw32/msys mingw32(because qt5 for mingw only has 32bit): http://sourceforge.net/projects/mingw/files/latest/download
  • install Qt for mingw32 here: http://download.qt-project.org/official_releases/qt/5.1/5.1.1/
  • uninstall Go amd64 and install Go386: https://code.google.com/p/go/downloads/detail?name=go1.2rc2.windows-386.msi
  • set GOARCH=386
  • set CPATH=C:\MinGW\include;C:\Qt\Qt5.1.1\5.1.1\mingw48_32\include;C:\Qt\Qt5.1.1\5.1.1\mingw48_32\include\QtCore\5.1.1\QtCore
  • set LIBRARY_PATH=C:\MinGW\lib;C:\Qt\Qt5.1.1\5.1.1\mingw48_32\lib
  • set PATH=C:\Qt\Qt5.1.1\5.1.1\mingw48_32\bin;C:\MinGW\bin;%path% (!important, put Qt's path in front of MinGW's path otherwise it'll complain libstdc++-6.dll missing as Qt's path contains a different libstd++-6.dll)
  • download pkg-config from http://sourceforge.net/projects/pkgconfiglite/files/ and select the latest version and extract to c:\MinGW\bin
  • download glib dev version from http://www.gtk.org/download/win32.php and extract content to c:\MinGW
  • install python3 win32
  • download pexport in msys terminal:
    • pexports /c/Windows/SysWOW64/python33.dll >py33.def
    • dlltool -D python33.dll -d py33.def -l libpython33.a
    • put libpython33.a in c:/mingw/lib
  • install libffi in msys terminal and mount c:/mingw32 /mingw
    • ./configure --prefix=/mingw
    • make
    • make install
  • change cgo.go:
    // #cgo CFLAGS: -Ic:/python33/include
    // #cgo LDFLAGS: -Lc:/Python33/libs -Lc:/mingw/lib -ldl -lpython33
    // #cgo pkg-config: libffi
    
    but when I do go test in gopy, I get errors from lock.go:193, which is very strange, I'll keep investigating.

@adzenith
Copy link
Contributor

adzenith commented Nov 4, 2013

What are the errors?

@jackielii
Copy link

the error is useless. you will know it when you read lock.go: func (lock *Lock) dec() bool, it's basically the BaseObject can't be converted to Long
but if you're interested, here it is:

C:\Users\hb19623\Gocode\src\lime\3rdparty\libs\gopy>go test
# lime/3rdparty/libs/gopy/lib
lib\utils.c:254:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     "GoObjMember",             /*tp_name*/
     ^
lib\utils.c:254:5: warning: (near initialization for 'goObjMemberType.tp_basicsi
ze') [enabled by default]
lib\utils.c:272:5: warning: initialization makes pointer from integer without a
cast [enabled by default]
     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
     ^
lib\utils.c:272:5: warning: (near initialization for 'goObjMemberType.tp_doc') [
enabled by default]
lib\utils.c:273:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     "GoObjMember objects",     /* tp_doc */
     ^
lib\utils.c:273:5: warning: (near initialization for 'goObjMemberType.tp_travers
e') [enabled by default]
lib\utils.c:282:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     objmemb_getset,            /* tp_getset */
     ^
lib\utils.c:282:5: warning: (near initialization for 'goObjMemberType.tp_base')
[enabled by default]
lib\utils.c:285:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     (descrgetfunc)objmemb_get, /* tp_descr_get */
     ^
lib\utils.c:285:5: warning: (near initialization for 'goObjMemberType.tp_descr_s
et') [enabled by default]
lib\utils.c:286:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     (descrsetfunc)objmemb_set, /* tp_descr_set */
     ^
lib\utils.c:286:5: warning: (near initialization for 'goObjMemberType.tp_dictoff
set') [enabled by default]
lib\utils.c:335:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     "GoNatMember",             /*tp_name*/
     ^
lib\utils.c:335:5: warning: (near initialization for 'goNatMemberType.tp_basicsi
ze') [enabled by default]
lib\utils.c:353:5: warning: initialization makes pointer from integer without a
cast [enabled by default]
     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
     ^
lib\utils.c:353:5: warning: (near initialization for 'goNatMemberType.tp_doc') [
enabled by default]
lib\utils.c:354:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     "GoNatMember objects",     /* tp_doc */
     ^
lib\utils.c:354:5: warning: (near initialization for 'goNatMemberType.tp_travers
e') [enabled by default]
lib\utils.c:363:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     natmemb_getset,            /* tp_getset */
     ^
lib\utils.c:363:5: warning: (near initialization for 'goNatMemberType.tp_base')
[enabled by default]
lib\utils.c:366:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     (descrgetfunc)natmemb_get, /* tp_descr_get */
     ^
lib\utils.c:366:5: warning: (near initialization for 'goNatMemberType.tp_descr_s
et') [enabled by default]
lib\utils.c:367:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     (descrsetfunc)natmemb_set, /* tp_descr_set */
     ^
lib\utils.c:367:5: warning: (near initialization for 'goNatMemberType.tp_dictoff
set') [enabled by default]
tick
tick
--- FAIL: TestLock (0.07 seconds)
panic: (*py.BaseObject) (0x51aa20,0x1e279650) [recovered]
        panic: (*py.BaseObject) (0x51aa20,0x1e279650)
goroutine 7 [running]:
runtime.panic(0x51aa20, 0x1e279650)
        C:/Go/src/pkg/runtime/panic.c:266 +0xa6
testing.func┬À005()
        C:/Go/src/pkg/testing/testing.go:383 +0xd9
runtime.panic(0x51aa20, 0x1e279650)
        C:/Go/src/pkg/runtime/panic.c:248 +0xe8
lime/3rdparty/libs/gopy/lib.(*Lock).dec(0x2e4a02e8, 0x0)
        C:/Users/hb19623/Gocode/src/lime/3rdparty/libs/gopy/lib/lock.go:203 +0x1
64
lime/3rdparty/libs/gopy/lib.(*Lock).Unlock(0x2e4a02e8)
        C:/Users/hb19623/Gocode/src/lime/3rdparty/libs/gopy/lib/lock.go:227 +0x5
5
lime/3rdparty/libs/gopy.TestLock(0x2e4a9240)
        C:/Users/hb19623/Gocode/src/lime/3rdparty/libs/gopy/lock_test.go:30 +0x3
6
testing.tRunner(0x2e4a9240, 0x6baa4c)
        C:/Go/src/pkg/testing/testing.go:389 +0x87
created by testing.RunTests
        C:/Go/src/pkg/testing/testing.go:469 +0x6d2
goroutine 1 [chan receive]:
testing.RunTests(0x562994, 0x6baa40, 0x6, 0x6, 0x1)
        C:/Go/src/pkg/testing/testing.go:470 +0x6ed
testing.Main(0x562994, 0x6baa40, 0x6, 0x6, 0x6bea20, ...)
        C:/Go/src/pkg/testing/testing.go:401 +0x6a
main.main()
        lime/3rdparty/libs/gopy/_test/_testmain.go:57 +0x82
goroutine 3 [syscall]:
runtime.goexit()
        C:/Go/src/pkg/runtime/proc.c:1396
exit status 2
FAIL    lime/3rdparty/libs/gopy 3.676s

@quarnster
Copy link
Member

Your gopy is outdated, please sync.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

I followed jackielii's instuctions. Thanks! I got further at least.

go test in gopy still failing. Here is the trace:

c:\Go_1_2_rc3_w32\site-lib\src\lime\3rdparty\libs\gopy>go test
# lime/3rdparty/libs/gopy/lib
lib\utils.c:254:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     "GoObjMember",             /*tp_name*/
     ^
lib\utils.c:254:5: warning: (near initialization for 'goObjMemberType.tp_basicsi
ze') [enabled by default]
lib\utils.c:272:5: warning: initialization makes pointer from integer without a
cast [enabled by default]
     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
     ^
lib\utils.c:272:5: warning: (near initialization for 'goObjMemberType.tp_doc') [
enabled by default]
lib\utils.c:273:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     "GoObjMember objects",     /* tp_doc */
     ^
lib\utils.c:273:5: warning: (near initialization for 'goObjMemberType.tp_travers
e') [enabled by default]
lib\utils.c:282:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     objmemb_getset,            /* tp_getset */
     ^
lib\utils.c:282:5: warning: (near initialization for 'goObjMemberType.tp_base')
[enabled by default]
lib\utils.c:285:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     (descrgetfunc)objmemb_get, /* tp_descr_get */
     ^
lib\utils.c:285:5: warning: (near initialization for 'goObjMemberType.tp_descr_s
et') [enabled by default]
lib\utils.c:286:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     (descrsetfunc)objmemb_set, /* tp_descr_set */
     ^
lib\utils.c:286:5: warning: (near initialization for 'goObjMemberType.tp_dictoff
set') [enabled by default]
lib\utils.c:335:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     "GoNatMember",             /*tp_name*/
     ^
lib\utils.c:335:5: warning: (near initialization for 'goNatMemberType.tp_basicsi
ze') [enabled by default]
lib\utils.c:353:5: warning: initialization makes pointer from integer without a
cast [enabled by default]
     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
     ^
lib\utils.c:353:5: warning: (near initialization for 'goNatMemberType.tp_doc') [
enabled by default]
lib\utils.c:354:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     "GoNatMember objects",     /* tp_doc */
     ^
lib\utils.c:354:5: warning: (near initialization for 'goNatMemberType.tp_travers
e') [enabled by default]
lib\utils.c:363:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     natmemb_getset,            /* tp_getset */
     ^
lib\utils.c:363:5: warning: (near initialization for 'goNatMemberType.tp_base')
[enabled by default]
lib\utils.c:366:5: warning: initialization from incompatible pointer type [enabl
ed by default]
     (descrgetfunc)natmemb_get, /* tp_descr_get */
     ^
lib\utils.c:366:5: warning: (near initialization for 'goNatMemberType.tp_descr_s
et') [enabled by default]
lib\utils.c:367:5: warning: initialization makes integer from pointer without a
cast [enabled by default]
     (descrsetfunc)natmemb_set, /* tp_descr_set */
     ^
lib\utils.c:367:5: warning: (near initialization for 'goNatMemberType.tp_dictoff
set') [enabled by default]
# lime/3rdparty/libs/gopy/lib
C:\Users\jonth\AppData\Local\Temp\go-build414125791\lime\3rdparty\libs\gopy\lib\
_obj\_cgo_export.o: In function `_PyObject_GC_TRACK':
c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/memory.go:18: undefin
ed reference to `_PyGC_generation0'
c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/memory.go:18: undefin
ed reference to `_PyGC_generation0'
c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/memory.go:18: undefin
ed reference to `_PyGC_generation0'
C:\Users\jonth\AppData\Local\Temp\go-build414125791\lime\3rdparty\libs\gopy\lib\
_obj\memory.cgo2.o: In function `_PyObject_GC_TRACK':
c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/memory.go:18: undefin
ed reference to `_PyGC_generation0'
c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/memory.go:18: undefin
ed reference to `_PyGC_generation0'
C:\Users\jonth\AppData\Local\Temp\go-build414125791\lime\3rdparty\libs\gopy\lib\
_obj\memory.cgo2.o:c:/Go_1_2_rc3_w32/site-lib/src/lime/3rdparty/libs/gopy/lib/me
mory.go:18: more undefined references to `_PyGC_generation0' follow
collect2.exe: error: ld returned 1 exit status
FAIL    lime/3rdparty/libs/gopy [build failed]

@adzenith
Copy link
Contributor

adzenith commented Nov 5, 2013

I don't have a Windows machine, so I'm not sure how much help you can be, but if you figure anything out we'd love to hear how you got it to work.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

I suspect my latest error (linker unable to find definition for _PyGC_generation0) is caused by memory.go using a reference to _PyObject_GC_TRACK which is the macro version of PyObject_GC_Track . This requires the build system to be able to access gcmodule.c to find the definition of _PyGC_generation0. Not sure why this works on linux as I don't have a linux machine handy.

memory.go is in some sense an extension module and in the extension documentation it says that the macros should not be used for extension modules. I am at work but will see if replacing the macro with the function will fix it when I get home.

@jackielii
Copy link

@l1n3n01z Yes, you're right, I've no idea how this works in Linux, but I inserted a line:

//     PyGC_Head *_PyGC_generation0;

just after

// #include "utils.h"

and it compiles, but I don't know if it's the right thing to do.

After done that and go test. You'll get that error that trace back to lock.go:193

@quarnster thanks. but I have no luck after updating gopy to c880d66, still the same error. I'll keep investigating, and maybe come back with a pull request:)

@quarnster
Copy link
Member

Did the "tick" prints go away at least? If not it's not updated as that test was removed. There was a fix in the lock test so that PyFinalize isn't called until python has actually finished which might have been a cause of the issue you are seeing. But if you are updated and you are still seeing it, I don't know what's broken

@jackielii
Copy link

Yes, the tick was gone.

About this error, I printed the python type and see it's "int" and with value of "1", but in go arena it's a *py.BaseObject, not a *py.Long. Any idea how this happened?

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

In memory.go I changed line 18 to
// PyObject_GC_Track(obj);
and I fail with the same error as @jackielii

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

(tl;dr: &C.PyLong_Type != &PyLong_Type in utils.c)

Further investigation reveals:

lock.dec()

calls

dict.GetItemString()

calls

obj2ObjErr

calls

newObject

which has this switch statement

switch C.getBasePyType(obj) {
        [stuff]
    case &C.PyLong_Type:
        return (*Long)(o)
        [more stuff]
    }

However! C.getBasePyType(obj) is never matched in the switch statement so newObject returns newBaseObject(obj) which causes the returned object to be of the wrong type as @jackielii observed.

More curiously,
utils.c : getBasePyType returns from correct if statement (i.e. PyLong_Check(o) is true), so it should match!

fmt.Println(unsafe.Pointer(C.getBasePyType(obj)) ) 

prints 0x1e23e158 which is the same value as internally in utils.c
but

fmt.Println(unsafe.Pointer((&C.PyLong_Type)) 

prints 0x6bf784

I'm not sure what conclusions to draw from this :)

I'll keep looking.

@jackielii
Copy link

EDIT: sorry, my test file was wrong, please ignore this. I get same error as the original one.

@l1n3n01z I went through exactly the same stuff as you noted here. I wrote a test file called long_test.go in lib folder:

package py

import (
    "fmt"
    "testing"
)

func TestLong(t *testing.T) {
    l := NewLong(10)
    d, err := NewDict()
    if err != nil {
        t.Fatal(err)
    }
    if err = d.SetItemString("gopy.count", l); err != nil {
        t.Fatal(err)
    }
    if l2, err := d.GetItemString("gopy.count"); err != nil {
        t.Fatal(err)
    } else {
        if l3, ok := l2.(*Long); !ok {
            t.Fail()
        } else {
            fmt.Println(l3.Int64())
        }
    }
}

It actually passes. So the problem might lie in

dict := newDict(C.PyThreadState_GetDict())

in lock.go:159, :169, :188

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

I also created a test, but in gopy root folder

package pytesting

import (
    "lime/3rdparty/libs/gopy/lib"
    "testing"
    "fmt"
)

func TestLong2(t *testing.T) {
    py.Initialize()
    defer py.Finalize()
    l := py.NewLong(10)
    d, err := py.NewDict()
    if err != nil {
        t.Fatal(err)
    }
    if err = d.SetItemString("gopy.count", l); err != nil {
        t.Fatal(err)
    }
    if l2, err := d.GetItemString("gopy.count"); err != nil {
        t.Fatal(err)
    } else {
        if l3, ok := l2.(*py.Long); !ok {
            t.Fail()
        } else {
            fmt.Println(l3.Int64())
        }
    }
}

This fails in exactly the same manner as expected, i.e. the object is changed into a base object.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 5, 2013

I'm a bit confused. I was going back and forth, and now I seem to be unable to run your test singly. How are you running your test without running into a failure first?

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

If I add

// static inline long longCheck(PyObject *o) { return PyLong_Check(o); }

to object.c
and add this above the switch statement

if C.longCheck(obj) != 0 {
    fmt.Println("longch")
    return (*Long)(o)   
}

then TestLong2 passes.
So I suggest using a variety of similiar checks instead of the switch statement until wiser people can tell us why

&C.PyLong_Type != &PyLong_Type(in C code)

and also why this works in Linux. (My utterly uneducated guess is that the whole of python is being compiled at the same time or something, rather than just being linked in)

I must admit that I am a bit concerned that there may be a plethora of similar bugs waiting for us.

@quarnster
Copy link
Member

What's the output of this:

package main

/*
#cgo CFLAGS: -I/usr/local/include/python3.3m -I/usr/local/include/python3.3m -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
#cgo LDFLAGS: -L/usr/local/lib -ldl -framework CoreFoundation -lpython3.3m -framework CoreFoundation

#include <Python.h>
PyTypeObject* getLongObj() { return &PyLong_Type; }
*/
import "C"

import "fmt"

func main() {
    C.Py_InitializeEx(0)
    defer C.Py_Finalize()
    a := &C.PyLong_Type
    b := C.getLongObj()
    fmt.Printf("a: %+v\nb: %+v\nequal: %v\n", a, b, a == b)
}

As a reference, on my mac it's:

a: &{ob_base:{ob_base:{ob_refcnt:67 ob_type:0x43266c0} ob_size:0} tp_name:0x42dcff9 tp_basicsize:24 tp_itemsize:4 tp_dealloc:0x41f2830 tp_print:<nil> tp_getattr:<nil> tp_setattr:<nil> tp_reserved:<nil> tp_repr:0x41f2840 tp_as_number:0x431eda0 tp_as_sequence:<nil> tp_as_mapping:<nil> tp_hash:0x41f2870 tp_call:<nil> tp_str:0x41f2840 tp_getattro:0x4203d40 tp_setattro:0x4203f60 tp_as_buffer:<nil> tp_flags:17568768 tp_doc:0x431eeb0 tp_traverse:<nil> tp_clear:<nil> tp_richcompare:0x41f2930 tp_weaklistoffset:0 tp_iter:<nil> tp_iternext:<nil> tp_methods:0x431f110 tp_members:<nil> tp_getset:0x431f290 tp_base:0x4326980 tp_dict:0x4761758 tp_descr_get:<nil> tp_descr_set:<nil> tp_dictoffset:0 tp_init:0x4212d30 tp_alloc:0x420f0b0 tp_new:0x41f2a70 tp_free:0x4205080 tp_is_gc:<nil> tp_bases:0x47651d0 tp_mro:0x47617e8 tp_cache:<nil> tp_subclasses:0x47615a8 tp_weaklist:0x47697e0 tp_del:<nil> tp_version_tag:180 _:[0 0 0 0]}
b: &{ob_base:{ob_base:{ob_refcnt:67 ob_type:0x43266c0} ob_size:0} tp_name:0x42dcff9 tp_basicsize:24 tp_itemsize:4 tp_dealloc:0x41f2830 tp_print:<nil> tp_getattr:<nil> tp_setattr:<nil> tp_reserved:<nil> tp_repr:0x41f2840 tp_as_number:0x431eda0 tp_as_sequence:<nil> tp_as_mapping:<nil> tp_hash:0x41f2870 tp_call:<nil> tp_str:0x41f2840 tp_getattro:0x4203d40 tp_setattro:0x4203f60 tp_as_buffer:<nil> tp_flags:17568768 tp_doc:0x431eeb0 tp_traverse:<nil> tp_clear:<nil> tp_richcompare:0x41f2930 tp_weaklistoffset:0 tp_iter:<nil> tp_iternext:<nil> tp_methods:0x431f110 tp_members:<nil> tp_getset:0x431f290 tp_base:0x4326980 tp_dict:0x4761758 tp_descr_get:<nil> tp_descr_set:<nil> tp_dictoffset:0 tp_init:0x4212d30 tp_alloc:0x420f0b0 tp_new:0x41f2a70 tp_free:0x4205080 tp_is_gc:<nil> tp_bases:0x47651d0 tp_mro:0x47617e8 tp_cache:<nil> tp_subclasses:0x47615a8 tp_weaklist:0x47697e0 tp_del:<nil> tp_version_tag:180 _:[0 0 0 0]}
equal: true

@jackielii
Copy link

@quarnster the result of that program on my machine is:

$ go run gopytest.go
a: &{ob_base:{ob_base:{ob_refcnt:505667928 ob_type:0x1e125860} ob_size:504525360} tp_name: tp_basicsize:1986950281 tp_itemsize:0 tp_dealloc:0x748bdf14 tp_print:0x748bdfc8 tp_getattr:0x748be124 tp_setattr: tp_reserved:0x74059ef7 tp_repr: tp_as_number:0x7711f8bc tp_as_sequence: tp_as_mapping:0x74d91826 tp_hash:0x74d9183e tp_call:0x74dad35b tp_str:0x74d913e0 tp_getattro:0x74d9322c tp_setattro:0x74d93475 tp_as_buffer:0x74e14c54 tp_flags:1960384598 tp_doc:0x74d979b0 tp_traverse:0x74d9516b tp_clear:0x74d95183 tp_richcompare:0x74d91222 tp_weaklistoffset:1960399187 tp_iter:0x74d9496a tp_iternext:0x74d934a9 tp_methods:0x74db796c tp_members:0x74d948cb tp_getset:0x74d94977 tp_base:0x74d9438f tp_dict:0x74d989a9 tp_descr_get:0x74d91695 tp_descr_set:0x74d9325b tp_dictoffset:1960557255 tp_init:0x74db7d16 tp_alloc:0x74d91136 tp_new:0x74d91282 tp_free:0x74d9165c tp_is_gc:0x74d92cdc tp_bases: tp_mro:0x74c82900 tp_cache:0x74c48e6b tp_subclasses:0x74be9894 tp_weaklist:0x74bf76ac tp_del:0x74be9cee tp_version_tag:1958802771}
b: &{ob_base:{ob_base:{ob_refcnt:67 ob_type:0x1e241408} ob_size:0} tp_name:0x1e1e81f8 tp_basicsize:12 tp_itemsize:2 tp_dealloc:0x1e0a5ae0 tp_print: tp_getattr: tp_setattr: tp_reserved: tp_repr:0x1e0a4960 tp_as_number:0x1e23e0d0 tp_as_sequence: tp_as_mapping: tp_hash:0x1e0a5c30 tp_call: tp_str:0x1e0a4960 tp_getattro:0x1e0aeb00 tp_setattro:0x1e0aed00 tp_as_buffer: tp_flags:17568768 tp_doc:0x1e23de70 tp_traverse: tp_clear: tp_richcompare:0x1e0a5b70 tp_weaklistoffset:0 tp_iter: tp_iternext: tp_methods:0x1e23dd48 tp_members: tp_getset:0x1e23de08 tp_base:0x1e241708 tp_dict:0x29541c0 tp_descr_get: tp_descr_set: tp_dictoffset:0 tp_init:0x1e0b95b0 tp_alloc:0x1e0b80b0 tp_new:0x1e0a73a0 tp_free:0x1e0b0130 tp_is_gc: tp_bases:0x29514b0 tp_mro:0x2954620 tp_cache: tp_subclasses:0x2954080 tp_weaklist:0x29568a0 tp_del: tp_version_tag:179}
equal: false

@quarnster
Copy link
Member

"a" looks completely messed up. I'd search for an existing or open up a new bug

@quarnster
Copy link
Member

Could be issue 4339 or a variant thereof. Does your python end up as a dll or a static library? If you change it to the other form, does that make any difference?

@jackielii
Copy link

@quarnster I didn't compile python with mingw from scratch, I downloaded binary installer for windows 32bit. and use pexport and dlltool to create from python33.dll to libpython33.a

see the comment: #119 (comment)

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

I concur, It seems to be the same bug. I am linking against python as a dll and PyLong_Type is exported in a similar manner as in issue 4339.

I've been searching for something like this using variants/combinations of the search words "golang", "static linking", "golang dll", "static variable", "cgo" but not found anything. Stupidly I didn't search the golang bug database directly.

Question is, is the way forward to access the static variables as suggested in 4339, using short inline wrapper functions (this worked for me in my test) and change a lot of code in the project, or do we link statically against Python? It seems in any case that Python should be internal to the project, as it needs the special compilation of signal handling.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

Actually it seems that building Python on Win using MingW is quite unorthodox and apparently is a major hassle (impossible according to some, though others have managed to get at least a Python, though without some modules building properly).

It will also result in incompatibility with binary extensions. Most people on Win use binary extensions as building Python stuff (language itself and/or extensions) in general, using MSVC, is a huge effort and requires downloading tons of hard to find Microsoft stuff.

@quarnster
Copy link
Member

FWIW, IIRC there's something odd going on with mingw32/64 as I've stumbled upon issues using a mingw created dll from python in the past. Don't know if it's possible to use standard ms' cl together with go, but that might be another path.

using MSVC, is a huge effort and requires downloading tons of hard to find Microsoft stuff.

Actually, they probably just require the commandline compiler not the full MSVC. The commandline compiler tools are in the Windows 7 sdk.

using short inline wrapper functions (this worked for me in my test) and change a lot of code in the project

IMO not this one because it adds complexity that shouldn't be needed and if any other dll is used in the future similar problems wouldn't be solved by this work around.

do we link statically against Python

Is it known for sure that this fixes this issue?

It seems in any case that Python should be internal to the project, as it needs the special compilation of signal handling.

Ideally building Python should be part of the build system discussed in #107.

@quarnster
Copy link
Member

BTW, does windows even have sigaltstack? It's possible a standard non-modified python would work just fine on windows, except for the 4339 of course.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

using short inline wrapper functions (this worked for me in my test) and change a lot of code in the project

IMO not this one because it adds complexity that shouldn't be needed and if any other dll is used in the future similar problems wouldn't be solved by this work around.

Not entirely sure if this is such a big hurdle. It seems to me to me that there are relatively few of those static variables lying around anyway, and to link against a dynamic library through a static export library does seem to be the accepted way of doing things in Windows.

Any other dlls which we wanted to build against through cgo would have to use the same workaround, yes, but that would be inevitable anyway.

Using these wrappers wouldn't really affect anyone else, except it would make the code slightly more indirect in these few cases, and would have some minor effects on speed. As the object thunking is done quite a bit, we could also invest a bit into just having constants for the base types and just returning a constant for the switch statement.

I'm happy to do this work.

On the other hand: The solution of compiling python into the project seems to be a much bigger hurdle in Windows, requiring either of two very difficult things, getting golang to use the msvc ecology or python to compile with mingw.

On whether python on Windows has sigalstack, I am unsure (not entirely sure what a sigalstack is, TBH, ehemm..), but the test for checking for it results in a negative with the default python (from here http://stackoverflow.com/questions/19546418/how-to-compile-python-3-without-sigaltstack-enabled ). So it should be possible to use an off-the-rack Python.

>>> import faulthandler
>>> print(hasattr(faulthandler, '_stack_overflow'))
False

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

@jackielii For future reference it would be useful if you could paste in the complete gopytest.go file you ran, as I am sure you changed some of the cgo flags before running it from what they were in the original file from @quarnster .

Also we should clean up this discussion and put it up on the wiki ASAP for other utterly lost Windows devs 😃

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 6, 2013

Copied @jackielii first post to https://github.com/limetext/lime/wiki/Building-on-Windows . Cleaned it up a little bit. We should then refine it :-)

@quarnster
Copy link
Member

I'm happy to do this work.

@l1n3n01z, ok go for it.

And thanks for kicking off the wiki page!

@ntwb
Copy link

ntwb commented Nov 7, 2013

I haven't had time to setup all the things but I will do in the next week (time permitting).

I would seriously take a look at checking out the following repo for Windows users.

https://github.com/lukesampson/scoop/

Currently included packages:
Go: https://github.com/lukesampson/scoop/blob/master/bucket/go.json
Python 3: https://github.com/lukesampson/scoop/blob/master/bucket/python.json
MSYS: https://github.com/lukesampson/scoop/blob/master/bucket/msys.json

Check out some of the others also https://github.com/lukesampson/scoop/tree/master/bucket

There are no packages for Oniguruma or qt5,

I haven't tested any of this yet but I am quite sure (and hoping) that this will make much of what is above in this ticket not required. I am also in the 'I know nothing boat' regarding HAVE_SIGALTSTACK so that could be an issue if IT IS required.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 7, 2013

Great idea. I just heard about scoop also just this week. It would definitely simplify all the installation, and it would also help with isolating all the stuff in a single directory. Am I right that we could even write our own packet definition and it would just take care of all the preliminaries?

So going forward, we could use this to simplify the installation and the cgo windows flags to isolate the windows specific things in the build.

I also think that qt5 should be made completely optional, so that you if want it you specify "qt" in your build tags. I suspect that qt5 is just there as a proof of concept and that the idea is that in the future you could use pretty much any GUI kit that you are willing to write a front end for.

@quarnster
Copy link
Member

I'd prefer to just use cmake which can be configured to download, patch and build all dependencies as needed and can generate project files for your favorite build system whether that is pure makefiles, msvc, eclipse, xcode or whatever.

Yes the qt5 frontend is completely broken (as opposed to the termbox frontend which is just partially broken ;)). QML looks like a much better approach imo if people want to use qt5. People might also want to look into creating a skia frontend, which is what ST3 is using to render with, created issue #129 for that.

The graphics for ST3 themes is pretty much layered 9-patch ui elements IIRC, so shouldn't be too hard to code up. In the history of the gh-pages branch there's a css version and I think old_master contains some code for QT5 stylesheets or whatever they were called.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 7, 2013

On cmake: I'm not familiar with cmake, and was not thinking of using scoop as a build system per se. Only as a helper for installing the needed software. Is cmake a good fit for that? I found this discussion http://stackoverflow.com/questions/8153519/how-to-automatically-download-c-dependencies-in-a-cross-platform-way-cmake which looks like it is relevant.

@quarnster
Copy link
Member

Is cmake a good fit for that?

Yes, one of my other repos downloads source code for compilers, cross compiles the compilers, then downloads, patches, builds and installs all dependencies to be able to cross compile XBMC for the Boxeebox.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 7, 2013

Excellent :)

Anyway, back to the topic at hand. @jackielii I have updated my lime fork https://github.com/l1n3n01z/lime with the fixes I made to object.go, using constant numbers as type identifiers. It fixes all but one test for me. Can you please test on your machine?

@quarnster I have not tested on linux or mac, and not sure what our integration model should be. I can probably set up a VM for linux, but not OsX

The last test which is failing for me ends in a segfault or something of the sort. It should be possible to run all tests successfully by commenting out module_test.go:112

    // {"Test2", "called2", "i", []interface{}{10}},

It seems that this codepath invokes a call through libffi which fails spectacularly. No idea why. I'm not a hundred percent sure, but I think I have found the line that fails through judicious printing and exception throwing. Of course this being c it is quite possible that the actual error is somewhere else.

The line in question is utils.c:132

    ffi_call(&cif, FFI_FN(Py_BuildValue), &result, arg_values);

We should create a minimum repro for this ffi_call failure in a test. I should be able to do it in the weekend but it's up for grabs :)

@jackielii
Copy link

@l1n3n01z Hi, I cloned your fork and ran the tests, everything is passing except TestMethod2!

When run just TestMethod2 it crashes with "... is stopped working..." message box (I'm using Windows 7)

Great work, Thanks!

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 8, 2013

I think I have solved the last crash. libffi is interfacing with Python which - because it is compiled with msvc - uses msvc declspec. So it needs to be configured to use the correct declspec.

Can you try the following, which fixes the crash for me?: In utils.c:127, change

    status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, c+1,
                          &ffi_type_pointer, arg_types);

to

    status = ffi_prep_cif(&cif, FFI_MS_CDECL, c+1,
                          &ffi_type_pointer, arg_types);

It should fix the last test. The actual fix will require a bit more finesse not to break compatibility for other architectures and also needs to do the change everywhere where libffi is used. It also seems to me that gopy requires a bit more unit tests, since the PyParse_Tuple codepath is not even touched.

I hope to get a patch out soon.

@quarnster
Copy link
Member

The actual fix will require a bit more finesse not to break compatibility for other architectures and also needs to do the change everywhere where libffi is used.

We can make the cmake build system select the correct one (#107). I'll work on it this weekend.

It also seems to me that gopy requires a bit more unit tests, since the PyParse_Tuple codepath is not even touched.

Yes, the original gopy didn't have any unit tests at all and the ones that are there now were all created by myself to figure out where things were broken IIRC. Please do add more tests as you see fit both for gopy and lime.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 8, 2013

At another computer and the fix is not working there, I may have been too hasty. We'll see :)

@jackielii
Copy link

@l1n3n01z yes, It's not working on my system either.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 8, 2013

I was returning a value from a shortcut in the test that passed 😊

In other news. libffi seems to be borked. I'm using it internally for some testing and it plain doesn't work when passing any arguments at all.

In utils.c I added the following functions

long testlongfromvoid() {
    printf("test void\n");
    return 10l;
}

long testlongfromint(int32_t i) {
    printf("returning %d\n", (int)i);
    printf("returning %ld\n", (long)(i+2));
    return (long)(i+2);
}

First I checked some things. I replaced doBuildValue with the following as a sanity check:

PyObject *doBuildValue(char *fmt, ArgValue values[], int c) {
    return PyLong_FromLong(10l);
}

This works and the test passes.

When I replace it with this, the test also passes and prints out as expected "test void"

PyObject *doBuildValue(char *fmt, ArgValue values[], int c) {
    ffi_cif cif;
    ffi_type *args[1];
    void *argvalues[1];
    long result;
    int32_t arg = 8;
    args[0] = &ffi_type_sint32;
    argvalues[0] = &arg;

    int numargs = 0;
    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, numargs,&ffi_type_slong, args) == FFI_OK)
    {
       ffi_call(&cif, FFI_FN(testlongfromvoid), &result, argvalues); // Calling with no params!
    }
    return PyLong_FromLong(result);
}

If I do the same thing, but making ffi call testlongfromint instead, testlong from int returns some garbage of course as I don't pass it any parameters, but it returns the garbage and the test fails in a controlled manner.

HOWEVER! If I do this:

PyObject *doBuildValue(char *fmt, ArgValue values[], int c) {
    ffi_cif cif;
    ffi_type *args[1];
    void *argvalues[1];
    long result;
    int32_t arg = 8;
    args[0] = &ffi_type_sint32;
    argvalues[0] = &arg;

    int numargs = 1; // <=== CHANGED NUM PARAMETERS
    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, numargs,&ffi_type_slong, args) == FFI_OK)
    {
       ffi_call(&cif, FFI_FN(testlongfromint), &result, argvalues); // Calling with params OMG!!
    }
    return PyLong_FromLong(result);
}

libffi thrashes the stack and everything fails horribly. I have tested a number of different ffi types and calling conventions. It always dies horribly.

Not sure what to do TBH. Talk to the libffi guys, I guess.

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 8, 2013

Another thing. Why is libffi not being called with ffi_prep_cif_var before calling the variadic function PyBuild_Value?

Why does this code actually work in linux/OsX?

@quarnster
Copy link
Member

Why does this code actually work in linux/OsX?

My guess would be the same c compiler being used for both python and libffi.

I didn't write the original code so don't know it too well, but I think libffi is only used for the variable argument functions. Getting gopy working aside, are these problematic code paths important for lime specifically? The easy solution might be to just remove them.

@jackielii
Copy link

There is a "clone" of gopy that eliminated libffi, I don't know if we can use it? (I didn't look into the code myself)

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 8, 2013

@quarnster I'm not sure we can remove the codepaths, I suspect this is heavily used. I can look into it. It might actually be good to know what functionality is required of gopy and why. I was under the impression that it would be used for all of the python code.

@jackielii That's quite probable, it looks like ffi is only used to call two python API functions, and the only reason it is used is because these take variadic arguments. There might be easier ways to get the same functionality using varargs. I will look into that.

@jackielii
Copy link

silly me, forgot to paste the url!!!
https://github.com/qiniu/py

@quarnster
Copy link
Member

It doesn't look like the ffi path is used by lime. I'll remove it in an upcoming commit

@l1n3n01z
Copy link
Author

l1n3n01z commented Nov 9, 2013

Excellent news! Looking forward to it.

@quarnster
Copy link
Member

I've made lots of changes all over the place. There are still odd things going on with python, but if lime/backend/sublime is disabled it's now possible to run the termbox frontend on windows and all other packages pass their tests. See latest build instructions for some small guidance on the cmake build system.

@l1n3n01z
Copy link
Author

I've been busy with other things, but I'll try cmake from scratch over the weekend. Thanks for all the work on it @quarnster . Did you have the opportunity to try it out on Win?

@jackielii Did you ever get linking errors for onigiruma when building the editor? Onigiruma is supposed to be linked statically I think, at least the mingw build creates only static libs, but it seems cgo is not entirely happy about that.

@quarnster
Copy link
Member

Yes, my previous comment was with Windows 7.1. FWIW I removed my windows Go installation and just let the build system download Go in case that makes any difference regarding the linking errors you're seeing.

@quarnster
Copy link
Member

BTW, the static lib is a workaround for issue 4339 which only shows up for dlls. If it's possible to compile python 3 as a static lib on windows too, that would be ideal but is not something I've looked into.

This was referenced Jan 9, 2014
@quarnster
Copy link
Member

This might be of interest: https://github.com/bendmorris/static-python/tree/3.3

@quarnster
Copy link
Member

I think #228 has superseeded this one. Please re-open if I'm mistaken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants