makefile 相关知识

来源:互联网 发布:淘宝助理导入快递模板 编辑:程序博客网 时间:2024/06/03 21:00

基本介绍:

GNU的make工作时的执行步骤入下:
1. 读入所有的Makefile。
2. 读入被include的其它 Makefile。
3. 初始化文件中的变量。
4. 推导隐晦规则,并分析所有规则。
5. 为所有的目标文件创建依赖关系链。
6. 根据依赖关系,决定哪些目标要重新生成。
7. 执行生成命令。
1-5步为第一个阶段,6-7为第二个阶段。第一个阶段中,如果定义的变量被使用了,那么make会把其展开在使用的位置。

如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。

make的include 关键字

在Makefile使用include关键字可以把别的Makefile文件包含进来,这很像C语言的#include预编译指令,被包含的文件会原样的放在当前文件的包含位置。

make命令开始时会找寻include所指出的其它Makefile,并把其内容安置在当前的位置。就好像C/C++的#include指令一样。如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么make还会在其他目录下找。如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。

-include<filename> 表示无论include过程中出现什么错误都要继续执行。和其它版本make兼容的相关命令是 sinclude 其作用也是表示出现找不到文件的情况下make 仍然继续执行。 在命令前面加 - 表示在执行的过程中即使出现问题也要执行完命令。

此处需要例子进行演示。

make的自动推导

GNU的make可以自动推导文件以及文件依赖关系以及相应的编译命令,于是我们就没必要去在每一个[.o]文件后都写上编译命令。只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中。如果make找到一个whatever.o,那么whatever.c就会是whatever.o的依赖文件并且编译命令 cc -c whatever.c 也会被推导出来。

此处需要例子进行演示。

文件搜寻

大的工程中有大量的源文件,通常的做法是把这许多的源文件分类并存放在不同的目录中。所以当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make让make在自动去找。Makefile文件中的特殊变量“VPATH”就是完成这个功能的。如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src : ../headers

上面的的定义指定两个目录,“src”和“../headers”,目录由“冒号”分隔。另一个设置文件搜索路径的方法是使用make的“vpath”关键字(注意,它是全小写的),这不是变量这是一个make的关键字,这和上面提到的那个VPATH变量很类似,但是它更为灵活。它可以指定不同的文件在不同的搜索目录中,这是一个很灵活的功能。

它的使用方法有三种:

1. vpath < pattern> < directories>         为符合模式< pattern>的文件指定搜索目录<directories>。

2. vpath < pattern>                                   清除符合模式< pattern>的文件的搜索目录。

3. vpath                                                      清除所有已被设置好了的文件搜索目录。

< pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如“%.h”表示所有以“.h”结尾的文件。< pattern>指定了要搜索的文件集,< directories>则指定了的文件集的搜索的目录。例如:  vpath %.h ../headers   该语句表示 make在“../headers”目录下搜索所有以“.h”结尾的文件(如果某文件在当前目录没有找到的话)。

伪目标

“.PHONY” 显示地指明一个目标是伪目标。例如:

.PHONY : clean

 它”向make说明,clean 只是一个标签,与源文件中是否有clean这个文件无关。 make 是按照规程中依赖文件的时间是否新于目标文件是时间

来决定是否执行生成规则的命令。 伪目标没有对应的磁盘文件,所以当 执行 make clean 的时候,该条规则对应的命令总是要执行的。

当伪目标是Makefile中的默认目标( 第一个目标) 的时候, 当 执行 make  的时候 , $(targets) 会被生成。

targets := app1 app2 app3.PHONY :  allall : $(targets)xxxxx #shell cmdsapp1 : app1.cpp$(CXX) $<  -o  $@app2 : app2.cpp$(CXX) $<  -o  $@app3 : app3.cpp$(CXX) $<  -o  $@

makefile 函数的使用

在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。函数的返回值可以当做变量来使用。

函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(<function> <arguments> )

调试Makefile常用的函数

