When trying to freeze a script which imports any distutils module (for example, distutils.dist), the script fails at runtime with an exception like this:
> from distutils import dist, sysconfig
E ImportError: cannot import name dist(In my case, the error was raised by matplotlib, which tries to import distutils.dist).
The problem is easy to reproduce:
$ virtualenv myenv
$ source myenv/bin/activate
$ pip install cx_freeze# contents of setup.py
from cx_Freeze import setup, Executable
build_exe_options = {}
setup(
name="foo",
version="0.1",
description="My app",
options={"build_exe": build_exe_options},
executables=[Executable("foo_main.py", base=None)],
)# contents of foo_main.py
import distutils.dist$ python setup.py buildRunning the produced executable should raise the same error (tested with cx-freeze 4.3.4).
This problem happens because distutils does not install all its modules into the virtualenv, it only creates a package with some magic code in the __init__ file to import its submodules dynamically. This is a problem to cx-freeze's static module analysis, which complains during the build command that it can't find distutils modules.
The workaround used was to tell cx-freeze to exclude distutils and add the package from the original interpreter (not from the virtualenv) manually.
# contents of setup.py
from cx_Freeze import setup, Executable
import distutils
import opcode
import os
# opcode is not a virtualenv module, so we can use it to find the stdlib; this is the same
# trick used by distutils itself it installs itself into the virtualenv
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
build_exe_options = {'include_files': [(distutils_path, 'distutils')], "excludes": ["distutils"]}
setup(
name="foo",
version="0.1",
description="My app",
options={"build_exe": build_exe_options},
executables=[Executable("foo_main.py", base=None)],
)
THANKS A LOT !