Makefile 文件的编写
学习前的准备
GCC、GDB、Makefile
- gcc编译器可以将C、C++等语言源程序、汇编程序编译、链接成可执行程序。
- gdb是 GNU 开发的一个Unix/Linux下强大的程序调试工具。
- gcc可以按照Makefile内容对C语言进行批量编译
GCC简介
编译原理
gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步
1.预处理,生成.i的文档[预处理器cpp]
2.将预处理后的文档不转换成汇编语言,生成文档.s[编译器egcs]
3.有汇编变为目标代码(机器代码)生成.o的文档[汇编器as]
4.连接目标代码,生成可执行程式[链接器ld]
gcc这条命令用来将源代码生成可执行程序,下面来看一下gcc的常用选项。
① 预处理:gcc -E -o hello.i hello.c
预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输出到一个“.i”文件中等待进一步处理。
② 编译:gcc -S -o hello.s hello.i
编译就是把C/C++代码(比如上面的”.i”文件)“翻译”成汇编代码。
③ 汇编:gcc -c -o hello.o hello.s
o:object file(OBJ文件) 这里表现为二进制目标文件
汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现位ELF目标文件(OBJ文件)。
④ 链接:gcc -o hello hello.o
链接就是将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序。
总结:在编译过程中。除非使用了”-c”,“-S”,或”-E”选项(或者编译错误阻止了完整的过程),否则统一完整链接步骤。
譬如:gcc hello.c
和gcc -o hello hello.c
都已经完成链接操作。
又如:gcc -c -o hello.o hello.c
不完整
关于程序的编译和链接
在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于函数与变量的声明的正确这一项,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File.
GCC命令选项和参数的顺序
1、如果只做编译,不做链接(-c 选项,只生成.o文件,不生成执行文件),对参数顺序没有要求。
2、不同类的选项没有顺序要求(如多个 -I 属于同一类)。
3、gcc在链接时,对参数中的库的顺序有要求,参数右侧的库会先于左侧的库加载;不同库中有相同的符号定义时,链接顺序不同会产生不同结果。
常用选项:
选项 | 含义 | |
---|---|---|
0 | 标准输入 | stdin = standard input |
1 | 标准输出 | stdout = standard output |
2 | 标准错误输出 | stderr = standard error |
【用法】
1.想要把make输出的全部信息,输出到某个文件中,最常见的办法就是:
1 | make xxx > build_output.txt |
此时默认情况是没有改变2=stderr的输出方式,还是屏幕,所以,如果有错误信息,还是可以在屏幕上看到的。
2.只需要把make输出中的错误(及警告)信息输出到文件中ing,可以用:
1 | make xxx 2> build_output.txt |
相应地,由于1=stdout没有变,还是屏幕,所以,那些命令执行时候输出的正常信息,还是会输出到屏幕上,你还是可以在屏幕上看到的。
3.只需要把make输出中的正常(非错误,非警告)的信息输出到文件中,可以用:
1 | make xxx 1> build_output.txt |
相应地,由于2=stderr没有变,还是屏幕,所以,那些命令执行时候输出的错误信息,还是会输出到屏幕上,你还是可以在屏幕上看到的。
4.想要把正常输出信息和错误信息输出到分别的文件中,可以用:
1 | make xxx 1> build_output_normal.txt 2>build_output_error.txt |
即联合使用了1和2,正常信息和错误信息,都输出到对应文件中了。
5.所有的信息都输出到同一个文件中:
1 | make xxx > build_output_all.txt 2>&1 |
其中的2>&1表示错误信息输出到&1中,而&1,指的是前面的那个文件:build_output_all.txt 。
注意:上面所有的1,2等数字,后面紧跟着大于号’>’ ,中间不能有空格
总结
至此,已经可以阅读大部分软件的 Makefile 了~~~
附件
文章中的实例附件在这里