Why does cx_freeze for Python 3 packs a project into 8000+ files whereas cx_freeze for Python 2 packed the same project in 25 files?

Viewed 469

Let's say numpy_example.py is:

import numpy as np
a = np.array([1, 2, 3])
print(a)
  • With Python 2.7.9, generating an executable from this with cxFreeze 4.3.3, with:

    "C:\python27\python.exe" "C:\python27\Scripts\cxfreeze" numpy_example.py 
       --target-dir=.\cxfreeze_x64_py2 --base-name=Win32GUI 
       --target-name=test.exe --exclude-modules=Tkinter,scipy,Crypto,_ssl,bz2,_yaml 
       --include-modules=lxml._elementpath
    

    gave 25 files (only .dll, .pyd and .exe files) for a total of 71 MB, with no subfolder:

    enter image description here

  • With Python 3.7.6, generating an executable with cxFreeze 6, with the same command-line command gives a total of 8533 files for a total of 374 MB!

    In particular, there is the Lib subfolder containing many libraries unused for this project:

    enter image description here

    Also, with the Python 2 version, Numpy was packed into 9 .pyd files (and nothing else), whereas here in the Python 3 version it's split in many files and subfolders.

Question: what has changed in cx_freeze, resulting in this less efficient packing?

And how to get a similar packing with cx_freeze for Python 3 than with Python 2?

2 Answers

This seems to be the answer: it's a feature, since cx_freeze 5.0: https://cx-freeze.readthedocs.io/en/latest/releasenotes.html#version-5-0-november-2016

Added support for storing packages in the file system instead of in the zip file. There are a number of packages that assume that they are found in the file system and if found in a zip file instead produce strange errors. The default is now to store packages in the file system but a method is available to place packages in the zip file if they are known to behave properly when placed there. (Issue #73)

Linked: Cx_Freeze build is not including python libraries in zip file

As you pointed out in your own answer, this appears to be the desired functionality. There are other packages out there that can compile to a single executable.

I assume you only want to use cxfreeze, if you know which packages your program doesn't need, you can simply list all of them with the --exclude-modules flag as you have been. You can filter out packages through trial and error by building your application and then renaming the included libraries in the lib directory one by one, adding any unnecessary packages to your excludes list. I was able to reduce the numpy example from 3500~ files to ~1000 this way.

You can utilise the distutils functionality which I found easier when trying to reduce the final package size.

from cx_Freeze
import setup, Executable
import sys

build_exe_options = {
  "excludes": ["tkinter", ...your excludes here...],
  "optimize": 0
}

setup(
  name = "TestProgram",
  version = "0.1",
  description = "MyDescription",
  options = {
    "build_exe": build_exe_options
  },
  executables = [Executable("main.py",
    base = ("Win32GUI"
      if sys.platform == "win32"
      else None))]
)
py setup.py build

Finally, the cxfreeze FAQ has a question about creating a single file, although that's not what you're after, it states to use IExpress to create a self-extracting archive (or 7zip), which might be useful to you if package size is the main concern.

Related