Linux 动态库(显式、隐式)加载以及应用

linux开发感受最深的莫过于linux的动态库加载了,仅仅凭借这一点这支撑起了公司的灵活多变的业务。一个嵌入式Linux系统粗略的可以划分为系统层和应用层;应用层中基本都是10个以上的App来支撑起一个功能完备的嵌入式产品,这么多代码维护起来必然是十分的麻烦的,而且增减或者定制功能是一个挑战,这个时候就不得不提及程序的模块化;这个时候动态库的好处就来了,例如一个动态库就代表一个功能,如果你需要该功能那么就将该动态库或者App打包(若有XML配置文件那么加一下)加到烧写包里面,都不需要修改代码。例如我一个产品,甲客户需要ABCD这4个功能点,乙客户需要ACDEG这个5个功能点,丙客户需要ABDFG这5个功能点,那么你只需要将ABCDEFG这个7个功能点封装成七个可以动态加载动态库就可以,之后不同的客户只需要将现有功能组合一下,再加上定制需求即可快速发布产品,因此动态库的加载需要细致的学习一下。

Linux动态库文件是以lib开头.so结尾的文件(例如libtest.so),可以被其他程序引用,调用其中所封装的方法或者结构。想要其中的定义的方法或者函数被外界调用,需要将指定的函数导入到符号表,将函数定义为 extern C 全局接口即可,不然在打包strip(strip主要用于剥离一些调试信息等,减小文件大小)时候就会丢失符号,导致无法被引用。参见文章 动态库符号表。生成动态库使用编译器执行如下指令即可完成,例如将max.c 编译生成 libmax.so。

gcc -fPIC -shared -o libmax.so max.c

App程序在linux运行的时候会去环境变量 LD_LIBRARY_PATH 所包含的路径中查找动态库,动态库的加载主要有两种方式:

一、显式加载

显式加载,程序在运行的过程中执行加载动态库,主要由头文件 <dlfcn.h>中的动态库操作函数函数来管理,各个函数相关的功能可以具体看 动态库加载函数文章

#include <dlfcn.h>

void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);

一般用慢加载的方式调用dlsym取出动态库中的函数,将其赋值给一个函数指针以便调用。为了能方便的管理插件,一般将一个App的插件都打包成相同的函数名的接口,那么App只需要读取路径下的动态库数量,逐一取出并且调用初始化接口完成功能,这样增删插件都不用改动代码

extern "C" {
    LoadPlus(AppClass *_app);
    Init();
    Schedule();
    Deinit();
}

例如我常用的接口如下,

LoadPlus(AppClass *_app);  完成插件的加载 包括内存申请等操作,AppClass *_app是一个传入动态库的指针,用于回调原App的方法实现调用其他插件的功能或者调用App的功能 。

Init();  初始化操作 申请资源等。

Schedule();  放入一个线程中不断调用。

Deinit();  退出App时调用一般用于释放插件申请的资源。

二、隐式加载

隐式加载就是在程序编译的时候就进行链接并且检查,直接在编译的时候加入编译的链接参数,例如你需要将libmax.so链接到test.c所生成可执行文件中,如下链接即可。

gcc -o test test.c -L. -lmax

一般隐式加载的动态库若未能找到会直接导致App程序崩溃,而显式加载的方式可以通过检查返回来规避。

这里顺便提一下静态库,静态库也就是以 .a结尾结尾的库,链接同动态库,静态库是将库中的代码全部都编译进App程序中。所以不需要将静态库放入到运行环境中。但是有一个问题们就是,相同的代码若是被调用次数过多那么必然导致,程序臃肿,而且每次修改静态库程序都要进行重新编译,带来了极大的不便利。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值