ronaldoussoren / py2app

py2app is a Python setuptools command which will allow you to make standalone Mac OS X application bundles and plugins from Python scripts.
Other
343 stars 36 forks source link

Need PyGObject recipe [py2app segfaults on PyGObject hello world] #357

Open dstromberg opened 3 years ago

dstromberg commented 3 years ago

I'm attempting to bundle up a test program (an "hello world") as a macOS app using py2app.

The error I get is:

/Applications/hello.app/Contents/MacOS/hello
objc[823]: Class GNotificationCenterDelegate is implemented in both /Applications/hello.app/Contents/Frameworks/libgio-2.0.0.dylib (0x106e9f2f0) and /usr/local/opt/glib/lib/libgio-2.0.0.dylib (0x107a0b2f0). One of the two will be used. Which one is undefined.
make: *** [go] Segmentation fault: 11

The program, which runs fine outside of py2app, is:

$ cat hello.py
cmd output started 2021 Tue Jun 08 03:19:44 PM PDT
#!/usr/bin/env python3

"""Just say hi."""

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk  # noqa

window = Gtk.Window(title="Title")
button = Gtk.Button(label='Hello World!')
button.show()
button.connect("clicked", Gtk.main_quit)
window.add(button)
window.show()
window.connect("destroy", Gtk.main_quit)
Gtk.main()

My setup.py looks like:

$ cat setup.py
cmd output started 2021 Tue Jun 08 03:20:30 PM PDT
"""
This is a setup.py script derived from https://stackoverflow.com/questions/5608080/how-to-specify-py2app-icon .

Usage:
    python3 setup.py py2app
"""

from setuptools import setup

app = ['hello.py']
options = {
    'iconfile': 'icon/hello.png',
    'packages': ['gi'],
}

setup(
    app=app,
    options={'py2app': options},
    setup_requires=['py2app'],
)

And here's the Makefile I've been using, which includes creation of the icon file:

$ cat Makefile
cmd output started 2021 Tue Jun 08 03:21:11 PM PDT
go: clean
    ./hello.py
    pbmtext 'hello!' | pnmtopng > icon/hello.png
    python3 setup.py py2app
    (cd dist && tar cflS - hello.app) | (cd /Applications && tar xvfp -)
    /Applications/hello.app/Contents/MacOS/hello

clean:
    rm -rf build dist
    rm -f icon/hello.png

I'm using homebrew CPython 3.9.5 and py2app==0.24 on macOS Big Sur (11.4). py2app was installed with pip.

I'm afraid I have little idea why it would be segfaulting.

Here's the tail end of a dtruss -f /Applications/hello.app/Contents/MacOS/hello . I had to run it as root, since macOS apparently dislikes dtruss as an unprivileged user:

 2094/0x4060:  fcntl(0x4, 0x32, 0x7FFEEFBEDF70)      = 0 0
 2094/0x4060:  close(0x4)        = 0 0
 2094/0x4060:  stat64("/usr/local/opt/glib/lib/libglib-2.0.0.dylib\0", 0x7FFEEFBF5E80, 0x0)      = 0 0
 2094/0x4060:  stat64("/usr/local/opt/glib/lib/libgio-2.0.0.dylib\0", 0x7FFEEFBF5E80, 0x0)       = 0 0
 2094/0x4060:  open("/usr/local/opt/glib/lib/libgio-2.0.0.dylib\0", 0x0, 0x0)        = 4 0
dtrace: error on enabled probe ID 1700 (ID 468: syscall::pread:return): invalid kernel access in action #13 at DIF offset 20
 2094/0x4060:  fcntl(0x4, 0x62, 0x7FFEEFBED5F0)      = 0 0
 2094/0x4060:  fcntl(0x4, 0x65, 0x7FFEEFBED740)      = 0 0
 2094/0x4060:  mmap(0x1078C9000, 0x144000, 0x5, 0x40012, 0x4, 0x0)       = 0x1078C9000 0
 2094/0x4060:  mmap(0x107A0D000, 0x8000, 0x3, 0x40012, 0x4, 0x0)         = 0x107A0D000 0
 2094/0x4066:  workq_kernreturn(0x100, 0x7000095D5B80, 0x1)      = 0 -2

