1.程序在编译成.o文件时,编译链检测语法,函数和变量是否申明。而在链接成执行文件时,编译链只会检测函数和变量是否定义,将所有的.o文件链接在一起,即将所有的执行方法与变量的地址链接起来,并不会管源文件,而当.o文件太多时将其打包成库,即.a文件。编译和链接可以分步进行。
2.Makefile执行流程:
2.1、读入所有的 Makefile。
2.2、读入被 include 的其它 Makefile。
2.3、初始化文件中的变量。
2.4、推导隐晦规则,并分析所有规则。
2.5、为所有的目标文件创建依赖关系链。
2.6、根据依赖关系,决定哪些目标要重新生成。
2.7、执行生成命令。
3.Makefile的语法的中心是 target:prerequisites
Command
或者是 targets : prerequisites ; command
command
...
目标,依赖文件,命令,其中命令必须以一个table建开始,Makefile文件才能识别,命令为任意shell命令,如果命令太长,你可以使用反斜框(‘\’)作为换行符。
4.makefile中隐匿规则会将.o目标的依赖文件自动视为.c如果找不到.c会去找其他的相关文件.xxx,然后使用默认的编译规则编译,所以在特别熟练前尽量不要让隐匿规则发生作用。
5.伪目标:.PHONY : clean
clean :
rm edit $(objects)
.PHONY为伪目标环境变量,其后面的是make的执行目标,可以使make分块运行你想执行的部分。如 make clean 。伪目标一般没有依赖的文件。其语法为
伪目标1:目标1 目标2 目标3...
伪目标2:目标4 目标5 目标6 ...
伪目标3:伪目标1 伪目标2 ...
伪目标申明环境变量:伪目标1 伪目标2 伪目标3...
相关目标语句...例子:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
6.Makefile指定运行文件时 make -f XXX(文件名),指定运行文件里面某一个目标时, make MMM(目标或者伪目标)。如果这个Makefile文件包含其他Makefile文件则include xxx1 xxx2(其他Makefile文件名)
7.源文件搜索路径环境变量:VPATH,使用方法,VPATH = src:../headers,目录使用冒号分开。
8.通配符:*,*在命令中使用时,会展开,如clean:
rm -f *.o
在目标中不会,如print: *.c;lpr -p $?;touch print,这个*.c就是文件*.c
如果在目标中使用*.c来展开使用函数wildcard,函数使用方法参照后面。
9.静态模式,目标变量和模式变量,多行变量,环境变量:
静态模式:里面包含模式符号%,其语法为
objects = foo.o bar.o
$(objects): %.o: %.c 目标集:目标模式:依赖文件模式
$(CC) -c $(CFLAGS) $< -o $@ command
目标集就是一系列目标,可以用通配符*(wildcard),其作用是将目标集中 的全部目标由相应的依赖文件生成,省略目标集,那么Makefile会寻找整 个工程中的目标模式依次执行命令。
目标变量:
prog : CFLAGS = -g 目标:赋值表达式(变量赋值)
prog : prog.o foo.o bar.o 目标:依赖文件
$(CC) $(CFLAGS) prog.o foo.o bar.o command
当我们设置了这样一个变量,这个变量会作用到由这个目标所引发的所有的规则中去。其他地方变量的值保持不变。
模式变量:%.o : CFLAGS = -O
同样,模式变量的语法和“目标变量”一样。作用一样。
多行变量:define two-lines
echo foo
echo $(bar)
endef
define 指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以 endef 关键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量
环境变量:make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖。
10.make执行过程中,会将执行命令显示出来,在命令前面加上@,命令将不会打印出来显示。
11.当命令在同一行用分隔符表示时,后面的命令会在之前命令的行为上执行,如cd /home/hchen cd /home/hchen;pwd
pwd 打印当前路径 打印切换以后的命令
12.我们可以在 Makefile 的命令行前加一个减号“-”(在 Tab 键之后),标记为不管命令出不出错都认为是成功的。
13.命令包的格式 define 变量名
Command1
Command2
....
endef 使用方法和变量使用的方法一样。变量会像一个宏一样展开。在需要使用到这个命令集合的地方$(变量名)即可。
14.赋值方法: =
右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值,A = $(B);B = $(A) 容易发生递归赋值 少用
:=
正常赋值,右边使用变量时只能是已经定义好的,否则为空。
FOO ?= bar
其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做。可以用来保存编译器的名字
+= 追加赋值
15.在Makefile中,所有变量的赋值有个特点就是易变的会覆盖不变的(局部覆盖全局)。想要相反处理需要相关设置,
①Make命令行的参数会覆盖Makefile中赋值的变量的值(环境变量值等),如果你想在Makefile中进行赋值语句,在赋值语句之前加入override <variable> += <more text>
②在make命令行加入-e 系统环境变量将覆盖 Makefile 中定义的环境变量
③总控 Makefile 的变量可以传递到下级的 Makefile 中(如果你显示的声明),但是不会覆盖下层的 Makefile 中所定义的变量,除非指定了“-e”参数。
④如果你不想让某些变量传递到下级 Makefile 中,那么你可以这样声明:
unexport <variable ...>。
16.Makefile的参数和函数,以及系统环境变量需要多看,多记多使用。和正则表达式元字符一样,都很重要。