Fortran调用C++函数时出现undefined reference to 'SolveBIE_'错误求助
undefined reference to 'SolveBIE_'的问题 我来帮你排查这个链接错误的问题,之前我也踩过Fortran和C++交互的类似坑,主要从这几个核心方向入手解决:
一、先搞定C++的名字修饰问题
C++编译器默认会对函数名做「名字修饰」(Name Mangling),把函数名改成一串奇奇怪怪的符号,而Fortran找的是你写的SolveBIE_这个原始名字,自然就找不到了。解决办法很简单:用extern "C"把你的SolveBIE_函数包裹起来,强制编译器用C风格的无修饰名字。
举个例子,如果你把test.c改成test.cpp(毕竟是C++代码,后缀用cpp更清晰),然后在文件里这么写:
// 用extern "C"块包裹,避免名字被修饰 extern "C" { // 声明SolveBIE_函数(参数列表按你实际的来) void SolveBIE_(/* 你的参数,比如int* n, double* arr */); } // 函数定义也放在extern "C"里 extern "C" void SolveBIE_(/* 参数 */) { // 这里正常调用part01、part02里的函数就行——只要这些函数只在C++内部调用,不用给它们加extern "C" }
如果你的part01.c和part02.c是纯C代码,直接用gcc编译就行;如果是C++代码,同样可以用extern "C"处理(但如果只是内部调用,没必要)。
二、确认静态库kf.a包含了所有必要的目标文件
链接器找不到符号,大概率是你的kf.a里根本没把SolveBIE_所在的test.o打包进去!生成静态库的时候,要把所有依赖的目标文件都加进去:
正确的编译打包步骤:
# 编译C/C++源文件成目标文件 gcc -c part01.c -o part01.o # 纯C用gcc,C++用g++/icpc gcc -c part02.c -o part02.o g++ -c test.cpp -o test.o # 用g++编译C++代码,加-fPIC如果需要动态库,但静态库不用 # 打包成静态库kf.a,把所有.o都加进去 ar rcs kf.a part01.o part02.o test.o
验证库里面的符号:
你可以用nm命令检查kf.a里有没有SolveBIE_:
nm kf.a | grep SolveBIE_
如果输出里有T SolveBIE_,说明这个符号已经在库里面了;要是没输出,就是打包的时候漏了test.o,重新打包就行。
三、调整Fortran的调用方式和Makefile链接逻辑
1. 用bind(C)显式指定函数名
不同Fortran编译器对函数名的下划线处理可能不一样,比如有些会自动给函数名加下划线,有些不会。为了避免这种差异,最好在Fortran代码里用bind(C)显式指定要调用的符号名:
interface subroutine SolveBIE() bind(C, name='SolveBIE_') ! 这里根据你的实际参数声明,比如: ! integer, intent(in) :: n ! double precision, intent(inout) :: array(*) end subroutine SolveBIE end interface
这样Fortran编译器就会精准找SolveBIE_这个符号,不会乱加后缀。
2. 确保Makefile里的链接顺序正确
链接的时候,库文件要放在目标文件的后面,不然链接器可能会跳过库的符号查找。比如你的Makefile可以这么写:
# 假设你的Fortran主程序是main.f90 FC = ifort CC = gcc CXX = g++ # 编译Fortran目标文件 main.o: main.f90 $(FC) -c main.f90 -o main.o # 编译C/C++目标文件 part01.o: part01.c $(CC) -c part01.c -o part01.o part02.o: part02.c $(CC) -c part02.c -o part02.o test.o: test.cpp $(CXX) -c test.cpp -o test.o # 生成静态库 kf.a: part01.o part02.o test.o ar rcs kf.a part01.o part02.o test.o # 链接生成可执行文件 main: main.o kf.a $(FC) main.o -o main ./kf.a clean: rm -f *.o *.a main
注意最后链接那一行,kf.a要放在main.o后面。
四、检查编译器的ABI兼容性
如果用Intel的ifort编译器链接,最好C/C++代码也用Intel的icc/icpc编译,避免不同编译器的ABI(应用二进制接口)不兼容导致的符号问题。比如把上面的CC换成icc,CXX换成icpc:
CC = icc CXX = icpc
这样编译出来的目标文件和Fortran代码的兼容性更好,不容易出奇怪的链接错误。
按照这几个步骤排查下来,应该就能解决undefined reference的问题了。
内容的提问来源于stack exchange,提问作者Yue

