学习makefile前,这里先汇总一下gcc相关的知识点。
//gcc参数说明: https://www.cnblogs.com/chaguang/p/8306106.html
gcc 是 GUN Compiler Collection的缩写,可以支持多种语言编译,比如 C,C++,Java, pascal 等
*
预处理(pre-processing)E:插入头文件,替换宏
*
编译(Compiling)S:编译成汇编
*
汇编(Assembling) c:编译成目标文件
*
链接 (Linking):链接到库中,变成可执行文件
gcc -E hello.c -o hello.i
gcc -S hello.i –o hello.s
gcc –c hello.s –o hello.o
gcc hello.s –o hello 链接,生成可执行文件
/hello 运行
也可以一次性完成:
gcc hello.c –o hello
但一般情况下生成.o文件比较好,可以重定位文件,让别人使用
gcc常用选项
选项名
作用
o
生成目标
c
取消链接步骤,编译源码并最后生成目标文件
E
只运行C预编译器(头文件,宏等展开)
S
生成汇编语言文件后停止编译(.s文件)
Wall
打开编译告警(所有)
g
嵌入调试信息,方便gdb调试
llib
链接 lib 库 (这里是小写 L ) 相当于 C++ #pragma comment(lib, “xxx.lib”)
Idir
增加 include 目录 (这里是大写 i ) 头文件路径
LDir
增加 lib 目录 (编译静态库和动态库)
Make简介:
工程管理器,顾名思义,是指管理较多的文件。
Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作。
Makefile格式
target:dependency_files
<TAB> command
说明:如果dependency_files文件的日期要比target文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。
所以我们可以知道make命令的工作规则:
(1)如果这个工程没有编译过,那么我们的所有c文件都要编译并被链接。
(2)如果这个工程的某几个c文件被修改,那么我们只编译被修改的c文件,并链接目标程序。
(3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的c文件,并链接目标程序。
例(1)
hello.o:hello.c hello.h
gcc -c hello.c -o hello.o
例(2)
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
f1.o:f1.c
gcc -c -wall f1.c -o f1.o
main.o:main.c
gcc -c -wall main.c -o main.o
clean:
rm *.o test
(1)-c表示编译,-o表示连接
(2)clean命令的使用,make clean(用于清除相关的中间文件)
(3) clean 不是一个文件,它只不过是一个动作名字,有点像c语言中的label一 样,其冒号后什么也没有,那么,make就不会自动去找它的依赖性,也就不会自动执行其后所定义的命令。 要执行其后的命令,就要在make命令后明显得指出这个label的名字。这样的方法非常有用,我们可以在一 个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。
例如:在下面的图片上,我们要执行clean:后面的命令时,要在终端敲入make clean 命令,才能执行makefile文件clean:后面那些指令。
针对于上面的文件内容,来说明一下当执行一个make命令时,makefile文件是怎么被执行的。
make会在当前目录下(所以我们要想针对不同目录下的c文件和h文件进行make,还需要特殊的写法)找名字叫“Makefile”或“makefile”的文件。如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个 文件,并把这个文件作为最终的目标文件。如果test文件不存在,或是test所依赖的后面的 .o 文件的文件修改时间要比 test这个 文件新,那么,他就会执行后面所定义的命令来生成 test这个文件。如果 test所依赖的 .o 文件也不存在,那么make会在当前文件中找目标为 .o 文件 的依赖性,如果找到则再根据那一个规则生成 .o 文件。当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生 成make的终极任务,也就是执行文件 test了。
这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在 找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所 定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系 之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
参考:https://seisman.github.io/how-to-write-makefile/introduction.html