如何将MKL静态链接至Fortran生成的共享对象(.so)中?
问题分析与解决方案
你的核心问题是静态链接MKL库到共享对象时,链接顺序和库的排列顺序错误,导致链接器没有将MKL的符号纳入最终的.so文件中。以下是具体修正步骤:
1. 修正链接命令的顺序
GNU链接器是按从左到右的顺序处理输入文件的:只有当遇到未定义符号时,才会从后续的库中查找符号定义。你当前的链接命令把MKL库放在目标文件之前,链接器处理库时还没有看到需要这些符号的目标文件,因此不会将MKL的符号加入.so。
修改Makefile中的链接规则:
# Link $(OUTPUT_LIBRARY): $(OBJ_ALL) $(FC) -o $@ $^ $(LDFLAGS)
将目标文件$^放在$(LDFLAGS)之前,确保链接器先处理你的代码,再从MKL库中解析未定义符号。
2. 修正MKL静态库的排列顺序
MKL库存在明确的依赖层级:接口库(libmkl_gf_ilp64.a)依赖线程库(libmkl_sequential.a),线程库依赖核心库(libmkl_core.a)。你当前的顺序完全颠倒了,导致链接器无法正确解析依赖。
调整Makefile中的库定义:
## Linkeroptions ilp := $(MKLROOT)/lib/libmkl_gf_ilp64.a sequential := $(MKLROOT)/lib/libmkl_sequential.a core := $(MKLROOT)/lib/libmkl_core.a LDFLAGS := -m64 -shared -Wl,--start-group $(ilp) $(sequential) $(core) -Wl,--end-group -lpthread -lm -ldl
同时去掉LDFLAGS中的-Wall——这是编译器警告标志,链接器不需要该参数。
3. (可选)强制包含MKL库的所有符号
如果调整顺序后仍有未定义符号,可以使用--whole-archive参数强制链接器包含静态库的所有内容(代价是.so体积会增大):
LDFLAGS := -m64 -shared -Wl,--whole-archive $(ilp) $(sequential) $(core) -Wl,--no-whole-archive -lpthread -lm -ldl
注意--whole-archive之后必须加--no-whole-archive,避免影响后续的系统库(如pthread、m)。
验证与测试
执行以下命令重新编译:
make clean && make release
再用nm -u OI.so检查,MKL相关的符号(如dgemm_、dsyev_)应该不再出现在未定义符号列表中。
内容的提问来源于stack exchange,提问作者Toni
相关产品推荐
相关产品推荐

