学写makefile(《跟我一起写Makefile-陈皓》笔记)

来源:互联网 发布:xilinx mac 编辑:程序博客网 时间:2024/05/22 13:03

1、Makefile用来告诉make命令如何编译和链接文件,规则是:

1) 如果这个工程没有编译过,那么所有C文件都要编译并被链接

2) 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。

3) 如果这个工程的头文件被改变了,那么需要编译引用了这几个头文件的C文件并链接目标程序。

2、注意:makefile文件中每行必须要以[table]键开始

3、可以使用include标识符,语法是:include <filename>

4、GNU的make工作时的执行步骤如下:

1) 读入所有的makefile

2) 读入被include指定的其他makefile

3) 初始化文件中的变量

4) 推导隐晦规则,并分析所有规则

5) 为所有的目标文件创建依赖关系链

6) 根据依赖关系,决定哪些目标要重新生成

7) 执行生成命令

1-5为第一阶段:如果定义的变量被使用了,那么make会把其展开在使用的位置。

5、在makefile编写规则中可以使用的通配符:“*”,“?”,“[…]”。

6、特殊变量VPATH,在make寻找文件的依赖关系时,该变量把一个路径告诉make,让他自动寻找。(多个目录之间使用“:”分割)。

7、vpath是make工具的一个关键字,比VPATH更灵活:

1)vpath<pattern> <dir>:为符合模式<pattern>的文件指定搜索目录

2)vpath<pattern>:清楚符合模式<pattern>的文件的所有目录

3)vpath:清除所有已被设置好的文件搜索目录

Vpath使用方法中的<pattern>需要包含“%”字符,表示匹配0或者若干字符(相当与*)。例子:$(objs): %.o: %.c

8、自动化变量:

“$<”:依赖目标中的第一个目标名字。

“$@”: 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。

“$%”: 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a (bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows 下是[.lib]),那么,其值为空。

“$?”: 所有比目标新的依赖目标的集合,以空格分隔。

“$^”:所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。

“$+”:这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。

“$*”:这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。

“$(@D)”:表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"

就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。

“$(@F)”:表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir$@)"。

9、CFLAGS 表示用于 C 编译器的选项,

CXXFLAGS 表示用于 C++ 编译器的选项。这两个变量实际上涵盖了编译和汇编两个步骤。

CFLAGS: 指定头文件(.h文件)的路径,如:CFLAGS=-I/usr/include -I/path/include。同样地,安装一个包时会在安装路径下建立一个include目录,当安装过程中出现问题时,试着把以前安装的包的include目录加入到该变量中来。

LDFLAGS:gcc 等编译器会用到的一些优化参数,也可以在里面指定库文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安装一个包都几乎一定的会在安装目录里建立一个lib目录。如果明明安装了某个包,而安装另一个包时,它愣是说找不到,可以抒那个包的lib路径加入的LDFALGS中试一下。

LIBS:告诉链接器要链接哪些库文件,如LIBS = -lpthread-liconv

10、参数-M:自动的生成头文件依赖。GNU的c/c++编译器使用的是-MM,否则会把一些标准库的头文件也包含进来。

11、make会把要执行的命令行在命令执行前输出到屏幕上,用@字符在命令行前的话这个命令不被make显示出来。Make –s参数是全面禁止命令的显示。

12、如果要将变量传递到下一级,那么使用export关键字声明(unexport)。

13、在makefile中如果使用“=”为变量赋值,可以嵌套赋值(可能产生递归出错),比如:

A=$(b)

B=$(c)

C=”hello”

但是使用“:=”的话就不能这样赋值了,前边的变量不能使用后边的变量,只能使用在前边已经定义好的变量。

14、“+=”符号给变量追加值,例子:

objs=a.o b.o

objs +=

14、make的系统变量MAKELEVEL表示如果make有一个嵌套执行的动作,那么这个变量会记录当前Makefile的调用层数。

15、makefile中的字符串处理函数:

名称

语法

功能

返回

字符串替换函数-subst

$(subst <from>, <to>, <text>)

把字符串<text>中的<from>字符串替换成<to>

函数返回被替换过后的字符串

模式字符串替换函数-patsubst

$(patsubst <pattern>, <repalcement>, <text>)

查找<text>中的单词是否符合模式<pattern>,如果匹配的话则以<repalcement>替换

函数返回被替换过后的字符串

去空格函数-strip

$(strip <string>)

去掉<string>字串中开头和结尾的空字符

返回被去掉空格的字符串值

查找字符串函数—findstring

$(findstring <find>,<in>)

在字串<in>中查找<find>字串

如果找到,那么返回<find>,否则返回空字符串

过滤函数—filter

$(filter <pattern...>,<text>)

以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词。可以有多个模式。

