Originally posted by jhoekx December 14, 2022
We were trying to use cx_Freeze to generate a Windows .exe that includes the sklearn
module. Quite a few workaround were needed.
(venv) PS > pip freeze
cx-Freeze==6.13.1
joblib==1.2.0
lief==0.12.3
numpy==1.23.5
packaging==22.0
scikit-learn==1.2.0
scipy==1.9.3
threadpoolctl==3.1.0
example.py
:
import sklearn
def run():
print("OK")
if __name__ == "__main__":
run()
setup.py
:
from cx_Freeze import Executable, setup
setup(
name="example",
version="0.1",
description="sklearn",
executables=[Executable("example.py")],
options={
"build_exe": {
"include_msvcr": True,
},
}
)
Running this fails with:
File "C:\Users\<>\source\freeze-sklearn\venv\lib\site-packages\sklearn\__init__.py", line 80, in <module>
from . import _distributor_init # noqa: F401
File "C:\Users\<>\source\freeze-sklearn\venv\lib\site-packages\sklearn\_distributor_init.py", line 21, in <module>
WinDLL(op.abspath(vcomp140_dll_filename))
File "C:\Users\<>\AppData\Local\Programs\Python\Python310\lib\ctypes\__init__.py", line 374, in __init__
self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module 'C:\Users\<>\source\freeze-sklearn\build\exe.win-amd64-3.10\lib\sklearn\.libs\vcomp140.dll' (or one of its dependencies). Try using the full path with constructor syntax.
This happens because the failing module sklearn._distributor_init
contains:
import os
import os.path as op
from ctypes import WinDLL
if os.name == "nt":
libs_path = op.join(op.dirname(__file__), ".libs")
vcomp140_dll_filename = op.join(libs_path, "vcomp140.dll")
msvcp140_dll_filename = op.join(libs_path, "msvcp140.dll")
WinDLL(op.abspath(vcomp140_dll_filename))
WinDLL(op.abspath(msvcp140_dll_filename))
These files are not included by cx_Freeze
.
Forcing them in include_files
does not work either, because they are in the C runtime files and are as such not copied.
The workaround we used was to monkey patch the offending module out of existence:
import sys
import types
sys.modules["sklearn._distributor_init"] = types.ModuleType("mock")
That is not sufficient to make the example work though. This fixes the exception above, but sklearn
includes scipy
, which has two problems: 2 packages should be included and we need to copy over another DLL.
The final working example.py
is:
import sys
import types
sys.modules["sklearn._distributor_init"] = types.ModuleType("mock")
import sklearn
def run():
print("OK")
if __name__ == "__main__":
run()
And setup.py
:
from cx_Freeze import Executable, setup
setup(
name="example",
version="0.1",
description="sklearn",
executables=[Executable("example.py")],
options={
"build_exe": {
"include_msvcr": True,
"packages": [
"scipy.optimize",
"scipy.integrate",
],
"include_files": [
('venv/Lib/site-packages/scipy.libs', 'lib/scipy.libs'),
],
},
}
)
Would you consider any of these worthy of opening an issue for? Or is there a better solution?