c++编译与链接
编译与链接
编译与链接的过程可以分解为4个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。
1. 预处理
首先是源代码文件helloworld.cpp和相关的头文件,如iostream等被预处理器cpp预处理成一个.i文件。第一步预处理的过程相当于如下命令(-E表示只进行预处理):
g++ -E helloworld.cpp -o helloworld.i
其中:-E的编译选项,意味着只执行到预编译,直接输出预编译结果。
预处理过程主要处理那些源代码文件只能够的以“#”开始的预编译指令。比如#include、#define等。
2. 编译
编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析以及优化后产生相应的汇编代码文件,这个过程往往是整个程序构建的核心部分,也是最复杂的部分之一。上面的编译过程相当于如下命令:
g++ -S helloworld.i -o helloworld.S
究竟编译器做了什么?从最直观的角度来讲,编译器就是将高级语言翻译成机器语言的一个工具。比如可以用C/C++语言写的一个程序可以使用编译器将其翻译成机器可以执行的指令及数据。编译的过程一般分为6步:扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成和目标代码优化,整个过程如图所示。
3. 链接
把每个源代码模块独立地编译,然后按照要将它们“组装”起来,这个组装模块的过程就是链接。链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确的衔接。
(1)静态链接
对函数库的链接是放在编译时期完成的是静态链接。所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已复制到相关位置。这些函数库被称为静态库,通常文件名为“libxxx.a”的形式。
g++ -S helloworld.i -o helloworld.S
-c的选项,表示只执行到编译。
由.o文件创建静态库(.a文件),执行命令:
ar cr libmymath.a sub.o add.o
会生成libmymath.a文件。
ar命令的r选项:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar会显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。
ar命令的c选项:创建一个库。不管库是否存在,都将创建。
顺便介绍下ar的tv参数,
ar tv libxxx.a
可以显示库文件中有哪些目标文件,显示文件名、时间、大小等详细信息。
在程序中使用静态库,执行命令g++-o main main.cpp-L.-lmymath,会生成main文件。-L指定库文件位置。
(2)动态链接
除了静态链接,也可以把对一些库函数的链接载入推迟到程序运行时期(runtime),这就是动态链接库(dynamic link library)技术。动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。
以下命令得到动态库文件libmamath.so:
g++ -fPIC -o add.o -c add.cpp
g++ -fPIC -o sub.o -c sub.cpp
g++ -shared -o libmath.so add.cpp sub.cpp
也可以直接一条命令搞定:
g++ -fPIC -shared -o libmath.so add.cpp sub.cpp
-fPIC:表示编译为位置独立的代码。不用此选项的话编译后的代码是位置相关的,所以动态载入时是通过代码复制的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
动态库的使用方式与静态库相同。