$(info TEXT )
可以输出makefile中的宏定义,是我常用的Makefile 调试函数之一。
$(info  ******** CC = $(CC)) 输出

********CC = cc

字符串处理类函数

$(subst <from>,<to>,<text> )
名称:字符串替换函数——subst。
功能:把字串<text>中的<from>字符串替换成<to>。
返回:函数返回被替换过后的字符串。

例子:

$(strip <string> )
名称:去空格函数——strip。
功能:去掉<string>字串中开头和结尾的空字符。
返回:返回被去掉空格的字符串值。

例子:

$(words <text> )
名称:单词个数统计函数——words。
功能:统计<text>中字符串中的单词个数。
返回:返回<text>中的单词数。

例子:

$(word <n>,<text> )
名称:取单词函数——word。
功能:取字符串<text>中第<n>个单词。(从一开始)
返回:返回字符串<text>中第<n>个单词。如果<n>比<text>中的单词数要大返回空字符串。
例子:

$(wordlist <s>,<e>,<text> )
名称:取单词串函数——wordlist。
功能:从字符串<text>中取从<s>开始到<e>的单词串。<s>和<e>是一个数字。
返回:返回字符串<text>中从<s>到<e>的单词字串。如果<s>比<text>中的单词数要大返回空字符串。如果<e>大于<text>的单词数返回从<s>开始到<text>结束的单词串。

例子:

$(sort <list> )
名称:排序函数——sort。
功能:给字符串<list>中的单词排序(升序)。
返回:返回排序后的字符串。
备注:sort函数会去掉<list>中相同的单词

示例:

目录操作相关的函数

$(dir <names...> )
名称:取目录函数——dir。
功能:从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。
返回:返回文件名序列<names>的目录部分。
示例: $(dir src/foo.c hacks)返回值是“src/  ./”。
$(notdir <names...> )
名称:取文件函数——notdir。
功能:从文件名序列<names>中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。
返回:返回文件名序列<names>的非目录部分。
示例: $(notdir src/foo.c hacks)返回值是“foo.c hacks”。

shell函数

shell函数不同于除“wildcard”函数之外的其它函数。make可以使用它来和外部通信。
 函数功能:函数“shell”所实现的功能和shell中的引用(``)相同。实现了命令的扩展。意味着需要一个shell 命令作为它的参数,而返回的结果是此命令在shell中的执行结果。make仅仅对它的回返结果进行处理;make将函数的返回结果中的所有换行符(“\n”)或者一对 “\n\r” 替换为单空格并去掉末尾的回车符号(“\n”)或者 “\n\r” 。函数展开式时,它所调用的命令(它的参数)得到执行。除了对它的引用出现在规则的命令行中和递归的变量定义引用以外,大多数情况下,make在读取Makefile时函数shell就被扩展。
 返回值:函数 “shell” 的参数在shell中的执行结果。
 函数说明:函数本身的返回值是其参数的执行结果,没有进行任何处理。对结果的处理是由make进行的。当对函数的引用出现在规则的命令行中,命令行在执行时函数引用才被展开。展开过程函数参数的执行时在另外一个shell进程中完成的,因此对于出现在规则命令行的多级“shell”函数引用需要谨慎处理,否则会影响效率(每一级的“shell”函数的参数都会有各自的shell进程)。
示例1:
contents := $(shell cat foo)
将变量“contents”赋值为文件“foo”的内容,文件中的行在变量中使用空格(而不是换行符)分割。
示例2:
files := $(shell echo *.c)
将变量“files”赋值为当前目录下所有.c文件的列表(文件名之间使用空格分割)。在shell中之行的命令是“echo *.c”,它会返回当前目录下的所有.c文件列表。上例的执行结果和函数“$(wildcard *.c)”的结果相同。

参考资料

http://blog.csdn.net/ruglcc/article/details/7814546

http://www.yayu.org/book/gnu_make/  点击打开链接


0 0
原创粉丝点击