一、编译器驱动程序
首先梳理一下源文件到可执行文件的整个过程,下面是两个源文件的组成main.c和sum.c
// main.cint sum(int *a, int n);int array[2] = { 1, 2 };int main() {
int val = sum(array, 2);
return val;}
// sum.cint sum(int *a, int n) {
int i, s = 0;
for (i = 0; i < n; i++) {
s += a[i];
}
return s;}
使用命令:gcc -Og -o prog main.c sum.c调用GCC的驱动程序。下图是静态链接,链接器将可重定位的目标文件组合起来,形成一个可执行目标文件prog。这个链接的过程可以分为三个步骤:
它首先运行C预处理器cpp,将C源程序main.c翻译成一个ASCII码的中间文件main.i
接下来,C编译器cc1将main.i翻译成一个ASCII汇编语言文件main.s
最后,汇编器as将main.s翻译成一个可重定位目标文件main.o,此时的目标文件还不能执行,需要通过链接器将其与所依赖的函数(如sum.o)链接到一块才可以生成可执行文件
在运行可执行文件prog时,shell调用操作系统中一个叫做加载器的函数,他将可执行文件prog中的代码和数据复制到内存,然后将控制转移到这个程序的开头。
二、预处理
2.1 -E 只激活预处理
GCC不会保留预处理文件(.i文件),但可以通过-E选项在预处理阶段完毕后停止编译,将预处理信息保存到一个文件。
gcc -E main.c -o main.i
gcc -E main.c > main.i
2.2 -C 保留注释信息
在预处理的时候,不删除注释信息,一般和-E搭配使用。
2.3 -D 在编译的时候定义宏的。
-D后面直接跟宏名,相当于定义这个宏,默认这个宏的内容是1,如gcc -DDEBUG。
-D后面跟 key=value 表示定义key这个宏,它的内容是value,如gcc -DNAME=Peter。
#include
int value = VALUE;
printf("value = %d\n", value);
return 0; }
gcc -DVALUE=12 define.c
输出:value = 12
2.4 -o 选项
指定生成目标的名称,gcc main.c sum.c -o main,整个编译阶段都可以用。
三、编译
3.1 -S 只激活预处理和编译
只激活预处理和编译,把源文件编译成为汇编文件后停止,源文件可以是.c文件,也可以是.i文件。
gcc main.c -o main.s -S
gcc main.i -o main.s -S
3.2 -save-temps 输出中间代码
输出编译过程中所有的中间代码。
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c
loongson@loongson-pc:~/workspace/cpptest$ gcc main.c sum.c -o main -save-temps
loongson@loongson-pc:~/workspace/cpptest$ ls
main main.c main.i main.o main.s sum.c sum.i sum.o sum.s
3.3 -O# 编译优化
根据不同等级进行编译优化:
-O0:不进行优化处理。
-O1(-O):对编译出的代码进行优化。
-O2:进行比-O高一级的优化。
-O3:产生更高级别的优化。
3.4 -I 指定额外的头文件搜索路径
先在指定的路径中搜索要包含的头文件,若找不到,则在标准路径(/usr/include,/usr/lib及当前工作目录)上搜索。
gcc luacallc.c -o luacallc -g -I /home/loongson/workspace/luajit/src/ -lluajit-5.1 -L /home/loongson/workspace/luajit/lib -Wl,-rpath,/home/loongson/workspace/luajit/lib
3.5 -funsigned-char 、-fno-signed-char、-fsigned-char 、-fno-unsigned-char设置char类型
这四个参数是对 char 类型进行设置, 决定将 char 类型设置成 unsigned char(前两个参数)或者 signed char(后两个参数)。
#include
int main() {
char value = -8;
printf("value = %d\n", value);
return 0; }
loongson@loongson-pc:~/workspace/cpptest$ gcc define.c -o define
loongson@loongson-pc:~/workspace/cpptest$ ./define
value = -8
loongson@loongson-pc:~/workspace/cpptest$ gcc define.c -o define -funsigned-char
loongson@loongson-pc:~/workspace/cpptest$ ./define
value = 248
loongson@loongson-pc:~/workspace/cpptest$ gcc define.c -o define -fno-signed-char
loongson@loongson-pc:~/workspace/cpptest$ ./define
value = 248
loongson@loongson-pc:~/workspace/cpptest$ gcc define.c -o define -fsigned-char
loongson@loongson-pc:~/workspace/cpptest$ ./define
value = -8
loongson@loongson-pc:~/workspace/cpptest$ gcc define.c -o define -fno-unsigned-char
loongson@loongson-pc:~/workspace/cpptest$ ./define
value = -8
四、汇编
4.1 -c 只激活预处理,编译,和汇编
只激活预处理,编译,和汇编,把源文件编译成可重定位目标文件,源文件可以是.c、.i、.s文件。
gcc main.c -o main.o -c
gcc main.i -o main.o -c
gcc main.s -o main.o -c
4.2 objdump 命令,反汇编
objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。
反汇编应用程序,objdump -d main.o
显示文件头信息,objdump -f main.o
显示制定section段信息(comment段),objdump -s -j .comment main.o
五、链接
如果程序需要使用某个动态库中的函数,则在程序的编译阶段和之后的运行阶段都需要链接这个动态库, 即编译时链接和运行时链接。
5.1 编译时链接
1)-L 指定编译时库的路径
指定编译时,搜索使用到的库的路径,可以是静态库,也可以是动态库,-L.表示当前路径。
2)-l 指定编译时引用库的名字
指定编译时使用到的库名称,可以是静态库,也可以是动态库,静态库libmine.a和动态库libmine.so均可使用-lmine。
3)ar命令 集合多个文件为一个文件
ar命令至少需要两个参数才能运行,用于建立,修改备存文件或从备存文件中抽取成员。一个备存文件是一个包含了很多其它文件的单独的文件,原始文件(成员)的内容、权限、时间属性、属主和组都在备存文件中得到保留,在抽取时可以得到恢复。
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c
loongson@loongson-pc:~/workspace/cpptest$ gcc sum.c -o sum.o -c
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c sum.o
loongson@loongson-pc:~/workspace/cpptest$ ar -cr libmine.a sum.o
loongson@loongson-pc:~/workspace/cpptest$ ls
libmine.a main.c sum.c sum.o
loongson@loongson-pc:~/workspace/cpptest$ gcc main.c -o main -lmine -L.
loongson@loongson-pc:~/workspace/cpptest$ ls
libmine.a main main.c sum.c sum.o
5.2 运行时链接
1)-Wl,-rpath 指定运行时动态库路径
用于指定程序运行时查找动态链接库的路径,多个路径是使用冒号隔开,这样就不用添加路径到 /etc/ld.so.conf 文件中或者环境变量LD_LIBRARY_PATH了,在需要多个so版本共存时很有用。
2)-shared 生成共享目标文件
生成共享目标文件,与-fPIC一起通常用在建立共享库时。
3)-fPIC 生成位置无关代码
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行(共享库被加载时,在内存的位置不是固定的)。
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c
loongson@loongson-pc:~/workspace/cpptest$ gcc sum.c -o libsum.so -shared -fPIC //编译动态库
loongson@loongson-pc:~/workspace/cpptest$ ls
libsum.so main.c sum.c
loongson@loongson-pc:~/workspace/cpptest$ gcc main.c -o main -lsum -L. -Wl,-rpath,. //链接动态库
loongson@loongson-pc:~/workspace/cpptest$ ls
libsum.so main main.c sum.c
5.3 -static 禁止使用动态库
此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行。
六、其他
6.1 -w、-Wall、-Werror 警告相关
-w:不生成警告信息。
-Wall:生成所有警告信息。
-Werror:将警告信息当作错误来处理,一般与-Wall搭配使用(-Wall -Werror只要有警告信息则编译停止)。
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c
loongson@loongson-pc:~/workspace/cpptest$ gcc main.c sum.c -o main -Wall -Werror
main.c: In function ‘main’:
main.c:12:6: error: unused variable ‘a’ [-Werror=unused-variable]
12 | int a = 0;
| ^
cc1: all warnings being treated as errors
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.
loongson@loongson-pc:~/workspace/cpptest$ gcc main.c sum.c -o main -Wall
main.c: In function ‘main’:
main.c:12:6: warning: unused variable ‘a’ [-Wunused-variable]
12 | int a = 0;
| ^
loongson@loongson-pc:~/workspace/cpptest$ ls
main main.c sum.c
6.2 -g、-gstabs、-gstabs+、-ggdb 产生调试信息
-g:可以产生供GDB调试的可执行文件。
-gstabs:产生stabs格式的调试信息,不包括GDB调试信息。
-gstabs+:产生stabs格式的调试信息,包括GDB调试信息。
-ggdb:尽可能的生成GDB可以使用的调试信息
6.3 -std 指定编译版本
指定采用什么版本的规范进行编译,如-std=c89、-std=c99。
6.4 @ 指定文件制定编译选项
可以使用@然后跟着文件名做编译选项,文件中的内容会连接在后面。
loongson@loongson-pc:~/workspace/cpptest$ ls
main.c sum.c temp.txt
loongson@loongson-pc:~/workspace/cpptest$ cat temp.txt
main.c sum.c -o main
loongson@loongson-pc:~/workspace/cpptest$ gcc @temp.txt
loongson@loongson-pc:~/workspace/cpptest$ ls
main main.c sum.c temp.txt
1
6.5 -M 、-MM、-MD、-MMD生成文件关联的头文件信息
这几个参数,在Makefile中会经常用到,代替手动将头文件添加到规则中:
-M:生成.c文件编译生成的默认目标文件名和所依赖的所有头文件信息,包括系统文件和项目中的文件,即#include造成的所有依赖关系。
-MM:与-M一样,但是不包括系统文件造成的依赖关系,只包括引用的项目中的文件。
-MD:和-M相同,但是输出将导入到.d的文件里面。
-MMD:和-MM相同,但是输出将导入到.d的文件里面。
Comments NOTHING