PyQt5 Executable is crashing with Missing DLL

2019-07-22 19:13发布

问题:

My issue is related to a pyqt5 executable I created with pyinstaller. The only command I'm using is:

pyinstaller script.py

I'm not very experienced with Pyinstaller's output messages. So I'm posting this question in case someone else can help me figure out what the missing modules or files are.

Here is copy of the entire Compile output:

Github - Pyinstaller Output

Here is a copy of the error that appears.. it happens like in a millisecond:

Any comments or help are appreciated. If you think you have a possible solution, please attempt an answer. I'm sure its worth looking into. Hopefully, its something simple and due to my lack of knowledge.

One other note, I'm importing/using the module ibm_db and the wrapper module ibm_db_dbi.

Here is a copy of my spec file:

# -*- mode: python -*-

block_cipher = None

added_files = [
                (r'C:\Python37\Lib\site-packages\ibm_db_dlls\ibm_db.dll', '.')
              ]

a = Analysis(['InheritMainWindow.py'],
             pathex=['c:\\Python37\\PDFMaker_v3\\Prototype',
                     'C:\\Python37\\Lib\\site-packages\\',
                     'C:\\Python37\\Lib\\site-packages\\sqlalchemy\\connectors\\',
                     'C:\\Python37\\Lib\\site-packages\\clidriver\\',
                     'C:\\Python37\\Lib\\site-packages\\ibm_db_dlls',
                     'C:\\Python37\\Lib\\site-packages\\ibm_db.py'],
             binaries=[('ibm_db.dll', 'ibm_db_dlls')],
             datas=[],
             hiddenimports=['ibm_db', 'ibm_db_dbi'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='InheritMainWindow',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )

a.binaries = [x for x in a.binaries if os.path.dirname(x[1]).find("IBM") < 0]
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='InheritMainWindow')

PS you should be able to repeat the issue with the following:

import ibm_db
print('hello!')

in command prompt:

pyinstaller hello.py

Upon executing the exe inside the dist folder, you'll get the same above error.

Here is a list of the things I'm tried to resolve this:

1) Providing a full path in the binary like this:

binaries=[(r'C:\Python37\Lib\site-packages\ibm_db_dlls\ibm_db.dll', 'ibm_db_dlls')]

This makes no difference the crash still occurs. And I was already seeing the ibm_db_dlls folder appear in my dist folder. So the binary is being added, but its just not being seen.

2) From the ibm developer forum here: https://developer.ibm.com/answers/questions/448999/python-3-db2-windows-10-problems-and-script-compil/

A suggested solution was using the --clean option. I've tried this option on 'hello.py', where it only is importing the ibm_db package and it actually works as an exe. But this solution doesn't work on my main project.

Correction: This does NOT work even on the simple hello.py example.

Final update: I've provided a solution below!

回答1:

So I solved the issue. And I'm expecting this should help a lot of folks. First part of solution is the PATHEX list. I had to update this list to point to all my system's IBM directories:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['InheritMainWindow.py'],
             pathex=['c:\\Python37\\PDFMaker_v3',
                     'C:\\Python37\\Lib\\site-packages\\ibm_db_dlls',
                     'C:\\Program Files (x86)\\ibm\\gsk8\\lib', 
                     'C:\\Program Files (x86)\\ibm\\gsk8\\bin', 
                     'C:\\Program Files (x86)\\IBM Informix Client SDK\\bin', 
                     'C:\\Program Files (x86)\\IBM\\SQLLIB_01\\BIN', 
                     'C:\\Program Files (x86)\\IBM\\SQLLIB_01\\FUNCTION', 
                     'C:\\Program Files (x86)\\IBM\\SQLLIB_01\\BIN', 
                     'C:\\Program Files (x86)\\IBM\\SQLLIB_01\\FUNCTION', 
                     'C:\\Program Files (x86)\\ibm\\gsk8\\lib', 
                     'C:\\Program Files (x86)\\ibm\\gsk8\\bin', 
                     'C:\\Program Files (x86)\\IBM Informix Client SDK\\bin'],
             binaries=[(r'C:\Python37\Lib\site-packages\ibm_db_dlls\ibm_db.dll', 'ibm_db_dlls')],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='InheritMainWindow',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='InheritMainWindow')

The next part of the answer was really tricky in figuring out. Its found inside the imb_db.py file:

import os

if 'clidriver' not in os.environ['PATH']:
    os.environ['PATH'] = os.environ['PATH'] + ";" + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'clidriver', 'bin')  
def __bootstrap__():
   global __bootstrap__, __loader__, __file__
   import sys, pkg_resources, imp
   __file__ = pkg_resources.resource_filename(__name__,'ibm_db_dlls\\ibm_db.dll')
   __loader__ = None; del __bootstrap__, __loader__
   imp.load_dynamic(__name__,__file__)
__bootstrap__()

I had to update my path variable to include clidriver directory:

C:\Python37\Lib\site-packages\clidriver\bin

the imb_db.py is suppose to be adding this to the path, but its adding in in the wrong format or directory. So that the next line:

__file__ = pkg_resources.resource_filename(__name__,'ibm_db_dlls\\ibm_db.dll')

Ends up not finding the .dll file. So after making these two updates, the program runs and succesfully connects to a remote DB2 database.



回答2:

@RockAndRoleCoder Thanks for your question and answer. I had met the same situation in Windows7 Python3.7 ibm-db 3.0.1
with your hint,I think the reason is that exe can't find *.dll in clidriver\bin and ibm_db.dll, and solve it with a similar method in two steps

Frist: the same as you, add clidriver directory to system path

**\site-packages\clidriver\bin

Second pack with argument --add-binary

 Pyinstaller --add-binary **\Lib\site-packages\ibm_db_dlls\ibm_db.dll;.\ibm_db_dlls myproject.py

Then it's OK!