gcc编译器的过程有预处理、编译、汇编、链接几个步骤。
平时我们都不太关注,这是什么鬼,这里简单说明一下,以便于理解gcc工作原理。
总结:
gcc -E -o main.i main.c //只预处理,将库文件展开
gcc -S -o main.s main.c //编译,将.c编译成汇编
gcc -c -o main.o main.s //编译+汇编,将汇编码转换成ELF机器码
gcc -o main main.o //链接,将.o文件链接库生成可执行文件
1、 gcc常用的参数有:
gcc --help
Usage: gcc [options] file...
-v Display the programs invoked by the compiler
-E Preprocess only; do not compile, assemble or link
-S Compile only; do not assemble or link
-c Compile and assemble, but do not link
-o <file> Place the output into <file>
2、示例
main.c文件为例讲解gcc编译过程。
#finename:main.c
#include<stdio.h>
#define NUM 15
#define DEBUG
int main()
{
printf("num:%d\n", NUM);
#ifdef DEBUG
printf("hello debug\n");
#endif
return 0;
}
a- 预处理 -E
就是将你文件里的宏展开。
你可以打开你的main.i看到里面是什么。
粗略看了下,就是将一些数据类型什么的给展开到预处理文件main.i,以及main.c里用到的宏给展开。自己看下吧。
gcc -E -o main.i main.c //只预处理,将库文件展开
b- 编译 -S
就是将你的c代码编译成汇编语言,打开main.s可以看到是汇编码
gcc -S -o main.s main.c //编译,将.c编译成汇编
c- 汇编 -c
就是将上一步生成的.s的汇编码生成ELF格式的机器码。
gcc -c -o main.o main.s //编译+汇编,将汇编码转换成ELF机器码
可以用file命令查看文件类型
file main.o
main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
d- 链接 -o
就是将上一步生成的.o和系统库OBJ文件、库文件进行链接,生成可执行文件。
gcc -o main main.o //链接
file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2ba667769aa54a32ab02b9bd5e7d09f53938c564, not stripped
查看编译过程
gcc -v -o main main.o //链接
查看可执行文件依赖的库
ldd main
linux-vdso.so.1 => (0x00007ffce31b1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd1ecfaf000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd1ed379000)
好了,gcc编译的步骤和原理就这样,有个大概的认知了吧
3、 简化gcc编译命令
上面的编译步骤很详细,一步步的,让我们知道.c文件是如何生成可执行文件的。但是实际编译过程中这样写也太折磨人了吧。。。
gcc默认对.c文件进行预处理,-c指明编译+汇编,-o指将输出文件进行链接成可执行文件。
上述步骤可以简化为:
gcc -c -o main.o main.c
gcc -o main main.o
4- Makefiel脚本
我们平时写一个.c文件进行测试学习一些C语言用法,用gcc还可以。
但是每次都写这两行,还是会感到不爽,Makefile脚本就是来解放你的。
写一个通用的Makefile脚本,里边内容就是以gcc编译命令。
当你想执行编译的文件前,只需make一下,搞定!
前边写了几个Makefile的帖子,可以参考下。
5- 动态库 静态库(了解)
动态库:生成的可执行文件运行时,必须将依赖的库加载到内存中。默认动态链接。
静态库:将依赖的库写进可执行文件。文件较大。
gcc$ gcc -static -o main_static main.o //静态链接
gcc$ gcc -o main_share main.o //动态链接
gcc$ ls -l
-rwxrwxrwx 1 root root 8656 Aug 3 16:43 main
-rwxrwxrwx 1 root root 17130 Aug 3 16:03 main.i
-rwxrwxrwx 1 root root 1616 Aug 3 16:08 main.o
-rwxrwxrwx 1 root root 543 Aug 3 16:05 main.s
-rwxrwxrwx 1 root root 8656 Aug 3 2020 main_share
-rwxrwxrwx 1 root root 912816 Aug 3 16:48 main_static