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

Py2app creates broken bundles with wxPython Phoenix (4.0.0 and higher) #252

Open ronaldoussoren opened 5 years ago

ronaldoussoren commented 5 years ago

Original report by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


Hi,

This afternoon I have been trying to build an application bundle with py2app, for a wxPython-based GUI. However, I kept getting an "image not found" error when starting, even though the program worked fine un-bundled.

I tried several different things across macOS 10.14 - 10.9, including rolling back to wxpython 4.0.1 and py2app 0.14 (worked previously), before realising that the dynamic library load path is wrong for the .so files under /Contents/Resources/lib/python3.x/lib-dynload/wx/:

Using otool -L, I saw that the path was, for example, @loader_path/libwx_baseu_net-3.0.0.4.0.dylib, instead of @executable_path/../Frameworks/libwx_baseu_net-3.0.0.4.0.dylib.

Changing them manually for _core.so, _adv.so and siplib.so fixed the issues, and all was fine after that. The other .so files that depend on dynamic libraries seem okay, like the ssl one, but these were not changed when packaging. It used to work with py2app 0.14, but it doesn't seem to anymore, for some unknown reason. Any ideas?

I had a look at the source code, but couldn't figure out where the issue was. I'm happy to fix and submit a pull request if you give me some pointers.

Hamish

ronaldoussoren commented 5 years ago

Original comment by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


Oh, I forgot: This was on python 3.7. I also rolled back to 3.6, but it didn't help. I would just use py2app 0.13, which used to be a good one, but it doesn't work on python 3.7 it turns out.

ronaldoussoren commented 5 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


Is this something you can reproduce with one of the wxPython examples included in the py2app repository?

ronaldoussoren commented 5 years ago

Original comment by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


Yes - Just tried it and it fails for 2.4/doodle as well as 2.5/doodle.

I saw it say "--- Skipping recipe wx ---" during the build if that's of any relevance by the way. I had a look at the recipes but I wasn't sure if it mattered. I'm using wxPython 4.0.3 installed via pip.

The same thing is happening to the same files as reported by otool -L.

ronaldoussoren commented 5 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


Great, that means I should be able to reproduce the issue on my end and that makes it easier to fix the issue.

ronaldoussoren commented 5 years ago

Original comment by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


I've been doing some more digging in the source to try and pinpoint it, and perhaps it's something to do with get_runtime_preferences() in build_app.py, but I can't see where the dylibs get their load path set.

ronaldoussoren commented 5 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


I can reproduce the issue on my machine, but haven't tried debugging it yet.

The dylib load path is set by macholib.

The code base of py2app is (sadly enough) quite complex. I have plans to do a clean rewrite (with proper unit tests, ...), but no time line on when I'll get around working on that.

ronaldoussoren commented 5 years ago

Original comment by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


Oh I'm glad, I was worried it was somehow something to do with my setup, because I wouldn't have had a clue what it was.

I thought it might be macholib. I'll keep looking when I have some spare time and try to figure it out.

ronaldoussoren commented 5 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


a quick workaround: "python setup.py py2app --packages=wx"

The problem is that py2app currently does not properly understand "@loader_path" in the dylib load path. I'll see if I can find a solution for this.

ronaldoussoren commented 5 years ago

Original comment by Hamish McIntyre-Bhatty (Bitbucket: hamishmb, GitHub: hamishmb).


Thanks, the workaround works for me as well.

ronaldoussoren commented 5 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


Issue #254 was marked as a duplicate of this issue.

ronaldoussoren commented 5 years ago

Original comment by Shunya Ishii (Bitbucket: Shunya-141, ).


I have same error with another framework.

I tried command "python3 setup.py py2app" to create app bundle, but app not worked and I had following error:

