如何将MKL静态链接到共享对象?

问题描述 投票:0回答:1

我的一般任务:

我有一个 Fortran 工具,它使用 MKL 库中的函数 dgemm、dgemv、dgesvx 和 dsyev。我需要将代码编译为共享对象 (.so),以使其在不同的电脑上运行。我正在使用 gfortran 编译器和链接器。 MKL 库的链接必须是静态,因为另一台电脑上未安装 MKL 和 gfortran。

My .so 本身不是可执行文件,而是访问其函数的 Python 工具的一部分 - 因此 Fortran 代码中没有类似于 main() 函数的东西。 (我在这方面有几个错误,所以我想在这里提一下......)

我尝试过的:

(1) 我使用 Intel Link Line Advisor 来确定所需的标志。生成的链接器 (LDFLAGS) 和编译器标志 (FFLAGS) 是:

  • FFLAGS := -m64 -fdefault-integer-8 -I"${MKLROOT}/include"
  • LDFlAGS := -m64 -Wl,--start-group ${MKLROOT}/lib/libmkl_gf_ilp64.a ${MKLROOT}/lib/libmkl_sequential.a ${MKLROOT}/lib/libmkl_core.a -Wl,--end -group -lpthread -lm -ldl

(2) 由于个人需求,我添加了以下Flag: FF标志:

  • -打印所有警告的墙
  • -fPIC 用于位置无关代码
  • -O3 用于优化 LDF 标志:
  • -打印所有警告的墙
  • -shared 创建共享对象(.so)

(3) 我将所有内容合并到一个 Makefile 中。

OUTPUT_LIBRARY := OI.so

MKLROOT := /opt/intel/oneapi/mkl/latest/

# Name of Compiler
FC := gfortran

# Compileroptions
FFLAGS := -Wall -m64 -fPIC -fdefault-integer-8 -I"${MKLROOT}/include"  # -fdec-math ist veraltet, wird daher entfernt
FFLAGS_RELEASE := -O3
FFLAGS_DEBUG := -g

## Linkeroptions
core := $(MKLROOT)/lib/libmkl_core.a
ilp := $(MKLROOT)/lib/libmkl_gf_ilp64.a
sequential := $(MKLROOT)/lib/libmkl_sequential.a
LDFLAGS := -Wall -m64 -shared -Wl,--start-group $(core) $(ilp) $(sequential) -Wl,--end-group -lpthread -lm -ldl

# Source-Files
SRC := S_Module_ivu.for\
 s_analyse_IVU.for\
 covsrt.for\
 gaussj.for\
 mrqcof.for\
 mrqmin.for\
 nrrank.f\
 S_acsurf_ivu.for\
 S_diff_ivu.for\
 S_expo_fit_neu_ivu.for\
 S_getac_ivu.for\
 S_justl.for\
 S_ord_ivu.for\
 S_PERCENTILE_ivu.for\
 getKanal.f90\
 S_fileprocs_ivu.f90\
 S_setoiparams_ivu.f90\
 SS_oi_ivu.f90\
 S_ANA_VARIANZ_IVU.FOR\
 S_CORRECS_ivu.FOR\
 S_FUNC_DEF_ivu.FOR\
 S_LOCGEO_ivu.FOR\
 S_NORMC_IVU.FOR\
 S_SCALCWTSW_ivu.FOR

SRC_for := $(filter %.for,$(SRC))
SRC_FOR := $(filter %.FOR,$(SRC))
SRC_f := $(filter %.f,$(SRC))
SRC_f90 := $(filter %.f90,$(SRC))

OBJ_for := $(patsubst %.for,%.o,$(SRC_for))
OBJ_FOR := $(patsubst %.FOR,%.o,$(SRC_FOR))
OBJ_f := $(patsubst %.f,%.o,$(SRC_f))
OBJ_f90 := $(patsubst %.f90,%.o,$(SRC_f90))
OBJ_ALL := $(OBJ_for) $(OBJ_FOR) $(OBJ_f) $(OBJ_f90)

