原文转载
觉得挺好的 就转过来了
记录了一些要点,以便复习
1,makefile规则及书写(目标 依赖 命令 ; tab \)
2,makefile工作方式(两个阶段(读取makefile 重建目标) 以相当于栈的方式重建 变量展开)
3,两种风格的makefile
4,完整的makefile中的5个东西(显示规则,隐式规则,变量定义,指示符和注释)
5,makefile命令(建议Makefile)
6,包含其它makefile(支持的文件名 不以tab开始 支持变量函数等 两种使用场合 非绝对路径的查找目录 )
7,-的作用
8,了解变量MAKEFILES和MAKEFILE_LIST
9,重载另一个makefile(一个%规则 其依赖的目标只有一个空命令)
10,变量展开(立即展开(:= define 依赖中的变量 条件语句) 延后展开(= ?= 命令中的变量) 两者均可(+=))
11,第一个目标不作为终极目标的两种情况(. %)
12,通配符在变量与在命令中的使用方式。
13,VPATH与vpath(前者为变量 后者为关键字 只对自动变量有效 当前目录优先)
14,伪目标(.PHONY 可以作为依赖以执行多个目标)
循环实现递归:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
伪目标实现:
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
foo: baz
15,强制目标(依赖于一个只有空语句的目标)
16,空目标文件一般用来记录上一次执行此规则命令的时间。
17, makefile的特殊目标(.PHONY .DEFAULT 等)
18,多目标
19,多规则目标(命令只能出现在一个规则中,如果有多个命令,以最后一条的为准 以.开头的多规则目标可以给出多条重建命令)
20,静态模式(% $*)
21,双冒号规则(同一目标不能即是单冒号又是双冒号 定义各自的命令 执行更新依赖对应的目标)
22,自动产生依赖,假设当前文件中有一个main.c,有两个子目录comm和cmpt,里面分别有comm.h,comm.c以及cmpt.h,cmpt.c
VPATH = comm:cmpt
FLAGS := -Wall -g
SOURCES := main.c comm/comm.c cmpt/cmpt.c
#OBJECTs = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
OBJECTS := $(notdir $(SOURCES))
OBJECTS := $(OBJECTS:.c=.o)
all:$(OBJECTS)
$(CC) -o $@ $^;
$(OBJECTS):%.o:%.c
$(CC) $(FLAGS) -c $^
-include $(SOURCES:.c=.d)
%.d:%.c
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$;\
sed 's,\($*\).o[:]*,\1.o $@:,g' < $@.$$$$ > $@;\
rm -r $@.$$$$
23,命令前的符号(- @)
24,多行命令在独立的进程中执行的,所有要使前面的命令对后面有影响,则接在;后
25,make选项(-n(--just-print) -s(--slient) -k(--keep-going) -i(--ignore-errors)-w(--print-directory) -C )
26,make的递归执行( 两种方式:cd subdir && $(MAKE)和$(MAKE) -C subdir 使用变量MAKE的原因 变量的传递(使用export环境变量的方式传递 给make带参数) SHELL与MAKEFALGS始终自动传递,可用unexport取消某些变量,将其置空可以取消命令选项的继承,CFoW这些选项不会赋给MAKEFLAGS -e覆盖子目录变量 MAKELEVEL递归的深度
27,用指示符define/endef定义命令包
28,空命令target:;一般用;而不用一行以tab开始的空白。空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令。
29,变量的定义与引用(用$()或${})
30,变量的展开方式,参见前面。这也解释了为什么变量可以在后面定义。
31,定义空格(一般变量值中的前导空格字符在变量引用和函数调用时被丢弃,可以采用如下方式 :
nullstring :=
space := $(nullstring) # end of the line
make对变量进行处理时变量值中尾空格是不被忽略的dir := /foo/bar # directory to put the frobs in中dir的值是/foo/bar加4个空格)
32,$(var:A=B) $(var:%.c=%.o)
33,变量嵌套引用(a := $($(x)) 尽量避免)
34,= := ?= +=
35,如果不希望命令行指定的变量值替代在Makefile中的变量定义,那么我们需要在Makefile中使用指示符"override"来对这个变量进行声明,像下边那样:override VARIABLE = VALUE 变量在定义时使用了"override",则后续对它值进行追加时,也需要使用带有"override"指示符的追加方式。否则对此变量值的追加不会生效。
36,目标变量(TARGET ... : VARIABLE-ASSIGNMENT,eg:all : FLAG = -c 一个多目标指定的变量的作用域是所有这些目标的上下文,它包括了和这个目标相关的所有执行过程)
37,模式指定变量(PATTERN ... : VARIABLE-ASSIGNMENT,eg:%.o : CFLAGS += -O 当单独使用"%"作为目标时,指定的变量会对所有类型的目标文件有效。)
38,条件执行(if*** else endif ifeq ifneq(其参数可以(),'''', """",''""等) ifdef ifndef
39,函数(一般形式$(ffunc arg1,arg2) $(subst from,to,text) $(patsubst pattern,replacement,text)与之相似的有变量的高级用法 $(strip string)它同时会合并多个空格为一个 $(findstring find,in) $(filter pattern...,text) $(filter-out pattern...,text) $(sort list)它会去掉重复 $(word n,text) $(wordlist s,e,text) $(words text) $(firstword names...) $(dir names...) $(notdir names...) $(basenames names...) $(suffix names...) $(addsuffix suffix,names...) $(addprefix prefix,names...) $(join list1,list2) $(wildcard pattern) $(foreach var,list,text) $(if condition,then-part,else-part) call $(valude variable) $(origin variable) $(shell command) $(error test...) $(warning text...)
40,make的返回状态(0成功 2错误 1在执行make时使用了"-q"参数,而且当前工程中存在过时的目标文件)
41,make参数(
-f(--file) 指定文件
-n(--just-print) 仅打印命令
-t(--touch) 修改时间为当前时间
-q(--question)检查目标是否是最新返回0或1
-W(--what-if=) 需要指定一个文件名,假定此文件的时间为当前时间,执行是依赖于此文件的将被重建,但实际上并不修改时间。通常"-W"参数和"-n"参数一同使用,可以在修改一个文件后来检查修改会造成那些目标需要被更新,但并不执行更新的命令,只是打印命令。
"-W"和"-t"参数配合使用时,make将忽略其它规则的命令。只对依赖于"-W"指定文件的目标执行"touch"命令,在没有使用"-s"时,可以看到那些文件执行了"touch"。
"-W"!!和"-q"参数配合使用时。由于将当前时间作为指定文件的时间戳(目标文件相对于系统当前时间是过时的),所以make的返回状态在没有错误发生时为1,存在错误时为2。
-i(--ignore-errors) 执行过程中忽略命令执行的错误。
-I(--include-dir=)DIR指定被包含makefile文件的搜索目录。
-k(--keep-going) 执行命令错误时不终止make的执行。
-S(--no-keep-going) 取消“-k”选项。在递归的make过程中子make通过“MAKEFLAGS”变量继承了上层的命令行选项
-r(--no-builtin-rules) 取消所有内嵌的隐含规则。
-R(--no-builtin-variables)取消所有内嵌的隐含变量。
42,make的隐含规则
1. 编译C程序
“N.o”自动由“N.c” 生成,执行命令为“$(CC) -c $(CPPFLAGS) $(CFLAGS)”。
2. 编译C++程序
“N.o”自动由“N.cc”或者“N.C” 生成,执行命令为“$(CXX) -c $(CPPFLAGS) $(CFLAGS)”。建议使用“.cc”作为C++源文件的后缀,而不是“.C”
43,隐含命令变量
AR 函数库打包程序,可创建静态库.a文档。默认是“ar”。
AS 汇编程序。默认是“as”。
CC C编译程序。默认是“cc”。
CXX C++编译程序。默认是“g++”。
CO 从 RCS中提取文件的程序。默认是“co”。
CPP C程序的预处理器(输出是标准输出设备)。默认是“$(CC) -E”。
RM 删除命令。默认是“rm -f”。
44,命令参数变量
CFLAGS 执行“CC”编译器的命令行参数(编译.c源文件的选项)。
CXXFLAGS 执行“g++”编译器的命令行参数(编译.cc源文件的选项)。
COFLAGS 执行“co”的命令行参数(在RCS中提取文件的选项)。
CPPFLAGS 执行C预处理器“cc -E”的命令行参数(C 和 Fortran 编译器会用到)。
45,模式规则(%.o:%.c;command... )
46,自动化变量(
$@ 表示规则的目标文件名。
$% 当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。
$< 规则的第一个依赖文件名。
$? 所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件)。
$^ 规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件名,代表的是库成员(.o文件)。
$+ 类似“$^”,但是它保留了依赖文件中重复出现的文件。
$* 在模式规则和静态模式规则中,代表“茎”
45,万用规则(当模式规则的目标只是一个模式字符“%”(它可以匹配任何文件名)时,我们称这个规则为万用规则。)
阅读(928) | 评论(0) | 转发(0) |