12

This has come up quite a few times on the cx_Freeze mailing lists

(see

cx_Freeze and moving files around

Creating fewer files when freezing a Python application

cx_freeze python single file? )

and it seems to me like it ought to be a simple fix, but I can't see how to begin.

I have a python application that depends on scipy, wxpython, numpy and a bunch of other packages that each have a LOT of dynamically linked libraries. The main executable folder gets very cluttered with PYD and DLL files and it is hard to even find the executable amongst all the files. My users are not particularly computer savvy, so clarity is very important.

I don't require a single executable like can theoretically be generated by bbfreeze. I like how the distutils setup.py file works with cx_Freeze and in every other way cx_Freeze is pretty much brilliant.

All I want is a way to clean up the main executable folder. I would be completely happy with manually moving the DLL files into a freeze_libs folder or something and then munging the shared library loading path to help it find the dynamic libraries if that is possible. Or something like that.

Thanks

Community
  • 1
  • 1
ibell
  • 1,070
  • 8
  • 29
  • Have a look at the [ConsoleSetLibPath](https://bitbucket.org/anthony_tuininga/cx_freeze/src/default/cx_Freeze/initscripts/ConsoleSetLibPath.py) initscript. It should be possible to tweak that to look for libraries in a subfolder. – Thomas K Jan 08 '14 at 17:26
  • How do you use that initscript? It looks very promising but I don't see how to integrate it. – ibell Jan 08 '14 at 20:01
  • If you're using a setup.py script, specify an `init_script` option for `build_exe` ([docs](http://cx-freeze.readthedocs.org/en/latest/distutils.html#build-exe)). Or if you're using the `cxfreeze` command, there's a [--init-script flag](http://cx-freeze.readthedocs.org/en/latest/script.html#cmdoption--init-script). – Thomas K Jan 08 '14 at 22:43

2 Answers2

3

I understand your frustration. What I tend to do is take the entire build folder and move it to the program files directory assuming you are using a windows machine. Then create a shortcut on the desktop to the executable. I then generally change the icon to something pleasing to the eye. In other words all the system files are hidden and all you are left with is a single nice looking icon on the desktop.

Denis Priebe
  • 2,640
  • 1
  • 23
  • 33
3

"manually" did it , but is this the correct way ? i'm on win7 x64 cx_freeze 4.3.2

my init_script, combined from Console.py and ConsoleSetLibPath.py

import encodings
import os
import sys
import warnings
import zipimport

paths = os.environ.get("LD_LIBRARY_PATH", "").split(os.pathsep)
if DIR_NAME not in paths:
    paths.insert(0, DIR_NAME)
    os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(paths)
    os.execv(sys.executable, sys.argv)

sys.frozen = True
sys.path = sys.path[:4]

# i added this line
sys.path.append(r'lib')

os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")

m = __import__("__main__")
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)

# The following if/else is copied from ConsoleSetLibPath.py
if INITSCRIPT_ZIP_FILE_NAME != SHARED_ZIP_FILE_NAME:
    moduleName = m.__name__
else:
    name, ext = os.path.splitext(os.path.basename(os.path.normcase(FILE_NAME)))
    moduleName = "%s__main__" % name

code = importer.get_code(moduleName)
exec code in m.__dict__

versionInfo = sys.version_info[:3]
if versionInfo >= (2, 5, 0) and versionInfo <= (2, 6, 4):
    module = sys.modules.get("threading")
    if module is not None:
        module._shutdown()

Then i save this file in C:\Python27\Lib\site-packages\cx_Freeze\initscripts as ConsoleSetLibPathx.py and in my setup.py

setup(
    name = 'xxx',
    version = '0.1',
    options = {'build_exe': {'includes':includes,
                             'excludes':excludes,
                             'packages':packages,
                             'include_files':includefiles,
                             'create_shared_zip':True,
                             'include_in_shared_zip':True,
                              # use the "hacked" init_script ?
                             'init_script':'ConsoleSetLibPathx',
                             'include_msvcr':True,
                             }

                             }, 
    executables = [exe]
)

# Am i supposed to do the mkdir lib , and copy *.pyd *.dll into it in the end of this setup.py here? 
# I verified this is working by manually creating lib dir and copy all files inside, it works.

i feel i should do it in the options, or somewhere, but don't quite understand the cx_freeze doc right now. maybe --target-dir or --default-path or --replace-paths ? not sure how to use them

edit: sorry this needs improving, when i test this in another clean win7 in vmware, it's working but it's acting weird, my code of non-blocking read keypress is not working. not sure which part is wrong.

Shuman
  • 3,914
  • 8
  • 42
  • 65
  • No, I don't think there's an option to do this without editing the initscript at present. – Thomas K Mar 09 '14 at 19:17
  • By the way, in the section at the top modifying `LD_LIBRARY_PATH`, I think you may need to change the line `paths.insert(0, DIR_NAME)` to `paths.insert(0, os.path.join(DIR_NAME, 'lib'))`. That only affects Unix systems, though. For Windows, I think you may need to add the same directory to the `PATH` environment variable. – Thomas K Mar 09 '14 at 19:23
  • Where is `DIR_NAME` coming from? I am getting a an error on the line `os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(paths)` because the value is too long. This seems strange, because on Windows this should be `lib`, three characters. – Marshall Davis Oct 17 '15 at 23:09
  • I can only get initscript to work like this: `Executable(..., initScript='foo')` In the latest version of cx_Freeze – Bryce Guinta Aug 03 '17 at 19:34