make工程管理器
一、make概述
目的:
在大型项目开发中,利用make工具自动完成编译工作,以避免多次手工键入GCC命令进行编译。
功能:
1、如果仅修改了某几个源文件,则只重新编译这几个源文件。
2、如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。
3、如果工程中有几个c文件没被编译,则编译并连接这几个c文件。
方式:
通过一个称为makefile的文件来完成并自动维护编译工作。
文件主要内容:
定义了源文件之间的依赖关系,说明了如何编译各个源文件并连接生成可执行文件。
优点:
自动化编译,一旦写好,只需要一个make命令,即可自动编译整个工程,提高软件开发的效率。
二、makefile基本结构
2.1makefile文件内容
1)make工具创建的目标体,通常是目标文件或可执行文件。
2)要创建的目标体所依赖的文件
3)创建每个目标体时需要运行的命令
格式为:
target:dependency_files
<tab>command
需要执行makefile时,只需要在命令行中输入make即可。
2.2 makefile执行原理
示例:
工程中有一个头文件和五个c文件。
a.c b.c d.c e.c program.c main.h
其中main.h包含a.c/b.c/d.c/e.c并在program.c源文件中被调用。
则makefile文件内容为:
#makefile
program:main.o a.o b.o d.o e.o
gcc main.o a.o b.o d.o e.o -o program
main.o:main.c main.h
gcc -c main.c -o main.o
a.o:a.c
gcc -c a.c -o a.o
b.o:b.c
gcc -c b.c -o b.o
d.o:d.c
gcc -c d.c -o d.o
e.o:e.c
gcc -c e.c -o e.o
clean:
rm *.o program
要点:
1)#以后为注释,一行如果不够,使用反斜杠“\”续写。
2)make命令需要在makefile文件目录下执行。
3)要删除执行文件和所有的中间目标文件,执行make clean命令。
4)依赖关系可以理解为目标文件由哪些依赖文件生成,换言之,目标文件是哪些文件更新的结果。
5)执行过程为:命令行输入make后,首先在当前目录下找到“makefile”文件或者“makefile”文件夹里的文件。找到第一个目标文件(这里目标文件为第一行的program)。由于当前目录下所依赖的文件main.o不存在,因此在文件中查找main.o的依赖文件。由于当前目录下存在main.c和main.h文件,因此执行目标体运行的命令gcc -c main.c -o main.o以此类推直到可以生成program文件为止。
6)注意:在找寻过程中,如果出现错误,如最后被依赖的文件不存在,make就会直接退出并报错。而对于所定义的命令的错误,或是编译不成功,make就不会处理。
7)命令行中执行make命令时,即使依赖文件存在,make也会自动对比目标文件和依赖文件的修改日期。如果依赖文件的修改日期比目标文件的更新,make也会重新执行目标体运行的命令。
8)上述执行的过程为(理解为寻找依赖关系):
gcc -c main.c -o main.o
gcc -c b.c -o b.o
gcc -c d.c -o d.o
gcc -c e.c -o e.o
三、makefile变量
解决问题:
在大型项目中,如果需要在makefile文件中删除、添加或修改某个多次引用的文件(如*.o),则容易遗忘或者编写过程乏味。采用变量的方式可以很好的解决这类问题。
变量定义方式
1)递归展开方式:即变量一次展开后,如果还包含其他变量,则继续展开,即变量的嵌套。格式为VAR=var
2)简单扩展方式:即变量只展开一次。格式为:VAR:=var
变量引用方式:$(VAR)
变量类型:分为用户自定义变量、预定义变量、自动变量及环境变量。
用户自定义变量,如:
objects=main.o a.o b.o d.o e.o
program:$(objects)
gcc $(objects) -o program
预定义变量:
包含了常见编译器、汇编器的名称及其编译选项。如CC为C编译器的名称,默认值为cc,在宿主机中进行开发调试时采用其他编译器进行编译,当需要移植到其他架构的目标机器上时,需要修改,如这里修改为CC=gcc,以实现交叉编译过程。
自动变量:
用于简化编译语句中包含的目标文件和依赖文件。
命令格式 | 含义 |
$* | 不包含扩展名的目标文件名称 |
$+ | 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件 |
$< | 第一个依赖文件的名称 |
$? | 所有时间戳比目标文件晚的依赖文件,并以空格分开 |
$@ | 目标文件的完整名称 |
$^ | 所有不重复的依赖文件,以空格分开 |
$% | 如果目标是归档成圆,则该变量表示目标的归档成员名称 |
环境变量:
如果用户在makefile中定义了与环境变量相同名称的变量,那么用户自定义变量将会覆盖同名的环境变量。
四、makefile规则
1.隐式规则
隐式规则如C编译:“.c”变为“.o”的隐式规则为:$(CC)-c $(CPPFLAGS) $(CFLAGS)
则上述示例中可以省略main.c、a.c、b.c、d.c、e.c的编译命令。
2.模式规则
可以自己定义规则。