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

Bundlin app on OSX: resources files not bundled #2460

Closed
JPFrancoia opened this issue Feb 13, 2017 · 5 comments
Closed

Bundlin app on OSX: resources files not bundled #2460

JPFrancoia opened this issue Feb 13, 2017 · 5 comments

Comments

@JPFrancoia
Copy link

Hi,

TL; DR

In my setup.spec, I have this block at the end:

    app = BUNDLE(exe,
                 name='ChemBrows.app',
                 icon=None,
                 bundle_identifier=None)

When run on OSX, I except PyInstaller to create the app ChemBrows.app. It does, but the directory ChemBrows.app/Contents/MacOs only contains the executable and 2 other files (the std lib, I think). All the libraries are missing, and should be in this directory. Copying them from the non-app-bundled directory allows the app to work properly. Is there an option to allow PyInstaller to copy all the libs here ?

Here is the long version of my setup.spec:

# -*- mode: python -*-

import os
import distutils.util

DIR_PATH = os.getcwd()
COMPILING_PLATFORM = distutils.util.get_platform()

PATH_EXE = [os.path.join(DIR_PATH, 'gui.py')]

with open('config/version.txt', 'r', encoding='utf-8') as version_file:
    version = version_file.read().strip()

if COMPILING_PLATFORM == 'win-amd64':
    platform = 'win'
    STRIP = False
elif COMPILING_PLATFORM == 'linux-x86_64':
    platform = 'nix64'
    STRIP = True
elif "macosx" and "x86_64" in COMPILING_PLATFORM:
    platform = 'mac'
    STRIP = True


block_cipher = None

added_files = [('images/*', 'images'),
               ('journals/*', 'journals'),
               ('config/data.bin', 'config'),
               ('config/regex.txt', 'config'),
               ('config/stop_words.txt', 'config'),
               ('config/tuto.txt', 'config'),
               ('config/version.txt', 'config'),
               ('config/whatsnew.txt', 'config'),
               ('config/fields/*', 'config/fields')
               ]

imports = ['packaging', 'packaging.version', 'packaging.specifiers',
           'packaging.requirements', 'sklearn.neighbors.typedefs']

excludes = ['pyi_rth_pkgres', 'pyi_rth_qt5plugins', 'lib2to3', 'runpy',
            'xmlrpc', 'doctest', 'tty', 'getopt', 'tcl', 'certifi', 'tkinter']


a = Analysis(['gui.py'],
             pathex=PATH_EXE,
             binaries=None,
             datas=added_files,
             hiddenimports=imports,
             hookspath=[],
             runtime_hooks=[],
             excludes=excludes,
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)

pyz = PYZ(a.pure, a.zipped_data,
          cipher=block_cipher)

rm_bins = ['libQtWebKit', 'libQtGui', 'libQtXmlPatterns', 'libmysqlclient',
           'libQt3Support', 'libwebp', 'libXss', 'libXft', 'libcrypto',
           'libtcl', 'libtk', 'libX11', 'libgstreamer', 'libgcrypt',
           'libQtOpenGL.so', 'libfbclient', 'libfreetype', 'libgcc_s',
           'libsqlite3', 'libQtDBus', 'libsystemd', 'libgstvideo', 'liborc',
           'libharfbuzz', 'libpcre', 'libmng', 'bncursesw', 'libgstbase',
           'libgstaudio', 'liblcms2', 'libQtSvg', 'liblapack', 'libatlas',
           'libgobject', 'libquadmath', 'libgsttag', 'libmpdec',
           'libgstpbutils', 'libxcb-glx', 'libICE', 'libQtXml',
           'libfontconfig', 'libglapi', 'libgraphite2', 'libexpat',
           'libXext', 'liblz4', 'libqdds', 'libqgif', 'libqjp2', 'libqsvg',
           'libqtga', 'libqwbmp', 'libqwebp', 'libqtiff', 'libQt5PrintSupport',
           'libunistring', 'libgnutls', 'libglib-2.0', 'libkrb5', 'libgmp',
           'libcups', 'libstdc++', '_cffi_backend', 'libQt5Svg', 'libssl',
           '_decimal']

full_tuples = []
for each_bin in a.binaries:
    for each_rm_bin in rm_bins:
        if each_rm_bin in each_bin[0]:
            full_tuples.append((each_bin[0], None, None))

a.binaries = a.binaries - TOC(full_tuples)

exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='ChemBrows',
          debug=False,
          strip=STRIP,
          upx=True,
          console=False)

coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=STRIP,
               upx=True,
               name='ChemBrows-{}-{}'.format(version, platform))

if platform == 'mac':
    app = BUNDLE(exe,
                 name='ChemBrows.app',
                 icon=None,
                 bundle_identifier=None)
@henrykironde
Copy link
Contributor

@JPFrancoia, did you manage to get this resolved? I am also having the same problem

@JPFrancoia
Copy link
Author

JPFrancoia commented Feb 15, 2017

Nope, but I found a workaround: https://github.com/chembrows/ChemBrows/blob/unstable/deploy/deploy.py

Basically, after pyinstaller has done its job, I use:

 copy_tree('dist/ChemBrows/', 'dist/ChemBrows.app/Contents/MacOS/')

This line will copy all the files (libs and resource files) that are in the non-bundled directory, into the bundled directory (the .app folder).

Note that you could also do it by hand.

In fact, it's not really a workaround. I just don't copy the files manually...

I'm really surprised PyInstaller doesn't do it alone.

@jmason86
Copy link

Are you using the --onefile option when you call pyinstaller? For example,
pyinstaller ChemBrows.py --onefile --clean —windowed

@JPFrancoia
Copy link
Author

Nope, I'm not using the onefile option. In this case, I'm almost sure it would create a big exe and put it in the right place. The bundled app would work out of the box.

But I don't want to use the onefile option. It bundles everything into a big exe, and perfs are not as good as with the onedir mode.

@raphendyr
Copy link

raphendyr commented Mar 9, 2019

Problem is in the autogenerated spec file. The bundle has exe instead of coll. So replace:

app = BUNDLE(exe,

with

app = BUNDLE(coll,

And then the relevant files are copied in the application.

Difference between --onefile and --onedir is the COLLECT object and how binaries, data and other collections are distributed between them. Checkout by inspecting spec files generated with different options. Any case, I presume the osx spec generation has a bug and always presumes one file case.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants