make规则(整理)

来源:互联网 发布:阿里云服务器安装l2tp 编辑:程序博客网 时间:2024/05/08 23:13

1.linux下的.a库就是很多.o文件的集合,这些.o文件通过ar命令打包进去。

2.Makefile/makefile的作用是告诉以make命令需要怎么样的去编译和链接程序。

3.在Makefile中如果语句太长可以用\来换行,换行后的下一行正文开始前可以加空格补齐。
例如:
    rm edit main.o kbd.o command.o display.o \
       insert.o search.o files.o utils.o

4.make会找第一个目标文件并把这个文件作为最终的目标文件。

5.依赖文件是最终交由make来分析各个文件之间的联系,而命令(均以TAB键开头)最终是交由shell执行的。

6.自动推导
command.o : command.c defs.h command.h
    cc -c command.c
注意:命令行中并没有defs.h和command.h。
只要make看到一个.o文件,它就会自动的把.c文件加在依赖关系中,并且cc -c command.c 也会被推导出来。所以上面两条语句可以简化为:
command.o : defs.h command.h

7.伪目标
.PHONY : clean
clean :
    -rm -f *.o
.PHONY意思表示clean是一个“伪目标”,而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。其实不用将clean声明为伪目标也是可以的,但是如果正好工程目录下有一个名为clean的文件效果就不一样了,因为make不管伪目标存不存在都会去重新生成它。

8.命令一般书写在另一行的开始,并且前面加上TAB键,也可以写在依赖关系的后面,二者用分号隔开。

9.通配符*、?、[...]可以在规则(描述依赖关系)、命令以及变量中使用。
objects = *.o
objects并不会被展开为所有的.o文件的集合,而就是指*.o。

10.使用伪目标来生成多个目标(可执行文件)
all : prog1 prog2 prog3
.PHONY : all
注:从这里也可以看出.PHONY可以放在后面,这样做的原因是make会把.开头的目标当做默认目标。

11.Makefile的规则中的目标可以不止一个,其支持多目标。

12.静态模式
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”。

13.大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
需要提醒一句的是,如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。
GNU组织建议把编译器为每一个源文件的自动生成的依赖关系放到一个文件中,为每一个“name.c”的文件都生成一个“name.d”的Makefile文件,[.d]文件中就存放对应[.c]文件的依赖关系。

14.命令前面加上一个@表示执行该命令的时候该条命令不会被输出,其余的输出保留。

15.“$(sources:.c=.d)”中的“.c=.d”的意思是做一个替换,把变量$(sources)所有[.c]的字串都替换成[.d]

16.如果make执行时,带入make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的。

17.需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。

18.make执行完的返回代码的查看,在终端上输入
# echo $?
这个环境变量里面保存的是上一条命令的执行返回值,make执行成功返回的值是0。

19.make处理不同目录下的makefile
subsystem:
    cd subdir && $(MAKE)
其等价于:
subsystem:
    $(MAKE) -C subdir
如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
export <variable ...>
如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明:
unexport <variable ...>
如果你要传递所有的变量,那么,只要一个export就行了。有两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量不管你是否export,其总是要传递到下层Makefile中
还有一个在“嵌套执行”中比较有用的参数,“-w”或是“--print-directory”会在make的过程中输出一些信息,让你看到目前的工作目录。当你使用“-C”参数来指定make下层Makefile时,“-w”会被自动打开的。

20.如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以“define”开始,以“endef”结束,如:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
在后续要使用自定义的这个命令使用形如$(run-yacc)来引用。

21.变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空字符(空格、回车等)。变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。
第一种方式(递归定义方式),也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。
第二种方式(非递归定义方式),使用符号“:=”,值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
第三种方式“?=”,例如FOO ?= bar其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做。

22.如果我们要定义一个变量,其值是一个空格,那么我们可以这样来:
nullstring :=
space := $(nullstring) # end of the line

23.变量值的追加
如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符用第一个变量来表示开始,用#表示定义结束。

24.局部变量
prog : CFLAGS = -g
这条语句的意思是,CFLAGS这个变量是定义在prog目标里面,作用域也仅限于这个目标的规则中,如果有全局变量同名,局部变量优先全局变量。

25.模式变量
模式变量就是定义一种模式,将变量定义在符合这种模式的所有目标上。
make的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式给所有以[.o]结尾的目标定义目标变量:
%.o : CFLAGS = -O

26.关键字ifeq的意思表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。else表示条件表达式为假的情况。endif表示一个条件语句的结束,任何一个条件表达式都应该以endif结束。

27.关键字ifdef
语法是:ifdef <variable-name>
如果变量<variable-name>的值非空,那到表达式为真。
foo =
注意:向上面这样定义一个变量是没有定义成功的。特别注意的是,make是在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,最好不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。

28.函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(<function> <arguments>)或是${<function> <arguments>}
这里,<function>就是函数名,<arguments>是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。

29.make的退出码
make命令执行后有三个退出码:
0 —— 表示成功执行。
1 —— 如果make运行时出现任何错误,其返回1。
2 —— 如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。

30.指定makefile文件
make –f hchen.mk

31.我们不想让我们的makefile中的规则执行起来,我们只想检查一下我们的命令,或是执行的序列。于是我们可以使用make命令的下述参数:
“-n”:不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试makefile很有用处。
“-W <file>” :大写的W,这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件所发生的规则命令。
“-C <dir>” :指定读取makefile的目录。如果有多个“-C”参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。
“-I <dir>”:指定一个被包含makefile的搜索目标。可以使用多个“-I”参数来指定多个目录。
“-v”:输出make程序的版本、版权等关于make的信息。
“-w”:输出运行makefile之前和之后的信息。这个参数对于跟踪嵌套式调用make时很有用。

32.链接Object文件的隐含规则
“<n>”目标依赖于“<n>.o”,例如:
x : y.o z.o会被执行为--> cc x.o y.o z.o -o x

33.你可以使用模式规则来定义一个隐含规则。一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有"%"字符。"%"的意思是表示一个或多个任意字符。在依赖目标中同样可以使用"%",只是依赖目标中的"%"的取值,取决于其目标。有一点需要注意的是,"%"的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的"%"则发生在运行时。而"s.%.c"则表示以"s."开头,".c"结尾的文件名(文件名的长度至少为5)。如果"%"定义在目标中,那么,目标中的"%"的值决定了依赖目标中的"%"的值,也就是说,目标中的模式的"%"决定了依赖目标中"%"的样子。

34.自动变量
$@:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$<:依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$^:所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$%:仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$?:所有比目标新的依赖目标的集合。以空格分隔。
$+:这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*:这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。

35.函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是由命令"ar"来完成打包工作。

感谢:陈皓 《跟我一起写 Makefile》

0 0
原创粉丝点击