Numpy 2.3.2下f2py链接多文件Fortran77代码失败求助
问题背景
原Fortran77代码「NSCool」通过f2py编译为Python包,在Python3.7下运行正常,适配Python3.12后升级至Numpy 2.3.2出现编译/导入失败问题。运行环境为MacOS Ventura 13.7.6,已通过Macports安装gfortran14、Python3.12及相关依赖。
以下针对三种编译方式分别给出问题分析与修复方案:
版本A:直接链接所有依赖目标文件
问题分析
导入时报错symbol not found in flat namespace '_accretion_rate',且nm命令无法在最终.so文件中找到该符号,核心原因是f2py命令中文件顺序错误:链接器按顺序处理符号,主程序文件NSCool_2.f需放在依赖目标文件之后,否则无法正确解析依赖库中的符号。
修复方案
修改Makefile中NSCool_Py_A的规则,将依赖目标文件$(DEPENDS)移至主程序文件前:
NSCool_Py_A: NSCool_2.f $(DEPENDS) $(F2PY) -c -m NSCool_Py_A $(DEPENDS) NSCool_2.f \ --f77exec=$(COMPILER) \ --f77flags="$(OPTIONS)" \ --include-paths=$(CODE_DIR) @echo "This is NSCool_Py_A"
编译完成后,执行nm -gU NSCool_Py_A.cpython-312-darwin.so | grep _accretion_rate,若能看到该符号则说明修复成功,即可正常导入测试。
版本B:链接静态库
问题分析
导入时报错dynamic module does not define module export function (PyInit_NSCool_Py_B),但nm能找到该符号,原因包括:
--f77flags中库名写错(应为-lNSCool_lib_stat而非-lNSCool_lib)- 静态库符号未被强制加载,导致部分符号丢失
修复方案
修正库名并添加强制加载静态库符号的参数:
NSCool_Py_B: NSCool_2.f NSCool_lib_stat $(F2PY) -c -m NSCool_Py_B NSCool_2.f \ --include-paths=$(CODE_DIR) \ --f77exec=$(COMPILER) \ --f77flags="$(OPTIONS) -L$(COMPILER_LIB) -lgfortran -L$(CODE_DIR) -lNSCool_lib_stat" \ --link-flags="-bundle -undefined dynamic_lookup -Wl,-force_load,$(CODE_DIR)/libNSCool_lib_stat.a" @echo "This is NSCool_Py_B"
版本C:链接动态库
问题分析
导入时报错符号_accretion_rate在动态库中存在但无法找到,原因是错误使用了仅适用于静态库的-force_load参数,干扰了动态库的符号解析逻辑。
修复方案
移除-force_load参数,保留正确的rpath设置:
NSCool_Py_C: NSCool_2.f NSCool_lib_dyn $(F2PY) -c -m NSCool_Py_C NSCool_2.f \ --f77exec=$(COMPILER) \ --include-paths=$(CODE_DIR) \ -L$(CODE_DIR) -lNSCool_lib_dyn \ --link-options="-bundle -undefined dynamic_lookup -Wl,-rpath,@loader_path" @echo "This is NSCool_Py_C"
内容的提问来源于stack exchange,提问作者Dany Page

