从 Python 3.7.6 切换到 Python 3.10.3 后未找到 DLL

DLL not found after switching from Python 3.7.6 to Python 3.10.3

我正在尝试将库升级到 Python 3.10。到目前为止,我一直在使用3.7.6.

在我的库中,我使用的是 DLL。在包 __init__.py 中,我将 DLL 路径添加到 PATH 变量中。因为我想让代码兼容 32 位和 64 位系统,所以我在运行时检查位数并将适当的 DLL 文件夹添加到 PATH:

import os
import sys

# Add libs to PATH environment variable such that DLLs can be loaded.
# Load either x64 or x86 depending on whether we are running a 32/64
# bit system.
package_directory = os.path.dirname(os.path.abspath(__file__))
if sys.maxsize > 2**32:
    path_dir = os.path.join(package_directory, 'libs', 'x64')
else:
    path_dir = os.path.join(package_directory, 'libs', 'x86')

os.environ['PATH'] += os.pathsep + path_dir

对应的文件夹结构为

package_root
|- libs
   |- x64
      |- libbristolpolled.dll
      ...
   |- x86
      |- libbristolpolled.dll
      ...

然后在子包中,我使用:

from ctypes import CDLL

dll = "libbristolpolled.dll"
_lib_bristlp = CDLL(dll)

这在 3.7.6 中运行良好,但在 3.10.3 中失败并出现以下错误消息:

  File "C:\...\lib\site-packages\optoMD\sensor\optical\bristol\dll_api.py", line 37, in <module>
    _lib_bristlp = CDLL(dll)  # The correct DLL
  File "C:\Program Files\Python310\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module 'libbristolpolled.dll' (or one of its dependencies). Try using the full path with constructor syntax.

如果我改用绝对路径,正如错误消息所暗示的那样,它会起作用:

from ctypes import CDLL

dll = r"C:\...\libs\x64\libbristolpolled.dll"
_lib_bristlp = CDLL(dll)

旧方法不再起作用的原因是什么,或者我怎样才能让它再次起作用?我不希望在我的代码中有绝对路径,我喜欢这样的事实,我在初始化文件中处理一次 DLL 路径,然后我只需要使用文件名导入 DLL。

这个特殊的功能(通过在PATH环境变量中添加一个.dll的路径来查找)has been removed in Python 3.8. As per the notice, the new function os.add_dll_directory提供;引用文档了解更改原因:

New in version 3.8: Previous versions of CPython would resolve DLLs using the default behavior for the current process. This led to inconsistencies, such as only sometimes searching PATH or the current working directory, and OS functions such as AddDllDirectory having no effect.

未来更便携的解决方案是尝试使用该功能,或者像您当前在 dll 变量上使用 os.path.dirnameos.path.join 那样生成绝对路径- 即保持与先前 Python 版本的兼容性;这也假设那些 .dll 文件没有外部依赖性,如果有,this thread 有关于手头问题的更多细节(即使有绝对路径 - 尽管它似乎确实适用于你的程序和库,这对你的用例来说应该不是问题。