Linux系统下Fortran编译和链接第三方库

问题描述

  初学者通常会在Windows系统上通过IDE编译运行Fortran程序,然而,涉及大型计算以及多线程并行过程,Fortran的应用场景是在集群和超算上,就需要考虑在Linux系统编译和链接MKL和MPI这些基础的第三方计算库。由于linux上习惯上不使用图形化界面,一般的编译过程以命令行的形式显示,所以需要掌握一些手动编译的操作。以下仅给出一个笔者实操的解决方案。

P.S. 本文所有方案基于主流的Intel Visual Fortran(IVF)编译环境,默认你的操作系统已安装

解决方案

Linux系统上Fortran编译运行基础

编译和链接命令

  作为一门解释型语言,Fortran的运行需要编译已有代码并链接各种运行时库对应第三方库才能建立机器码可执行文件(即.exe文件),所以完成整个运行过程需要掌握相应的编译和链接命令。

IVF的编译命令:ifort [options] file1 [file2 …]

此处options如果为“-c”意为compile,即编译;“-o”则是根据对象文件生成可执行文件,即object的首字母缩写;“-g”为generate,生成;“-L”为link,链接之意,主要用于指定并链接第三方库;“-I”为include,用于指定编译Fortran代码的标准文件,不同的第三方库都有对应的include地址和标准文件。我们主要用到以上几种编译命令。实际的编译运行过程如下:

1
2
ifort -c example1.f90 example2.f90 ...
ifort example1.o example2.o ... -o yourProgramName

这里需要注意你的程序文件之间相互的依赖性,“-c”编译生成object(.o)文件的过程是严格遵循依赖优先级的,例如,这里example2.f90需要调用example1.f90,它们的顺序不能颠倒。

静态库和动态库1

简要说明二者的区别。

(1)按照操作系统的不同有以下后缀名不同的两类

1
2
win32平台下,静态库后缀一般为.lib,动态库为.dll
linux平台下,静态库后缀一般为.a,动态库为.so

(2)按照链接过程的不同区分静态库和动态库:

  静态库是在程序编译的过程中链接到目标代码,而动态库则是在程序运行的过程中载入内存参与程序的运行。可见静态库的链接过程会增加可执行程序的体积,相应增强了程序的可移植性,因为目标代码在编译链接静态库之后生成的可执行文件不再依赖系统运行环境的设置。而调用动态库,无需在程序编译的时候链接库文件,从而可以在程序运行时随时替换对应动态库,只需要保证程序运行的过程能找到动态库文件即可,方便程序后期的升级和扩展。

链接第三方库

  我们可以使用“-l”命令完成静态库的链接

1
ifort -o example1.o example2.o -I$(your Include's Direction ) -L$(your Lib's Direction)$(the required lib-file)

通过如上操作,便可以将存在第三方库依赖的程序进行编译链接并生成可执行文件。

  综上可以看出,如果涉及编译一个较为复杂的工程,则需要大量的手动输入,在实际编译过程中是很不方便的,所以我们需要用到makefile对这些文件统一处理。

建立一个makefile文件,统一处理编译和链接过程

  在Linux系统上为了简化Fortran和C这些解释型语言的编译过程,一个成熟的解决方案是make统一编译。这里给出一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mkllib=/public/home/users/app/compiler/intel-2017.8/compilers_and_libraries_2017.8.262/linux/mkl/lib/intel64 
mklinc=/public/home/users/app/compiler/intel-2017.8/compilers_and_libraries_2017.8.262/linux/mkl/include
mpilib=/public/home/users/app/compiler/intel-2017.8/compilers_and_libraries_2017.8.262/linux/mpi/lib64
mpiinc=/public/home/users/app/compiler/intel-2017.8/compilers_and_libraries_2017.8.262/linux/mpi/include64
FCCFLAG=-lmkl_lapack95_lp64
FCC=mpiifort

origin:origin.f90 nrtype.o nrutil.o
$(FCC) -o bulk origin.f90 nrtype.o nrutil.o -I$(mklinc) -I$(mpiinc) -L$(mkllib) $(FCCFLAG) $(mpilib)/libmpi.a -mkl
nrtype.o:nrtype.f90
$(FCC) nrtype.f90 -c
nrutil.o:nrutil.f90
$(FCC) nrutil.f90 -c
clean:
rm -f *.o origin
rm -f *.mod origin

  Makefile是Linux系统下的一种编译脚本,make的用法这里不做具体展开,具体可以参考B站的视频2。这里的makefile主要包含Intel计算库MKL以及并行计算库MPI的路径和对应include的位置,视已安装库文件的具体路径而定。数学库IntelMKL和并行计算库IntelMPI是科学计算中常用的第三方库,所以以此为例,做简要说明。

  本人这里使用了MKL lapack95的函数库,所以在库文件调用一栏填写的是“-lmkl_lapack95_lp64 ”,这个依据实际编程需要的库而定,在调用MKL的情况下还需要在编译命令一栏后加上“-mkl”命令,才能完成最终的编译。而链接并行计算的库文件则是“libmpi.a”这个静态库文件。如makefile文件所示,引用多个库的标准文件和库文件可以分别写在一起,同时连接编译,这里不用考虑前后顺序。

  需要注意的是,由于程序用到了并行计算,所以实际的编译命令“ifort”需要改成“mpiifort”。

参考内容

1. https://blog.51cto.com/u_12444109/3032520

2. https://www.bilibili.com/video/BV1Mx411m7fm?spm_id_from=333.337.search-card.all.click&vd_source=7ffaf781bf9e178e533a627b572b618b