为何调用Fortran DLL时Python入口点需在其父目录?如何实现任意调用?
问题原因
这是Windows DLL加载机制导致的问题,和Fortran代码本身、gfortran编译方式无直接关联。Windows加载DLL时,会按固定顺序搜索依赖库:
- 当前进程的工作目录
- Windows系统目录、系统32目录等
- PATH环境变量中的目录
当你从src/entry.py运行时,进程工作目录是src,而dep1.dll、dep2.dll在wrappers目录,不在搜索路径内,因此加载foo.dll时找不到依赖。
解决方案
以下几种方法可以实现从任意位置调用该DLL:
方法1:临时修改PATH环境变量
在加载foo.dll前,将wrappers目录添加到系统PATH中,让Windows能找到依赖库。示例代码:
import os from pathlib import Path from ctypes import LoadLibrary # 假设self._dll_path是foo.dll的绝对路径Path对象 wrappers_dir = self._dll_path.parent.parent # 从lib目录向上一级到wrappers # 将wrappers目录插入PATH最前面,优先搜索 os.environ['PATH'] = str(wrappers_dir) + os.pathsep + os.environ['PATH'] # 现在加载DLL self._libHandle = LoadLibrary(str(self._dll_path))
- 优点:对进程内所有DLL加载生效,无需切换目录
- 缺点:仅修改当前Python进程的PATH,不影响系统全局设置
方法2:临时切换工作目录到wrappers
加载DLL前切换到wrappers目录,让Windows在该目录下搜索依赖,加载完成后切回原目录:
import os from pathlib import Path from ctypes import LoadLibrary # 保存原工作目录 original_cwd = os.getcwd() wrappers_dir = self._dll_path.parent.parent try: os.chdir(wrappers_dir) self._libHandle = LoadLibrary(str(self._dll_path)) finally: # 无论加载成功与否,都切回原目录 os.chdir(original_cwd)
- 优点:无需修改环境变量
- 缺点:如果DLL在运行时动态加载依赖(而非加载时静态依赖),可能再次出现找不到的问题
方法3:编译时指定依赖搜索路径(推荐)
修改gfortran的编译链接参数,让foo.dll加载时自动从父目录(wrappers)查找依赖,彻底解决路径问题。编译命令添加-Wl,-rpath,$ORIGIN/../选项:
gfortran -shared -o wrappers/lib/foo.dll your_fortran_source.f90 -Wl,-rpath,$ORIGIN/../
$ORIGIN表示当前DLL所在的目录(即wrappers/lib),$ORIGIN/../就是wrappers目录- 编译完成后,
foo.dll会自动到wrappers目录寻找dep1.dll、dep2.dll,无论Python脚本在哪个位置运行
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

