1.隐晦规则(自动推导):
指定一个目标为.o文件时后面的依赖列表自动会添加本身的.c文件
即:
command.o : command.c defs.h command.h 与command.o : defs.h command.h等价
表示command.o目标由头文件defs.h command.h和command.c生成
2. .PHONY : clean作用:
eg:
$ cat -n Makefile1
clean:
rm -f app
$ cat -n Makefile2
.PHONY: clean
clean:
rm -f app
两个makefile文件,如果当前目录下存在一个clean的文件会导致因为存在与Makefile1中一个目标为clean同名的文件而报错,原因是因为
Makefile会根据文件的更新时间来判断文件是否更新(make),当输入Makefile时,首先判断最终生成的目标为clean,而当前目录下存在
这个文件时由于没有更新所以makefile会判断为文件没有修改过所以不会进行编译,从而报错:make: 'clean' is up to date
而在目标前一行添加.PHONY会优化这个问题,.PHONY是个伪目标文件,表示不会生成一个文件clean只是单纯的一个伪目标。
3.makefile的默认目标一般是第一个目标也是最终的目标,所以一般不要将清空目标放在第一个(一般最后)
4.-号
eg:
...
...
.PHONY : clean
clean :
-rm $(obj)
...
...
-号的作用是在make clean时即使有些文件会出现问题,但是不会立即因为错误返回而后面的指令没有执行,它会使得继续做后面的事情。
无论这条命令执行的成功还是失败都认为是成功。
5.可以使用任意名称来书写Makefile,但是make时需要通过-f或者--file参数来制定
eg:
make -f Make.Linux
make --file Make.AIX
6.makefile引用别的makefile通常用include
eg:
include foo.make a.mk b.mk c.mk e.mk f.mk
这些文件如果没有以相对路径或者绝对路径指定的话,会首先在当前的目录下查找。
7.VPATH与vpath区别
都是指定一些目录去寻找依赖文件和目标文件
VPATH后面一般加相对路径的路径,多个以:区分
eg:
VPATH = src:../headers
vpath有三个用法:
1、vpath
为符合模式
2、vpath
清除符合模式
3、vpath
清除所有已被设置好了的文件搜索目录
eg:
vpath %.h ../headers 该语句表示,要求 make 在“../headers”目录下搜索所有以“.h”结尾的文件。
8.伪目标一般没有依赖文件,可以将多个目标作为最终(第一个为目标标签)的依赖文件
eg:
all: app1 app2 ...
...
...
app1: app1.c app1.h
...
...
app2: app2.c app2.h
...
...
9.多个目标依赖相同的文件时可以在:前面填入多个目标,make每一个目标的时候都执行一样的操作
10.过滤函数—filter
$(filter PATTERN…,TEXT)
函数功能:过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所有符合此模式的单词。可
以使用多个模式。模式中一般需要包含模式字符“%”。存在多个模式时,模式表达式之间使用空格分
割。
返回值:空格分割的“TEXT”字串中所有符合模式“PATTERN”的字串。
函数说明:“filter”函数可以用来去除一个变量中的某些字符串。
eg:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
使用“$(filter %.c %.s,$(sources))”的返回值给 cc 来编译生成目标“foo”,函数返回值为“foo.c
bar.c baz.s”
11.makefile的静态模式
形式为
eg:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是
“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是
“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。而命令中的“$<”
和“$@”则是自动化变量(见[makefile笔记]之七),“$<”表示所有的依赖目标集(也就是 “foo.c bar.c”),
“$@”表示目标集(也就是“foo.o bar.o”)。
相当于执执行了:
$(CC) -c foo.c -o foo.o
$(CC) -c bar.c -o bar.
12.字符串处理函数-subst
$(subst FROM,TO,TEXT)
功能:将TEXT中的东西从FROM变为TO
返回:函数返回被替换过后的字符串。
eg:
TARGETS = 111.cpp 222.cpp 333.cpp
OTARGETS= $(subst cpp,o,$(TARGETS))
LTARGETS= $(subst cpp,lo,$(TARGETS))
%.o: %.cpp
g++ -c -o $@ $<
all: objs libs
13.使用编译器 -M 自动生成依赖选项
注意:这个是编译器的编译选项推导出来的输出效果不是makefile的语法。
在make时编译器会自动生成对应的依赖关系
eg:
cc -M app.c 等价于:app.o :app.c app.h defs.h
如果使用的是GNU的C/C++编译器需要使用-MM选项,否则会将一些标准的库的头文件包含进来
eg:
如果gcc -MM main.c的输出是main.o: main.c defs.h则gcc -M main.c 的输出可能就是:
main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h
14.替换操作$(sources:.c=.d)
“.c=.d”的意思是做一个替换,把变量$(sources)所有[.c]的字串都替换成[.d]
15.@符号:同步放在字符命令行前,这个命令不会被make显示出来
eg:
@echo 正在编译 XXX 模块...... 其显示的结果为:正在编译 XXX 模块......
16.-n 或者 --just-print参数
在make时使用以上某个参数只会显示命令,但是不会执行,一般用于调试
17.-s 或者 --slient参数
全面禁止命令的显示
18. ;号使用在两条命令之间
当某条命令依赖于上一条命令所产生的结果时不能将两条命令分成两行书写,应该使用;号隔开
并且将其写在同一行
eg:
exec:
cd /home/vmuser
pwd
执行cd的结果没有作用,pwd打印当前的makefile路径
exec:
cd /home/vmuser;pwd
这样pwd会打印cd作用后的路径也就是/home/vmuser
19.-i 或者 --ignore-errors参数
在使用make时添加上面的参数时,本makefile中的所有命令都会忽略错误。如果一个规则以.IGNORE作为目标的,那这个规则中的所有命令
都会被忽略错误。
eg:
clean:clean2
clean2 :
.IGNORE:
rm kak.o
执行make clean,当前目录下没有kak.o文件,当添加.IGNORE目标的时候运行make clean不会发生错误,不添加时会由于rm操作不存在的文
件而报错。
20.-k 或者 --keep-going参数
如果规则中命令出错了,那么就终止该规则的执行,但继续执行其他规则。
21. exports
用法export
用于将变量传递给下级的makefile,其中SHELL与MAKEFLAGS两个变量不需要exports就可以传递到下一级makefile中,如果不想将上层的系
统级环境(MAKEFIAGS)传递给下一级可以这样操作:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
其中$(MAKE)中是个变量的形式,其目的就是我们可以改变这个变量来添加make的一些参数以减少维护的工作量。
22.-w 或者 --print-directory参数
用于在调用下级makefile是用于输出当前工作目录的信息,例如下级的makefile目录是/home/vmuser,如果我们使用make -w来执行的话,
当进入该目录时,我们会看见make: Entering directory `/home/vmuser'.离开时make: Leaving directory `/home/vmuser'
注意:当使用-C参数指定make下级makefile时,-w参数会自动打开,如果参数中有使用-s(--slient)即全面禁止命令的显示或者是
--no-print-directory那么-w总是会失效。
23.define .... endef定义命令包
define 指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以 endef 关键字结束。其工作方式和“=”操作符一样。变量的
值可以包含函数、命令、文字,或是其它变量。 因为命令需要以[Tab]键开头, 所以如果你用 define 定义的命令变量中没有以[Tab]键
开头,那么 make 就不会把其认为是命令。
eg:
define two_commands
echo 1111111111111
echo 22222222222
endef
相当于two_commands = echo 1111111111111;echo 22222222222
可以直接调用$(two_commands)
24. “=”、“:=”、“?=” 、“+=”
eg:
y := $(x) bar
x := foo
其y的值为bar
y = $(x) bar
x = foo
其y的值为foo bar
因为=以使用后面加载的变量来定义,而:=只能使用前面定义好了的变量
eg:
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
eg:
objects = main.o foo.o bar.o utils.o
objects += another.o
$(objects)的值变成“main.o foo.o bar.o utils.o another.o”,如果变量之前没有定义过,那么, “+=”会自动变成“=”。
25. #号使用
#一般是一个注释符号,也可以用来表示变量的终止符号
eg:
dir := /home/dir #end
sub := /home/vmuser
print:
@echo $(dir)$(sub)
这里在定义两个变量,将第一个变量值设置为“/home/dir”,并且加一个空格然后加上了一个#end注释,make print的时候显示:
“/home/dir /home/vmuser”,其中两个字符串之间有个空格,这个要注意在定义变量的时候最好注意#注释的是否合理。如果下文使用
newdir := $(dir)/work 时会导致newdir的值/home/dir /work导致使用时出现问题!
eg:
nullstring :=
space := $(nullstring) # end of the line
nullstring是一个Empty类型的变量,先用一个Empty变量来标明变量的值开始了,而后面采用“#”注释符来表示变量定义的终止,这样,
我们可以定义出其值是一个空格的变量。
26.override
在定义变量时在变量名前添加这个关键字使得可以通过make命令键入时在make后面添加对这个变量的更改语句,更改后的内容将作用在
makefile中。仅限于override定义的变量。
eg:
override CFLAGS = -Wall –g
在make时命令行写入的是 make CFLAGS=-O2 此时在makefile中使用$(CFLAGS)就是-Wall –g -O2
27.目标变量
用法:
类似override可以将某些变量加以追加,在目标后的依赖出添加对应的操作使得在整个目标规则中变量以variable-assignment操作的值存在
eg:
cflags = -wall
auto: cflags += -o
auto:
@echo $(cflags)
auto1:
@echo $(cflags)
make auto 得到的结果是-wall -o,而make auto1的结果是-wall。可知只有在对应目标的规则(auto)中cflags的值才经过了+= -o操作,
在规则以外且没有定义这个目标变量的目标内如auto1内不会改变这个变量的值还是为-wall。
未完待更新。。。