R加载gfortran编译的Fortran DLL报错:符号名不在加载表中
解决R调用gfortran编译的Fortran DLL无法识别符号的问题
我之前折腾过R和Fortran交互的坑,看你的情况,核心问题出在你用了Intel Fortran的专属编译指令!DEC$,但实际用gfortran编译——gfortran完全不识别这些指令,导致你的子例程根本没被导出到DLL里,而且你要检查的是子例程名sr1/sr2,不是DLL文件名test,这才是is.loaded返回False的关键。
下面是分步解决方法:
1. 修改Fortran代码,适配gfortran的符号导出规则
把原来的Intel指令换成gfortran支持的bind(C)属性,同时使用iso_c_binding模块保证类型匹配(R和C的类型对应更严谨)。修改后的test.f90代码如下:
use, intrinsic :: iso_c_binding ! Computes the square of a number subroutine sr1(a, b) bind(C, name='sr1') implicit none integer(c_int), intent(in) :: a integer(c_int), intent(out) :: b b = a * a end subroutine sr1 ! Computes the cube of a number subroutine sr2(x, y) bind(C, name='sr2') implicit none integer(c_int), intent(in) :: x integer(c_int), intent(out) :: y y = x * x * x end subroutine sr2
bind(C, name='sr1'):强制子例程使用C风格的符号命名,避免gfortran默认的名字修饰(比如加下划线),让R能准确找到符号。integer(c_int):匹配C语言的int类型,和R中的integer类型对应,避免类型不兼容。intent(in/out):明确参数的输入输出属性,让编译器优化同时避免潜在的内存问题。
2. 重新编译DLL(gfortran命令)
在Windows命令行中执行以下编译命令(确保gfortran在系统PATH里):
gfortran -shared -o test.dll test.f90
-shared:告诉编译器生成动态链接库(DLL)而不是可执行文件。- 重点:如果你的R是64位版本,必须用64位的gfortran编译,否则会出现加载失败或者位数不匹配的问题。
3. 在R中正确调用子例程
加载DLL后,检查子例程的符号(不是DLL文件名),然后用.Fortran()调用:
# 加载DLL(替换成你的实际文件路径) dyn.load("C:/your_folder/test.dll") # 检查子例程是否加载成功 is.loaded("sr1") # 正常应该返回TRUE is.loaded("sr2") # 正常应该返回TRUE # 调用sr1计算平方 result_sr1 <- .Fortran("sr1", a = as.integer(5), b = integer(1)) cat("5的平方是:", result_sr1$b, "\n") # 调用sr2计算立方 result_sr2 <- .Fortran("sr2", x = as.integer(4), y = integer(1)) cat("4的立方是:", result_sr2$y, "\n") # 用完记得卸载DLL dyn.unload("C:/your_folder/test.dll")
- 注意:
.Fortran()要求参数必须是R的原生类型,所以要用as.integer()把数值转成整数类型,输出参数要预先分配空间(比如integer(1))。
常见排查点
- 检查gfortran和R的位数是否一致:打开R输入
.Machine$sizeof.pointer,如果返回8就是64位,gfortran也要用64位版本(比如MinGW-w64的gfortran)。 - 确保DLL路径正确:可以用
file.exists("your_path/test.dll")检查文件是否存在。 - 如果还是有问题,用
nm test.dll(需要MinGW的nm工具)查看DLL里的导出符号,确认sr1和sr2是否在列表里。
内容的提问来源于stack exchange,提问作者khajlk
相关产品推荐
相关产品推荐

