一个完整的Makefile文件由5部分构成:显式规则、隐含规则、使用变量、文件指示和注释。

1、显式规则
显式规则指明了目标文件、依赖文件、生成或更新目标文件所使用的命令。有些规则没有命令,这些规则只是描述了文件间的依赖关系。例如:

foo.o:foo.c defs.h
    gcc -c -g foo.c

规则两个作用:

  • 目标文件是否过时(不存在或比依赖文件早);
  • 重新生成foo.o,命令中没有明确指出defs.hfoo.c已经包含过头文件,这也是作为依赖文件出现的原因;

一般形式:

目标文件列表  分隔符  依赖文件列表  [; 命令]
    [命令]
    [命令]

书写规则几个注意点:
(1)规则命令两种写法:命令和“目标文件、依赖文件”放在同一行,使用,将命令和依赖文件分开;命令放在下一行作为独立命令行,以Tab键开头,Makefile中所有以Tab键开头的都作为命令行处理;
(2)Makefile中$表示使用变量或函数,规则中需要$的地方,书写两个连续的$$
(3)Makefile中较长的行,使用反斜线\将其书写到独立的物理行上;

2、依赖的类型
makefile文件有两种依赖,一种是前面提到的,依赖文件列表中的任一文件比目标文件新,则需重新生成目标文件;还有一种如下:

foo.o:foo.c | somelib
    gcc -o foo foo.c somelib

|前面的文件是普通依赖文件,如果foo.c过时,将导致foo重新生成,如果|后面过时则不会重新生成,第二行命令不会重新生成。

3、命令行属性
一条规则可以有一个或多个命令行,每个命令行以Tab键开头,可以在Tab键后写上+,-,@,如果不写,将使用缺省的命令——命令遇到错误就推出make。
+:本行命令始终被执行,即使运行make命令时使用-n,-q,-t选项(前提目标文件过时,需要执行命令更新);
-:执行本行命令,遇到错误继续执行而不退出make;
@:执行本行命令时不在屏幕上打印命令内容。
例如:

file.o:file.c head1.h head2.h
    -mv file.o /tmp
    gcc -c file.c

其含义是:如果file.o过时,先将file.o备份到tmp目录下,然后再生成新的目标文件;第一次执行时,由于file.o不存在,mv会出错,默认情况下,一旦发生错误,make就会停止运行,在mv前面加上减号-,遇到错误,make忽略它继续运行。

4、伪目标
makefile中文件分为两类:实目标文件和伪目标。实目标是真正要生成的,存在在硬盘上;伪目标不要求生成实际文件,为了让make执行的一些辅助命令,如打印一些信息,删除无用的中间文件。
例如:

clean:
    -rm -f *.o

含义:删除当前目录下,以.o结尾的文件,遇到错误继续执行;clean没有依赖文件,总是认为它是最新的,因此不会执行第二行的命令,为了执行clean后面的命令,shell提示符下使用命令make clean
如果当前目录下有一个名为clean的文件,输入make clean不会执行下面的命令,需要将clean声明为伪目标。将一个目标声明为伪目标的方法是将它作为特殊目标“.PHONY”的依赖,如下:

.PHONY : clean

clean被声明为伪目标之后,无论目录下是否有名为clean文件,make clean都会执行rm命令,而且,当一个目标被声明为伪目标之后,make在执行规则命令时不会试图查找该目标的依赖文件,从而提高make效率,也不要担心目标与文件重名而不能实现我们的目的。

.PHONY : clean
clean:
    -rm -f *.o

makefile中伪目标也有可以有自己的依赖。在一个目录下如果需要生成多个可执行程序1,可以在一个makefile文件中实现,因为makefile中第一个目标是最终目标,通常用伪目标all作为最终目标,它的依赖文件就是那些需要创建的可执行程序。

all : program1 program2 program3
.PHONY : all
program1: program1.c utils.h
    gcc -o program1 program1.c
program2: program2.c utils.h
    gcc -o program2 program2.c
program3: program3.c utils.h
    gcc -o program3 program3.c

all作为终极目标,make生成依赖文件(program1 program2 program3),也可以单独生成目标文件(make program1)。

5、特殊目标

  • .PHONY:目标“.PHONY”的所有依赖被视为伪目标,前面提到过;
  • .IGNORE:目标“.IGNORE”后面的依赖文件,生成这些依赖文件在执行时遇到错误,make将忽略错误继续执行,功能类似与命令行属性“-”,当此命令没有依赖文件时,忽略所有错误;
  • .SUFFIXES:该目标的依赖被认为是一个后缀列表,在检查后缀规则时使用;
  • .SILENT:该目标依赖的文件,执行生成依赖文件时,make不会打印执行的命令行;如果“.SILENT”后面没有依赖文件,则表示执行makefile中所有命令都不会打印;
.SILENT:module2.o
modeule2.o:module2.c head2,h
    gcc -c module2.c

在执行第三行命令时,不会打印命令,它等价于:

modeule2.o:module2.c head2,h
    @gcc -c module2.c
  • .PRECIOUS:该目标依赖的文件会受到特别对待,如果make被kill终止或遇到意外终止,这些依赖不会被删除,而且这些依赖文件是中间文件,在不需要时也不会被删除;
  • .INTERMEDIATE:该目标依赖的文件当做中间文件对待,如果“.INTERMEDIATE”后面没有依赖文件,该规则是没有意义的;

6、含有多个目标的规则
一个规则可以含有多个目标,规则所定义的命令对所有目标都有效。一个具有都目标的规则相当于多个规则。多目标规则意味着所有目标有相同的依赖文件,规则命令中可以使用自动变量,从而可以把几天类似的规则归为一条,例如:

module1.o module2.o module3.o:command.h

7、搜索目录
较大的项目源文件、头文件、库文件放在不同的目录中,make需要到不同的目中去寻找依赖文件。当文件所在目录发生变化后,可以不用更改makefile文件规则,只改变依赖文件的搜索目录。
make可以识别一个特殊变量“VPATH”,通过“VPATH”可以指定依赖文件的搜索目录。当规则的依赖文件不存在时,make会在此变量所指定的目录下去寻找这些依赖文件。
定义变量“VPATH”时,是用空格或者冒号将多个需要搜索的目录分开。make搜索目录的顺序是按照变量“VPATH”定义的目录顺序进行的(当前目录永远是第一搜索目录)。例如对变量定义如下:

VPATH= /usr/src:../headers

定义了两个搜索目录:“/usr/src”和“../headers”。

另一个设置文件搜索目录的方式是使用make的“vpath”(小写)关键字,方法如下:
(1)vpath<pattern><directories>
为符合模式<pattern>的文件指定搜索目录<directories>
(2)vpath<pattern>
清除符合模式<pattern>的文件指定搜索目录
(3)vpath
清除所有已被设置好的文件搜索目录

vpath中的<pattern>需要包含%字符,%表示匹配零个或若干字符,例如%.h表示所有以“.h”结尾的文件。<pattern>指定了要搜索的文件集,<directories>指定了文件集的搜索目录。例如:

vpath %.h ../headers

该语句表示在../headers”目录下搜索以“.h”结尾的文件(当前目录没有找到的话)。

可以重复使用vpath语句,以指定不同的搜索策略。如果连续的vpath语句出现了相同的<pattern>,make会按照vpath语句先后顺序来执行搜索。

vpath %.c src1
vpath % scr2
vpath %.c src3

表示以“.c”结尾的文件,现在src1目录中寻找,然后是“scr2”,最后是“scr3”。

标签: none

评论已关闭