多版本动态库的变量测试

Posted 李迟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多版本动态库的变量测试相关的知识,希望对你有一定的参考价值。

前面写有文章探讨动态库环境变量传递问题,本文介绍加载不同版本动态库的函数调用情况。

问题提出

某工程使用到动态库,由于动态库存在不同版本,因此都会加载,后按需调用。为了观察“按需调用”情况,模拟实际使用情况,但作了简化,只观察某一变量的变化情况。

工程代码

设计思路

工程比较简单,分应用程序和动态库,但源码在同一目录,只是通过 Makefile 编译得到不同的目标文件。动态库的不同版本,版本号和累加的变量cnt不同。每次编译,需将得到的动态库改名,即使用文件文件名区别不同的版本:libfoobar_0.solibfoobar_1.solibfoobar_2.so。。

在测试函数中,创建不同线程,根据动态库文件名调用动态库。

实现代码

dl.cpp实现代码:

// 全局变量,库中没有多线程,故不加锁
static int cnt = 0; // 0表示版本0,1表示版本1,等
​
int GetVersion(char *version)

    int ver = 2;
    sprintf(version, "ver: 0.%d", ver);
    return 0;

​
int Foo()

    printf("Foo...\\n");
    return 0;

​
int Bar()

    printf("Bar...\\n");
    return 0;

​
DL_API_t gAPI = 
    .name = "MyLib",
    GetVersion,
    Foo,
    Bar,
;
///
​
int foo()

    printf("foo22...\\n");
    cnt++; // 累加1,下同
    return 0;

​
int bar()

    printf("bar22...\\n");
    cnt++;
    return 0;

​
int getcnt()

    return cnt;

​
int init()

    cnt = 100;
    return 0;

​
int uninit()

    cnt = 0;
    return 0;

测试代码

​
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
​
#include <string.h>
#include <errno.h>
​
#include <thread>
​
#include "dl.h"
​
typedef int (*pfoo_t)();
​
pfoo_t pfoo;
​
void* myfunc(int a)

    char filename[128] = 0;
    sprintf(filename, "./libfoobar_%d.so", a);
    void* handle = dlopen(filename, RTLD_LAZY); // 必须加路径
    if (handle == NULL)
    
        printf("open %s failed.\\n", filename);
        return NULL;
    
    
    printf("load %s handler: %p\\n", filename, handle);
    char version[64] = 0;
    DL_API_t* aLib = (DL_API_t*)dlsym(handle, "gAPI");
    if (!aLib)
    
        printf("dlsym failed: %s\\n", dlerror());
        return NULL;
    
    
    aLib->GetVersion(version);
    printf("ver: %s\\n", version);
​
    #if 0
    if (aLib->Foo)
    
        aLib->Foo();
    
    #endif
    #if 0
    pfoo = (pfoo_t)dlsym(handle, "init");
    if (pfoo)
    
        pfoo();
    
    #endif
​
    pfoo = (pfoo_t)dlsym(handle, "foo");
    if (pfoo)
    
        pfoo();
    
    
    // 复用指针
    pfoo = (pfoo_t)dlsym(handle, "bar");
    if (pfoo)
    
        pfoo();
    
​
    pfoo = (pfoo_t)dlsym(handle, "getcnt");
    if (pfoo)
    
        int ret = pfoo();
        printf("cnt: %d\\n", ret);
    
    
    dlclose(handle);
    
    return NULL;

​
int main(void)

    printf("so test...\\n");
​
    void* handle = dlopen("./libfoobar.so", RTLD_LAZY); // 必须加路径
    if (handle == NULL)
    
        printf("open failed.\\n");
        //return -1;
    
    printf("in main handler: %p\\n", handle);
#define TEST_THREAD_NUM 3
    int threadnum = TEST_THREAD_NUM;
    std::thread threads[TEST_THREAD_NUM];
    for(int i = 0; i < threadnum; i++)
    
​
        threads[i] = std::thread(myfunc, i);
        sleep(2); // 让不同线程错开运行
    
​
    // 线程不一定占满,故要判断再join
    for (auto& t: threads) 
        if (t.joinable())
            t.join();
    
​
    if (handle)  dlclose(handle);
    
    return 0;

动态库里的接口函数,在形式设计上是相同的:参数为空,返回值为空,因此在测试代码中可以复用函数指针。 对于使用dlopen打开动态库、用dlsym获取动态库函数接口的做法,可以不提供头文件,提前是函数封装得比较,比如提供纯粹功能接口,而不对外开放结构体。

以上两点在前面的文章没有提到,此处特意说明。

测试

测试结果:

so test...
in main handler: 0x1292060
load ./libfoobar_0.so handler: 0x7f26d4000910
ver: ver: 0.0
foo22...
bar22...
cnt: 2
load ./libfoobar_1.so handler: 0x7f26d4000910
ver: ver: 0.1
foo22...
bar22...
cnt: 3
load ./libfoobar_2.so handler: 0x7f26d4000910
ver: ver: 0.2
foo22...
bar22...
cnt: 4

根据设计思路,libfoobar_0.so中变量初始化为0,所以版本号为0.0,经过2个函数累加,最终值为2。类似地,libfoobar_1.so初始化为1,累加后的值为3,libfoobar_2.so初始化为2,累加后的值为4。

小结

某些应用场合中,会存在“相同”动态库的不同版本,本文对此进行测试。像申请内存、释放,多线程等情况没有深入研究。从输出日志看,加载不同动态库,其返回的句柄值是一样的,但的确能体现出不同的版本,此为何原因,暂时不知道。

以上是关于多版本动态库的变量测试的主要内容,如果未能解决你的问题,请参考以下文章

多环境变量配置

多环境变量配置

多环境变量配置

qmake使用实践:包含动态库的Qt4工程

如何将qt静态库代码还原动态库

Linux 动态链接库包含静态链接库的方法