如何使用新版f2py编译旧Fortran模块?
错误原因分析
- 新版f2py的符号导出规则变更:旧版f2py默认会导出Fortran模块内的所有子程序,而NumPy 1.26.4附带的f2py默认只导出模块中显式声明为
public的子程序,或在f2py接口文件(.pyf)中指定的子程序。如果unknown_subroutine是模块内的私有子程序,或未被f2py明确标记为需要导出,就会触发找不到符号的错误。 - 编译器符号可见性限制:新版gfortran默认的符号可见性设置更严格,若编译时未指定合适的选项,模块内的子程序可能无法被动态库正确导出。
- 旧编译指令兼容性问题:原Makefile中的f2py命令格式可能不符合新版要求,比如缺少显式指定模块、子程序的参数,导致f2py无法正确识别需要包装的符号。
修复步骤
检查Fortran模块的子程序访问权限
打开mod_spatialaverage模块代码,确保需要被Python调用的unknown_subroutine被声明为public。在模块开头添加:public :: unknown_subroutine如果该子程序仅为模块内部使用,那可能是代码或f2py配置错误地尝试导出它,需排查调用逻辑或f2py配置。
使用f2py接口文件显式指定导出内容
生成并编辑f2py接口文件(.pyf),明确告诉f2py要包装的模块和子程序:- 先生成模板接口文件:
f2py -m your_module_name mod_spatialaverage.f90 -h your_module_name.pyf - 打开生成的
your_module_name.pyf,在module mod_spatialaverage块内添加unknown_subroutine的声明(需匹配Fortran中的参数定义),示例:python module your_module_name interface module mod_spatialaverage subroutine unknown_subroutine(arr, result, n) real, intent(in) :: arr(:,:) real, intent(out) :: result(:) integer, intent(in) :: n end subroutine unknown_subroutine # 其他需要导出的子程序也一并添加 end module mod_spatialaverage end interface end python module your_module_name - 用接口文件重新编译:
f2py -c --fcompiler=gfortran your_module_name.pyf mod_spatialaverage.f90
- 先生成模板接口文件:
调整编译选项与Makefile
更新Makefile中的编译命令,确保gfortran生成位置无关代码(动态库必需),并适配新版f2py:FC = gfortran FFLAGS = -c -fPIC F2PY = f2py F2PYFLAGS = --fcompiler=gfortran your_module_name.so: mod_spatialaverage.o $(F2PY) $(F2PYFLAGS) -c -m your_module_name mod_spatialaverage.o mod_spatialaverage.o: mod_spatialaverage.f90 $(FC) $(FFLAGS) $<核对子程序名称大小写
新版f2py对Fortran符号的大小写处理更严格,检查Python代码中调用的子程序名与Fortran模块中的定义是否完全一致(包括大小写),避免因大小写不匹配导致符号查找失败。
内容的提问来源于stack exchange,提问作者msi_gerva
相关产品推荐
相关产品推荐

