make
是Linux下的一个工具,根据makefile的内容进行源文件的编译,也就是一个解释Makefile指令的命令行工具,执行make命令时,会先查找Makefile的文件作为编译文件,找不到再查找makefile,它根据Makefile中的第一个目标依次找它依赖的目标
make
执行后会有3个退出码
1. 什么都不提示表示执行成功
2. 返回1
,说明make运行时产生错误
3. 若使用了-q选项,使得make有一些目标不用更新,返回2
4. make的指令行要缩进一个tab键,不是4个空格
使用
make [options] [target]
-f filename 显式指定文件作为makefile
-C dirname 指定make在开始运行后的工作目录为dirname
-e 不允许在Makefile中替换环境变量的赋值
-k 执行命令出错时,放弃当前目标,继续维护其它目标,也就是跳过错误
-n 仅仅用于显示执行过程,不实际执行
-p 显示所有的变量和内部规则
-r 忽略内部规则
-s 执行单不显示命令,常用来检测Makefile的正确性
-S 若执行出错就退出
-t 修改每个目标的创建日期
-I 忽略运行make中执行命令的错误
-V 显示make的版本号
Makefile
的规则是若这个文件未被编辑过,则所有的C文件都会被编译和连接,若某几个文件被修改,则只需要编译修改后的文件,若头文件被修改,则只需要编译引用了这几个头文件的C文件
Makefile
包含5个方面的内容:
1. 显式规则:显式指出生成文件、依赖文件
2. 隐式规则:make有自动推导的功能,可以简略的写makefile
3. 变量定义:类似C的宏,会被扩展到其它引用的地方
4. 文件指示:可以向其它语言的include一样,包含其它Makefile文件
5. 注释:#
在规则里使用通配符
~/test
表示当前用户目录下的test
*
表示所有 eg rm *.o
表示移除所有的 .o
文件
?
匹配一个字符
[...]
$?
是一个自动化变量,表示所有比目标新的依赖文件的集合
Note
*.o
不会展开,想要展开的话使用 $(wildcard *.o)
objects=*.o
不会展开
objects:=$(wildcard *.o)
会展开
.PHONY
用来显式的指定一个目标为伪目标,不管这个文件是否存在,都执行命令
变量
变量可以是包含字符、数字、下划线,但不能是:
=
#
空字符(空格或者回车)
,大小写敏感,需要赋初值,使用时需要在变量前加$
,最好用()
或者 {}
将变量包裹起来,若要真实使用$
,要写成$$
eg: objects = program.o foo.o utils.o
program:$(objects)
gcc -o program $(objects)
$(objects):defs.h
:=
使得前边的变量不能使用后边的变量
?=
若值未定义,则使用后边的值
+=
给变量追加值,若前边的未定义,自动使用后边的值
define
将多条命令定义为一个变量
override <var>:=<val>
目标变量和模式变量
<target..>:<var-assignment>
<target..>:overide<var-assignment>
<target>为目标序列,<var-assignment>为各种表达式eg `:=` `?=` `+=`
模式变量就是将target写成pattern
eg %.o:CFLAGS=-O
常用函数调用
$(subst <from>,<to>,<text>) 将text中的from替换成to
$(patsubst <from>,<to>,<text>) 将查找符号模式pattern的单词进行替换
$(findstring <find>,<in>)在in中查找find,找到返回,否则返回空串
$(filter <pattern>,<text>)以pattern模式过滤字符串中的单词,保留符号pattern的
$(filter-out <pattern>,<text>)去除符号某个模式的
$(sort <list>)将list中的单词按字母升序排列
$(word <n>,<text>)从单词中取出第n个
$(wordlist <s>,<e>,<text>)从第start取到第n个
$(words <text>)单词个数统计
$(firstword <text>)取字符串的第一个单词
$(dir <names..>)从文件序列中取出目录
$(notdir <names..>)取文件名
$(suffix <names..>)取文件后缀
$(basename <names..>)取前缀
$(addsufix <suffix>,<names..>)加后缀
$(addprefix <prefix>,<names..>)加前缀
$(join <list1>,<list2>)将list2中的每个单词对应插入到list1后边
$(foreach <var>,<list>,<text>)list中的值被取出,放到var中,进行text的处理
$(if<condition>,<then-part>)
$(if<condition>,<then-part>,<else-part>)
$(call <express>,<param1>,<param2>)
eg. revers=$(2)$(1)
foo=$(call revers,a,b) 那么foo就是b a
$(origin <var>)判断变量是在哪里定义的
eg. ifdef a #如果存在变量a
ifeq "$(origin a)" "evnvirenment" #如果变量a是环境变量
a=test #将环境变量a重新定义
endif
endif
$(shell ..)直接执行shell命令
eg. a:=$(shell cat foo)将foo的内容赋值给a
控制make的函数
$(error <text..>)函数产生致命错误,错误信息为text
makefile的自动化变量
$@ 所有目标变量的集合
$% 仅当目标是函数库文件时,表示规则中的目标成员名
$< 依赖目标中的第一个目标名字,若依赖目标是以模式(%)定义的,则表示符合模式的一系列文集
$? 所有比目标新的依赖目标的集合
$^ 所有依赖目标的集合,若有重复,自动去除
$+ 同$^不去重
$* 目标模式中%及其之前的步伐
$(@D)|$(*D) 取文件目录部分
$(@F)|$(*F) 取文件部分,不包括后缀
$(%D) 函数包文件的目录部分
$(%F) 函数包文件成员的文件部分
$(<D) 依赖目标中的第一个目标的目录部分
$(<F) 依赖目标中的第一个目标的文件名部分
$(^D) 所有依赖目标的目录部分(无相同)
$(^F) 所有依赖目标的文件名部分(无相同)
$(+D) 所有依赖目标的目录部分(可以相同)
$(+F) 所有依赖目标的文件名部分(可以相同)
$(?D) 所有被更新文件的目录部分
$(?F) 所有被更新文件的文件名部分