一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,在Windows下是.obj文件,UNIX下是.o文件,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常需要告诉编译器头文件的所在位置。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
在大多数时候,由于源文件太多,编译生成的 中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是.lib文件,在UNIX下,是Archive File,也就是.a文件。
1.3 Makefile介绍
写一个Makefile来告诉make命令如何编译和链接C文件和头文件,规则是;
1) 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2) 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3) 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
1.3.1 Makefile的规则
Target…. : prerequisites…
Command
…
…
Target可以是一个目标文件,可以使ObjectFile,也可以是执行文件,还可以是一个标签(Label)
Prerequisite就是要生成target所需要的文件或是目标。
Command是make需要执行的命令
这是一个文件的依赖关系,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。
在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。
1.3.3 make是如何工作的?
在默认的方式下,也就是我们只输入make命令。那么,
1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件
2. 如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件。
3. 如果edit文件不存在,或是edit所依赖的后面的.o文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4. 如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件
通过上述分析,像clean这种没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,我们可以显示要make执行----make clean,以此来清除所有的目标文件,以便重编译。
1.3.4 makefile中使用变量
声明一个变量,叫objects,OBJECTS,objs等,以$(objects)的方式来使用这个变量。
1.3.5 让make自动推导
1.5.3在规则中使用通配符
Make支持三种通配符,“*”,“?”,“[…]”
波浪号(“~”)字符在文件名中有比较特殊的用途。如果是“~/test”,表示当前用户的$HOME目录下的test目录。而“~hchen/test”表示用户hchen的宿主目录下的test目录。
通配符代替了一系列的文件,如“*.c”表示所有后缀为c的文件。
1.5.4 文件搜寻
vpath关键字
vpath %.h ../headers
该语句表示,要求make在“../headers”目标下搜索所有以“.h”结尾的文件。
1.5.5 伪目标
“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所有make无法生成它的依赖关系和决定它是否要执行。只有通过显示地指明这个“目标”才能让其生效。
为了避免和文件重名,使用“.PHONY”来显示地指明一个目标是“伪目标”。
1.5.6 多目标
自动变量“$@”表示着目前规则中所有的目标的集合。
1.5.7 静态模式
“$<”表示所有的依赖目标集,“$@”表示目标集。
1.5.8 自动生成依赖性
gcc –MM main.c
GNU组织建议把编译器为每个源文件的自动生成的依赖关系放到一个文件中,为每个“name.c”的文件都生成一个“name.d”的Makefile文件,[.d]文件中就存放对应[.c]文件的依赖关系。
1.6 书写命令
1.6.4 嵌套执行make
Subsystem :
cdsubdir && $(MAKE)
传递变量到下级Makefile中,export <variable…>,
有两个变量,一个是SHELL,一个是MAKEFLAGS,总是要传递到下层Makefile中,特别是MAKEFLAGS变量,其中包含了make的参数信息。
1.6.5定义命令包
如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。以“define”开始,以“endef”结束。
1.7 使用变量
1.7.3 变量高级用法
第一种是变量值的替换
第二种时把变量的值再当成变量
1.9.2 字符串处理函数
$(subst <from>;,<to>;,<text>;)
名称:字符串替换函数----subst
功能:把字串<text>中的<from>字符串替换成<to>
$(patsubst<pattern>;,<replacement>;,<text>;)
名称:模式字符串替换函数----patsubst
功能:查找<text>;中的单词(单词以“空格”、“tab”或“回车”等分隔)是否符合模式<pattern>;,如果匹配的话,则以<replacement>;替换。
$(strip<string>;)
名称:去空格函数---strip
功能:去掉<string>;字符中开头和结尾的空字符。
$(findstring<find>;,<in>;)
名称:查找字符串函数---findstring
功能:在字串<in>中查找<find>字串
返回:如果找到,那么返回<find>;否则返回空字符串
$(filter <pattern…>;,<text>;)
名称:过滤函数---filter
功能:以<pattern>;模式过滤<text>;字符串中的单词,保留符合模式<pattern>;的单词
$(filter-out <patterm…>;,<text>;)
反过滤函数
$(sort <list>;)
排序函数---sort
功能:给字符串<list>;中的单词排序(升序)
$(word <n>;,<text>;)
取单词函数---word
功能:取字符串<text>中第<n>个单词。(从一开始)
$(wordlist <s>;,<e>;,<text>;)
取单词串函数---wordlist
功能:从字符串<text>;中取从<s>;开始到<e>;的单词串
$(words <text>;)
单词个数统计函数---words
功能:统计<text>;中字符串中的单词个数
$(firstword <text>;)
首单词函数---firstword
1.9.3 文件名操作函数
$(dir <names…>;)
名称:取目录函数---dir
功能:从文件名序列<names>;中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。
$(notdir <names..>;)
名称:取文件函数---notdir
功能:从文件名序列<names>;中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。
$(suffix <names…>;)
取后缀函数---suffix
功能:从文件名序列<names>;中取出各个文件名的后缀
$(basename <names….>;)
取前缀函数---basename
功能:从文件名序列<names>;中取出各个文件名的前缀部分。
$(addsuffix <suffix>;,<names…>;)
加后缀函数---addsuffix
功能:把后缀<suffix>;加到<names>;中的每个单词后面
$(addprefix <prefix>;,<names…>;)
加前缀函数---addprefix
$(join <list1>;,<list2>;)
名称:连接函数---join
功能:把<list2>;中的单词对应地加到<list1>
1.9.4 foreach函数
$(foreach <var>;,<list>;,<text>;)
功能:把参数<list>;中的单词逐一取出放到参数<var>;所指定的变量中,然后在执行<text>;所包含的表达式。每一次<text>会返回一个字符串,循环过程中,<text>的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串将会是foreach函数的返回值。
1.9.5 if函数
$(if <condition>;,<then-part>;)
自动变量
$@
表示规则中的目标文件集。
$@
仅当目标是函数库文件中,表示规则中的目标成员名。
$<
依赖目标中的第一个目标名字。
$?
所有比目标新的依赖目标的集合。
$^
所有的依赖目标的集合
$+
也是所有依赖目标的集合。
$*
这个变量表示目标模式中“%”及其之前的部分。