一、编译器驱动程序
首先梳理一下源文件到可执行文件的整个过程,下面是两个源文件的组成
main.c
和
sum.c
// main.c
int sum(int *a, int n);
int array[2] = { 1, 2 };
int main() {
int val = sum(array, 2);
return val;
}
// sum.c
int 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
只激活预处理
-E
GCC不会保留预处理文件(
.i
文件),但可以通过
-E
选项在预处理阶段完毕后停止编译,将预处理信息保存到一个文件。
gcc -E main.c -o main.i
gcc -E main.c > main.i
2.2
-C
保留注释信息
-C
在预处理的时候,不删除注释信息,一般和
-E
搭配使用。
2.3
-D
在编译的时候定义宏的。
-D
-
-D
后面直接跟宏名,相当于定义这个宏,默认这个宏的内容是1,如
gcc -DDEBUG
。 -
-D
后面跟
key=value
表示定义
key
这个宏,它的内容是
value
,如
gcc -DNAME=Peter
。
#include<stdio.h>
int main() {
int value = VALUE;
printf("value = %d\n", value);
return 0;
}
gcc -DVALUE=12 define.c
输出:value = 12
2.4
-o
选项
-o
指定生成目标的名称,
gcc main.c sum.c -o main
,整个编译阶段都可以用。
三、编译
3.1
-S
只激活预处理和编译
-S
只激活预处理和编译,把源文件编译成为汇编文件后停止,源文件可以是
.c
文件,也可以是
.i
文件。
gcc main.c -o main.s -S
gcc main.i -o main.s -S
3.2
-save-temps
输出中间代码
-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#
编译优化
-O#
根据不同等级进行编译优化:
-
-O0
:不进行优化处理。 -
-O1(-O)
:对编译出的代码进行优化。 -
-O2
:进行比
-O
高一级的优化。 -
-O3
:产生更高级别的优化。
3.4
-I
指定额外的头文件搜索路径
-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类型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
这四个参数是对
char
类型进行设置, 决定将
char
类型设置成
unsigned char
(前两个参数)或者
signed char
(后两个参数)。
#include<stdio.h>
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
只激活预处理,编译,和汇编,把源文件编译成可重定位目标文件,源文件可以是
.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
objdump
命令是Linux下的反汇编
目标文件
或者
可执行文件
的命令,它以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。
-
反汇编应用程序,
objdump -d main.o
-
显示文件头信息,
objdump -f main.o
-
显示制定section段信息(comment段),
objdump -s -j .comment main.o
五、链接
如果程序需要使用某个动态库中的函数,则在程序的编译阶段和之后的运行阶段都需要链接这个动态库, 即编译时链接和运行时链接。
5.1 编译时链接
1)
-L
指定编译时
库
的路径
-L
指定编译时,搜索使用到的库的路径,可以是静态库,也可以是动态库,
-L.
表示当前路径。
2)
-l
指定编译时引用库的名字
-l
指定编译时使用到的库名称,可以是静态库,也可以是动态库,静态库
libmine.a
和动态库
libmine.so
均可使用
-lmine
。
3)
ar命令
集合多个文件为一个文件
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
指定运行时
动态库
路径
-Wl,-rpath
用于指定程序
运行时
查找动态链接库的路径,多个路径是使用冒号隔开,这样就不用添加路径到
/etc/ld.so.conf
文件中或者环境变量
LD_LIBRARY_PATH
了,在需要多个
so
版本共存时很有用。
2)
-shared
生成共享目标文件
-shared
生成共享目标文件,与
-fPIC
一起通常用在建立共享库时。
3)
-fPIC
生成位置无关代码
-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
禁止使用动态库
-static
此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行。
六、其他
6.1
-w
、
-Wall
、
-Werror
警告相关
-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
-gstabs
-gstabs+
-ggdb
-
-g
:可以产生供GDB调试的可执行文件。 -
-gstabs
:产生
stabs格式
的调试信息,
不包括
GDB调试信息。 -
-gstabs+
:产生
stabs格式
的调试信息,
包括
GDB调试信息。 -
-ggdb
:尽可能的生成GDB可以使用的调试信息
6.3
-std
指定编译版本
-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
6.5
-M
、
-MM
、
-MD
、
-MMD
生成文件关联的头文件信息
-M
-MM
-MD
-MMD
这几个参数,在Makefile中会经常用到,代替手动将头文件添加到规则中:
-
-M
:生成
.c
文件编译生成的默认目标文件名和所依赖的所有头文件信息,包括系统文件和项目中的文件,即
#include
造成的所有依赖关系。 -
-MM
:与
-M
一样,但是不包括系统文件造成的依赖关系,只包括引用的项目中的文件。 -
-MD
:和
-M
相同,但是输出将导入到
.d
的文件里面。 -
-MMD
:和
-MM
相同,但是输出将导入到
.d
的文件里面。
参考链接:
https://blog.csdn.net/qq_35865125/article/details/87868653
https://blog.csdn.net/gangyanliang/article/details/73162231
https://blog.csdn.net/hktkfly6/article/details/61922685
https://blog.csdn.net/tsxw24/article/details/10220735
https://www.runoob.com/w3cnote/gcc-parameter-detail.html