通过dlopen使用动态库

在和别人合作开发的时候,往往存在一方提供库供另一方调用。这个过程存在编译依赖问题,库更新问题。为了解耦,这里可以使用dlopen的方式去使用动态库。

示例如下:

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>

#include "abupdate.h"

typedef int (*FuncptrType)(st_update_progress *);

extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;

const char getopt_str[] = "xz:y::";
static struct option long_options[] =
	{
		{"update",							optional_argument, 0, 'a'},
		{"mask",							optional_argument, 0, 'b'},
		{"switch_boot_slot",				no_argument, 0, 'c'},
		{"cancel_switch_boot_slot",			no_argument, 0, 'd'},
		{"set_current_slot_success",		no_argument, 0, 'e'},
		{"rollback",						no_argument, 0, 'f'},
		{"get_boot_slot",					no_argument, 0, 'g'},
		{"help",							no_argument, 0, 'h'},
};

static int usage(void)
{
	printf("usage:\n");
	printf("       abupdate_app --help\n");
	printf("       abupdate_app --update=/data/update.zip --mask=0xff\n");
	printf("       abupdate_app --switch_boot_slot\n");
	printf("       abupdate_app --cancel_switch_boot_slot\n");
	printf("       abupdate_app --set_current_slot_success\n");
	printf("       abupdate_app --rollback\n");
	printf("       abupdate_app --get_boot_slot\n");
	return 0;
}

// 此函数是一个回调函数,用于提供给底层库反馈升级进度
static int progress_callback(st_update_progress update_progress)
{
	printf("rollback total: %d%%  soc: %d%%  mcu:%d%%  camera:%d%%\n", update_progress.total, update_progress.soc, update_progress.mcu, update_progress.camera);
	return 0;
}

// 此函数主动调用获取升级进度的接口
static int thread_get_progress(void *arg)
{
	int ret = 0;
	st_update_progress update_progress;
	FuncptrType ge_progress_func = NULL;
	ge_progress_func = (FuncptrType)arg;
	while(1)
	{
	    ret = ge_progress_func(&update_progress);
		if(ret == 0)
		{
		    printf("total: %d%%  soc: %d%%  mcu:%d%%  camera:%d%%\n", update_progress.total, update_progress.soc, update_progress.mcu, update_progress.camera);
		}
		else
		{
		    printf("get progress error.\n");
		}

		sleep(1);
	}
	return 0;
}


