cloudmatrix / esky

an auto-update framework for frozen python apps
BSD 3-Clause "New" or "Revised" License
363 stars 74 forks source link

PyQt, different library pathes linux/windows #102

Closed JPFrancoia closed 8 years ago

JPFrancoia commented 8 years ago

Hi again,

After I opened #101 , I realized I was doing something wrong to solve two different issues (and maybe more). My wrong solution was going to lead to a lot of troubles, but I was corrected.

However, I now have plenty of issues to fix.

So, here comes my setup.py:

if sys.platform in ['win32', 'cygwin', 'win64']:
    base = "Win32GUI"

    # Copy the sqlite driver
    my_data_files.append(('sqldrivers', ['C:\Python34\Lib\site-packages\PyQt4\plugins\sqldrivers\qsqlite4.dll']))

    FREEZER = 'cx_Freeze'
    FREEZER_OPTIONS = dict()

elif sys.platform == 'darwin':
    pass
else:
    my_data_files.append(('sqldrivers', ['/usr/lib/qt4/plugins/sqldrivers/libqsqlite.so']))
    FREEZER = 'cx_Freeze'
    FREEZER_OPTIONS = dict()

Classic, I want to use PyQt and its sqlite, so I copy the driver in the appropriate directory. When the program is bundled with esky, I have this folder on Linux and windows:

my_program/
    exe_esky
    one_lib
    libpython3.4
    my_program/
        sqldrivers/
            sqlite.lib
        exe_exe
        esky_files/

When I run my program (by launching exe_esky.......), it goes well on Linux, but not on Windows: I get the error 'driver not found' when I try to access my sqlite database. I assume the path for the driver is not set properly

['~/my_program/my_progam']
['~/my_program']

For some reason, Windows is not looking at the right place for the sql drivers.

However, adding this line in exe_esky solved the issue on Windows:

QtGui.QApplication.addLibraryPath(path_of_the_sql_drivers)

By telling the exe where to look for, the program finds the drivers.

Do you know why I get these two different behaviours ?

timeyyy commented 8 years ago

@JPFrancoia Is there an actual issue here? As per your other post,The wiki is available for anyone to edit so feel free to add something ins there if you fell information is missing.

Esky shells out to different freezers, you need to make sure that the freezing is working correctly, then you can move on to blaming esky.

Quick google search... https://www.google.de/search?q=freezing+pyqt+sqlite&ie=utf-8&oe=utf-8&gws_rd=cr&ei=2CBXVrG1JIOFPu2pspgC, first result has your answer...

JPFrancoia commented 8 years ago

Yes I think there is an issue here, but I'm not sure if Esky is to blame, you're right. I just think it is strange to modify the core code of the program to make the bundle work.

About the google search, the problem is not that it's not working, it is just that the path for the library is not set properly after bundling.

But a fix exists, so just in case one day someone has the same problem, we can reopen the issue.

timeyyy commented 8 years ago

as far as i can understand it messing around with the cx freeze settings was enough to get it working on windows

Thanks Anil, it worked just fine! Just complementing for those who face the same problem in the future, I had to copy the C:\Python26\Lib\site-packages\ PyQt4\plugins\sqldrivers dir to my frozen app target-dir. The only file needed in my case was qsqlite4.dll (which refers to QSqlite), but it has to be in a folder named ''sqldrivers'' into the target-dir for the app to work.

timeyyy commented 8 years ago

there are many edge cases with the freezers that require manual intervention, pyinstaller is preconfigured to correctly pull in those sorts of things, unfortunately we haven't go around to supporting them yet :(, it would be nice to have things work out of the box

JPFrancoia commented 8 years ago

Hum, not sure we understood each other. I didn't mess around with the cx_freeze settings.I modified the file exe_esky, my program.

The directory sqldrivers is at the right place. Running directly exe_exe, as I was doing i #101 , worrks. I have no problem with the sqldriver.

However, exe_esky tries to find the driver in the top level folder, at ['~/my_program']. I get this behaviour on windows only.

It seems the top level exe doesn't hand over to the second level exe, or some sort of stuff like that.

timeyyy commented 8 years ago

Can you confirm that your application works fine when frozen without esky (on both platforms )

JPFrancoia commented 8 years ago

I do confirm.

With this setup.py:

#!/usr/bin/python
# coding: utf-8

import sys, os
from cx_Freeze import setup, Executable

my_data_files = []

