Trying to load a third-party library with cdll:
import ctypes, os
lib_dir = '/path/to/directory/containing'
# this won't work:
#os.environ['DYLD_LIBRARY_PATH'] = lib_dir
lib = ctypes.CDLL(os.path.join(lib_dir, 'theLib.dylib'))
however the library "theLib.dylib" (dummy name) has some dependencies, which are specified relative to @executable_path
, so when loading the library from Python, @executable_path
is the path of the python3
executable and not the path of the original application itself, hence the dependent libraries are not found:
Traceback (most recent call last):
lib = lib = ctypes.CDLL(os.path.join(lib_dir, 'theLib.dylib'))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ctypes/__init__.py", line 376, in __init__
self._handle = _dlopen(self._name, mode)
^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: dlopen(/path/to/directory/containing/theLib.dylib, 0x0006):
Library not loaded: @executable_path/../Frameworks/libqscintilla2_qt5.13.dylib
Referenced from: <E0DE6A39-96C2-35A2-9F4F-1020295BB09B> /path/to/directory/containing/theLib.dylib
Reason: tried:
'/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/Resources/Python.app/Contents/Frameworks/libqscintilla2_qt5.13.dylib' (no such file),
'/usr/local/lib/libqscintilla2_qt5.13.dylib' (no such file),
'/usr/lib/libqscintilla2_qt5.13.dylib' (no such file, not in dyld cache)
With the install_name_tool
it is possible to permanently modify the library being loaded to rewrite @executable_path/../Frameworks/libqscintilla2_qt5.13.dylib
to something else, e.g. simply libqscintilla2_qt5.13.dylib
but I don't want to do that as it breaks the library for the original application.
I could symlink those dylibs inside the app bundle to /usr/local/lib, where dyld would also try to load them , but that would make a mess in my /usr/local/lib...
Are there any other options to it, e.g. remap @executable_path
to some other path on the fly (at library load-time)?
Insert the library in that dyld cache as mentioned in the dyld error?
Placing a wrapper executable in @executable_path
that simply exec()
s the target python interpreter, so that the executable path has the desired value? (probably this would break app's signature?)