9.2 make命令和makefile文件
9.2.3 makefile文件中的注释
makefile文件中的注释以#号开头,一直延续到这一行的结束.和C语言的源文件注释一样,makefile文件中的注释可以帮助程序的编写者以及其他人理解最初编写这个文件的目的.9.2.4 makefile文件中的宏
mkaefile文件允许使用宏以一种更通用的格式来书写它们.通过语句MACRONAME=value在makefile文件中定义宏, 引用宏的方法是使用$(MACRONAME)或${MACRONAME}.make的某些版本还接受$MACRONAME的用法.如果想把一个宏的值设置为空,可以令等号=后面为空.
makefile文件中的宏常被用于设置编译器的选项.在软件的开发过程中,通常开发人员不会对编译结果进行优化,而是将调试信息包含进去.但是对于软件的发行版,往往又需要反过来,即编译结果是一个不包含调试信息的容量较小的二进制可执行文件,使其执行速度尽可能快.
Makefile1文件的另一个问题是,它假设编译器的名字是gcc,而在其他UNIX系统中,编译器的名字可能是cc或c89.如果想要将makefile文件移植到另一个版本的UNIX系统中,或在现有的系统中使用另一个编译器,为了使其工作,将不得不修改makefile文件中许多行的内容.宏是用来收集所有这些与系统相关内容的好办法,通过使用宏定义,可以方便地修改这些内容.
宏通常是在makefile文件中定义的,也可以在调用make命令时在命令行上给出宏定义,例如命令make CC=c89.命令行上的宏定义将覆盖在makefile文件中的宏定义.当在makefile文件之外使用宏定义时,要注意宏定义必须以单个参数的形式传递,所以应避免在宏定义中使用空格或者给宏定义加引号.
编写Makefile2,它使用了一些宏定义
make命令将$(CC),$(CFLAGS)和$(INCLUDE)替换为相应的宏定义,这与C语言编译器对#define语句的处理方式很相似.
事实上,make命令内置了一些特殊的宏定义,通过使用它们,可以让makefile文件变得更加简洁.
宏 定义
$? 当前目录所依赖的文件列表中比当前目录文件还要新的文件
$@ 当前目录的名字
$< 当前依赖文件的名字
$* 不包括后缀名的当前依赖文件的名字
在makefile文件中,可能还会看到下面两个有用的特殊字符,它们出现在命令之前.
-:告诉make命令忽略所有错误.
@:告诉make在执行某条命令前不要将该命令显示在标准输出上.如果想用echo命令给出一些说明信息,这个字符将非常有用.
9.2.5 多个目标
通常制作不止一个目标文件或者多组命令集中到一个位置来执行是很有用的,可以通过扩展makefile文件来达到这一目的.下面的例子中,在makefile文件中增加一个clean选项来删除不需要的目标文件,增加一个install选项来将编译成功的应用程序安装到另一个目录下.
编写Makefile3
clean:
-rm main.o 2.o 3.o
install: myapp
@if [ -d $(INSTDIR) ]; \
then \
cp myapp $(INSTDIR);\
chmod a+x $(INSTDIR)/myapp;\
chmod og-w $(INSTDIR)/myapp;\
echo "Installed in $(INSTDIR)";\
else \
echo "Sorry, $(INSTDIR) does not exist";\
fi
Makefile3中有几处需要注意(如上所示):
首先,特殊目标all仍然只指定了myapp这一个目标.因此,如果在执行make命令时未指定目标,它的默认行为就是创建目标myapp.
其次是两个新增的目标:clean和install. 目标clean用rm命令来删除目标文件.rm命令以减号-开头,减号-的含义让make命令忽略rm命令的执行结果.这意味着,即使由于目标文件不存在而导致rm命令返回错误,命令make clean也会成功.用于制作目标clean的规则并未给目标clean定义任何依赖关系,行clean: 后面是空的,因此该目标总被认为是过时的,所以在执行make命令时,如果指定目标clean,则该目标所对应的规则将总被执行.
目标install依赖于myapp,所以make命令知道它必须首先创建myapp,然后才能执行制作该目标所需的其他命令.用于制作install目标的规则由几个shell脚本命令组成.由于make命令在执行规则时会调用一个shell,并且会针对每个规则使用一个新shell,所以 必须在上面每行代码的结尾加上一个反斜杠\,让所有shell脚本命令在逻辑上处于同一行,并作为一个整体传递给一个shell执行.这个 命令以符号@开头,表示make在执行这些规则之前不会在标准输出上显示命令本身.
目标install按顺序执行多个命令将应用程序安装到其最终位置.它并没有在执行下一个命令前检查前一个命令的执行是否成功.如果这点很重要,则可以将这些命令用符号&&连接起来.例如cp myapp (INSTDIR) \
&&对于shell而言,每个后续命令只在前面的命令都执行成功的前提下才被执行.