C管理工具MakeFile
Make简介
- 工程管理器,顾名思义是指管理较多的文件
- Make工程管理器也就是个"自动编译管理",这里的"自动"是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它能够读入Makefile文件的额内容来执行大量的编译工作
- Make将只编译改动的代码文件,不用完全编译
Makefile基本结构
Makefile是Makee读入的额唯一配置文件
- 由make工具创建的目标体(target),通常是目标文件或可执行文件
- 要创建的目标体所依赖的文件(dependennncy_file)
- 创建每个目标体时需要运行的命令(command)
- 注意:命令行前面必须是一个"TAB键",否则编译错误为:*** missing separator. Stop
Makefile格式
target:dependency_file <TAB>command
Makefile test:f1.o f2.o main.o gcc f1.o f2.o main.o f2.o:f2.c gcc -c Wall f2.c -o f2.o f1.o:f1.c gcc -c -Wall f1.c -o f1.o main.0:main.c gcc -c -Wall main.c -o main.o .PHONY:clean clean: rm -rf *.o // 解释 先执行test 发现依赖f1.o,f2.o,main.o依次执行下面的代码 .PHONY:clean 因有些任务如果文件是最新的Makefile就不会执行而这条指令声明无论什么情况都会执行 // 使用make命令执行makefile文件 $ make // 指定make执行命令 例如清除 $ make clean
变量
用来代替一个文本字符串:
- 系列文件的名字
- 传递给编译器的参数
- 需要运行的程序
- 需要查找源码的额目录
- 你需要输出信息的目录
- 你想做的其他事情
变量定义的几种方式
- 递归展开方式:VAR=$(BAR);BAR=$(UGH);UGH=ugh
- 优点:
- 可以向后引用
- 缺点:
- 使用不当容易造成死循环 例如 CFLASG=$(CFLASG) -0
- 优点:
- 简单方式:VAR:=var
- 其他: VAR?=bar (如果VAR没有定义过则这条语句生效,如果定义过则不生效)
变量使用(用`$`或`$$`来表示)
$(VAR)
Makefile FILES = f1.o f2.o main.o test:$(FILES) gcc $(FILES) f2.o:f2.c gcc -c Wall f2.c -o f2.o f1.o:f1.c gcc -c -Wall f1.c -o f1.o main.0:main.c gcc -c -Wall main.c -o main.o .PHONY:clean clean: rm -rf *.o
Makefile中的预定义变量
-
AR 库文件维护程序的名称,默认值为ar。
-
AS 汇编程序的名称,默认为as
- CC c编译器的名称,默认值为cc
- CPP c预编译器的名称,默认值为$(CC) -E
- CXX c++编译器的名称,默认值为g++
- FC FORTRAN编译器的名称,默认值为f77
- RM 文件删除程序的名称,默认为rm -f
自动变量
- $* 不包含扩展名的目标文件名称
- $+ 所有的依赖文件,以空格愤怒开,并以出现的先后为序,可能包含重复的依赖文件
- $< 第一个依赖文件的名称
- $? 所有时间戳比目标文件呢晚的依赖文件,并以空格分开
- $@ 目标文件的完成名称
- $^ 所有不重复的目标依赖文件,以空格分开
- $% 如果目标是归档成员,则该变量表示目标的归档成员名称
Makefile FILES = f1.o f2.o main.o test:$(FILES) gcc $(FILES) f2.o:f2.c gcc -c Wall f2.c -o $@ f1.o:f1.c gcc -c -Wall f1.c -o $@ main.0:main.c gcc -c -Wall main.c -o $@ .PHONY:clean clean: rm -rf *.o
Make的一些参数
$ make
- -c dir读入指定目录下的Makefile
- -f file读入当前目录下的file文件作为Makefile
- -i 忽略所有的命令执行错误
- -I dir指定被包含的Makefile所在目录
- -n 只打印要执行的命令,但不执行这些命令
- -p 显示make变量数据库和隐含规则
- -s 在执行命令时不显示命令
- -w 如果make在执行过程中改变目录,打印当前目录名
Makefile的的隐含规则
- 编译c程序的隐含规则
- "<n>.o"的目标的依赖会自动推导为"<n>.c",并且其生成命令是"$CC" -c $(CPPFLAGS) $(CFLASS) CFLASS是留给用户的插槽可以自定义一些其他参数,但是以变量的形式出现
Makefile
// 我们上面的测试就可以精简至如下 FILES = f1.o f2.o main.o test:$(FILES) gcc $(FILES) f2.o:f2.c f1.o:f1.c main.0:main.c .PHONY:clean clean: rm -rf *.o
- 链接Object文件的隐含规则
- "<n>"目标依赖于"<n>.o",通过运行C的编译器来运行链接程序生成(一般是"ld"),其命令是:"$(CC) $(LDFLAGS) <n>.o"
- "$(LOADLIBES) $(LELIBS)",这个规则对于只有一个源文件的工程有效,同时也对多个Object文件(不同的源文件生成)的也有效。例如如下
- 规则
- x:x.o y.o z.o
- 并且"x.c"、"y.c"、"z.c"都存在,隐含规则将执行如下命令
- cc -c x.c -o x.o
- cc -c y.c -o y.o
- cc -c z.c -o z.o
- cc x.o y.o z.o -o x
- 如果没有一个源文件(例如上例中的x.c)和你的目标名字(如上例的x)相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错
- 规则
Makefile // 我们上面的测试就可以精简至如下 test:f1.o f2.o main.o .PHONY:clean clean: rm -rf *.o
VPATH(虚路径)
- 在一些大的工程中,有大量的源文件,我们通常的做法是吧这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是吧一个路径告诉make,让make在自动去找
- Makefile文件的特殊变量"VPATH"就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去寻找依赖文件和目标文件。如果定义了这个变量,那么,make就会在当前目录找不到的情况下,到指定目录中去寻找文件了
- VPATH=xxx1:../xxx2
- 上面的定义指定两个目录,"xxx1"和"../xxx2",make还会按照这个顺序进行搜索。目录由"冒号"分隔。(当然,当前目录永远是最高优先搜索的地方)
Songzhibin