coin-or / python-mip

Python-MIP: collection of Python tools for the modeling and solution of Mixed-Integer Linear programs
Eclipse Public License 2.0
527 stars 92 forks source link

PyInstaller does not bundle CBC libraries #76

Closed pgoelz closed 2 years ago

pgoelz commented 4 years ago

I put the following example script into test.py:

from mip import *
m = Model(sense=MAXIMIZE, solver_name=CBC)
v1 = m.add_var(var_type=BINARY)
v2 = m.add_var(var_type=BINARY)
m.add_constr(v1 + v2 == 1)
m.objective = 2 * v1 + 3 * v2
m.optimize()
print(v1.x, v2.x)

When running pyinstaller test.py, everything compiles without warning, but the binary will crash on execution with the following error:

Using Python-MIP package version 1.7.3
cbc not found
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    m = Model(sense=MAXIMIZE, solver_name=CBC)
  File "mip/model.py", line 101, in __init__
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "/usr/local/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 623, in exec_module
    exec(bytecode, module.__dict__)
  File "mip/cbc.py", line 455, in <module>
NameError: name 'cbclib' is not defined
[30415] Failed to execute script test

I narrowed down the problem to pyinstaller not recognizing the imports of the libraries in mip/libraries, and not copying them along into the executable. For these cases, pyinstaller has a hook mechanism. I wrote the following text to a file hook-mip.py in the same directory:

import os
from PyInstaller.utils.hooks import get_package_paths

datas = []
_, mip_path = get_package_paths("mip")
lib_path = os.path.join(mip_path, "libraries")

for f in os.listdir(lib_path):
    if f.endswith(".so") or f.endswith(".dll") or f.endswith(".dylib"):
        datas.append((os.path.join(lib_path, f), "mip/libraries"))

If I then run pyinstaller --clean --additional-hooks-dir=. test.py, the binary runs correctly. I intend to make a pull request at pyinstaller, and will reference this issue.

sebheger commented 2 years ago

Duplicate to #198