要从 c++ 调用 Fortran 例程,我一直在使用:extern "C" voidroutinename_(...) 带有附加的下划线,使其与 Fortran 子例程名称“ROUTINENAME”兼容。
当我将 c++ 与 BLAS 或 LAPACK 链接时,它只能在没有下划线的情况下工作。将 c++ 与这些用 Fortran 编写的库链接起来有什么区别,这使得下划线变得不必要?
我可能是错的,因为信息很少,但是...
从这里开始_
:第一个 F77 编译器在 ABI 中的函数名称后面附加了一个。这种行为与 C 不同,C 仅采用函数名称并将其用作 ABI 中的名称。
一些 F77 编译器的行为不同,而是将整个子例程名称大写,因此当 C 看到时foo()
就变成了这样FOO()
。UNIX Fortran 编译器模仿 C 的行为,只是复制粘贴了名称,所以这foo()
也在foo()
ABI 中。
但是,如果您在此处查看 BLAS 与 C 的参考实现的绑定,您会发现它们在处理 F77 时正在处理尾随下划线。我敢打赌,在过去,下划线是 F77 ABI 的一个更常见的特征,而不是没有它们。
后来,Fortran 2003 引入了与 C 的互操作性(参见此处)。当使用某些 Fortran 结构时,这使得函数命名方案相同(请参阅此处)。
因此,我将大胆猜测这与 Fortran 版本之间的 ABI 差异有关。甚至只是跨编译器,因为不同的编译器在 Fortran 中似乎有不同的行为。
所以,再次,我不确定这是否与你的情况相匹配,因为你的问题没有太多要继续的,但我不能把这一切都放在评论中,所以这里是一个“答案” .
如果我错了,请告诉我,这样我可以更正 MAH 的帖子。
tl; dr:因为编译器版本
我给出了一个关于链接 BLAS 的一般答案,不仅是这个问题,这个问题的答案在下面的末尾。
首先,您需要确保使用 (+lapack) 安装了 BLAS
$ sudo apt-get install libblas-dev liblapack-dev
然后您可以在程序文件之后使用 -lblas 进行链接。或者您可以使用 make 文件。
例如:g++ test.o dmatrix_denseCM.o mmio.o -o output -lblas
就我而言,我更喜欢使用 OpenBlas,您可以在 makefile 中使用以下内容。
完成后,您应该拥有文件 libopenblas.a,即 openblas 库
这个目录OpenBLAS/libopenblas.a应该在同一个工作目录中。
.cc 文件中的示例代码:
extern "C"{
void dgemm_( const char &TRANSA, const char &TRANSB, const int &M, const int &N, const int & K, const double & ALPHA, const double *A, const int & LDA, const double *B, const int &LDB, const double &BETA, double *C, const int & LDC);
}
此外,当从 C 调用 LAPACK 或 BLAS 例程时,请注意,由于 Fortran 语言不区分大小写,因此例程名称可以是大写或小写,带有或不带有尾随下划线。例如,以下名称是等效的:
LAPACK:dgetrf、DGETRF、dgetrf_ 和 DGETRF_
BLAS:dgemm、DGEMM、dgemm_ 和 DGEMM_英特尔® 数学核心函数库 11.3 更新 4 开发人员指南
您可以添加有关用于编译 BLAS 的 FORTRAN 编译器的更多信息,例如:
使用 -U 选项编译 Fortran 程序,该选项告诉编译器保留函数/子程序名称的现有大写/小写区别。
Fortran 编译器通常会在出现在入口点定义和调用中的子程序名称后附加下划线 (_)。此约定不同于具有相同用户分配名称的 C 过程或外部变量。这里
C++ 中的名称修饰在 C 中造成问题。因为 C 不支持重载,所以我们必须使用 extern "c"{}。