我正在尝试构建一个 Fortran 程序,但我收到有关未定义引用或未解析外部符号的错误。我已经看到 another question 关于这些错误,但那里的答案大多特定于 C++。
用 Fortran 编写时这些错误的常见原因是什么,我该如何修复/防止它们?
在构建 Fortran 程序时,这是一个针对整个错误类别的典型问题。如果您已被推荐到此处或您的问题作为此问题的副本关闭,您可能需要阅读多个答案中的一个或多个。从 this answer 开始,它充当所提供解决方案的目录。
我正在尝试构建一个 Fortran 程序,但我收到有关未定义引用或未解析外部符号的错误。我已经看到 another question 关于这些错误,但那里的答案大多特定于 C++。
用 Fortran 编写时这些错误的常见原因是什么,我该如何修复/防止它们?
在构建 Fortran 程序时,这是一个针对整个错误类别的典型问题。如果您已被推荐到此处或您的问题作为此问题的副本关闭,您可能需要阅读多个答案中的一个或多个。从 this answer 开始,它充当所提供解决方案的目录。
您可以通过多种方式查看此类错误。您可能会在尝试构建程序(链接错误)或运行程序(加载错误)时看到它。不幸的是,很少有一种简单的方法可以查看导致错误的原因。
此答案提供了其他答案的摘要和链接,以帮助您导航。您可能需要阅读所有答案才能解决您的问题。
出现此类链接错误的最常见原因是您没有正确 specified external dependencies 或没有 put all parts of your code together correctly 。
当试图运行你的程序时,你可能有一个 missing or incompatible runtime library 。
如果构建失败并且您指定了外部依赖项,则可能有一个 programming error ,这意味着编译器正在寻找错误的东西。
undefined reference
/ unresolved external symbol
错误的最常见原因是未能链接提供符号的库(通常是函数或子例程)。
例如,当使用 BLAS 库中的子例程(如 DGEMM
)时,必须在链接步骤中使用提供此子例程的库。
在最简单的用例中,链接与编译相结合:
gfortran my_source.f90 -lblas
-lblas
告诉链接器(此处由编译器调用)链接 libblas
库。它可以是动态库(.so、.dll)或静态库(.a、.lib)。
请注意,库的名称可以不同,因为 BLAS 有多种实现(MKL、OpenBLAS、GotoBLAS、...)。但它总是从 lib...
缩短为 l...
,就像在 liopenblas.so
和 -lopenblas
中一样。
如果库位于链接器看不到它的位置,则可以使用 -L
标志显式添加目录以供链接器考虑,例如:
gfortran -L/usr/local/lib -lopenblas
您还可以尝试将路径添加到链接器搜索的某个环境变量中,例如 LIBRARY_PATH
,例如:
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/lib
当链接和编译分离时,在链接步骤中链接库:
gfortran -c my_source.f90 -o my_source.o
gfortran my_source.o -lblas
大多数 Fortran 编译器需要将您的代码链接到它们自己的库。这应该会自动发生,无需您进行干预,但这可能由于多种原因而失败。
如果您使用 gfortran
进行编译,则此问题将表现为对 libgfortran
中符号的未定义引用,这些符号均名为 _gfortran_...
。这些错误消息看起来像
undefined reference to '_gfortran_...'
此问题的解决方案取决于其原因:
安装编译器时应该已经自动安装了编译器库。如果编译器没有正确安装,这可能不会发生。
这可以通过正确安装库、正确安装编译器来解决。可能值得卸载错误安装的编译器以避免冲突。
注:卸载编译器时要谨慎:如果您卸载系统编译器,它可能会卸载其他必要的程序,并可能导致其他程序无法使用。
如果编译器库安装在非标准位置,编译器可能无法找到它。您可以告诉编译器库在哪里使用 LD_LIBRARY_PATH
,例如作为
export LD_LIBRARY_PATH="/path/to/library:$LD_LIBRARY_PATH"
如果您自己找不到编译器库,则可能需要安装一个新副本。
如果您安装了多个版本的编译器,您可能还安装了多个版本的编译器库。这些可能不兼容,编译器可能会找到错误的库版本。
这可以通过将编译器指向正确的库版本来解决,例如通过使用 LD_LIBRARY_PATH
如上所述。
如果您正在链接直接调用链接器,或者通过 C(或其他)编译器间接调用链接器,那么您可能需要告诉该编译器/链接器包含 Fortran 编译器的运行时库。例如,如果使用 GCC 的 C 前端:
gcc -o program fortran_object.o c_object.o -lgfortran
我们在单独的文件 module.f90
和主程序 program.f90
中有一个模块。
如果我们这样做
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
类似这些消息的链接时间错误可能是出于许多原因与链接器更一般用途相同的原因,而不仅仅是汇编了Fortran程序。其中一些内容涉及C ++链接的 linked question 和 another answer 在此处:未能指定库或以错误的顺序提供它们。
但是,编写Fortran程序会导致链接错误。
不支持的内在
如果子例程引用旨在指代内在的子例程,则如果编译器未提供该子例程固有的,则可能会导致链接时间错误:它被认为是外部子例程。
使用
unsupported_intrinsic
编译器提供的`` undefined reference to
unsupportedintrinsic'implicit none
intrinsic :: my_intrinsic
call my_intrinsic
end program
Error: Function ‘my_intrinsic’ at (1) has no IMPLICIT type
Error: Procedure ‘my_intrinsic’ called at (1) is not explicitly declared
module mod
implicit none
contains
integer function sub()
sub = 1
end function
end module
use mod, only :
implicit none
integer :: sub
print *, sub()
end
undefined reference to `main'