make 实用程序使用智能化方法执行程序编译和链接任务。通常,大型应用程序由一组源文件和 INCLUDE 文件组成,需要与许多库进行链接。修改任何一个或多个源文件,都需要对那一部分程序进行重新编译,并且要重新链接。指定组成应用程序的各文件间的相互依赖性以及重新编译和重新链接每一程序块所需的命令,可以自动执行这一过程。指令文件中有了这些说明,make 便会确保只重新编译那些需要重新编译的文件,并确保重新链接时使用生成可执行文件所需要的那些选项和库。以下讨论内容提供了一个如何使用 make 的简单示例。有关摘要信息,请参见 make(1S)。
名为 makefile 的文件以结构化方式告知 make,哪些源文件和目标文件依赖其他文件。它还定义了编译和链接文件所需的命令。
例如,假设您的程序有四个源文件以及相应的 makefile 文件:
demo% ls makefile commonblock computepts.f pattern.f startupcore.f demo% |
假设 pattern.f 和 computepts.f 都有一个名为 commonblock 的 INCLUDE,并且您希望编译每个 .f 文件并将这三个可重定位的文件与一系列库一起链接成一个名为 pattern 的程序。
这时,makefile 将会如下所示:
demo% cat makefile pattern: pattern.o computepts.o startupcore.o f95 pattern.o computepts.o startupcore.o -lcore95 \ -lcore -lsunwindow -lpixrect -o pattern pattern.o: pattern.f commonblock f95 -c -u pattern.f computepts.o: computepts.f commonblock f95 -c -u computepts.f startupcore.o: startupcore.f f95 -c -u startupcore.f demo% |
makefile 的第一行表明 pattern 的创建取决于 pattern.o、computepts.o 和 startupcore.o。下一行及其后续各行给出了由可重定位的 .o 文件和库创建 pattern 的命令。
makefile 中的每一条目都是一项规则,它描述了目标对象的依赖性以及创建该对象所需的命令。规则的结构为:
target: dependencies-listTAB build-commands
依赖性-每一条目的头一行均是为目标文件命名,其后是目标依赖的所有文件。
命令-每一条目随后还有一行或多行,这些行指定将生成本条目相应的目标文件的 Bourne shell 命令。这些命令行中的每一行都必须用一个制表符缩进。
make 命令可以进行无参数调用,只需键入:
demo% make |
make 实用程序在当前目录中查找名为 makefile 或 Makefile 的文件并从该文件中获取指令。
make 实用程序:
读取 makefile,确定其必须处理的所有目标文件、这些目标文件依赖的文件以及生成这些目标文件所需的命令。
查找每个文件的最后更改日期和时间。
如果有任何目标文件比其依赖的任一文件的生成时间更早,则使用 makefile 中与该目标相应的命令重新生成该目标文件。
make 实用程序的宏功能允许进行简单的无参数字符串替换。例如,可将组成目标程序 pattern 的可重定位文件的列表表示为单个宏字符串,使其更易于更改。
宏字符串定义具有以下格式:
NAME = string
宏字符串的使用方式如下所示:
$(NAME)
make 会用宏字符串的实际值来替换它。
以下示例将命名所有目标文件的宏定义添加到 makefile 的开头:
OBJ = pattern.o computepts.o startupcore.o |
现在便可在依赖性列表以及与 makefile 中的目标 pattern 相应的 f95 链接命令中同时使用宏了。
pattern: $(OBJ) f95 $(OBJ) -lcore95 -lcore -lsunwindow \ -lpixrect -o pattern |
对于名称为单个字母的宏字符串,可以省略括号。
make 宏的初始值可以用 make 的命令行选项进行覆盖。例如:
FFLAGS=–u OBJ = pattern.o computepts.o startupcore.o pattern: $(OBJ) f95 $(FFLAGS) $(OBJ) -lcore95 -lcore -lsunwindow \ -lpixrect -o pattern pattern.o: pattern.f commonblock f95 $(FFLAGS) -c pattern.f computepts.o: f95 $(FFLAGS) -c computepts.f |
现在,简单的无参数 make 命令将会使用上面设置的 FFLAGS 值。不过,这可以通过命令行来覆盖:
demo% make "FFLAGS=–u -O" |
这里,make 命令行中的 FFLAGS 宏定义会覆盖 makefile 的初始值,并且会将 -O 标志和 -u 标志一起传递给 f95。请注意,也可以在命令中使用 "FFLAGS=",将宏重置为空字符串使其不再有效。
为使 makefile 更易编写,make 将根据目标文件的后缀,使用自身的缺省规则。
缺省规则在文件 /usr/share/lib/make/make.rules 中。在识别缺省的后缀规则时,make 会将 FFLAGS 宏指定的任何标志、-c 标志以及要编译的源文件名都作为参数进行传递。此外,make.rules 文件还使用 FC 宏赋予的名称作为要使用的 Fortran 编译器的名称。
以下示例两次说明了这一规则:
FC = f95 OBJ = pattern.o computepts.o startupcore.o FFLAGS=–u pattern: $(OBJ) f95 $(OBJ) -lcore95 -lcore -lsunwindow \ -lpixrect -o pattern pattern.o: pattern.f commonblock f95 $(FFLAGS) -c pattern.f computepts.o: computepts.f commonblock startupcore.o: startupcore.f |
make 使用缺省规则编译 computepts.f 和 startupcore.f。
.f90 文件存在缺省的后缀规则,这些规则将会调用 f95 编译器。
然而,除非将 FC 宏定义为 f95,否则 .f 和 .F 文件的缺省后缀规则会调用 f77 而非 f95。
而且,当前没有为 .f95 和 .F95 文件定义后缀规则,.mod Fortran 95 模块文件将会调用 Modula 编译器。要对此进行补救,需要在调用 make 的目录下为 make.rules 文件创建您自己的本地副本,同时对该文件进行修改,添加 .f95 和 .F95 后缀规则,删除 .mod 的后缀规则。有关详细信息,请参见 make(1S) 手册页。
使用特殊目标 .KEEP_STATE 检查命令的依赖性及隐藏依赖性。
当 .KEEP_STATE: 目标有效时,make 会根据状态文件检查用于生成目标的命令。如果自上次 make 运行以来命令已更改,make 会重新生成此目标。
当 .KEEP_STATE: 目标有效时,make 将从 cpp(1) 以及其他编译处理器中读取任何“隐藏”文件(例如 #include 文件)的相应报告。如果目标相对于这些文件中的任何文件已过期,make 会重新生成它。