int main(int argc, char *argv[])
{
	int ret = 0;
	int opt = 0;
	int longindex = 0;
	int cmd = 0;
	char update_path[256] = {0};
	int upgrade_mask = 0;
	pthread_t thread_progress;

	void *handle = NULL;
	int (*update_func)(char *, progress_call_back_pointer, int);
	int (*ge_progress_func)(st_update_progress *);
	int (*switch_boot_slot_func)(void);
	int (*cancel_switch_boot_slot_func)(void);
	int (*set_current_slot_success_func)(void);
	int (*rollback_func)(void);
	int (*cancel_update_func)(void);
	int (*get_boot_slot_func)(void);


	while((opt = getopt_long(argc, argv, getopt_str, long_options, &longindex)) != -1)
	{
		switch(opt)
		{
			case 'a':
				memset(update_path, 0, sizeof(update_path));
				snprintf(update_path, sizeof(update_path), "%s", optarg);
				cmd = 'a';
				printf("update_path:%s\n", update_path);
				break;
			case 'b':
				upgrade_mask = strtol(optarg, NULL, 16);
				cmd = 'b';
				printf("upgrade_mask:0x%x\n", upgrade_mask);
				break;
			case 'c':
				cmd = 'c';
				printf("switch_boot_slot.\n");
				break;
			case 'd':
				cmd = 'd';
				printf("cancel_switch_boot_slot.\n");
				break;
			case 'e':
				cmd = 'e';
				printf("set_current_slot_success.\n");
				break;
			case 'f':
				cmd = 'f';
				printf("rollback.\n");
				break;
			case 'g':
				cmd = 'g';
				printf("get_boot_slot.\n");
				break;
			case 'h':
				usage();
				return 0;
			default:
				printf("cmd is error.\n");
				usage();
				return -1;
		}
	}

	handle = dlopen("libabupdate.so", RTLD_LAZY);
	if (handle == NULL)
	{
	    printf("dlerror:%s\n", dlerror());
	    return -1;
	}

	dlerror();

	if(cmd == 'a' || cmd == 'b')
	{
	    if(strlen(update_path) != 0 && upgrade_mask != 0)
	    {
			update_func = dlsym(handle, "ab_update");
			if(update_func == NULL)
			{
			    printf("dlerror:%s\n", dlerror());
			    dlclose(handle);
			    return -1;
			}
			ge_progress_func = dlsym(handle, "ab_get_progress");
			if(ge_progress_func == NULL)
			{
			    printf("dlerror:%s\n", dlerror());
			    dlclose(handle);
			    return -1;
			}

			
			ret = pthread_create(&thread_progress, NULL, thread_get_progress, ge_progress_func);
			ret = update_func(update_path, progress_callback, upgrade_mask);
			if(ret != 0)
			{
				printf("ab_update failed\n");
				dlclose(handle);
				return -1;
			}
			pthread_cancel(thread_progress);
			printf("ab_update success\n");
	    }
	}
	else if(cmd == 'c')
	{
	    switch_boot_slot_func = dlsym(handle, "ab_switch_boot_slot");
		if(switch_boot_slot_func == NULL)
		{
			printf("dlerror:%s\n", dlerror());
			dlclose(handle);
			return -1;
		}
		ret = switch_boot_slot_func();
		if(ret != 0)
		{
			printf("switch_boot_slot failed\n");
			dlclose(handle);
			return -1;
		}
		printf("switch_boot_slot success\n");
	}
	else if(cmd == 'd')
	{
	    cancel_switch_boot_slot_func = dlsym(handle, "ab_cancel_switch_boot_slot");
		if(cancel_switch_boot_slot_func == NULL)
		{
			printf("dlerror:%s\n", dlerror());
			dlclose(handle);
			return -1;
		}
		ret = cancel_switch_boot_slot_func();
		if(ret != 0)
		{
			printf("cancel_switch_boot_slot failed\n");
			dlclose(handle);
			return -1;
		}
		printf("cancel_switch_boot_slot success\n");
	}
	else if(cmd == 'e')
	{
	    set_current_slot_success_func = dlsym(handle, "ab_set_current_slot_success");
		if(set_current_slot_success_func == NULL)
		{
			printf("dlerror:%s\n", dlerror());
			dlclose(handle);
			return -1;
		}
		ret = set_current_slot_success_func();
		if(ret != 0)
		{
			printf("set_current_slot_success failed\n");
			dlclose(handle);
			return -1;
		}
		printf("set_current_slot_success success\n");
	}
	else if(cmd == 'f')
	{
	    rollback_func = dlsym(handle, "ab_rollback");
		if(rollback_func == NULL)
		{
			printf("dlerror:%s\n", dlerror());
			dlclose(handle);
			return -1;
		}
		ret = rollback_func();
		if(ret != 0)
		{
			printf("rollback failed\n");
			dlclose(handle);
			return -1;
		}
		printf("rollback success\n");
	}
	else if(cmd == 'g')
	{
	    get_boot_slot_func = dlsym(handle, "ab_get_boot_slot");
		if(get_boot_slot_func == NULL)
		{
			printf("dlerror:%s\n", dlerror());
			dlclose(handle);
			return -1;
		}
		ret = get_boot_slot_func();
		if(ret != 0)
		{
			printf("get_boot_slot failed\n");
			dlclose(handle);
			return -1;
		}
		printf("get_boot_slot success\n");
	}
	else
	{
		usage();
		return -1;
	}

	return 0;
}



/**
 * ./abupdate_app update.zip mask
 */
#if 0
int main(int argc, char *argv[])
{
	int upgrade_mask = 0;
	int ret = 0;
	if (argc != 3)
	{
		usage();
		return -1;
	}

	upgrade_mask = strtol(argv[2], NULL, 16);
	ret = ab_update(argv[1], progress_callback, upgrade_mask);
	if (ret != 0)
	{
		printf("ab_update failed\n");
		return -1;
	}
	return 0;
}
#endif

### 使用 `dlopen` 函数在 C++ 中加载动态库 #### 创建共享对象 (SO) 文件 为了展示如何使用 `dlopen` 来加载动态库,在 Linux 下创建一个简单的共享对象文件作为例子。 定义接口头文件 `testso.h`: ```cpp #ifndef TEST_SO_H_ #define TEST_SO_H_ class Ia { public: virtual void say_hello() = 0; }; extern "C" Ia* getClass(); #endif // TEST_SO_H_ ``` 实现该接口的具体类 `testso.cpp`: ```cpp #include "testso.h" #include <iostream> class Ca : public Ia { public: void say_hello() override { std::cout << "Hello from dynamic library!" << std::endl; } }; Ia* getClass() { static Ca instance; return &instance; } ``` 编译成共享库: ```bash g++ -fPIC -shared -o libhello.so testso.cpp ``` #### 主程序调用动态链接库 编写主应用程序 `main.cpp` 如下所示,通过 `dlopen`, `dlsym` 和 `dlclose` 进行动态库操作[^1]。 ```cpp #include <dlfcn.h> #include "testso.h" int main(int argc, char **argv) { void *handle; handle = dlopen("./libhello.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } // Reset errors dlerror(); using get_class_t = Ia*(*)(); get_class_t get_class = reinterpret_cast<get_class_t>(dlsym(handle, "getClass")); const char *dlsym_error = dlerror(); if (dlsym_error != nullptr) { fprintf(stderr, "%s\n", dlsym_error); dlclose(handle); exit(EXIT_FAILURE); } Ia *ia = get_class(); ia->say_hello(); dlclose(handle); return 0; } ``` 编译并执行上述代码可以验证是否成功实现了预期功能。此过程展示了怎样利用 C++ 的面向对象特性和 Linux 提供的 API 完成动态模块化编程[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

monkey_llll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值