C++源文件到可执行文件过程
源程序 预处理->编译和优化->汇编->链接->可执行文件
1.预处理(Preprocessing)
读取源程序,对其中的伪指令(以#开头的指令(宏定义、条件编译指令、头文件包含指令))和特殊符号进行处理
gcc -E main.c -o main.i
2.编译阶段(Compilation)
把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。
gcc -S main.c -o main.s
3.汇编过程(Assembly)
把汇编语言代码翻译成目标机器指令
gcc -c main.s hello.s -o hello.o
4.链接程序(Linking)
将main.o和hello.o以及一些其他必要的目标文件组合起来,包含各函数库的入口,创建可执行目标文件。
gcc main.o hello.o -o hello
GCC文件后缀名
后缀 | 含义 |
---|---|
.h .hpp .hxx | C/C++头文件 |
.c .cpp .cc .cxx | C/C++源代码文件 |
.i .ii | 预处理过的C源代码文件 |
.s | 汇编代码 |
.S | 经过预编译的汇编代码 |
.o | 目标机器指令 |
.a(linux) .lib(Win32) | 静态链接库 |
.so(linux) .dll(Win32) | 动态链接库 |
库
库文件命名规范
在 linux 下,库文件一般放在/usr/lib和/lib下,
静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号
库比较
依据链接时期的不同,库又有静态库和动态库之分。
静态库是在链接阶段被链接的。所以生成的可执行文件就不受库的影响了。即使库被删除了,程序依旧能够成功执行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序执行时调用,相关库删除之后程序不能正常运行。
假设多个程序链接了同一个库,则每个生成的可运行文件就都会有一个库的副本,必定会浪费系统空间。
动态库是在程序执行时被链接的,所以磁盘上仅仅须保留一份副本,因此节约了磁盘空间。
静态库可以在程序移植前将相关库链接进去,只需移植可执行文件,方便。
动态库牺牲了运行效率。
静态库
静态库,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
可以简单看成是一组目标文件(.o/.obj文件)的集合
创建过程
编译成目标文件.o
gcc -c index.cpp -o index.o
通过ar工具将目标文件打包成.a静态库文件,生成静态库libindex.a
ar -crv libindex.a index.o
在程序中链接静态库,生成的hello.static就不再依赖libindex.a了
gcc test.c libindex.a -L ./ -o hello.static
# -L后面是 要链接的静态库地址(-Lxxx中间有没有空格都行)
或
gcc test.c -l index -L./ -static -o hello.static
#这里-l之后紧接是库名(注意-lxxxx中间有没有空格都行,且省略后缀),但是要增加-static说明是静态库
动态库
特点
- 动态库把对一些库函数的链接载入推迟到程序运行的时期
- 可以实现进程之间的资源共享。(因此动态库也称为共享库)
- 将一些程序升级变得简单。(增量更新,只需更新库)
- 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显式调用)
创建过程
编译成目标文件.o
gcc -c index.cpp -o index.o
由.o文件创建动态库文件
gcc -shared -fPCI index.o -o libindex.so
# 64位机要加上这个参数-fPCI
在程序中链接动态库
gcc test.c -lindex -L./ -o test.out
常见的链接库
在编译带有线程库的函数时得在后面加-lpthread,编译使用了libevent库的文件时,得在后面加上-levent,还有编译json或异步I/O等时都得在编译时都得加上特有的链接库