my_data_files += ['.{}images{}'.format(os.path.sep, os.path.sep)]
my_data_files += ['.{}journals{}'.format(os.path.sep, os.path.sep)]
my_data_files += ['.{}config{}'.format(os.path.sep, os.path.sep)]
my_data_files += ['.{}config{}fields{}'.format(os.path.sep, os.path.sep, os.path.sep)]

base = None
if sys.platform in ['win32', 'cygwin', 'win64']:
    base = "Win32GUI"
    my_data_files.append(('C:\Python34\Lib\site-packages\PyQt4\plugins\sqldrivers\qsqlite4.dll', 'sqldrivers\qsqlite4.dll'))
elif sys.platform == 'darwin':
    pass
else:
    my_data_files.append(('/usr/lib/qt4/plugins/sqldrivers/libqsqlite.so', 'sqldrivers/libqsqlite.so'))

excludes = [
            'test_hosts',
            'test_worker',
            'misc',
           ]

includes = [
            'sip',
            'PyQt4.QtCore',
            'PyQt4.QtGui',
            'PyQt4.QtNetwork',
            'PyQt4.QtSql',
            'scipy.special.specfun',
            'scipy.integrate.vode',
            'scipy.integrate.lsoda',
            'scipy.sparse.csgraph._validation',
            'sklearn.utils.sparsetools._graph_validation',
            'scipy.special._ufuncs_cxx',
           ]

options = {
           "includes": includes,
           "excludes": excludes,
           "include_files": my_data_files,
           }

exe = Executable("gui.py", base=base)

setup(
    name="monprogramme",
    version="1.00",
    description="monprogramme",
    options={"build_exe": options},
    executables=[exe]
    )

And using

python setup.py build

The frozen apps work great on Windows and Linux.

With this setup.py:

#!/usr/bin/python
# coding: utf-8

import sys
import os
from esky.bdist_esky import Executable
from setuptools import setup

def get_all_files_in_dir(directory):

    """Get all the files in a directory, and
    return a list bdist formatted"""

    list_files = []

    for file in os.listdir(directory):
        f1 = directory + file
        if os.path.isfile(f1):  # skip directories
            f2 = (directory, [f1])
            list_files.append(f2)

    return list_files

my_data_files = []

# Add the data in images, journals, and config
my_data_files += get_all_files_in_dir('.{}images{}'.format(os.path.sep, os.path.sep))
my_data_files += get_all_files_in_dir('.{}journals{}'.format(os.path.sep, os.path.sep))
my_data_files += get_all_files_in_dir('.{}config{}'.format(os.path.sep, os.path.sep))
my_data_files += get_all_files_in_dir('.{}config{}fields{}'.format(os.path.sep, os.path.sep, os.path.sep))

base = None
if sys.platform in ['win32', 'cygwin', 'win64']:
    base = "Win32GUI"
    # Copy the sqlite driver
    my_data_files.append(('sqldrivers', ['C:\Python34\Lib\site-packages\PyQt4\plugins\sqldrivers\qsqlite4.dll']))

    FREEZER = 'cx_Freeze'
    FREEZER_OPTIONS = dict()

elif sys.platform == 'darwin':
    pass
else:
    my_data_files.append(('sqldrivers', ['/usr/lib/qt4/plugins/sqldrivers/libqsqlite.so']))
    FREEZER = 'cx_Freeze'
    FREEZER_OPTIONS = dict()

excludes = [
            # Personal modules
            'test_hosts',
            'test_worker',
            'misc',
           ]

includes = [
            'sip',
            'PyQt4.QtCore',
            'PyQt4.QtGui',
            'PyQt4.QtNetwork',
            'PyQt4.QtSql',
            'scipy.special.specfun',
            'scipy.integrate.vode',
            'scipy.integrate.lsoda',
            'scipy.sparse.csgraph._validation',
            'sklearn.utils.sparsetools._graph_validation',
            'scipy.special._ufuncs_cxx',
           ]

build_exe_options = {
                     'bdist_esky': {
                                    'freezer_module': FREEZER,
                                    'freezer_options': FREEZER_OPTIONS,
                                    'includes': includes,
                                    'excludes': excludes,
                                   },
                     }

exe_esky = Executable("gui.py", gui_only=True)

setup(name="Test",
      version='1',
      data_files=my_data_files,
      options=build_exe_options,
      scripts=[exe_esky],
      )

The code works great on Linux, but I have no access to the sql driver on Windows.