1Makefile概述
1.1 makefile 基本知识
GNU make来构建和管理一个的工程,使整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile文件的编写。
Makefile文件描述了整个工程的编译、连接等规则,其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。Makefile描述了工程中所有文件的编译顺序、规则,有自己的书写格式、关键字和函数。为工程编写Makefile的好处是能够使用一行命令来完成自动化编译极大提高了效率
我们还可以使用make工具来做一些其它的事。例如,有这样的需求:当我们修改了某个或者某些文件后,需要能够根据修改的文件来自动对相关文件进行重建或者更新。GNU make工具为我们实现这个目的提供了非常有利的支持。。make执行时,根据Makefile的规则检查文件的修改情况,决定是否执行定义的动作,那些修改过的文件将会被重新编译。
1.2 makefile简介
一个简单的Makefile描述规则组成:
:
COMMAND
...
target:规则的目标。可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标clean, 此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。
prerequisites:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。
command:规则的命令行。是make程序所要执行的动作。
一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。
2.makefile的规则
2.1 文件名使用通配符
Maekfile中表示一个单一的文件名时可使用通配符。可使用的通配符有:*?[…] Makefile中统配符可以出现在以下两种场合:
1. 可以用在规则的目标、依赖中,此时make会自动将其展开;
print: *.c
lpr -p $?
touch print
2. 可出现在规则的命令中,其展开是在执行此命令时完成。
clean:
rm -f *.o
除这两种情况之外的其它上下文中,不能直接使用通配符。二是需要通过函数wildcard来实现。
如果规则中的某一个文件的文件名包含作为统配符的字符(*.字符),在使用文件时需要对文件名中的统配字符进行转义处理,使用反斜线(\)来进行通配符的转义。例如foo\*bar,在Makefile中它表示了文件foo*bar
2.2目录搜索
在一个较大的工程中,一般会将源代码和二进制文件(.o文件和可执行文件)安排在不同的目录来进行区分管理。这种情况下,我们需要使用make提供的目录自动搜索依赖文件功能(在指定的若干个目录下搜索依赖文件)。
    2.2.1 一般搜索(变量VPATH
变量VPATH的定义中,使用空格或者冒号(:)将多个目录分开。例如对变量的定义如下:VPATH = src:../headers
它指定了两个搜索目录,src../headers。对于规则foo:foo.c如果foo.csrc目录下,此时此规则等价于foo:src:/foo.c
    2.2.2 选择性搜索(关键字vpath
它的使用方法有三种:
1vpath PATTERN DIRECTORIES
为符合模式PATTERN的文件指定搜索目录DIRECTORIES。多个目录使用空格或者冒号(:)分开。PATTERN需要包含模式字符%%意思是匹配一个或者多个字符,例如,%.h表示所有以.h结尾的文件。例如:
vpath %.h ../headers
其含义是:Makefile中出现的.h文件;如果不能在当前目录下到,则到目录../headers
寻。
2vpath PATTERN
清除之前为符合模式PATTERN的文件设置的搜索路径。
3vpath
清除所有已被设置的文件搜索路径。
2.3makefile伪目标
伪目标不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时我们也可以将一个伪目标称为标签。使用伪目标有两点原因:1. 避免在我们的Makefile中定义的只执行命令的的目标和工作目录下的实际文件出现名字冲突。2. 提高执行make时的效率。例:
clean:
rm *.o temp
当前工作目录下存在文件clean时,在我们输入make clean时。规则没有依赖文件,所以目标被认为是最新的而不去执行规则作定义的命令,命令rm将不会被执行。这并不是我们的初衷。为了避免这个问题,我们可以将目标clean明确的声明为伪目标。将一个目标声明为伪目标需要将它作为特殊目标.PHONY的依赖。如下:
.PHONY : clean
这样目标clean就是一个伪目标,无论当前目录下是否存在clean这个文件,我们输make clean之后,rm命令都会被执行。目标clean书写格式如下:
.PHONY: clean
clean:
rm *.o temp
2.4makefile的静态模式
    静态模式规则是这样一个规则:规则存在多个目标,并且不同的目标可以根据目标文件
的名字来自动构造出依赖文件。静态模式规则的基本语法:
TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...
COMMANDS
...
我们来看一个例子,它根据相应的.c文件来编译生成foo.obar.o文件:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
例子中,规则描述了所有的.o文件的依赖文件为对应的.c文件,对于目标foo.o,取其茎foo替代对应的依赖模式%.c中的模式字符%之后可得到目标的依赖文件foo.c。这
就是目标foo.o的依赖关系foo.o: foo.c,规则的命令行描述了如何完成由foo.c编译生成目标foo.o。命令行中$<$@是自动化变量,$<表示规则中的第一个依赖文件,$@表示规则中的目标文件。以上的规则就是描述了以下两个具体的规则:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
3.makefile规则的命令
规则的命令由命令行组成,他们被一条一条的执行。规则中除了第一条紧跟在依赖列表之后使用分号隔开的命令以外,其它的每一行命令行必需一[Tab]字符开始。多个命令行之间可以有空行和注释行,在执行规则时他们将被忽略。命令中字符#到行末的内容被认为是注释,#可以不在此行的行首,此时#之前的内容不会被作为注视处理。
3.1 命令的回显
    通常,make在执行命令行之前会把要执行的命令行进行输出。我们称之为回显,就好像我们输入命令执行一样。 如果要执行的命令行以字符@开始,则make在执行时这个命令就不会被回显。典型的用法是我们在使用echomakefile phony命令输出一些信息时。如:
@echo 开始编译XXX模块......
make执行时,将输出开始编译XXX模块......这个信息。如果在命令行之前没有字符@,那么,make的输出就是:
echo编译XXX模块......
编译XXX模块......
    3.2 命令执行的错误
    通常;规则中的命令在运行结束后,make会检测命令执行的返回状态,如果返回成功,那么就执行下一条命令。如果一个规则中的某一个命令出错,make就会放弃对当前规则的
执行,也有可能会终止所有规则的执行。 为了忽略一些无关命令执行失败的情况,我们可以在命令之前加一个减号-(在[Tab]字符之后),来告诉make忽略此命令的执行失败。例如对于clean目标我们就可以这么写:
clean:
-rm *.o
其含义是:即使执行“rm”删除文件失败,make也继续执行。
    3.3 make的递归执行
make的递归调用指的是:在Makefile中使用make作为一个命令来执行本身或者其它makefile文件。递归调用在一个存在有多级子目录的项目中非常有用。
subsystem:
cd subdir && $(MAKE)
其等价于规则:
subsystem:
$(MAKE) -C subdir
我们对这两个规则的命令进行简单说明,规则中$(MAKE)是对变量MAKE 的引用。
第一个规则命令的意思是:进入子目录,然后在子目录下执行make。第二个规则时用了make-C选项,同样是首先进入子目录而后再执行make
    3.4 变量和递归
    当上层make过程要将所执行的Makefile中的变量传递给子make过程时,需要明确地指出。在GNU make中,实现此功能的指示符是export。当一个变量使用export进行声明后,变量和变量的值将被加入到当前工作的环境变量中,以后make所执行的所有规则的命令都可以使用这个变量。
上层Makefile中定义的某一个变量需要传递给子make时,应该在上层Makefile中使用指示符export对此变量进行声明。格式如下:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。