返回符合模式<pattern>的字串

反过滤函数—filter-out

$(filter-out <pattern...>,<text>)

以<pattern>模式过滤<text>字符串中的单词,去除符合模式<pattern>的单词。可以有多个模式。

返回不符合模式<pattern>的字串

排序函数—sort

$(sort <list>)

给字符串<list>中的单词排序(升序)

返回排序后的字符串(sort 函数会去掉<list>中相同的单词)

取单词函数—word

$(word <n>,<text>)

取字符串<text>中第<n>个单词。(从一开始)

返回字符串<text>中第<n>个单词。如果<n>比<text>中的单词数要大,那么返 

回空字符串。

取单词串函数—wordlist

$(wordlist <s>,<e>,<text>)

从字符串<text>中取从<s>开始到<e>的单词串。<s>和<e>是一个数字。

返回字符串<text>中从<s>到<e>的单词字串。如果<s>比<text>中的单词数要大,那么返回空字符串。如果<e>大于<text>的单词数,那么返回从<s>开始,到<text>结束的单词串。

单词个数统计函数—words

$(words <text>)

统计<text>中字符串中的单词个数(如果我们要取<text>中最后的一个单词,我们可以这样:$(word $(words <te 

xt>),<text>))。

返回<text>中的单词数

首单词函数—firstword

$(firstword <text>)

取字符串<text>中的第一个单词(这个函数可以用 word 函数来实现:$(word 1,<text>))

返回字符串<text>的第一个单词。

16、字符串处理函数

名称

语法

功能

返回

取目录函数—dir

$(dir <names...>)

从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。

返回文件名序列<names>的目录部分

取文件函数—notdir

$(notdir <names...>)

从文件名序列<names>中取出非目录部分。非目录部分是指最后一个反斜杠(“ /”)之后的部分。

返回文件名序列<names>的非目录部分

取后缀函数—suffix

$(suffix <names...>)

从文件名序列<names>中取出各个文件名的后缀。

返回文件名序列<names>的后缀序列,如果文件没有后缀,则返回空字串。

取前缀函数—basename

$(basename <names...>)

从文件名序列<names>中取出各个文件名的前缀部分。

返回文件名序列<names>的前缀序列,如果文件没有前缀,则返回空字串。

加后缀函数—addsuffix

$(addsuffix <suffix>,<names...>)

把后缀<suffix>加到<names>中的每个单词后面。

返回加过后缀的文件名序列。

加前缀函数—addprefix

$(addprefix <prefix>,<names...>)

把前缀<prefix>加到<names>中的每个单词后面

返回加过前缀的文件名序列

连接函数—join

$(join <list1>,<list2>)

把<list2>中的单词对应地加到<list1>的单词后面。如果<list1>的单词个数要比<list2>的多,那么,<list1>中的多出来的单词将保持原样。如果<list2>的单词个数要比<list1>多,那么,<list2>多出来的单词将被复制到<list2>中。

返回连接过后的字符串

是用来做循环用的函数-foreach

$(foreach <var>,<list>,<text>)

把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环过程中,<text>

的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。

 

if 函数很像 GNU 的 make 所支持的条件语句—ifeq

$(if <condition>,<then-part>)

或者

$(if <condition>,<then-part>,<else-part>)

if 函数可以包含“else”部分,或是不含。即 if 函数的参数可以是两个,也可以是三个。<condition>参数是 if 的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,<then-part>会被计算,否则<else-part>会被计算。

而 if 函数的返回值是,如果<condition>为真(非空字符串),那个<then-part>会是整个函数的返回值,如果<condition>为假(空字符串),那么<else-part>会是整个函数的返回值,此时如果<else-part>没有被定义,那么,整个函数返回空字串。

call 函数

$(call <expression>,<parm1>,

<parm2>,<parm3>...)

个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用 call 函数来向这个表达式传递参数。

 

origin函数

$(origin <variable>)

并不操作变量的值,他只是告诉你你的这个变量是哪里来的

 

shell 函数

它的参数应该就是操作系统 Shell 的命令。它和反引号“`”是相同的功能。这就是说,shell 函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令 awk,sed 等等命令来生成一个变量

 

控制make 的函数

make 提供了一些函数来控制 make 的运行。通常,你需要检测一些运行 Makefile 时的

运行时信息,并且根据这些信息来决定,你是让 make 继续执行,还是停止。

 

17、make的命令执行后有三个退出码:

0-表示执行成功

1-   如果make运行时出现任何错误,返回1

2-   如果使用了make的-q选项,并且make使得一些目标不需要更新,那么返回2.

18、GNU make 找寻默认的Makefile 的规则是在当前目录下依次找三个文件“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。也可以使用”-f”或者是”--file”指定make执行的文件。 


0 0
原创粉丝点击