0

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?)

fferri
  • 18,285
  • 5
  • 46
  • 95

0 Answers0