I tried gdb, but got the dreaded:

$ gdb /Applications/hello.app/Contents/MacOS/hello
cmd output started 2021 Tue Jun 08 03:31:48 PM PDT
GNU gdb (GDB) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin20.3.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /Applications/hello.app/Contents/MacOS/hello...
(No debugging symbols found in /Applications/hello.app/Contents/MacOS/hello)
(gdb) run
Starting program: /Applications/hello.app/Contents/MacOS/hello
Unable to find Mach task port for process-id 2181: (os/kern) failure (0x5).
 (please check gdb is codesigned - see taskgated(8))
(gdb)

And running gdb as root, puzzlingly, hangs with almost no output:

$ sudo gdb /Applications/hello.app/Contents/MacOS/hello
cmd output started 2021 Tue Jun 08 03:32:30 PM PDT
Password:
GNU gdb (GDB) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin20.3.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /Applications/hello.app/Contents/MacOS/hello...
(No debugging symbols found in /Applications/hello.app/Contents/MacOS/hello)
(gdb) run
Starting program: /Applications/hello.app/Contents/MacOS/hello
[New Thread 0x1803 of process 2196]
[New Thread 0x1903 of process 2196]

Any suggestions?

Thanks!

dstromberg commented 3 years ago

I just noticed (I'm a relative macOS newb) that the "problem report" under "Show details" in the GUI gives a stack trace:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_platform.dylib        0x00007fff2058f552 _platform_strlen + 18
1   libgirepository-1.0.1.dylib     0x0000000106440142 0x106432000 + 57666
2   libgirepository-1.0.1.dylib     0x000000010643d561 g_irepository_find_by_gtype + 225
3   _gi.so                          0x00000001062c319b 0x1062b4000 + 61851
4   org.python.python               0x0000000105f0209c 0x105e50000 + 729244
5   org.python.python               0x0000000105eb76da _PyObject_MakeTpCall + 129
6   org.python.python               0x0000000105fafcbd 0x105e50000 + 1440957
7   org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
8   org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
9   org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
10  org.python.python               0x0000000105ebae7a 0x105e50000 + 437882
11  org.python.python               0x0000000105f2fa23 0x105e50000 + 916003
12  org.python.python               0x0000000105f24d84 0x105e50000 + 871812
13  org.python.python               0x0000000105faa8af _PyEval_EvalFrameDefault + 33941
14  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
15  org.python.python               0x0000000105f9c04f 0x105e50000 + 1359951
16  org.python.python               0x0000000105f02a43 0x105e50000 + 731715
17  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
18  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
19  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
20  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
21  org.python.python               0x0000000105fad489 _PyEval_EvalFrameDefault + 45167
22  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
23  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
24  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
25  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
26  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
27  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
28  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
29  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
30  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
31  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
32  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
33  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
34  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
35  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
36  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
37  org.python.python               0x0000000105fad526 _PyEval_EvalFrameDefault + 45324
38  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
39  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
40  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
41  org.python.python               0x0000000105fad526 _PyEval_EvalFrameDefault + 45324
42  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
43  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
44  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
45  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
46  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
47  org.python.python               0x0000000105fad489 _PyEval_EvalFrameDefault + 45167
48  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
49  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
50  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
51  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
52  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
53  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
54  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
55  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
56  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
57  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
58  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
59  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
60  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
61  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
62  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
63  org.python.python               0x0000000105fad526 _PyEval_EvalFrameDefault + 45324
64  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
65  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
66  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
67  org.python.python               0x0000000105fad526 _PyEval_EvalFrameDefault + 45324
68  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
69  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
70  org.python.python               0x0000000105fad489 _PyEval_EvalFrameDefault + 45167
71  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
72  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
73  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
74  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
75  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
76  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
77  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
78  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
79  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
80  org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
81  org.python.python               0x0000000105eb9744 0x105e50000 + 431940
82  org.python.python               0x0000000105eb99a5 _PyObject_CallMethodIdObjArgs + 252
83  org.python.python               0x0000000105fdb42a PyImport_ImportModuleLevelObject + 1028
84  org.python.python               0x0000000105f9a934 0x105e50000 + 1354036
85  org.python.python               0x0000000105f0209c 0x105e50000 + 729244
86  org.python.python               0x0000000105eb806d _PyObject_Call + 125
87  org.python.python               0x0000000105fad75e _PyEval_EvalFrameDefault + 45892
88  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
89  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
90  org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
91  org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
92  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
93  org.python.python               0x0000000105eb82f8 _PyFunction_Vectorcall + 376
94  org.python.python               0x0000000105eb9744 0x105e50000 + 431940
95  org.python.python               0x0000000105eb99a5 _PyObject_CallMethodIdObjArgs + 252
96  org.python.python               0x0000000105fdb263 PyImport_ImportModuleLevelObject + 573
97  org.python.python               0x0000000105faaf1e _PyEval_EvalFrameDefault + 35588
98  org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
99  org.python.python               0x0000000105f9c04f 0x105e50000 + 1359951
100 org.python.python               0x0000000105f02a43 0x105e50000 + 731715
101 org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
102 org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
103 org.python.python               0x0000000105eb8240 _PyFunction_Vectorcall + 192
104 org.python.python               0x0000000105fafc53 0x105e50000 + 1440851
105 org.python.python               0x0000000105fad562 _PyEval_EvalFrameDefault + 45384
106 org.python.python               0x0000000105fa12d6 0x105e50000 + 1381078
107 org.python.python               0x0000000106004567 0x105e50000 + 1787239
108 org.python.python               0x00000001060044b7 0x105e50000 + 1787063
109 org.python.python               0x0000000106001dac 0x105e50000 + 1777068
110 org.python.python               0x00000001060017ad 0x105e50000 + 1775533
111 org.python.python               0x0000000106001677 PyRun_SimpleFileExFlags + 67
112 org.pythonmac.unspecified.hello 0x000000010000280b 0x100000000 + 10251
113 org.pythonmac.unspecified.hello 0x00000001000011c6 main + 1668
114 org.pythonmac.unspecified.hello 0x0000000100000b20 start + 52

So it appears that the error is ultimately fatal in libsystem_platform.dylib ? I'm aware that doesn't necessarily mean the bug is in libsystem_platform .

Does anyone have any suggestions?

Thanks!

dstromberg commented 3 years ago

Here's something interesting. This works: DYLD_LIBRARY_PATH=/Applications/hello.app/Contents/Frameworks /Applications/hello.app/Contents/MacOS/hello ...but running the same command without DYLD_LIBRARY_PATH, as before, segfaults.

This might be useful for setting the executable's rpath: https://stackoverflow.com/questions/4513799/how-to-set-the-runtime-path-rpath-of-an-executable-with-gcc-under-mac-osx

dstromberg commented 3 years ago

Neither of these appeared to help: install_name_tool -add_rpath "@loader_path/Applications/hello.app/Contents/Frameworks" /Applications/hello.app/Contents/MacOS/hello install_name_tool -add_rpath "/Applications/hello.app/Contents/Frameworks" /Applications/hello.app/Contents/MacOS/hello

ronaldoussoren commented 3 years ago

I've had a quick look at PyGObject and it requires special handling in py2app to work properly. The "gi.repository" package is a virtual package where the submodules don't actually existing in the file system. I don't have time to look into this at the moment.

Given your message about DYLD_LIBRARY_PATH adding an LSEnvironment key to the Info.plist might help (see: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-106825)

Something like:

   <key> LSEnvironment</key>
   <dict>
     <key>DYLD_LIBRARY_PATH</key>
     <string>/Applications/hello.app/Contents/Frameworks</string>
   </dict>

That's just a workaround for the lack of support for PyGObject though, the application will only launch correctly when installed in /Applications/ (if this works at all). This will also only work when the application is launched through the system (double clicking in the Finder or using the open command, not when launched in the Terminal).

ronaldoussoren commented 3 years ago

Having looked at this again it is highly unlikely that I'll work on this because (a) I don't use this library myself and (b) installing PyGObject is non-trivial (no binary wheels, loads of C library dependencies). Installing might be easier through homebrew, but that's a tool I try to avoid.