Fortran项目自动化生成Makefile工具

| Comments

当项目代码量超过一定数目时,使用命令行手动编译就不合时宜了。这时我们可以使用make自动化工具,但make工具需要相应makefile文件定义编译执行规则。可是makefile需要自己写也挺麻烦的,那么有没有自动化生成makefile的工具呢?(果然lazy才是进步的动力啊)

C语言项目可以利用gcc的编译选项-M输出目标文件的依赖关系来达到目的。那么Fortran项目呢?

幸运的是有一些工具可以实现Fortran项目自动化生成makefile。以下是我从网上收集到的能实现该目的的工具:

  • mkmf

http://www.gfdl.noaa.gov/~vb/mkmf.html

  • mkdep

http://www.ii.uib.no/~avle/mkdep.html

  • fmkmf

http://www.geos.ed.ac.uk/homes/hcp/fmkmf

  • makedepf90

http://personal.inet.fi/private/erikedelmann/makedepf90/


下面简单介绍其中的mkmf用法。

mkmf是用perl5写的一个工具,用来从源代码中构建makefile文件。单个可执行程序是典型结果,但可以扩展到任何目的的makefile。

mkmf特色

  • mkmf能识别f90(modules and use)依赖,fortran的include语句以及cpp的#include指令;
  • 对文件名或模块名没有限制等;
  • 支持overlay概念(源代码以定义好的优先级在目录中维护);
  • 可以追踪cpp标志的变化,知道何时重新编译改变的源代码(即包含#ifdef的文件自上次调用后被改变了)
  • 可以在任何安装了perl5的unix平台上运行;
  • 以GPL许可发行,目前版本是14.0

用法

1
mkmf [-a abspath] [-c cppdefs] [-o otherflags] [-d] [-f] [-m makefile] [-p program] [-t template] [-v] [-x] [args]

其中:

  • -a abspath 连接abspath在所有源代码文件相对路径前面。如果-a没有指定,当前工作目录为abspath
  • cppdefs是传给源代码文件的cpp #defines列表:在此状态下如果有变化,将有选择的移除影响的目标文件。实际上就是定义makefile中CPPDEFS变量。
  • otherflags是传给源代码文件的编译器指令列表:它和cppdefs类似除了其可以为任意标记。同时,由于fortran约定,cpp只能调用于.F.F90文件,而otherflags应用于所有源代码文件(.f.f90)。定义makefile中OTHERFLAGS变量。
  • -dmkmf的调试标记(比-v更详细,但可能只用于修改mkmf本身修改时)。
  • -f是一个格式标记,用于限制Makefile行字符不超过256个。更长的行将使用换行符。
  • makefile是生成的makefile名称(默认为Makefile)。
  • template是一个文件,包含写在makefile开头的make宏或命令。Makefile中使用include指令引用模板文件。
  • program是最终目标的名称(默认为a.out)。mkmf最新的变化是如果program扩展名为.a的话,mkmf理解为是一个库。创建命令是$(AR) $(ARFLAGS),替代$(LD) $(LDFLAGS)
  • -v是mkmf的一个详细标记。
  • -x立即执行makefile
  • args是要搜索的目标和依赖的目录和文件列表。

Makefile结构

一个源代码文件指跟着源代码文件后缀的文件(目前是.F, .F90, .c, .f, .f90)。一个包含文件指跟着包含文件后缀的文件(目前是.H, .fh., .h, .h90, .inc)。一个有效的源代码文件也可以是包含文件。

列表中每个源代码文件假定在当前工作目录下输出相同的文件basename和.o后缀组成的目标文件。如果列表中超过一个源代码文件输出相同名称的目标文件,只有第一个被使用,其他被丢弃。这个功能允许overlays的使用:如果dir3包含基本源代码,dir2包含bug修复,dir1包含特殊运行的模块,mkmf dir1 dir2 dir3将创建能正确编译的makefile。注意优先级从左向又下降。这是编译器搜索库文件、头文件顺序,从左到又,第一个匹配后使随后的都无效。

makefile目前使用$(FC)运行Fortran文件,$(CC)运行C文件。编译器标记在$(FFLAGS)$(CFLAGS)中设置。最后的载入(链接)执行$(LD)。载入器的标记由$(LDFLAGS)设置。用于.F,.F90,.c文件的预处理标记在$(CPPFLAGS)设置。这些宏在大多数系统上有缺省意思,可以在模板文件中修改。预定义的宏可以通过运行make -p查看。

另外,宏$(CPPDEFS)用于预处理器。这可以包含cpp #defines,每次运行可能变化。cpp编译时不会改变的选项应该放在$(CPPFLAGS)

包含文件递归搜索。

对于不存在的文件默认行为是在当前工作目录下创建touch它们。

所有目标文件被链接进单个可行性文件。因此mkmf参数中只有一个主程序源。

[args]的处理

args参数列表从左向右顺序处理。参数可以是以下三种:

  • 如果参数是一个源代码文件,将加入源代码文件列表。
  • 如果参数是一个目录,目录下所有源代码文件被加入源代码文件列表。
  • 如果参数是一个常规文件,假定其包含源代码文件列表。任何不包含源代码文件的行被丢弃。如果一行包含超过一个单词,最后一个单词应该是源代码文件名称,该行其余部分是一个文件指定编译命令。

可能对单个文件提供特定的编译选项有用。例如:

1
2
3
a.f90
b.f90
f90 -Oaggress c.f90

会将a.f90, b.f90和c.f90加入到源代码文件列表。前两个文件将使用通用命令$(FC) $(FFLAGS)编译。但c.f90使用f90 -Oaggress编译。

目录abspath(通过-a指定)或当前工作目录总是第一个参数,即使args未提供。

参考文献:

Comments