Linux 动态链接库(.so)的使用

简介: 1. 背景 库:就是已经编写好的,后续可以直接使用的代码。 c++静态库:会合入到最终生成的程序,使得结果文件比较大。优点是不再有任何依赖。 c++动态库:动态库,一个文件可以多个代码同时使用内存中只有一份,节省内存,可以随主代码一起编译。

1. 背景

库:就是已经编写好的,后续可以直接使用的代码。

c++静态库:会合入到最终生成的程序,使得结果文件比较大。优点是不再有任何依赖。

c++动态库:动态库,一个文件可以多个代码同时使用内存中只有一份,节省内存,可以随主代码一起编译。缺点是需要头文件。

网友说:库就是除了main函数之外的其他代码,都可以组成库。

2. 只介绍动态库(工作中主要用动态库) 

C++使用动态库比C语言使用动态库稍微麻烦点。

因为C++支持函数重载(参数变量个数不同、参数类型不同、类型修饰符不同const/not const等),都会使得C++对函数名进行重写,不方便根据函数名查找对应函数

C++中可以使用extern关键字修饰对应的函数,表示函数名按照C言语分隔编译,不进行改写。(extern关键字另一个关键字修饰变量,表示变量在其他文件中已经定义。通常见于修饰全局变量)

3. 使用so文件需要的api

头文件 #include <dlfcn.h>

dlopen以指定的模式打开共享链接库。使用可以参考: http://man7.org/linux/man-pages/man3/dlopen.3.html

4. C++使用动态链接库实例

4.1 test.h

1 class Test{
2 public:
3     virtual int get();
4     virtual void set(const int num);
5 };

4.2 test.cpp

 1 #include <iostream>
 2 #include "test.h"
 3 
 4 int g_num = 0;   ///全局变量
 5 
 6 int Test::get() { return g_num; }
 7 void Test::set(const int num){ g_num = num; }
 8 
 9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 Test* create(){ return new Test; }
14 
15 #ifdef __cplusplus
16 }
17 #endif

 4.3 main.cpp

 1 #include <iostream>
 2 #include <dlfcn.h>
 3 #include "test.h"
 4 using namespace std;
 5 
 6 //声明函数指针
 7 typedef Test* (*so_init)();
 8 
 9 //定义插件类来封装,句柄用完后需要释放
10 struct Plugin{
11     void *handle;
12     Test *t;
13 
14     Plugin():handle(NULL), t(NULL) { }
15     ~Plugin(){
16         if(t) { delete t; }
17         if (handle) { dlclose(handle); }
18     }
19 };
20 
21 int create_instance(const char *so_file, Plugin &p){
22     //根据特定的模式打开so文件, 获取so文件句柄
23     //RTLD_NOW:需要在dlopen返回前,解析出所有未定义符号
24     //RTLD_DEEPBIND:在搜索全局符号前先搜索库内的符号,避免同名符号的冲突
25     p.handle = dlopen(so_file, RTLD_NOW | RTLD_DEEPBIND);
26     if (!p.handle) {
27         cout << "Cannot open library: " << dlerror() << endl;
28         return -1;
29     }
30 
31     //根据字符串"create"读取库中对应到函数, 并返回函数地址,可以理解为一种间接的“反射机制
32     so_init create_fun = (so_init) dlsym(p.handle, "create");
33     if (!create_fun) {
34         cout << "Cannot load symbol" << endl;
35         dlclose(p.handle);
36         return -1;
37     }
38 
39     //调用方法, 获取类实例 
40     p.t = create_fun();
41 
42     return 0;
43 }
44 
45 int main(){
46     Plugin p1;
47     Plugin p2;
48 
49     if (0 != create_instance("./libtest_1.so", p1)
50             || 0 != create_instance("./libtest_2.so", p2)){
51         cout << "create_instance failed" << endl;
52         return 0;
53     }
54 
55     p1.t->set(1);   //对库1中到全局变量进行设置
56     p2.t->set(2);   //对库2中到全局变量进行设置
57 
58     //输出两个库中的全局变量
59     cout << "t1 g_num is " << p1.t->get() << endl;
60     cout << "t2 g_num is " << p2.t->get() << endl;
61     return 0;
62 }

 

执行:

g++ -fPIC -shared test.cpp -o libtest_1.so

g++ -fPIC -shared test.cpp -o libtest_2.so

g++ -g -Wl,--no-as-needed -ldl main.cpp -rdynamic

相关文章
|
4月前
|
安全 Linux vr&ar
Linux的动态库和静态库
Linux的动态库和静态库
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
98 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
4月前
|
Linux API
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
|
5月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
160 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
4月前
|
Linux 网络安全 API
【Azure 应用服务】App Service For Linux 环境中,如何从App Service中获取GitHub私有库(Private Repos)的Deploy Key(RSA key)呢?
【Azure 应用服务】App Service For Linux 环境中,如何从App Service中获取GitHub私有库(Private Repos)的Deploy Key(RSA key)呢?
|
4月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
34 0
|
6月前
|
存储 Linux C语言
Linux|如何安装和运行多个 glibc 库
Linux|如何安装和运行多个 glibc 库
1160 5
|
6月前
|
Linux 编译器 C语言
Linux中的pkg-config:简化库依赖管理的利器
**pkg-config**是Linux下管理库依赖的工具,它通过读取库的`.pc`文件提供编译和链接参数。使用`pkg-config --cflags --libs &lt;library&gt;`获取编译和链接选项,例如`gcc -o test test.c $(pkg-config --cflags --libs glib-2.0)`。能进行版本检查、参数提取、依赖管理和路径搜索。列出所有包用`pkg-config --list-all`。最佳实践包括确保库正确安装、检查版本、配置`PKG_CONFIG_PATH`及使用构建工具。
|
6月前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
45 1
|
6月前
|
存储 编解码 Ubuntu
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
【QT】linux下alsa库的移植和QT中音视频的处理&笔记