社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

如何在Windows上正确定位Python中C扩展模块的DLL依赖关系?

Daniel • 3 年前 • 515 次点击  

我正在使用PyBind11为Python开发一个C++扩展。我的扩展依赖于CGAL,它依赖于MPFR和GMP。CGAL只是头文件,所以没有问题,但MPFR和GMP编译到共享库(Windows上的DLL文件)。

每种操作系统上的一切都可以编译和链接。在Windows上,我必须提供 CMAKE_PREFIX_PATH CMake的选项,以帮助它找到库的位置(在我的例子中,这些库是通过Miniconda安装的,所以它们位于 C:\Miniconda3\Library ),从而正确定位CGAL、GMP和MPFR。在编译和链接之后,Linux和Mac上的一切都运行良好,但在Windows上,出现了一个问题。简单地说,当我试图用Python导入扩展模块时,我遇到了错误

ImportError: DLL load failed while importing <mylibrary>: The specified module could not be found.

我知道这个错误意味着我的扩展所依赖的DLL(在本例中是MPFR和GMP)无法定位。如果我将包含这些DLL的目录添加到我的路径中,我希望这可以解决问题,但根据我读到的几篇文章,Python显然不再在路径中搜索DLL( example 1 , example 2 , example 3 , python docs ).相反,我们应该打电话 os.add_dll_directory() 告诉Python在哪里可以找到DLL。这对我来说毫无意义,因为作为库作者,我不知道,也不认为我应该依赖于用户决定安装库的位置。

例如,用户可能手动安装MPFR,也可能通过Conda或VCPKG安装MPFR,谁知道呢。每一个都会把它放在一个完全不同的位置,我不知道。在我的Python模块中,我怎么知道在哪里可以找到这些库呢?

This question 非常相似,但是DLL是与库源代码打包的,所以它们的位置很明显,而且 操作系统。添加_dll_目录() 这是一个明智的解决方案。在我的例子中,我依赖于用户可以在任何地方安装的外部DLL。

我将列举我迄今为止找到的次优解决方案。它们都不是特别好。

解决方案1 为了证实我的怀疑,即这些是找不到的库,我可以通过手动将相关的DLL文件复制到与编译的扩展模块相同的目录中来解决问题。当然,这个解决方案是手动的,不健壮,每次我进行新构建时都必须这样做。它也不是一个很好的解决方案,必须向想要编译我的库的用户描述。

解决方案2 在构建库的轮子时,我找到了Python脚本 delvewheel ,它会搜索控制盘所依赖的DLL并将它们添加到控制盘中(它实际上会找到DLL,因为它查看路径!!!)在分发控制盘的情况下,这似乎解决了问题,这很好,但在用户希望在本地手动编译和测试我的库的情况下,这没有帮助,除非他们也完成了构建控制盘的步骤,使用delvewheel修复它,然后安装它,这对本地开发/测试工作流没有意义。

解决方案3 我可以将DLL文件的位置硬编码为调用 操作系统。添加_dll_目录() .这是可行的,但当然,这很糟糕,因为这取决于我在哪里安装了它们!显然不适合将代码分发给其他人。

解决方案4 我可以要求用户指定一个指向DLL位置的特殊环境变量,然后将该环境变量的值传递给 操作系统。添加_dll_目录() 。这意味着用户每次要运行我的库时都必须指定一个特殊的环境变量。不太好。此外,如果多个依赖项位于不同的位置,它也不会起作用。

解决方案5 我还可以解析路径并将其中的每个位置传递给 操作系统。添加_dll_目录() ,就像这样。

if "add_dll_directory" in dir(os):
  for d in os.environ['path'].split(';'):
    if os.path.isdir(d):
      os.add_dll_directory(d)

这是可行的,但它似乎绕过了Python的全部目的,即不查看路径并使用 操作系统。添加_dll_目录() 首先。这有什么问题吗?这个 python changelog 这似乎表明安全性可能是一个问题?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/132905