一、概述
一个Makefile中主要包含的内容有,注释、文件包含、变量定义、条件判断、函数、规则,其中规则是整个Makefile的核心。一个Makefile的主要任务就在规则中完成。
1、注释
2、文件包含
3、变量定义
4、条件判断
5、函数
6、规则
二、注释
在Makefile中,也允许注释,但只提供单行注释,其注释符和shell一样,‘#’,凡是以#开头的行都认为是注释行。如下所示:
三、文件包含
在Makefile也和C语言一样有include的用法,include后面跟一个Makefile文件名,其功能和C语言中的include类似,就是把被包含的Makefile文件的内容全部原本的复制到包含文件中来,这个用法多用于在一个项目中有多个Makefile,分别在不同的目录下,这样我们可以写一个公共Makefile,这个Makefile中包含一些公共变量的定义,其他目录下的Makefile可以把这个公共Makefile文件包含进去。例子
四、变量定义
1、变量的基础
在Makefile中,变量定义主要有如下几种方式:
这些定义方式中,按照展开方式不同分两类,方式一、方式二、方式五,都是使用时展开,就是无论前面如何定义,变量真正的含义都是到使用的时候才展开,而方式三是直接展开,就是变量定义的时候就展开为真正的值,而方式四是追加变量,他的展开方式要看原有的变量是如何定义的。有这种区别就导致一种结果,第一类方式定义的变量可以递归引用当前还未定义的变量,而第二类则不允许这样。
变量的引用可以采用$(variable)和${variable}两种方式。
2、变量的高级应用
变量的替换引用:$(VAR:A=B)把变量VAR中的所有有A的地方都替换为B,如
override指示符:Makefile有一种特性,在Makefile中定义的常规变量,会被执行make命令是的参数变量覆盖,比如:
如果执行make时使用make CFLAGS=O2,那么CFLAGS会变为o2,
为了解决这个问题,可以使用override指示符
这样,参数变量中指定的内容不会覆盖Makefile中定义的变量。
目标指定变量和模式指定变量:通常Makefile中的变量都是全局的,而目标指定变量和模式指定变量都是对某个目标或者某种模式局部的,如:
五、条件判断
条件判断有如下四种形式:
六、函数
1、文本处理函数
subst
patsubst
strip
findstring
filter
filter-out
sort
word
words
wordlist
firstword
2、文件名处理
dir
notdir
suffix
basename
addsuffix
addprefix
join
wildcard
3、其他
error
warning
shell
origin
foreach
call
if
eval
value
七、规则
1、基础
规则是一个Makefile的核心,通俗的讲就是一句话:规则描述了何种情况下使用什么命令来重建一个特定的文件,三个元素,目标、依赖、命令,通常格式如下:
这三个要素都是有用户手动写出来的叫显示规则,如果没有,make也内建了一些常用的规则,make会自己去推导,这样的规则叫隐含规则。
2、显示规则
显示规则就是上面介绍的,规则的三要素都直接写出来的,
3、隐式规则
所谓隐式规则就是make会自动为一些目标推导依赖,推导命令的规则,可以在make中用-r或--no-builtin-rules来禁用。
下面列出c和c++相关的隐含规则:
1、编译c的隐含规则:<n>.o的目标的依赖会自动推导为<n>.c,并用命令$(CC) -c $(CPPFLAGS) $(CFLAGS)来生成.
2、编译c++的隐含规则:<n>.o的目标的依赖会自动推导为<n>.cc,并用命令$(CXX) -c $(CPPFLAGS) $(CFLAGS)来生成。
3、链接Object文件的隐含规则:<n>目标依赖于<n>.o,链接命令是$(CC) $(LDFLAGS)<n>.o $(LOADLIBES)$(LDLIBS),这一规则对多个依赖文件也是适用的,如x:y.o x.o z.o,但是依赖中至少要有同名的。
隐含规则通常都使用一些系统变量,先列出如下:
1、AR:默认是ar
2、CC:默认是cc
3、CXX:默认是g++
4、CPP:c程序的预处理器,默认是$(CC) -E
5、RM:删除文件,默认是rm -f
关于命令参数的变量:
1、ARFLAGS:打包程序AR的参数,默认是rv
2、CFLAGS:C语言的编译参数
3、CXXFLAGS:C++语言的编译器参数
4、CPPFLAGS:C预处理器参数
5、LDFLAFS:链接器参数
1、模式规则
隐含规则整体感觉太玄,但是可以用模式规则来定义隐含规则,它的目标中必须有%号,如:
这个就是模式规则,这个规则表明,所有<n>.c到<n>.o的编译都使用Command,而不是内建的默认命令。
2、静态模式规则
静态模式规则是模式规则中的一种特例,模式规则是对所有的符合模式的都起作用,而静态模式规则是对特定的目标是用的一种模式规则,如
其中%.o:%.c这个模式规则是只对objects这个目标起作用的。
3、自动化变量
在写一些规则的时候,如果要把所有的目标和依赖都写出来,会很不方便,所以需要有个变量可以自动的赋值为目标或依赖,自动化变量就是这样一些变量,下面列举几个常用的自动化变量:
1、$@:规则中所有的目标文件集
2、$<:依赖的第一个文件,如果依赖是以模式定义的,那就表示所有依赖文件集
3、$^:规则中的依赖文件集,并且是做了重复删除的
4、$+:跟$^一样,就是没做重复删除。
八 例子
根据项目的大小,可以把项目建成平铺式(小型项目)和嵌套式(大型项目),而这两种项目的Makefile文件也会稍有不同,前者通常一个Makefile就可以,放在顶层目录,而后者需要分不同模块写几个不同的Makfile,通过一个顶层的Makefile来包含。
下面介绍一个可以用在通常平铺项目中的通用Makefile:
这里用到一个实用的技术,就是利用gcc的-MM选项,来自动分析一个.c文件所包含的.h文件,并用一段shell代码来生成一个叫依赖文件的.d文件,这个文件中包含一组依赖关系如:
用来产生.d文件的规则就是下面这段
这其实是一个模式规则,所有.c文件到.d文件的编译都用这组命令。
生成.d文件后,包含进Makefile,就是一组规则,这就是自动生成依赖