linux c++动态链接库so编写

时间:2022-08-24 15:48:57

Linux下的动态链接库是.so文件,即:Shared Object,下面是一个简单的例子说明如何写.so以及程序如何动态载入.so中的函数和对象。

testso.h:

#ifndef _TESTSO_H
#define _TESTSO_H
extern "C" {
int myadd(int a, int b);
typedef int myadd_t(int, int); // myadd function type
}
#endif // _TESTSO_H

testso.cpp:

#include "testso.h"

extern "C"
int myadd(int a, int b)
{
return a + b;
}

编译so:

g++  -shared  -fPIC  -o testso.so testso.cpp

注意,-shared参数和-fPIC参数非常重要:
-shared 告诉gcc要生成的是动态链接库;
-fPIC 告诉gcc生成的生成的代码是非位置依赖的,方面的用于动态链接。

在主程序里调用这个动态链接库:
main.cpp:

#include 
#include
// for dynamic library函数

#include "testso.h"

void print_usage(void)
{
printf("Usage: main SO_PATH/n");
}

int main(int argc, char *argv[])
{
if (2 != argc) {
print_usage();
exit(0);
}

const char *soname = argv[1];

void *so_handle = dlopen(soname, RTLD_LAZY); // 载入.so文件
if (!so_handle) {
fprintf(stderr, "Error: load so `%s' failed./n", soname);
exit(-1);
}

dlerror(); // 清空错误信息
myadd_t *fn = (myadd_t*)dlsym(so_handle, "myadd"); // 载入函数
char *err = dlerror();
if (NULL != err) {
fprintf(stderr, "%s/n", err);
exit(-1);
}

printf("myadd 57 + 3 = %d/n", fn(57, 3)); // 调用函数

dlclose(so_handle); // 关闭so句柄
return 0;
}

编译主程序:
g++ main.cpp -o main -ldl

注意:要加上-ldl

好了,上面就是如何写和调用动态库中的C函数。
对于C++中的类,不能直接导出,需要通过继承的方式才能从动态链接库中导出:

=====================

testso.h:

#ifndef _TESTSO_H
#define _TESTSO_H

// 只能通过基类调用,因此需要先定义一个基类,然后在create中生成真正需要生成的对象。
class Base
{
public:
int a, b;

virtual int add(void)
{
return -1;
}
};

class A : public Base
{
public:
int add(void);
};

extern "C" {
Base* create(void);
void destroy(Base *p);

typedef Base* create_t(void); // create factory
typedef void destory_t(Base*); // destory
}

#endif // _TESTSO_H

testso.cpp:

#include "testso.h"

int A::add(void)
{
return a + b;
}

extern "C"
{
Base* create(void) // 注意:create函数必须返回Base的对象,不能直接返回A的
// 对象,否则后面调用A::add()的时候会提示错误。
{
return new A;
}

void destory(Base *p)
{
if (p) delete p;
}
}

main.cpp: // 这里需要注意

#include

#include
#include
#include "testso.h"

void print_usage(void)
{
printf("Usage: myso SO_PATH/n");
}

int main(int argc, char *argv[])
{
if (2 != argc) {
print_usage();
exit(0);
}

const char *soname = argv[1];

void *so_handle = dlopen(soname, RTLD_LAZY);
if (!so_handle) {
fprintf(stderr, "Error: load so `%s' failed./n", soname);
exit(-1);
}

dlerror();
create_t *create = (create_t*) dlsym(so_handle, "create");
if (NULL != err) {
fprintf(stderr, "%s/n", err);
exit(-1);
}
Base *pa = create();

pa->a = 57;
pa->b = 3;
printf("A.add(57, 3)=%d/n", pa->add()); // 注意,这里通过虚函数实现了
// 对A::add()的调用。

destory_t *destory = (destory_t*) dlsym(so_handle, "destory");
if (NULL != err) {
fprintf(stderr, "%s/n", err);
exit(-1);
}
destory(pa);
pa = NULL;

dlclose(so_handle);

printf("DONE!/n");
return 0;
}