I've got a Python 2.7 program that imports win32clipboard
. I tried to freeze it with cx_Freeze 4.2.3 on Windows XP SP3 32-bit, to create an installation MSI. I made a setup.py
according to the cx_Freeze documentation, and used the following command:
c:\python27\python.exe setup.py bdist_msi
When I run it on another PC that doesn't have Python 2.7 installed, I get an exception on the line that imports win32clipboard
:
ImportError: DLL load failed: The specified module could not be found.
I can see that win32clipboard.pyd
is being included in the build.
What dependency is missing, and how can I ensure it is included?
I eventually figured that win32clipboard.pyd
is being included, however, win32clipboard.pyd
depends on pywintypes27.dll
, which cx_Freeze is not copying from c:\windows\system32
.
The short-term hack is to manually copy c:\windows\system32\pywintypes27.dll
into build\exe.win32-2.7
, then run setup.py bdist_msi
again.
An improved hack is to use the following in the setup.py:
import os
import sys
import win32api
...
pywintypes_dll = 'pywintypes{0}{1}.dll'.format(*sys.version_info[0:2]) # e.g. pywintypes27.dll
build_exe_options = {..., "include_files": [ (os.path.join(win32api.GetSystemDirectory(), pywintypes_dll), pywintypes_dll)]}
...
setup( ...,
options = { 'build_exe': build_exe_options,
...,
},
...)
(It would be preferable for cx_Freeze to be improved to automatically detect the pywintype27.dll
dependency, but I guess that's always a work-in-progress.)
cx_Freeze uses a hooking mechanism to handle this sort of situation. The hooks are stored in the module cx_Freeze.hooks
. Each hook is named after the action being investigated, load or missing, and the module name. The module itself provides lots of examples.
Here is how you'd handle the win32clipboard module:
from cx_Freeze import hooks
def load_win32clipboard(finder, module):
finder.IncludeModule("pywintypes")
hooks.load_win32clipboard = load_win32clipboard
...
Now when cx_Freeze encounters win32clipboard, it will also include pywintypes. cx_Freeze already has a pywintypes hook that will copy the appropriate file.