动态链接库

2020-12-02 15:05:19 浏览数 (1)

动态链接库介绍

动态链接库,又称为共享链接库。采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。这样带来的好处是可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。同样这也带来了缺陷,此方式生成的可执行文件无法独立运行,必须借助相应的库文件。

和使用静态链接库生成的可执行文件相比,动态链接库生成的可执行文件的体积更小,因为其内部不会被复制一堆冗余的代码。在Linux系统中动态链接库通常以.so结尾,在Windows系统中动态链接库通常以.DLL结尾。

动态链接库的创建

和前文静态链接库的例子一致,这里给出helloworld_c.h文件和helloworld_c.c文件。

helloworld_c.h文件

代码语言:javascript复制
#ifndef HELLOWORLD_C_H
#define HELLOWORLD_C_H

#include <stdio.h>

#ifdef __cplusplus          //使用__cplusplus宏配合extern "C"来告诉C  链接器,这是一个C接口。

extern "C"{
#endif

void Print_HelloWorld();

#ifdef __cplusplus
}
#endif

#endif //HELLOWORLD_C_H

helloworld_c.c文件

代码语言:javascript复制
#include"helloworld_c.h"

void Print_HelloWorld()
{
    printf("Hello World!n");
}

下面来制作动态链接库。一般也可以分为两种方式。

  • 直接制作

GCC使用-shared 选项用于生成动态链接库;GCC使用-fpic(还可写成 -fPIC)选项的功能是,令 GCC 编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用相对地址,而非绝对地址。这样,无论将来链接库被加载到内存的什么位置,都可以正常使用。

代码语言:javascript复制
gcc -Wall -shared -fPIC helloworld_c.c -o libhello.so
  • 间接制作

首先编译生成中间文件,然后生成动态链接库。

代码语言:javascript复制
gcc -Wall -fPIC -o helloworld.c
gcc -shared helloworld_c.o main.cpp -o libhello.so

-Wall在第一个命令里包含了即可,因为-Wall在编译的时候起作用,而在链接的时候没有用。所以第二个命令没有该选项。

无论上述哪种方式,都会生成名为libhello.so的文件。通常我们都会使用第一种方式。

动态链接库的使用

动态链接库的使用也可以有两种不同的命令方式。

  • 直接使用当前目录下的动态链接库
代码语言:javascript复制
gcc -Wall libhello.so main.c
  • GCC使用-L和-l选项,选项的含义见静态链接库一文。
代码语言:javascript复制
gcc -Wall -L. -lhello main.c

无论是那种方式,我们都生成了a.out文件,但是这时候我们还无法执行它。因为它缺少libhello.so文件。我们可以使用ldd命令来查看它所需要的所有动态链接库。

代码语言:javascript复制
ldd a.out

可以看到libhello.so是not found,现在我们必须确保程序在运行时可以找到这个动态链接库。一般有下面几种方式。

  • 将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64)
  • 在终端输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效);
  • 修改~/.bashrc 或~/.bash_profile 文件,即在文件最后一行添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx(xxx 为动态库文件的绝对存储路径)。保存之后,执行source .bashrc指令(此方式仅对当前登陆用户有效)。

所以,正常来说,我们都会采用第一种方式。毕竟后两种方式可能不太友好。现在我把刚才生成的动态链接库复制到/lib下面去,然后尝试执行a.out文件。

差点忘了,我们再来看看这次生成的可执行文件的大小吧。

0 人点赞