1.实例分析
target...:prerequisites...
commmand
note:command must start with
1.1 make会自己查找makefile或makefile文件夹,并把文件中找到的第一个目标作为最终目标.
1.2 使用变量
var=xxx
$(var)
1.3 makefile会自动推导依赖关系
看到.o文件就会自动把.c文件加到依赖关系中
1.5 清空目标文件的规则
eg1:
clean:
rm edit $(objects)
eg2:
.PHONY : clean
clean:
-rm edit $(objects)
2. makefile文件概述
.显示规则.
.隐式规则.让makefile自动推导依赖关系
.变量定义.
.文件指示. include 文件名
.注释. # 在变量定义后加#注释会把#前的空格等作为变量的定义
3.make书写规则
3.2 规则中使用通配符 * ? [...]
可以用转义字符\* 来表示真正*
~ 表home目录或宿主目录
自动化变量:$@ 目标集; $< 依赖目标集; $? 第一个依赖目标集
object :=$(wildcard *.o) 就是说object是所用.o文件展开的结果
3.3 文件搜索
makefile自己寻找依赖文件和目标文件的路径默认是当前目录,可以用VPATH变量或vpath关键字添加搜索路径
3.3.1 VPATH 关键字
VPATH= src:../headers:$(topdir)/include
如上:路径间以分号隔开
3.3.2 vpath关键字
vpath pattern directories
为符合模式的文件指定搜索目录,模式中用到%通配符
vpath pattern
清除符合模式的搜索目录
vpath
清除所有的文件搜索目录
3.4 伪目标 .PHONY
不会生成目标文件,只执行命令
3.5 多目标 $@表目标集
3.6 静态模式
如:
$(objects): %.o: %.c
gcc -c $< -o $@
3.7 自动生成依赖性
GCC中的 -M 选项可以自动搜索源文件中包含的头文件并生成依赖关系
(gcc -M会把标准头文件包括进来,用-MM就不会)
GNU组织建议把编译器为每一个源文件的自动生成的依赖关系放到一个文件中,为每一个“name.c”的文件
都生成一个“name.d”的Makefile文件,[.d]文件中就存放对应[.c]文件的依赖关系。
这里,我们给出了一个模式规则来产生[.d]文件:
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > ; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < > $@; \
rm -f
这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,也就是[.d]文件,
第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件,“$@”表示模式“%.d”文件,如果有
一个C文件是name.c,那么“%”就是“name”,“$$$$”意为一个随机编号,第二行生成的文件有可能是
“name.d.12345”,第三行使用sed命令做了一个替换,关于sed命令的用法请参看相关的使用文档。第四行就是
删除临时文件。总而言之,这个模式要做的事就是在编译器生成的依赖关系中加入[.d]文件的依赖,即把依赖关系:
main.o : main.c defs.h
转成:
main.o main.d : main.c defs.h
于是,我们的[.d]文件也会自动更新了,并会自动生成了,当然,你还可以在这个[.d]文件中加入的不只是依
赖关系,包括生成的命令也可一并加入,让每个[.d]文件都包含一个完赖的规则。一旦我们完成这个工作,接
下来,我们就要把这些自动生成的规则放进我们的主Makefile中。我们可以使用Makefile的“include”命令,
来引入别的Makefile文件(前面讲过),例如:
sources = foo.c bar.c
include $(sources:.c=.d)
4.使用命令
4.1 显示命令
make会把其要执行的命令行在命令执行前输出到屏幕上。
当我们用“@”字符在命令行前,那么,这个命令将不被make显示出来
如:
@echo 正在编译XXX模块...... 显示:正在编译XXX模块.....
echo 正在编译XXX模块...... 显示:echo 正在编译XXX模块......
make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令
make参数“-s”或“--slient”则是全面禁止命令的显示
4.2 执行命令
如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令(管道作用)
4.3 命令出错
.命令前加-忽略出错
.,给make加上“-i”或是“--ignore-errors”参数,那么,Makefile中所有命令都会忽略错误
.一个规则是以“.IGNORE”作为目标的,那么这个规则中的所有命令将会忽略错误
.make的参数的是“-k”或是“--keep-going”,这个参数的意思是,如果某规则中的命令出错了,
那么就终止该规则的执行,但继续执行其它规则
4.4 嵌套执行make
subsystem:
cd subdir && $(MAKE)
其等价于:
subsystem:
$(MAKE) -C subdir
定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护。
这两个例子的意思都是先进入“subdir”目录,然后执行make命令
export
unexport
如果你要传递所有的变量,那么,只要一个export就行了。后面什么也不用跟,表示传递所有的变量
系统级的环境变量SHELL和MAKEFLAGS,管你是否export,其总是要传递到下层Makefile中.
还有一个在“嵌套执行”中比较有用的参数,“-w”或是“--print-directory”会在make的过程
中输出一些信息,让你看到目前的工作目录
当你使用“-C”参数来指定make下层Makefile时,“-w”会被自动打开的。
如果参数中有“-s”(“--slient”)或是“--no-print-directory”,那么,“-w”总是失效的。
4.5 定义命令包
如:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
5.使用变量
5.1 变量基础
变量大小写敏感
$(var),如果要使用$用$$来表示
5.2 变量赋值
. = 右侧的变量可以定义在文件的任何地方
. :=变量不能使用后面的变量,只能使用前面定义好的变量
. ?=变量没有被定义过就定义否则什么都不做
5.3 变量高级用法
. 变量的替换
.bar := $(foo:.o=.c) 把“$(foo)”中所有以“.o”字串“结尾”全部替换成“.c”
.静态模式定义的变量替换
bar := $(foo:%.o=%.c)
.把变量的值再当成变量 (嵌套)
5.4 追加变量值 +=
objects = main.o foo.o bar.o utils.o
objects += another.o
5.5 override 指示符
如果有变量是通常make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略。如果
你想在Makefile中设置这类参数的值,那么,你可以使用“override”指示符。其语法是:
override
override
当然,你还可以追加:
override
对于多行的变量定义,我们用define指示符,在define指示符前,也同样可以使用ovveride指示符,如:
override define foo
bar
endef
5.6 多行变量
define two-lines
echo foo
echo $(bar)
endef
5.7 环境变量
make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中
已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖。(如果make
指定了“-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量)
当make嵌套调用时(参见前面的“嵌套调用”章节),上层Makefile中定义的变量会以系统环境变量
的方式传递到下层的Makefile中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义
在文件中的变量,如果要向下层Makefile传递,则需要使用exprot关键字来声明。(参见前面章节)
5.8 目标变量
Makefile中定义的变量都是“全局变量”,在整个文件,我们都可以访问这些变量
自动化变量就属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义
为某个目标设置局部变量,这种变量被称为“Target-specific Variable”,作用范围只在这条规则以及连带规则中
其语法是:
如:
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c
foo.o : foo.c
$(CC) $(CFLAGS) foo.c
bar.o : bar.c
$(CC) $(CFLAGS) bar.c
5.9 模式变量
模式变量(Pattern-specific Variable),把变量定义在符合这种模式的所有目标上
如
%.o : CFLAGS = -o
6 使用条件判断
6.1 示例
ifeq ($(CC), gcc)
...
else
...
endif
6.2 语法
ifeq, ifneq, ifdef, ifndef
7. 使用函数
7.1 语法
$(
${
参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。
函数调用以“$”开头,以圆括号或花括号把函数名和参数括起
7.2 字符串处理函数
$(subst
名称:字符串替换函数——subst。
功能:把字串
返回:函数返回被替换过后的字符串。
$(patsubst
名称:模式字符串替换函数——patsubst。
功能:查找
模式
通配符“%”,表示任意长度的字串。如果
(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
返回:函数返回被替换过后的字符串。
$(strip
名称:去空格函数——strip。
功能:去掉
返回:返回被去掉空格的字符串值。
$(findstring
名称:查找字符串函数——findstring。
功能:在字串
返回:如果找到,那么返回
$(filter
名称:过滤函数——filter。
功能:以
可以有多个模式。
返回:返回符合模式
$(filter-out
名称:反过滤函数——filter-out。
功能:以
可以有多个模式。
返回:返回不符合模式
$(sort )
名称:排序函数——sort。
功能:给字符串中的单词排序(升序)。
返回:返回排序后的字符串。
示例:$(sort foo bar lose)返回“bar foo lose” 。
备注:sort函数会去掉中相同的单词。
$(word
名称:取单词函数——word。
功能:取字符串
返回:返回字符串
示例:$(word 2, foo bar baz)返回值是“bar”。
$(wordlist ,
名称:取单词串函数——wordlist。
功能:从字符串开始到和
返回:返回字符串到比开始,到
示例: $(wordlist 2, 3, foo bar baz)返回值是“bar baz”。
$(words
名称:单词个数统计函数——words。
功能:统计
返回:返回
示例:$(words, foo bar baz)返回值是“3”。
备注:如果我们要取
$(firstword
名称:首单词函数——firstword。
功能:取字符串
返回:返回字符串
示例:$(firstword foo bar)返回值是“foo”。
备注:这个函数可以用word函数来实现:$(word 1,
7.3 文件名操作函数
$(dir
名称:取目录函数——dir。
功能:从文件名序列
返回:返回文件名序列
示例: $(dir src/foo.c hacks)返回值是“src/ ./”。
$(notdir
名称:取文件函数——notdir。
功能:从文件名序列
返回:返回文件名序列
示例: $(notdir src/foo.c hacks)返回值是“foo.c hacks”。
$(suffix
名称:取后缀函数——suffix。
功能:从文件名序列
返回:返回文件名序列
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c .c”。
$(basename
名称:取前缀函数——basename。
功能:从文件名序列
返回:返回文件名序列
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo src-1.0/bar hacks”。
$(addsuffix
名称:加后缀函数——addsuffix。
功能:把后缀
返回:返回加过后缀的文件名序列。
示例:$(addsuffix .c,foo bar)返回值是“foo.c bar.c”。
$(addprefix
名称:加前缀函数——addprefix。
功能:把前缀
返回:返回加过前缀的文件名序列。
示例:$(addprefix src/,foo bar)返回值是“src/foo src/bar”。
$(join
名称:连接函数——join。
功能:把
那么,
返回:返回连接过后的字符串。
示例:$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”。
7.4 foreach 函数
$(foreach ,,
把参数中的单词逐一取出放到参数所指定的变量中,然后再执行
每一次
7.5 if函数
$(if
$(if
if函数的返回值是,如果
如果
没有被定义,那么,整个函数返回空字串。
7.6 call函数
$(call
当make执行这个函数时,
会被参数
7.7 orign 函数
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:
$(origin
注意,
Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:
“undefined”
如果
“default”
如果
“environment”
如果
“file”
如果
“command line”
如果
“override”
如果
“automatic”
如果
7.8 shell 函数
contents := $(shell cat foo)
7.9 make控制函数
$(error
$(warning
只是输出一段警告信息,而make继续执行。