- makefile总结
- 1.简介
- 2. 规则基础组成
- 3.make工作原理
- 4.makefile变量
- 5.隐含规则
- 6.伪目标
- 7.VPATH
makefile主要作用实现程序的“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,用于解释makefile中指令的命令工具,make命令执行的时候需要一makefile文件,告诉make命令如何工作。
使用make进行编译的时候,我们希望能够做到以下三点(三点规则):
- 如果这个工程没有编译过,那么我们的所有文件都要编译并被链接。
- 如果这个工程的某几个文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
- 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的文件,并链接目标程序。
makefile设计的好,可以实现只用一个make命令就完成编译和链接工作。
2. 规则基础组成makefile语句由三部分组成:目标体(target)、生成目标体所依赖的文件(dependency_files)、形成目标体所需要的命令(command)。其格式如下:
target:dependency_files command #注意:在command前有一个 tab
例:
hello.o:hello.c hello.h gcc -c hello.c -o hello.o
基础实例:
文件组成:f1.c、f2.c、main.c、head.h
-
f1.c内容如下:
#include
void print1(){ printf("Message:f1.cn"); } -
f2.c内容如下:
#include
void print2() { printf("Message:f2.cn"); } -
head.h内容如下:
void print1(); void print2();
-
main.c内容如下:
#include
#include "head.h" int main() { print1(); print2(); printf("end mainn"); return 0; }
此项目在不用makefile的进行编译,则需要先生成f1.o、f2.o和main.o,然后再使用生成的这些.o文件,生成最后的执行文件。使用makefile,可将此编译命令和流程写进makefile,用make命令编译。
makefiel文件内容如下:
test:f1.o f2.o main.o gcc f1.o f2.o main.o -o test f2.o:f2.c gcc -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息 f1.o:f1.c gcc -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o” main.o:main.c gcc -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里 clean: rm *.o test#删除.o和执行文件3.make工作原理
在输入make命令后,系统执行了以下几步:
-
make会在当前目录下找名字叫**“Makefile”或“makefile”**的文件。
-
如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个文件,并把这个文件作为最终的目标文件。
-
如果test文件不存在,或test所依赖的后面的 .o文件的文件修改时间要比test这个文件新(根据时间判断),那么他就会执行后面所定义的命令来生成test这个文件。
-
如果test所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(类似堆栈的过程)
-
当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件声明make的终极任务,也就是执行文件test了。
注:这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
补充:clean部分,没有被第一个目标文件(test)直接或间接关联,那么它后面所定义的命令将不会被自动执行。我们可以显示要make执行,通过命令——“make clean”,以此来清除所有的目标文件,以便重编译。
4.makefile变量makefile中定义变量,就像是C/C++语言中定义宏一样,它代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。此变量可以用在“目标”体,“依赖文件”, “命令”任何一部分中。通过变量对上述的例子改进,在上述例子中”f1.o f2.o main.o“这部分重复使用了两个,如果,我们需要增加文件时,需要改变这两个地方,我们可以用变量来代替此部分,在改变的时候只改变变量处即可。实现如下:
obj = f1.o f2.o main.o test:$(obj) gcc $(obj) -o test f2.o:f2.c gcc -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息 f1.o:f1.c gcc -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o” main.o:main.c gcc -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里 clean: rm *.o test#删除.o和执行文件
补充:
- makefile的预定义变量
例:用CC改写上述例子
obj = f1.o f2.o main.o test:$(obj) &(CC) $(obj) -o test f2.o:f2.c &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息 f1.o:f1.c &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o” main.o:main.c &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里 clean: rm *.o test#删除.o和执行文件
- makefile的自动变量
常用:$ @、$ ^、$<
-
$ @:表示目标集,“集”的意思就是组合,全部,有多个目标,$ @就是目标集合。
上例中第一句话 $ @ 等价于 test,即可改写如下:test:$(obj) &(CC) $(obj) -o $@ # 注:同样其他的规则都可以改写。
-
$^: 所有依赖目标的集合,注意,这里说的是“依赖”,也就是目标的组成元素。
上例中第一句话的 $ (obj)表示所有的依赖, $^可表示此全部的依赖,即可改写如下:obj = f1.o f2.o main.o test:$(obj) &(CC) $^ -o test #此处的$^等于 f1.o f2.o main.o
以上例子的第一句话,用$@、$^可以写为: obj = f1.o f2.o main.o test:$(obj) &(CC) $^ -o $@ #此处的$^等于 f1.o f2.o main.o
-
$ <依赖目标中的第一个目标名字,也就是上面说的$^中的第一个元素。
1.规则一:编译C语言的隐含规则
.o的目标的依赖会自动推导为.c文件,所以在写makefile时可以省略 .o到 .c的规则。
根据以上规则以上例子可以改为(f1.o,f2.o,main.o会因为隐含规则自动执行):
obj = f1.o f2.o main.o test:$(obj) &(CC) $(obj) -o test clean: rm *.o test#删除.o和执行文件
2.规则二:链接目标体的隐含规则
目标体依赖于.o文件,且.c文件存在时,链接命令可以隐含。
根据此规则,以上(规则一前的)makefile可以改写如下:
obj = f1.o f2.o main.o main: $(obj) #此处的main可以换为f1 f2.必须是存在的c文件的名字 clean: rm *.o test#删除.o和执行文件
此处包含的隐含规则有:
#根据规则二省略的 $(CC) &(obj) -o main #根据规则一省略的 f2.o:f2.c gcc -c f2.c -o f2.o f1.o:f1.c gcc -c f1.c -o f1.o main.o:main.c gcc -c main.c -o main.o6.伪目标
在此规则中clean就是一个伪目标,
clean: rm *.o test#删除.o和执行文件
此规则是为了清除我们生成的中间文件,以备重新编译,执行命令 make clean”。
因为此规则并不生成“clean”这个文件,所以“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,否则会报错。
有此文件还必须用此伪目标,不报错的解决方法:使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
.PHONY : clean
以上makefile可以改写为:
obj = f1.o f2.o main.o main: $(obj) #此处的main可以换为f1 f2.必须是存在的c文件的名字 .PHONY : clean clean: rm *.o test#删除.o和执行文件7.VPATH
在一些大的工程中,有大量的源文件,我们通常的做法是把许多的源文件分类,存放在不同的目录下。所以,当make需要找文件依赖关系时,可以在文件前加上路径,最好的办法就是把一个路径告诉make,让make在自动的去找。makefile文件中的特殊变量VPATH就是完成这么一个功能。如果没有指明这个变量,make只会在当前目录中去寻找依赖文件和目标文件。如果定义了这个变量,make就会在当前目录找不到的情况下,到指定的目录中去找寻文件了。
VPATH = src ../headers
上面的定义指定两个目录,‘src’和‘…/headers’,make会按照这个顺序进行搜索。当前目录永远是最高优先级搜索的地方。
例:以上例子的f1.c放在src1中,f2.c放在src2中,其他的在当前目录。则上述makefile文件如下:
0 VPATH = src1 src2 1 obj = f1.o f2.o main.o 2 test:$(obj) 3 &(CC) $(obj) -o test 4 f2.o:f2.c 5 &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息 6 f1.o:f1.c 7 &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o” 8 main.o:main.c 9 &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里 10 .PHONY : clean 11 clean: 12 rm *.o test#删除.o和执行文件 # 根据隐含规则4-9行可以省略。
按照这样写,生成的中间文件和执行文件都在当前目录下。可以显示指定生成的目录,如下:
0 VPATH = src1 src2 1 obj = f1.o f2.o main.o 2 test:$(obj) 3 &(CC) $(obj) -o test 4 src2/f2.o:f2.c 5 &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息 6 src1/f1.o:f1.c 7 &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o” 8 main.o:main.c 9 &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里 10 .PHONY : clean 11 clean: 12 rm *.o test#删除.o和执行文件 # 根据隐含规则4-9行可以省略。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)