作为一名C/C++程序员,对于编译链接的过程要了然于胸。首先大概介绍一下,编译分为3步,首先对源文件进行预处理,这个过程主要是处理一些#号定义的命令或语句(如宏、#include、预编译指令#ifdef等),生成*.i文件;然后进行编译,这个过程主要是进行词法分析、语法分析和语义分析等,生成*.s的汇编文件;最后进行汇编,这个过程比较简单,就是将对应的汇编指令翻译成机器指令,生成可重定位的二进制目标文件。以上就是编译的过程,下面主要介绍两种链接方式–静态链接和动态链接。
静态链接和动态链接两者最大的区别就在于链接的时机不一样,静态链接是在形成可执行程序前,而动态链接的进行则是在程序执行时,下面来详细介绍这两种链接方式。
多个可重定位模块(.o) +静态库(标准库、自定义库, .a文件,其中包括多个.o模块)关于静态库后面会详细说明
如何打包编程者经常使用的功能函数? 在静态库提出之前有2种方法:
比如,使用标准 C 库和数学库中函数的程序可以用形式如下的命令行来编译和链接,编译器只会拷贝被程序引用的目标模块:
unix> gcc main.c /usr/lib/libm.a /usr/lib/libe.a
构造一个名字叫libvector.a 的静态库,里面有两个成员目标文件构成:mulvec.c addvec.c
/*mulvec.c*/
void mulvec(int *x,int *y,int *z,int n)
{
int i;
for(i=0;i<n;i++)
z[i]=x[i]*y[i];
}
/* addvec.c*/
void addvec(int *x,int *y,int *z,int n)
{
int i;
for(i=0;i<n;i++)
z[i]=x[i]+y[i];
}
使用ar工具创建库:
gcc -c addvec.c multvec.c
ar rcs libvector.a addvec.o multvec.o
可以看到文件夹中已经生成了这个库
编写main2.c, 调用 addvec :
#include
#include "vector.h"
int x[2]={1,2};
int y[2]={3,4};
int z[2];
int main()
{
addvec(x,y,z,2);
printf("z= [%d,%d]\n",z[0],z[1]);
return 0;
}
编译和链接输入文件 main.o 和 libvector.a,执行指令:
gcc -O2 -c main2.c//生成.o文件
gcc -static -o p2 main2.o ./libvector.a//再用./p2指令可以可以运行可执行文件p2
动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。下面简单介绍动态链接的过程:
假设现在有两个程序program1.o和program2.o,这两者共用同一个库lib.o,假设首先运行程序program1,系统首先加载program1.o,当系统发现program1.o中用到了lib.o,即program1.o依赖于lib.o,那么系统接着加载lib.o,如果program1.o和lib.o还依赖于其他目标文件,则依次全部加载到内存中。当program2运行时,同样的加载program2.o,然后发现program2.o依赖于lib.o,但是此时lib.o已经存在于内存中,这个时候就不再进行重新加载,而是将内存中已经存在的lib.o映射到program2的虚拟地址空间中,从而进行链接(这个链接过程和静态链接类似)形成可执行程序。
共享库 (shared library) 是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模 块,在运行时,可以加载到任意的存储器地址,并和一个在存储器中的程序链接起来。这个过程 称为动态链接 (dynamic linking), 是由一个叫做动态链接器 (dynamic linker) 的程序来执行的。
gcc -shared -fPIC -o libvector.so addvec.c multvec.c
unix> gcc -o p2 main2.c ./libvector.so