checking for any import problems
Modules not found (unconditional imports):
 * PyQt4.QImage (PyQt4.QtCore, PyQt4.QtGui)
 * PyQt4.QPixmap (PyQt4.QtCore, PyQt4.QtGui)
 * PyQt4.qRgba (PyQt4.QtCore, PyQt4.QtGui)
 * PySide.QImage (PySide.QtCore, PySide.QtGui)
 * PySide.QPixmap (PySide.QtCore, PySide.QtGui)
 * PySide.qRgba (PySide.QtCore, PySide.QtGui)
 * PySide2.QImage (PySide2.QtCore, PySide2.QtGui)
 * PySide2.QPixmap (PySide2.QtCore, PySide2.QtGui)
 * PySide2.qRgba (PySide2.QtCore, PySide2.QtGui)
 * UserDict (PIL.PdfParser)
 * _gdbm (dbm.gnu)
 * cffi (Cryptodome.Util._raw_api, PIL.Image, PIL.PyAccess)
 * cffi.FFI (PIL.Image)
 * com (com.sun.jna)
 * com.jna (com.sun)
 * com.sun (com.sun.jna.platform)
 * cv2 (pyscreeze)
 * numpy (PIL.ImageFilter, pyscreeze)
 * olefile (PIL.FpxImagePlugin, PIL.MicImagePlugin)
 * ordereddict (pkg_resources._vendor.pyparsing)
 * pathlib2 (PIL.Image)
 * six.moves (Xlib.threaded, pynput._util) [module alias]
 * six.moves._thread (pynput._util) [module alias]
 * six.moves.queue (Xlib.threaded) [module alias]
 * win32com (win32com)
 * win32com.shell (win32com.shell)
 * win32com.shellcon (win32com.shell)

Modules not found (conditional imports):
 * Image (/Users/USER_NAME/...../venv3.6.1/lib/python3.6/site-packages/py2app/recipes/PIL/prescript.py)
 * PySide (PIL.ImageQt)
 * PySide.QtCore (PIL.ImageQt)
 * PySide2 (PIL.ImageQt)
 * PySide2.QtCore (PIL.ImageQt)
 * Tkinter (PIL.ImageTk, pymsgbox)
 * cffi (PIL.ImageTk)
 * com (pkg_resources._vendor.appdirs)
 * com.sun.jna (pkg_resources._vendor.appdirs)
 * com.sun.jna.platform (pkg_resources._vendor.appdirs)
 * win32com (pkg_resources._vendor.appdirs)
 * win32com.shell (pkg_resources._vendor.appdirs)

Done!

It told me the error of PyQt4 but I used PyQt5.

Finally, I executed the broken app on terminal, I had these error:

ImportError: dlopen(/Users/USER_NAME/...../MyApp.app/Contents/Resources/lib/python3.6/lib-dynload/PIL/_imaging.so, 2): Library not loaded: @loader_path/.dylibs/libjpeg.9.dylib
  Referenced from: /Users/USER_NAME/...../MyApp.app/Contents/Resources/lib/python3.6/lib-dynload/PIL/_imaging.so
  Reason: image not found
hamishmb commented 4 years ago

As noted by Yanone (#254), symlinks can be used to fix this. Below are the commands I use as a workaround.

cd dist/.app/Contents/Resources/lib/python3.8/lib-dynload/wx ln -s ../../../../../Frameworks/libwx_baseu-3.0.0.4.0.dylib ./ ln -s ../../../../../Frameworks/libwx_baseu_net-3.0.0.4.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_adv-3.0.0.4.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_core-3.0.0.4.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_stc-3.0.0.4.0.dylib ./ cd -

Hopefully this is useful to someone else too :)

hamishmb commented 3 years ago

NB: This fix can be modified for wxPython 4.1.x with wxWidgets 3.1.x as so:

cd dist/<appdir>/Contents/Resources/lib/python3.8/lib-dynload/wx ln -s ../../../../../Frameworks/libwx_baseu-3.1.5.0.0.dylib ./ ln -s ../../../../../Frameworks/libwx_baseu_net-3.1.5.0.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_adv-3.1.5.0.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_core-3.1.5.0.0.dylib ./ ln -s ../../../../../Frameworks/libwx_osx_cocoau_stc-3.1.5.0.0.dylib ./ cd -

But there are other issues with wxPython 4.1.x, even with this fix. I will report these shortly.

hamishmb commented 2 years ago

Okay, with current py2app, wxPython 4.1.1, and Python 3.9 (highest supported by wxPython as of right now), this workaround is no longer needed, and dark mode works too. I would close this but I cannot.