Makefile的理论学习记录
Posted 七 六 伍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Makefile的理论学习记录相关的知识,希望对你有一定的参考价值。
1:Makefile 的变量的四种基本赋值方式:
简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
2:自动化变量说明:
Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令,其结构如下所示:
targets : prerequisites
command
相关说明如下:
targets:规则的目标,可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;
prerequisites:是我们的依赖文件,要生成 targets 需要的文件或者是目标。可以是多个,也可以是没有;
command:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。
注意:我们的目标和依赖文件之间要使用冒号分隔开,命令的开始一定要使用Tab键。
2、它的具体工作顺序是:当在 shell 提示符下输入 make 命令以后。 make 读取当前目录下的 Makefile 文件,并将 Makefile 文件中的第一个目标作为其执行的“终极目标”,开始处理第一个规则(终极目标所在的规则)。在我们的例子中,第一个规则就是目标 “main” 所在的规则。
“.o” 文件为目标的规则处理有下列三种情况:
目标 “.o” 文件不存在,使用其描述规则创建它;
目标 “.o” 文件存在,目标 “.o” 文件所依赖的 “.c” 源文件 “.h” 文件中的任何一个比目标 “.o” 文件“更新”(在上一次 make 之后被修改)。则根据规则重新编译生成它;
目标 “.o” 文件存在,目标 “.o” 文件比它的任何一个依赖文件(".c" 源文件、".h" 文件)“更新”(它的依赖文件在上一次 make 之后没有被修改),则什么也不做。
3、如果我们的通配符使用在依赖的规则中的话一定要注意这个问题:不能通过引用变量的方式来使用,如下所示。
纯文本复制
OBJ=*.c
test:$(OBJ)
gcc -o $@ $^
我们去执行这个命令的时候会出现错误,提示我们没有 “.c" 文件,实例中我们相要表示的是当前目录下所有的 “.c” 文件,但是我们在使用的时候并没有展开,而是直接识别成了一个文件。文件名是 ".c”。
如果我们就是相要通过引用变量的话,我们要使用一个函数 “wildcard”,这个函数在我们引用变量的时候,会帮我们展开。我们把上面的代码修改一下就可以使用了。
OBJ=$(wildcard *.c)
test:$(OBJ)
gcc -o $@ $^
这样我们再去使用的时候就可以了。调用函数的时候,会帮我们自动展开函数。
4、"%.o" 把我们需要的所有的 “.o” 文件组合成为一个列表,从列表中挨个取出的每一个文件,"%" 表示取出来文件的文件名(不包含后缀),然后找到文件中和 "%"名称相同的 “.c” 文件,然后执行下面的命令,直到列表中的文件全部被取出来为止。
VPATH的使用
在 Makefile 中可以这样写:
VPATH := src
我们可以这样理解,把 src 的值赋值给变量 VPATH,所以在执行 make 的时候会从 src 目录下找我们需要的文件。
当存在多个路径的时候我们可以这样写:
VPATH := src car
或者是
VPATH := src:car
多个路径之间要使用空格或者是冒号隔开,表示在多个路径下搜索文件。
vpath的使用
学习了 VPATH的使用,我们再来了解一下关键字搜索 vpath 的使用,这种搜索方式一般被称作选择性搜索。使用上的区别我们可以这样理解:VPATH 是搜索路径下所有的文件,而 vpath 更像是添加了限制条件,会过滤出一部分再去寻找。
具体用法:
vpath PATTERN DIRECTORIES
vpath PATTERN
vpath
( PATTERN:可以理解为要寻找的条件,DIRECTORIES:寻找的路径 )
首先是用法一,命令格式如下:
vpath test.c src
可以这样理解,在 src 路径下搜索文件 test.c。多路径的书写规则如下:
vpath test.c src car 或者是 vpath test.c src : car
多路径的用法其实和 VPATH 差不多,都是使用空格或者是冒号分隔开,搜索路径的顺序是先 src 目录,然后是 car 目录。
其次是用法二,命令格式如下:
vpath test.c
用法二的意思是清除符合文件 test.c 的搜索目录。
最后是用法三,命令格式如下:
vpath
vpath 单独使的意思是清除所有已被设置的文件搜索路径。
8、Makefile ifeq、ifneq、ifdef和ifndef(条件判断)
关键字 功能
ifeq 判断参数是否不相等,相等为 true,不相等为 false。
ifneq 判断参数是否不相等,不相等为 true,相等为 false。
ifdef 判断是否有值,有值为 true,没有值为 false。
ifndef 判断是否有值,没有值为 true,有值为 false。
feq 和 ifneq
条件判断的使用方式如下:
ifeq (ARG1, ARG2)
ifeq ‘ARG1’ ‘ARG2’
ifeq “ARG1” “ARG2”
ifeq “ARG1” ‘ARG2’
ifeq ‘ARG1’ “ARG2”
实例:
libs_for_gcc= -lgnu
normal_libs=
ifeq(
(
C
C
)
,
g
c
c
)
l
i
b
s
=
(CC),gcc) libs=
(CC),gcc)libs=(libs_for_gcc)
else
libs=
(
n
o
r
m
a
l
l
i
b
s
)
e
n
d
i
f
f
o
o
:
(normal_libs) endif foo:
(normallibs)endiffoo:(objects)
$(CC) -o foo $(objects) $(libs)
ifdef 和 ifndef
使用方式如下:
ifdef VARIABLE-NAME
它的主要功能是判断变量的值是不是为空,实例:
实例 1:
bar =
foo = $(bar)
all:
ifdef foo
@echo yes
else
@echo no
endif
实例 2:
foo=
all:
ifdef foo
@echo yes
else
@echo no
endif
通过两个实例对比说明:通过打印 “yes” 或 “no” 来演示执行的结果。我们执行 make 可以看到实例 1打印的结果是 “yes” ,实例 2打印的结果是 “no” 。其原因就是在实例 1 中,变量“foo”的定义是“foo = $(bar)”。虽然变量“bar”的值为空,但是“ifdef”的判断结果为真,这种方式判断显然是有不行的,因此当我们需要判断一个变量的值是否为空的时候需要使用“ifeq" 而不是“ifdef”。
9、在书写伪目标的时候,需要声明目标是一个伪目标,之后才是伪目标的规则定义。目标 “clean” 的完整书写格式如下:
.PHONY:clean
clean:
rm -rf *.o test
使用伪目标有两点原因:
避免我们的 Makefile 中定义的只执行的命令的目标和工作目录下的实际文件出现名字冲突。
提高执行 make 时的效率,特别是对于一个大型的工程来说,提高编译的效率也是我们所必需的。
10、引用变量的格式为$(变量名),函数调用的格式如下:
$( ) 或者是 ${ }
其中,function 是函数名,arguments 是函数的参数,参数之间要用逗号分隔开。而参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号也可以使用花括号。这个其实我们并不陌生,我们之前使用过许多的函数,比如说展开通配符的函数 wildcard,以及字符串替换的函数 patsubst ,Makefile 中函数并不是很多。
今天主要讲的是字符串处理函数,这些都是我们经常使用到的函数,下面是对函数详细的介绍。
模式字符串替换函数,函数使用格式如下:
(
p
a
t
s
u
b
s
t
,
,
)
函
数
说
明
:
函
数
功
能
是
查
找
t
e
x
t
中
的
单
词
是
否
符
合
模
式
p
a
t
t
e
r
n
,
如
果
匹
配
的
话
,
则
用
r
e
p
l
a
c
e
m
e
n
t
替
换
。
返
回
值
为
替
换
后
的
新
字
符
串
。
实
例
:
O
B
J
=
(patsubst ,, ) 函数说明:函数功能是查找 text 中的单词是否符合模式 pattern,如果匹配的话,则用 replacement 替换。返回值为替换后的新字符串。实例: OBJ=
(patsubst,,)函数说明:函数功能是查找text中的单词是否符合模式pattern,如果匹配的话,则用replacement替换。返回值为替换后的新字符串。实例:OBJ=(patsubst %.c,%.o,1.c 2.c 3.c)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到的值是 “1.o 2.o 3.o”,这些都是替换后的值。
字符串替换函数,函数使用格式如下:
(
s
u
b
s
t
,
,
)
函
数
说
明
:
函
数
的
功
能
是
把
字
符
串
中
的
f
o
r
m
替
换
成
t
o
,
返
回
值
为
替
换
后
的
新
字
符
串
。
实
例
:
O
B
J
=
(subst ,, ) 函数说明:函数的功能是把字符串中的 form 替换成 to,返回值为替换后的新字符串。实例: OBJ=
(subst,,)函数说明:函数的功能是把字符串中的form替换成to,返回值为替换后的新字符串。实例:OBJ=(subst ee,EE,feet on the street)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“fEEt on the strEEt”。
去空格函数,函数使用格式如下:
(
s
t
r
i
p
)
函
数
说
明
:
函
数
的
功
能
是
去
掉
字
符
串
的
开
头
和
结
尾
的
字
符
串
,
并
且
将
其
中
的
多
个
连
续
的
空
格
合
并
成
为
一
个
空
格
。
返
回
值
为
去
掉
空
格
后
的
字
符
串
。
实
例
:
O
B
J
=
(strip ) 函数说明:函数的功能是去掉字符串的开头和结尾的字符串,并且将其中的多个连续的空格合并成为一个空格。返回值为去掉空格后的字符串。实例: OBJ=
(strip)函数说明:函数的功能是去掉字符串的开头和结尾的字符串,并且将其中的多个连续的空格合并成为一个空格。返回值为去掉空格后的字符串。实例:OBJ=(strip a b c)
all:
@echo $(OBJ)
执行完 make 之后,结果是“a b c”。这个只是除去开头和结尾的空格字符,并且将字符串中的空格合并成为一个空格。
查找字符串函数,函数使用格式如下:
(
f
i
n
d
s
t
r
i
n
g
,
)
函
数
说
明
:
函
数
的
功
能
是
查
找
i
n
中
的
f
i
n
d
,
如
果
我
们
查
找
的
目
标
字
符
串
存
在
。
返
回
值
为
目
标
字
符
串
,
如
果
不
存
在
就
返
回
空
。
实
例
:
O
B
J
=
(findstring ,) 函数说明:函数的功能是查找 in 中的 find ,如果我们查找的目标字符串存在。返回值为目标字符串,如果不存在就返回空。实例: OBJ=
(findstring,)函数说明:函数的功能是查找in中的find,如果我们查找的目标字符串存在。返回值为目标字符串,如果不存在就返回空。实例:OBJ=(findstring a,a b c)
all:
@echo $(OBJ)
执行 make 命令,得到的返回的结果就是 “a”。
过滤函数,函数使用格式如下:
(
f
i
l
t
e
r
,
)
函
数
说
明
:
函
数
的
功
能
是
过
滤
出
t
e
x
t
中
符
合
模
式
p
a
t
t
e
r
n
的
字
符
串
,
可
以
有
多
个
p
a
t
t
e
r
n
。
返
回
值
为
过
滤
后
的
字
符
串
。
实
例
:
O
B
J
=
(filter , ) 函数说明:函数的功能是过滤出 text 中符合模式 pattern 的字符串,可以有多个 pattern 。返回值为过滤后的字符串。实例: OBJ=
(filter,)函数说明:函数的功能是过滤出text中符合模式pattern的字符串,可以有多个pattern。返回值为过滤后的字符串。实例:OBJ=(filter %.c %.o,1.c 2.o 3.s)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“1.c 2.o”。
反过滤函数,函数使用格式如下:
(
f
i
l
t
e
r
−
o
u
t
,
)
函
数
说
明
:
函
数
的
功
能
是
功
能
和
f
i
l
t
e
r
函
数
正
好
相
反
,
但
是
用
法
相
同
。
去
除
符
合
模
式
p
a
t
t
e
r
n
的
字
符
串
,
保
留
符
合
的
字
符
串
。
返
回
值
是
保
留
的
字
符
串
。
实
例
:
O
B
J
=
(filter-out , ) 函数说明:函数的功能是功能和 filter 函数正好相反,但是用法相同。去除符合模式 pattern 的字符串,保留符合的字符串。返回值是保留的字符串。实例: OBJ=
(filter−out,)函数说明:函数的功能是功能和filter函数正好相反,但是用法相同。去除符合模式pattern的字符串,保留符合的字符串。返回值是保留的字符串。实例:OBJ=(filter-out 1.c 2.o ,1.o 2.c 3.s)
all:
@echo $(OBJ)
执行 make 命令,打印的结果是“3.s”。
排序函数,函数使用格式如下:
(
s
o
r
t
)
函
数
说
明
:
函
数
的
功
能
是
将
中
的
单
词
排
序
(
升
序
)
。
返
回
值
为
排
列
后
的
字
符
串
。
实
例
:
O
B
J
=
(sort ) 函数说明:函数的功能是将 中的单词排序(升序)。返回值为排列后的字符串。实例: OBJ=
(sort)函数说明:函数的功能是将中的单词排序(升序)。返回值为排列后的字符串。实例:OBJ=(sort foo bar foo lost)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“bar foo lost”。
注意:sort会去除重复的字符串。
取单词函数,函数使用格式如下:
(
w
o
r
d
,
)
函
数
说
明
:
函
数
的
功
能
是
取
出
函
数
中
的
第
n
个
单
词
。
返
回
值
为
我
们
取
出
的
第
n
个
单
词
。
实
例
:
O
B
J
=
(word , ) 函数说明:函数的功能是取出函数 中的第n个单词。返回值为我们取出的第 n 个单词。实例: OBJ=
(word,)函数说明:函数的功能是取出函数中的第n个单词。返回值为我们取出的第n个单词。实例:OBJ=(word 2,1.c 2.c 3.c)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“2.c”。
11、Makefile常用文件名操作函数
取目录函数,函数使用格式如下:
(
d
i
r
)
函
数
说
明
:
函
数
的
功
能
是
从
文
件
名
序
列
n
a
m
e
s
中
取
出
目
录
部
分
,
如
果
没
有
n
a
m
e
s
中
没
有
“
/
”
,
取
出
的
值
为
“
.
/
”
。
返
回
值
为
目
录
部
分
,
指
的
是
最
后
一
个
反
斜
杠
之
前
的
部
分
。
如
果
没
有
反
斜
杠
将
返
回
“
.
/
”
。
实
例
:
O
B
J
=
(dir ) 函数说明:函数的功能是从文件名序列 names 中取出目录部分,如果没有 names 中没有 “/” ,取出的值为 “./” 。返回值为目录部分,指的是最后一个反斜杠之前的部分。如果没有反斜杠将返回“./”。实例: OBJ=
(diLinux学习记录:Makefile