Makefile笔记
命名
文件保存以Makefile
或makefile
为名.当在当前目录下直接输入make
即可执行
如果不是默认的文件名, 可以使用-f
参数
make -f make.some
变量
变量基本用法
变量以
=
赋值
左侧是变量, 右侧是变量的值
objects = main.0 kbd.0 command.0 display.0 \
也可以使用变量来构造变量
A = $(B)B = $(A)
如上所示, 会让make陷入无限的变量展开过程中, 报错. 故可使用下面的:=
变量以
$(objects)
取值
变量使用时要在前面加上$
, 最好用()
或者{}
把变量括起来. 如果要使用真实的的$
, 用$$
变量以
:=
定义=
有可能导致递归定义, 故使用该表达式, 前面的变量不使用后面的变量, 只使用已经定义好的变量变量以
?=
定义
foo ?= bar
如果foo没有被定义过, 那么变量foo的值是bar, 否则, 这条语句什么也不做.
追加变量
+=
如果变量之前没有定义过,+=
自动变为=
, 反之则继承于前次的操作的赋值符. 前次是:=
, 那么此次为:=
; 前次为=
, 此次为=
override
指示符变量
用override
指示符的变量, 在make命令行参数中可以设置, 而Makefile中对这个变量的赋值会被忽略
override <varriable> = <value>override <varriable> := <value>
追加,
override <variable> += <more value>
多行变量
define
指示符后面跟的是变量名称, 而重起一行定义变量的值, 变量可以换行, 定义以endef
关键字结束. 变量的值可以包含函数,命令,文字或者其他变量环境变量
make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中,但是
如果 Makefile 中已定义了这个变量,或是这个变量由 make 命令行带入,那么系统的环
境变量的值将被覆盖。如果 make 指定了-e
参数,那么,系统环境变量将覆盖
Makefile 中定义的变量
变量高级用法
变量值的替换
替换变量中的共有部分, 格式为$(var:a=b)
或者${var:a=b}
, 把var中所有以结尾的字串替换成以b结尾
如下
foo := a.o b.o c.obar := $(foo:.o=.c)
定义了\${foo}变量,把\${foo}中所有以.o结尾的子串全部替换为以.c结尾,$(bar)的值是a.c b.c c.c
把变量值再再当成变量
x = yy = za := $($(x))
如上, \$(x)的值是y, \$(\$(x))就是\$(y), 那\$(a)就是z
依赖规则
规则语法
targets : prerequisites command
targes是文件名, 以空格分开, 可以使用通配符. 目标可以是一个文件, 也可能是多个文件.
command是命令行, 如果不与targets : prerequisites
一行, 必须以[Tagb键]开头, 如果在一行, 可用;
分割, 如下
targets : prerequisites ; command
prerequisites是目标所依赖的文件(或者依赖目标), 如果有一个以上的文件比 target 文件要新的话,command 所定义的命令就会被执行
伪目标
伪目标的规则类似上面的规则, 但是伪目标不是文件, 只是一个标签, 所以make无法生成它的依赖关系和决定它是否执行, 只有通过显示指定这个目标才能让其生效.
比如, make clean
科学可以执行下面的命令.
clean : rm *.o temp
为了避免和文件重命的情况, 使用特殊的额标记.PHONY
来显示的指明一个伪目标, 不管是否有同名文件
.PHONY : cleanclean : rm *.o temp
伪目标没有依赖文件 ,但是可以为伪目标指定所依赖的文件. 伪目标可以作为默认目标
.PHONY : all cleanall cleanobjall : prog1 prog2prog1 : prog1.o utils.o cc -o prog1 prog1.o util.oprog2 : proj2.o cc -o prog2 prog2.ocleanall : cleanobj cleandiff rm programcleanobj : rm *.odleandiff : rm *.diff
Makefile中的第一目标会被当做默认目标. all
伪目标依赖于其他的三个目标
目标和伪目标都可以成为依赖.
如上, make cleanall
, make cleanobj
都可以显示伪目标执行命令
多目标
Makefile的规则中的目标可以不止一个, 其支持多目标. 当让, 有自动化变量$@
吧表示目标的集合, 依次取出目标, 并执行命令.如下
bigoutput littleoutput : text.ggenerate text.g $@ > $@
静态模式定义的多目标
语法如下
<targets...> : <target-pattern> : <prereq-pattern><commmands>
targets 定义了一系列目标, 可以有通配符, 是目标的一个集合
targets-pattern 指明了目标集模式, 从目标集中选出一部分目标
prereq-pattern 是目标的依赖模式, 对target-pattern形成的模式再次进行依赖目标的定义, 对选出的目标进行再定义
For example.
objects = foo.o bar.oall : $(objects)$(objects) : %.o : %.c$(CC) -c $< -o $@
从目标集foo.o bar.o
中通过%.o
的目标集模式选出之后, 通过%.c
进行二次定义.
%<
自动化变量, 表示所有的依赖目标, 用%c
表示%@
表示目标集, 即%.o
规则中使用通配符
同bash一样, 支持三种通配符
符号 | 意义 |
---|---|
* | 0到无穷多个任意字符 |
? | 一个任意字符 |
[] | 一个[]内的字符(非任意字符). 例如, [abcd], a,b,c,d中的任意一个字符 |
[-] | 编码顺序内的字符. 例如, [0-9]代表0到9之间的所有数字 |
[^] | 反向选择. 例如, 1非a,b,c外的其他的任意一个字符 |
文件搜索
VPATH(大写)变量指定搜索目录
make默认在当前目录搜索文件, 然后再到VPATH
指定的目录去搜索.
VPATH = src:../headers
上面的定义指定两个目录,, 用:
分割, "src"和"../headers", make按照这个顺序进行搜索, 当然, 当前目录是最高优先级.
vpath(小写)关键字设定搜索规则和路径
三种使用方法
vpath <pattern> <directories>
为符合模式<patern>的文件指定搜索目录<directories>vpath <pattern>
清楚设置的符合模式<pattern>的文件的搜索目录vpath
清楚所有已被设置好的文件的搜索目录
vpath
使用的<pattern>中需要包含%
字符, 表示匹配零或者若干字符
vpath %c foo:barvpath %c usrvpath % blish
上面的语句表示.c
结尾的文件, 依次搜索"foo", "bar", "user", "blish"目录
条件判断
ifeq
条件语句开始, else
条件表达式为假, endif
表示一个条件语句的结束.
ifeq
, 比较参数arg1和arg2是否相同,相同则为真
ifeq '<arg1>' '<arg2>'ifeq "<arg1>" "<arg2>"ifeq '<arg1>' "<arg2>"ifeq "<arg1>" '<arg2>'
'ifneq`是否相同, 不同则为真
ifdef <variable-name>
判断变量的值非空, 则为真.只是测量变量是否有值, 并不会把变量扩展到当前位置
函数
函数调用以$
开头, 以圆括号或花括号把函数名和参数括起.参数以,
分隔, 函数名和参数之间以空格分隔;
$(<function> <arguments1,arguments2>) #小括号可换为大括号
常用的字符串处理函数
$(subst <from>,<to>,<text>)
把子串<text>中的<from>字符串替换为<to>, 返回替换后的子串(strip <string>)
去掉<string>子串中开头和结尾的空字符,返回被去掉空格的字符串(findstring <find>,<in>)
查找字符串函数, 在子串<in>中查找<find>子串, 如果找到, 返回<find>, 否则返回空字符串$(word <n>,<text>)
取单词函数, 取字符串<text>中的第<n>的单词, 从1开始.返回子串<text>中的第<n>个单词. 如果<n>比<text>中的单词要大, 返回空字符串$(wordlist <s>,<e>,<text>)
取字符串函数
从字符串<text>中取<s>开始到<e>的单词串, <s>和<e>是一个数字
特定字符
-
放在命令前, 无论出现什么错误, 继续执行
注释用#
字符
命令以[Tab]键开始
\
换行符, 类似c语言, 表示连接上一行
参考: 陈皓的Makefile教程
- abc ?