嵌入式linux学习笔记-- 对于动态库的一些操作 dlopen
最近公司重构代码,看到了公司的一位经验丰富的工程师的一些C++ 操作 属实有被秀到,估计光看他写的代码都够我写很多总结了。 根据他写的代码以及公司未来的代码的一些规划 我也总结一些无关痛痒的知识吧。
我们的新一代的代码架构将会去做到能实时的更换模块(就是c 编译出来的动态库 能动态的去加载! 目前的思路就是使用dlopen 以及dlclose的操作去动态的加载库文件) 之前一直没想到动态库的加载还可以这么的简单,高效。
下面的一些内容从大佬们的博客直接拼凑过来的 既然别人已经总结了一次 我就不去班门弄斧了
————————————————
版权声明:本文为CSDN博主「cybertan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cybertan/article/details/4383486
0 dlopen 相关的API
DLOPEN(3) Linux Programmer's Manual DLOPEN(3)#include <dlfcn.h>void *dlopen(const char *filename, int flag);char *dlerror(void);void *dlsym(void *handle, const char *symbol);int dlclose(void *handle);Link with -ldl.
0.1 dlopen()
该函数用来按照指定模式打开指定的共享库,将其影射到内存中,并且返回句柄。
第一个参数:指定共享库的名称,将会在下面位置查找指定的共享库。
-环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录。
-文件/etc/ld.so.cache中找到的库的列表,用ldconfig维护。
-目录usr/lib。
-目录/lib。
-当前目录。
第二个参数:指定如何打开共享库。
-RTLD_NOW:将共享库中的所有函数加载到内存
-RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数
0.2 dlsym()
void *dlsym(void *restrict handle, const char *restrict name);
该函数返回一个指向由name所确定的请求入口点的指针。调用dlsym时,利用dlopen()返回的共享库的phandle以及函数/变量名称作为参数,返回要加载函数/变量的入口地址。
0.3 dlerror()
dlerror 返回 NULL 或者一个指向描述最近错误的 ASCII 字符串的指针
0.4 dlclose()
关闭句柄并且取消共享目标文件的映射
1. 一个简单的demo
// main.cpp
#include <stdio.h>
#include <dlfcn.h>
int main(void)
{int abc = 123;printf("[%s] #line %d exec ...\n",__FUNCTION__,__LINE__);void *p = dlopen("./libmodule1.so",RTLD_LAZY);printf("[%s] #line %d p = %p\n",__FUNCTION__,__LINE__,p);printf("[%s] #line %d exec ...\n",__FUNCTION__,__LINE__);void* sym = dlsym(p,"temp1");printf("[%s] #line %d sym[temp1] = %p\n",__FUNCTION__,__LINE__,sym);printf("[%s] #line %d exec ...\n",__FUNCTION__,__LINE__);printf("[%s] #line %d exec ...\n",__FUNCTION__,__LINE__);return 0;
}
// module1.cpp
#include <stdio.h>
class temp{public:temp() {printf("[%s] #line %d exec ...\n",__FUNCTION__,__LINE__);printf("[%s] #line %d this = %p ...\n",__FUNCTION__,__LINE__,this);}
} temp1;
cmake_minimum_required(VERSION 3.16)
project(dlopenTest)add_executable(appmain.cpp)
target_link_libraries(app dl
)
add_library(module1 SHAREDmodule1.cpp
)
[jeason@centos7 dlopen]$ ls
CMakeLists.txt main.cpp module1.cpp
[jeason@centos7 dlopen]$ mkdir build && cd build
[jeason@centos7 build]$ cmake ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jeason/dlopen/build
[jeason@centos7 build]$ make
[ 25%] Building CXX object CMakeFiles/app.dir/main.cpp.o
[ 50%] Linking CXX executable app
[ 50%] Built target app
[ 75%] Building CXX object CMakeFiles/module1.dir/module1.cpp.o
[100%] Linking CXX shared library libmodule1.so
[100%] Built target module1
[jeason@centos7 build]$ ./app
[main] #line 7 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7f6091f79039 ...
[main] #line 10 p = 0x1bb2030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f6091f79039
[main] #line 15 exec ...
[main] #line 17 exec ...
[jeason@centos7 build]$
上面的例子里面 在动态库里面我创建了一个 类,然后就调用了类的构造函数,然后 这个函数就打印出来了
this = 0x7f6091f79039 这个地址和我后面使用 dlsym 函数获得的指针是一个地址,也就是说我可以用dlsym 拿到这个指针。
1.1 简单修改
简单修改一下代码 测试一下 dlclose 的一些特性
[jeason@centos7 build]$ make && ./app
Consolidate compiler generated dependencies of target app
[ 50%] Built target app
[ 75%] Building CXX object CMakeFiles/module1.dir/module1.cpp.o
[100%] Linking CXX shared library libmodule1.so
[100%] Built target module1
[main] #line 8 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7ff5f34b5041 ...
[main] #line 11 p = 0x15a6030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7ff5f34b5041
[~temp] #line 9 exec ...
[main] #line 18 exec ...
[main] #line 20 exec ...
[jeason@centos7 build]$
[jeason@centos7 build]$
我们可以明显的看到 temp 的构造和析构一直在被调用。
接下来屏蔽 dlclose 看一下效果
[jeason@centos7 build]$
[jeason@centos7 build]$ make && ./app
[ 25%] Building CXX object CMakeFiles/app.dir/main.cpp.o
[ 50%] Linking CXX executable app
[ 50%] Built target app
Consolidate compiler generated dependencies of target module1
[100%] Built target module1
[main] #line 8 exec ...
[temp] #line 5 exec ...
[temp] #line 6 this = 0x7f4435433041 ...
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 11 p = 0x1a0e030
[main] #line 12 exec ...
[main] #line 14 sym[temp1] = 0x7f4435433041
[main] #line 18 exec ...
[main] #line 20 exec ...
[~temp] #line 9 exec ...
[jeason@centos7 build]$
我们可以发现 这个类只是被构造了一次! 只是在程序退出的时候析构了一次,而且 我们还可以直接通过dlopen 拿到相同的一个指针
后面的需求实现就是看 程序猿自己去发挥了 要想实现 我们新版本的代码框架中动态的加载和卸载一些模块
嵌入式linux学习笔记-- 对于动态库的一些操作 dlopen相关推荐
- Linux学习笔记-生成动态库(补充说明)
1.在Makefile中创建动态库. 2.在动态库中共享class类型. Makefile文件如下: EXE=libexample.so SUBDIR=srcCXX_SOURCES=$(foreach ...
- 嵌入式linux学习笔记--TCP通讯整理
嵌入式linux学习笔记–TCP通讯整理 之前的项目中使用到了比较多的tcp 通讯相关的知识,一直也没有进行整理,今天准备拿出时间好好的整理一下TCP通讯的整个过程.预计会整理linux和window ...
- 迅为嵌入式Linux学习笔记4——进程
迅为嵌入式Linux学习笔记4--进程 进程指的是正在运行的程序,是操作系统分配资源的最小单位. 进程ID 每个进程都有唯一的标识符,这个标识符就是进程ID,简称pid 进程间通信的方法 管道通信:分 ...
- 迅为嵌入式Linux学习笔记5——进程间通信
迅为嵌入式Linux学习笔记5--进程间通信 管道通信 无名管道 无名管道只能实现有亲缘关系的进程之间的通信,比如父子进程. pipe函数: #include <unistd.h> int ...
- 嵌入式Linux学习笔记—fastboot烧写Android
本系列为本人在自学过程中的学习笔记,如有错误欢迎大家指正. 学习资料为讯为ITOP4412开发板. fastboot烧写Android 1.主要工具 OTG 接口烧写方式也叫 fastboot 烧写方 ...
- 【linux学习笔记】嵌入式linux学习笔记
目录: 1.SWAP 交换分区 2.GRUB 3.块设备和字符设备 4.shell 7.静态函数库\动态库 8.交叉编译 9.系统调用 10.文件 I/O编程 11.进程和线程 12.磁盘和文件系 ...
- 嵌入式linux编程,嵌入式Linux学习笔记 - 嵌入式Linux基础知识和开发环境的构建_Linux编程_Linux公社-Linux系统门户网站...
注:所有内容基于友善之臂Mini2440开发板 一.嵌入式Linux开发环境的构建 嵌入式开发一般分为三个步骤: 1.编译bootloader,烧到开发板 2.编译嵌入式Linux内核,烧到开发板 3 ...
- linux内核编译选项ccl,嵌入式Linux学习笔记(一)
注:所有内容基于友善之臂Mini2440开发板 一.嵌入式Linux开发环境的构建 嵌入式开发一般分为三个步骤: 1.编译bootloader,烧到开发板 2.编译嵌入式Linux内核,烧到开发板 3 ...
- 嵌入式linux学习笔记(一)
最近开始学习linux驱动编写,目前直接使用jz2440已移植好的系统配合视频开始学习驱动编写,但是总是出现这样那样的问题.于是决定重头开始,先自己移植内核,在开始驱动学习. 今天参照<嵌入式l ...
最新文章
- [再寄小读者之数学篇](2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]二次型的零点)...
- 梅尔频率倒谱系数(MFCC)资源
- golang reflect Pointer 获取 传入的interface信息
- hibernate数据类型_Hibernate类型初学者指南
- 精简SWT FormLayout的用法
- 获取iOS任意线程调用堆栈(五)完整实现:BSBacktraceLogger
- 计算机 项目管理 stage phase区别
- 熊猫烧香能破坏计算机硬件吗,熊猫烧香病毒会伤害电脑硬件吗?
- 电脑常用良心软件推荐!!!
- 统计学中p值计算公式_统计学中的P值应该怎么计算
- 两个excel宏病毒
- 7年阿里Java人教你:秒杀活动就应该这样玩?
- 用户名xxx不在sudoers文件中,此事将被报告
- 基于博客系统的访客日志记录
- Java核心编程(22)
- discuz论坛添加、更换返回顶部图标
- PC版微信内置浏览器 缓存文件保存位置
- video.js API 详解
- window的onload事件的用法
- 公园景区广播系统方案