You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS下ctypes.cdll.LoadLibrary忽略LD_LIBRARY_PATH加载库失败

问题描述

我有一个依赖VLC系列动态库的C++动态库,尝试在Python中通过如下代码加载libmylib.dylib时:

import ctypes
lib = ctypes.cdll.LoadLibrary('./libmylib.dylib')

出现如下报错:

File "test.py", line 5, in <module>
    lib = ctypes.cdll.LoadLibrary('./libmylib.dylib')
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/ctypes/__init__.py", line 443, in LoadLibrary
    return self._dlltype(name)
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/ctypes/__init__.py", line 365, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: dlopen(./libmylib.dylib, 0x0006): Library not loaded: @rpath/libvlc.dylib
  Referenced from: ./libmylib.dylib
  Reason: tried: '/usr/local/lib/libvlc.dylib' (no such file), '/usr/lib/libvlc.dylib' (no such file)

目前临时解决方式是显式预加载VLC依赖库,代码如下:

import ctypes
ctypes.cdll.LoadLibrary('/Applications/VLC.app/Contents/MacOS/lib/libvlccore.dylib')
ctypes.cdll.LoadLibrary('/Applications/VLC.app/Contents/MacOS/lib/libvlc.dylib')
lib = ctypes.cdll.LoadLibrary('./libmylib.dylib')

此前尝试设置LD_LIBRARY_PATH、LIBRARY_PATH等环境变量指向VLC库所在目录,均未生效,设置的环境变量如下:

VLC_PLUGIN_PATH=/Applications/VLC.app/Contents/MacOS/plugins
LD_LIBRARY_PATH=/Applications/VLC.app/Contents/MacOS/lib/
RUN_LD_PATH=/Applications/VLC.app/Contents/MacOS/lib/
LIBRARY_PATH=/Applications/VLC.app/Contents/MacOS/lib/

测试环境信息:

  • 操作系统:macOS Monterey 12.4
  • Python版本:3.8.9

问题更新

执行如下测试命令:

DYLD_LIBRARY_PATH=/Applications/VLC.app/Contents/MacOS/lib python3 -c 'import os; print(os.environ.get("DYLD_LIBRARY_PATH"))'

输出结果为None,所有DYLD_*开头的环境变量均被完全忽略,该现象与受系统保护机制影响的Python运行时有关。


解决方案

macOS从10.11版本开始引入SIP系统完整性保护机制,会对受保护目录下的可执行文件(比如系统自带Python、CommandLineTools安装的Python)启动时清空所有DYLD_开头的环境变量,这就是环境变量设置不生效的根本原因。你之前设置的LD_LIBRARY_PATH是Linux平台的动态库搜索路径变量,macOS本身不识别。以下是三种可行方案,按推荐优先级排序:

方案1:修改自有动态库的rpath配置(最推荐,无需修改Python侧代码)

不需要在Python侧做任何预加载操作,直接把VLC库的路径写入libmylib.dylib自身的rpath搜索列表即可。

  • 如果还没编译动态库,编译时添加如下链接参数:
    -Wl,-rpath,/Applications/VLC.app/Contents/MacOS/lib
    
  • 如果动态库已经编译完成,直接用系统自带的install_name_tool工具修改已有文件即可:
    install_name_tool -add_rpath /Applications/VLC.app/Contents/MacOS/lib ./libmylib.dylib
    

修改完成后可以用如下命令验证rpath是否添加成功:

otool -l ./libmylib.dylib | grep LC_RPATH -A2

输出中能看到你添加的VLC库路径就说明配置正确,之后直接运行最基础的ctypes加载代码就可以正常找到VLC依赖,不需要预加载,也不需要设置任何环境变量。如果担心VLC安装路径不固定,可以把rpath设置为@loader_path/xxx格式的相对路径,适配不同部署环境。

方案2:Python进程内手动添加全局搜索路径(无需修改动态库,无需逐个预加载依赖)

macOS的dyld提供了运行时添加动态库搜索路径的接口,可以在加载自有库之前,先通过ctypes调用系统接口把VLC库目录加入当前进程的全局搜索列表,代码如下:

import ctypes

# 加载系统动态库接口
libsystem = ctypes.CDLL("libSystem.dylib")
# 传入RTLD_GLOBAL标志将VLC目录加入全局搜索路径
vlc_lib_dir = b"/Applications/VLC.app/Contents/MacOS/lib"
libsystem.dlopen(vlc_lib_dir, 0x2)

# 之后直接加载自有库即可,不需要单独预加载libvlc、libvlccore
lib = ctypes.cdll.LoadLibrary('./libmylib.dylib')

这种方式不需要修改原有动态库,也不需要手动逐个加载依赖,系统dyld会自动在你指定的目录下检索所有依赖项。

方案3:换用非SIP保护的Python解释器

如果不想修改动态库也不想写额外的路径添加代码,可以卸载当前CommandLineTools自带的Python,改用官网安装包、Homebrew安装的Python(安装路径不在系统受保护目录下),此时DYLD_LIBRARY_PATH环境变量就不会被系统清空,设置后可正常生效:

DYLD_LIBRARY_PATH=/Applications/VLC.app/Contents/MacOS/lib python3 test.py

注意不要加sudo执行Python命令,sudo场景下SIP同样会清空所有DYLD_*开头的环境变量。


内容的提问来源于stack exchange,提问作者aleroot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:24:15