什么是未定义的引用/未解决的外部符号错误?如何在Fortran中修复它?
我正在尝试构建一个Fortran程序,但是我得到了关于未定义引用或未解析外部符号的错误。我已经看过这些错误,但是答案大多是针对C++的。 使用Fortran编写时,这些错误的常见原因是什么?如何修复/防止它们?不链接库什么是未定义的引用/未解决的外部符号错误?如何在Fortran中修复它?,fortran,linker-errors,undefined-reference,unresolved-external,Fortran,Linker Errors,Undefined Reference,Unresolved External,我正在尝试构建一个Fortran程序,但是我得到了关于未定义引用或未解析外部符号的错误。我已经看过这些错误,但是答案大多是针对C++的。 使用Fortran编写时,这些错误的常见原因是什么?如何修复/防止它们?不链接库 未定义引用/未解析外部符号错误最常见的原因是未能链接提供符号的库(通常是函数或子例程) 例如,当使用BLAS库中的子例程(如DGEMM)时,必须在链接步骤中使用提供该子例程的库 在最简单的用例中,链接与编译相结合: gfortran my_source.f90 -lblas -
未定义引用
/未解析外部符号
错误最常见的原因是未能链接提供符号的库(通常是函数或子例程)
例如,当使用BLAS库中的子例程(如DGEMM
)时,必须在链接步骤中使用提供该子例程的库
在最简单的用例中,链接与编译相结合:
gfortran my_source.f90 -lblas
-lblas
告诉链接器(这里由编译器调用)链接libblas
库。它可以是动态库(.so、.dll)或静态库(.a、.lib)。
请注意,库的名称可以不同,因为BLAS有多个实现(MKL、OpenBLAS、GotoBLAS等)。
但是它总是从lib…
缩短为l…
,就像liopenblas.so
和-lopenblas
一样
当链接和编译分离时,在链接步骤中链接库:
gfortran -c my_source.f90 -o my_source.o
gfortran my_source.o -lblas
类似于这些消息的链接时间错误的原因可能与链接器的更一般用途的原因相同,而不仅仅是编译了Fortran程序。其中有些内容涉及到C++链接,这里没有指定库,或者提供错误的顺序。 然而,在编写Fortran程序时,有一些常见的错误会导致链接错误 不支持的本质 如果子例程引用旨在引用内在子例程,那么如果编译器未提供该子例程内在,则可能导致链接时间错误:它被视为外部子例程
implicit none
call unsupported_intrinsic
end
如果编译器未提供不受支持的\u intrinsive
,我们可能会看到如下链接错误消息
undefined reference to `unsupported_intrinsic_'
undefined reference to `main'
如果我们使用的是非标准的,或者不是通常实现的,我们可以通过以下两种方式帮助我们的编译器报告这一点:
implicit none
intrinsic :: my_intrinsic
call my_intrinsic
end program
如果my_intrinsic
不是受支持的内部版本,则编译器将发出一条有用的消息:
Error: ‘my_intrinsic’ declared INTRINSIC at (1) does not exist
内在函数没有这个问题,因为我们使用的是隐式none
:
implicit none
print *, my_intrinsic()
end
对于某些编译器,我们可以使用Fortran 2018隐式
语句对子例程执行相同的操作
implicit none (external)
call my_intrinsic
end
外部程序而不是模块程序
正如我们可以尝试在程序中使用模块过程,但忘记将定义该过程的对象提供给链接器一样,我们也可以意外地告诉编译器使用外部过程(具有不同的链接符号名称)而不是模块过程:
module mod
implicit none
contains
integer function sub()
sub = 1
end function
end module
use mod, only :
implicit none
integer :: sub
print *, sub()
end
或者我们可能会忘记使用模块。同样,当我们错误地引用外部程序而不是外部程序时,我们经常看到这一点
当我们忘记使用模块时,使用implicit none(external)
可以帮助我们,但这不会捕获我们显式声明函数为外部函数的情况。我们必须小心,但是如果我们看到像这样的链接错误
undefined reference to `sub_'
然后我们应该认为我们引用了一个外部过程sub
,而不是一个模块过程:“模块名称空间”没有任何名称混乱。这是一个强烈的暗示,我们应该在哪里寻找
错误指定的绑定标签
如果我们与C进行互操作,那么很容易错误地指定符号的链接名称。如果不使用标准的互操作性工具,这是非常容易的,所以我不会费心指出这一点。如果您看到与C函数相关的链接错误,请仔细检查
如果使用标准设备,仍有可能出现故障。区分大小写是一种方式:链接符号名称区分大小写,但如果不全是小写,则必须告知Fortran编译器大小写:
interface
function F() bind(c)
use, intrinsic :: iso_c_binding, only : c_int
integer(c_int) :: f
end function f
end interface
print *, F()
end
告诉Fortran编译器向链接器询问符号f
,尽管我们在这里称它为f
。如果符号真的被称为F
,我们需要明确地说:
interface
function F() bind(c, name='F')
use, intrinsic :: iso_c_binding, only : c_int
integer(c_int) :: f
end function f
end interface
print *, F()
end
如果您看到链接错误因情况而异,请检查绑定标签
对于具有绑定标签的数据对象也是如此,并且还要确保任何具有链接关联的数据对象在任何C定义和链接对象中都有匹配的名称
不提供主程序
除非另有说明,否则编译器通常会假定它正在编译一个主程序,以便(使用链接器)生成一个可执行文件。如果我们不编译主程序,那就不是我们想要的。也就是说,如果我们正在编译模块或外部程序,以便以后使用:
module mod
implicit none
contains
integer function f()
f = 1
end function f
end module
subroutine s()
end subroutine s
我们可能会收到这样的消息
undefined reference to `unsupported_intrinsic_'
undefined reference to `main'
这意味着我们需要告诉编译器我们没有提供Fortran主程序。这通常使用-c
标志,但如果尝试构建库对象,则会有不同的选项。在这种情况下,编译器文档将提供适当的选项。编译器自己的库存在问题
大多数Fortran编译器需要将代码与它们自己的库相链接。这应该会自动发生,而无需您进行干预,但这可能会由于一些原因而失败
如果使用gfortran
进行编译,此问题将显示为对libgfortran
中符号的未定义引用,这些符号都命名为\u gfortran…
。这些错误消息如下所示
对“\u gfortran\u…”的未定义引用
此问题的解决方案取决于其原因:
gcc -o program fortran_object.o c_object.o -lgfortran
gfortran -c module.f90
gfortran program.f90 -o program
gfortran -c module.f90
gfortran module.o program.f90 -o program
gfortran -c module.f90
gfortran -c program.f90
gfortran module.o program.o -o program