# Default-Target: .so in release mode
all: release

release: FFLAGS += $(FFLAGS_RELEASE)
debug: FFLAGS += $(FFLAGS_DEBUG)

release: $(OUTPUT_LIBRARY)
debug: $(OUTPUT_LIBRARY)

# Compile
$(OBJ_for): %.o: %.for
    $(FC) $(FFLAGS) -c $< -o $@
$(OBJ_FOR): %.o: %.FOR
    $(FC) $(FFLAGS) -c $< -o $@
$(OBJ_f): %.o: %.f
    $(FC) $(FFLAGS) -c $< -o $@
$(OBJ_f90): %.o: %.f90
    $(FC) $(FFLAGS) -c $< -o $@

# Link
$(OUTPUT_LIBRARY): $(OBJ_ALL)
    $(FC) $(LDFLAGS) -o $@ $^

# Option for cleaning up
.PHONY: clean
clean:
    rm -f $(OBJ_ALL)
    rm -f *.mod
    rm -f $(OUTPUT_LIBRARY)

什么不起作用:

运行

make release
时,我没有收到任何错误消息,并且 OI.so 已成功创建。然而,当检查 OI.so 中的未定义符号时(使用
nm -u OI.so
),它们将所有必需的 MKL 函数列为未定义。由于这些未定义的函数,我的程序无法运行。

有什么建议我在这里做错了什么吗?

gfortran static-linking intel-mkl
1个回答
0
投票

抱歉,如果我来得太晚了。问题是 您的链接在引用库的对象文件之前消耗库1 该答案对您的 Makefile 的应用值得澄清。

GNU/Linux 链接器按照命令行顺序使用输入文件(目标文件和库),从不重新访问输入文件,但它会循环访问 重新访问由

--start-group/--end-group
选项包围的一系列静态库,解决未定义的引用,直到没有新的引用出现。在所有情况下,包括该例外,它只会考虑一个库(静态或共享)来查找未定义引用的定义已经在手。也就是说,由目标文件已输入引入的未定义符号(在命令行上明确命名的目标文件或从静态库中提取的目标文件)。与库相反,输入的任何显式命名的目标文件都会无条件链接到输出文件。

这意味着,在将某些显式命名的对象文件输入到链接之前,有 0 个未定义的引用需要解析,并且链接器将忽略所有库 - 即使它们可能提供链接器尚未解析的未定义引用的定义看。这种未定义的引用将一直存在,直到链接结束(除非再次输入必要的库),并且将以失败告终。 这些事实破坏了您的特定链接,因为您的 Makefile 编码错误,特别是链接规则:

$(OUTPUT_LIBRARY): $(OBJ_ALL) $(FC) $(LDFLAGS) -o $@ $^

其中 
LDFLAGS

是:

LDFLAGS := -Wall -m64 -shared -Wl,--start-group $(core) $(ilp) $(sequential) -Wl,--end-group -lpthread -lm -ldl

此分配 
LDFLAGS

在所有目标文件

$^
之前输入所有库,结果它们被忽略。
按照 GNU Make 的约定,应为 

LDFLAGS

分配链接选项

other
,而不是库选项,并且库选项应分配给 LDLIBS。要更正您的 Makefile,请指定:
LDFLAGS := -Wall -m64 -shared 
LDLIBS := -Wl,--start-group $(core) $(ilp) $(sequential) -Wl,--end-group -lpthread -lm -ldl

并将您的链接配方更改为:

$(OUTPUT_LIBRARY): $(OBJ_ALL) $(FC) $(LDFLAGS) -o $@ $^ $(LDLIBS)



我对这个问题的答案之一
    什么是未定义的引用/未解析的外部符号错误以及如何修复它?
  1. .
© www.soinside.com 2019 - 2024. All rights reserved.