Linux -C/C++静态链接库与动态链接库

C/C++静态链接库与动态链接库

  • 一、静态链接库(.a / .lib)
  • 二、动态链接库(.so / .dll)

一、静态链接库(.a / .lib)

静态链接库可以看做是一些目标文件(.o)的集合,在Linux系统中通常以.a结尾,在Window系统中通常以.lib文件结尾。

程序员利用静态链接库开发程序时,不需要将静态链接库的源码进行重新编译,只需要将.a/.lib文件与自己的.o/.obj文件进行链接即可。此外,如果你想将自己的函数提供给别人使用,但又不想直接将源码提供别比人,就可以生成静态链接库供别人使用。

下面的例子中,将hello.c编译为静态链接库libhello.a

// hello.c
#include "hello.h"

void hello(){
	printf("Hello World!\n");
}
// hello.h
#ifndef __HELLO_H
#define __HELLO_H
#include 

void hello();

#endif

生成静态链接库的步骤如下:

  1. 生成目标文件hello.o
$ gcc -c hello.c
  1. 创建静态链接库libhello.a,并向其中添加hello模块:
$ ar cr libhello.a hello.o

经过上述两个步骤可得到静态链接库文件:libhello.a

下面在main.c中使用libhello.ahello函数:

// main.c
#include "hello.h"
int main(void)
{
	hello();
	return 0;
}

下面的gcc命令生成可执行文件main

$ gcc -c main mian.c -L. -lhello

其中,-L.表示在当前路径搜索库文件,-lhello表示指定库文件为libhello.a

执行结果:

$ ./main
Hello World!

综上,生成并使用静态链接库的命令为如下三条:

$ gcc -o hello.c						// 生成目标文件hello.o
$ ar cr libhello.a hello.o			// 生成静态链接库文件libhello.a
$ gcc -c main main.c -L. -lhello		// 使用静态链接库文件生成可执行文件main

二、动态链接库(.so / .dll)

静态链接库有如下两个主要的缺点:

  1. 静态链接库在使用时被编译进了目标可执行文件,它的速度虽然快,但是造成了空间浪费。
  2. 当对静态链接库进行修改后,必须对所有源代码进行重新编译,使用起来比较麻烦。

动态链接库可以解决以上两个问题:

  1. 动态链接库在运行时才载入对应的模块,没有编译进可执行文件,可以实现多个实例共用一个动态链接库。
  2. 由于动态链接库无需编译进可执行文件,因此修改动态链接库后无需对源代码进行重新编译。

还是以上面的hello程序作为例子来生成动态链接库libhello.so

$ gcc -c -fPIC hello.c -o hello.o
$ gcc -shared hello.o -o libhello.so

编译main.c得到可执行文件main

$ gcc -o main main.c -L. -lhello

执行可执行文件结果如下:

$./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

下面两种方法可以解决这个问题:

  1. 使用如下命令将libhello.so加入环境变量:
$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH		# pwd表示当前路径
  1. libhello.so拷贝到/usr/lib文件夹中。

然后执行命令./main可得到期望结果:

$ ./main
Hello World!

综上,生成并使用动态链接库的命令为如下三条:

$ gcc -c fPIC hello.c -o hello.o
$ gcc -shared hello.o -o libhello.so
$ gcc -o main main.c -L. -lhello

其中,前两条命令可以合并:

$ gcc -fPIC -shared hello.c -o libhello.so
$ gcc -o main main.o -L. -lhello

其中,-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

你可能感兴趣的:(Linux)