一、GCC编译过程
1.一般程序编译的过程如下:
.c 文件【预处理】后生成 .i 文件,.i 文件经过【编译】后生成 .s (汇编码)文件,.s 文件经过【汇编】后生成 .o 文件,一个或多个 .o 文件【链接】生成可执行程序。
- 预处理: 对.c文件中的“#”进行展开,包括查找头文件和展开宏等 gcc -E -o main.i main.c
- 编译:将高级语言转化成汇编语言 gcc -S -o main.s main.i
- 汇编:将汇编语言转化成机器语言(01码) gcc -c -o main.o main.s
- 链接:将机器语言转化成可执行程序 gcc -o main main.o
gcc编译过程中用到的工具包括:cc1、as、collect2
2.gcc 常用选项:
常用选项 | 描述 |
-E | 预处理,开发过程中想快速确定某个宏可以使用“-E -dM” |
-S | 编译,将.i文件编译成.s(汇编码)文件 |
-c | 把预处理、编译、汇编都做了,但是不链接 |
-o | 指定输出文件 |
-I | 指定头文件目录 |
-L | 指定链接时库文件目录 |
-l | 指定链接哪一个库文件 |
头文件:
- < > :这种符号的头文件,编译器会去系统目录中查找该头文件,程序员可以用 -I 指定头文件的查找目录(此时,编译器先去程序员指定目录查找,再去系统目录查找)
- " ":这种符号的头文件,编译器会去当前目录查找
3.其他选项
gcc -E main.c // 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt // 把所有的宏展开,存在1.txt里
gcc -Wp,-MD,abc.dep -c -o main.o main.c // 生成依赖文件abc.dep,后面Makefile会用
echo 'main(){}'| gcc -E -v - // 它会列出头文件目录、库目录(LIBRARY_PATH)
二、GCC编译静态库和动态库
1.gcc多文件编译
- 直接一起编译生成可执行程序:gcc -o test a1.c a2.c a3.c ...
- 每个文件各自编译但不链接,等多有文件都编译好再一起链接: gcc -c -o a1.o a1.c gcc -c -o a2.o a2.c gcc -c -o a3.o a3.c ... gcc -o test a1.o a2.o a3.o ...
已有文件main.c , sub.c , sub.h. 三个文件内容如下:
//main.c 文件内容如下
#include <stdio.h>
#include "sub.h"
int main(int argc,char* argv[])
{
int i;
printf("Main fun\n");
sub_fun();
return 0;
}
//sub.h 文件内容如下
void sub_fun();
//sub.c 文件内容如下
#include <stdio.h>
#include "sub.h"
void sub_fun()
{
printf("Sub fun!\n");
}
- 直接编译生成可执行程序:gcc -o test main.c sub.c
- 先各自编译不链接,最后一起链接成可执行程序:gcc -c -o main.o main.c gcc -c -o sub.o sub.c gcc -o test1 main.o sub.o
2.静态库
以上面三个文件为例,sub.c可以作为编译成库文件和 main.o 链接
将sub.c编译成静态库文件,并且和main.o 链接生成可执行程序步骤:
#1.先只编译不链接main.c文件
gcc -c -o main.o main.c
#2.将sub.c编译成静态库文件
gcc -c -o sub.o sub.c
ar crs libsub.a sub.o
#3.链接
gcc -o test main.o libsub.a
#4.执行程序
./test
其中,libsub.a就是静态库文件。静态库文件链接生成的可执行程序占用内存大,因为是直接将代码搬移过去的,所以可执行程序运行时不需要再去找静态库文件了。
3.动态库
以上面三个文件为例,sub.c可以作为编译成库文件和 main.o 链接
将sub.c编译成动态库文件,并且和main.o 链接生成可执行程序步骤:
#1.只编译不链接main.c文件
gcc -c -o main.o main.c
#2.编译生成动态库文件
gcc -c -o sub.o sub.c
gcc -shared -o libsub.so sub.o
#3.将所有文件链接
gcc -o test main.o libsub.so #方法一
gcc -o test main.o -lsub -L ./ #方法二
#4.执行程序
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ #配置环境变量:动态库目录指定
./test
几点注意:
- 动态库文件链接的时候有两中表示方法;
- 第一种方法直接用之前编译生成的动态库.so 文件;
- 第二种方法用 -l 指定链接哪个库文件,如果动态库文件名字是libsub.so,那么用-l的时候只要sub就行,前面的lib和后面的.so都不要。-l 会去系统提供的库文件目录下查找库文件,但我们这里库文件是在当前目录下,所以用 -L 指定库文件目录;
- 含有动态库链接的程序,在运行时也会去查找动态库,系统默认是去/lib, /usr/lib目录去查找,若该动态库文件不在系统默认库文件目录下,要么将其拷贝到系统默认库文件目录,要么配置环境变量,指定动态库目录:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
三、总结
1.头文件
- < > :这种符号的头文件,编译器会去系统目录中查找该头文件,程序员可以用 -I 指定头文件的查找目录(此时,编译器先去程序员指定目录查找,再去系统目录查找)
- " ":这种符号的头文件,编译器会去当前目录查找
2.动态库文件链接时:-lxxx
- 系统指定lib目录
- -L dir:程序员指定目录
3.含动态库的程序运行时
- 系统指定目录:/lib , /usr/lib
- 程序员指定,配置环境变量:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./