代码改变世界

[转]在linux下如何使用Makefile对fortran程序进行编译

2012-11-14 20:38  H_OU  阅读(6425)  评论(0编辑  收藏  举报
-

在linux下写过不少的fortran程序,但很少写makefile文件,通常情况下我是手动用ifort或pgf90进行编译,虽然也在大型程序中写过一些代码,但因为都有现成的makefile文件,我也只是修改一下配置参数,先make clean,再make,只要生成可执行程序就算搞定了。今天心血来潮,自己写了几个Makefile,供大家参考。


一、不用Makefile的直接编译
比如有2个简单程序,主程序为main.F90,子程序为sub.F90. 如果直接编译的话,键入
ifort main.F90 sub.F90
就可以生成一个a.out文件,即为可执行程序了。
你也可以指定一个可执行程序的名字,如
ifort main.F90 sub.F90 -o bin.exe
则可以生成bin.exe,实际上与a.out是一样的。
当然,如果你不喜欢用子程序,或者子程序和主程序都写在一个F90文件中(如main.F90),上述的编译语句直接省掉sub.F90就行了,但不推荐这样写程序,特别是程序比较大的情况下,一是程序间的关系容易理不清,另外风险也大,万一哪天把程序删掉了或改错了,损失可就大了。


上面的编译也可以分两步进行,
ifort -c main.F90 sub.F90
ifort -o main.exe main.o sub.o
第一行称为编译compile,第二行称为链接link。这个过程最后还是生成main.exe,第一步生成main.o和sub.o两个目标文件,第二步将目标文件链接成可执行文件main.exe。这看起来有点多此一举,如果在程序不大,子程序不多的情况下,这确实是浪费体力,但如果有几十或几百个子程序(如WRF模式),编译一次可能要花几十分钟或几个小时,那么可以单独编译修改的那个程序生成相应的.o文件就行了,然后再执行第二步链接,这样可以节省不少时间。也就是说,第一步的编译可以分开进行:
ifort -c main.F90
ifort -c sub.F90
在有几个子程序的情况下,这样分开编译虽然花点工夫,还是值得的,因为程序很难一蹴而就,总要调试,总要修改,分解成若干子程序逐个编译更容易各个击破。


二、简单的Makefile文件
我们仍以一行编译语句为例,将其写在Makefiel文件中。使用vi建立一个新的Makefile文件,在其中写入:
main.exe: main.F90 sub.F90
ifort main.F90 sub.F90 -o main.exe
就可以了。你把已有的main.exe删掉,键入make,你会发现生成了新的main.exe. 这就是Makefile文件了,简单吧!
如果报错的话,你看看是不是Makefile中的第二行之前没有用tab键空格,必须用tab键,用空格键是不行嘀。


下面我们再来解释一下Makefile的写作格式
简而言之,Makefile的格式就是二行,第一行定义目标文件和依赖文件,:之前的main.exe为目标文件,:之前后的main.F90和sub.F90为依赖文件。第二行为执行语句,与手动编译相同。好像第一行还是多此一举,还不如手动编译只要一行就搞定,我们看完下一个例子再来讨论这一点。


那么对于编译和链接分解的语句如何写呢。重新打开Makefile文件,将原来的两行删去,再写入:
main.exe:main.o sub.o
ifort -o main.exe main.o sub.o
main.o:main.F90
ifort -c main.F90
sub.o:sub.F90
ifort -c sub.F90
这就可以了,是不是还发现一点异样?语句的顺序和前面手动编译时是反的,先是链接语句,后是编译语句,这一点我们稍后解释。还是先运行一下吧,将原来的.exe和.o文件都删掉,执行make后,是不是可以看到新生成了.o和.exe文件。你还可以试试将其中的main.F90进行修改(比如加一行空格,或加一条注释),再执行make,可以发现,仅更新了main.o和main.exe,而sub.o还是原来的生成时间。这就是make的优势。


我们先来解释一下目标文件和依赖文件的关系,如果任意一个依赖文件发生了改变,则要运行下一行的执行语句,即生成新的目标文件,否则跳过执行文件。在make执行的过程中,实际上并不是顺序执行的,而是先把所有的目标文件和依赖文件检查一遍,从最顶层的目标文件开始,再分解检查各个子目标,将发生变化的依赖文件标记下来,然后再从下向上执行标记语句,最后更新顶层的目标文件。所以写makefile文件的顺序必须是先写顶层的目标文件,也就是连接生成的.exe文件,然后再分别写编译要生成的.o文件,这与手动编译时是不同的。make的工作方式就象警察办案一样,先侦察推演,收集证据;再顺藤摸瓜,收网抓贼。


三、复杂一点的Makefile文件
下面这个例子中用到了变量定义和静态模式
SOURS = main.F90 sub.F90
OBJS = main.o sub.o
BIN = main.exe
F90 = ifort


${BIN}:${OBJS}
${F90} -o ${BIN} ${OBJS}
${OBJS}: %.o :%.F90
${F90} -c $<
先来说说变量定义,这个地球人都知道,只要会写shell脚本的人都能看的懂,如果子程序不多的话也没必要定义来定义去的。