C++使用技巧(十):C++编译生成与调用自定义静态库/动态库

一、引用资料

.c的文件                         C语言源代码文件;

.a的文件                        由目标文件构成的档案库文件;

.C,.cc或.cxx 的文件     C++源代码文件且必须要经过预处理;

.h的文件                         程序所包含的头文件;

.i 的文件                         C源代码文件且不应该对其执行预处理;

.ii的文件                         C++源代码文件且不应该对其执行预处理;

.m的文件                        Objective-C源代码文件;

.mm的文件                     Objective-C++源代码文件;

.o的文件                         编译后的目标文件;

.s的文件                         汇编语言源代码文件;

.S的文件                         经过预编译的汇编语言源代码文件。

cmake编译c++动态库so:https://blog.csdn.net/weixin_39536806/article/details/112519164

cmake另一种动态库生成:https://tashaxing.blog.csdn.net/article/

Windows10参考:https://blog.csdn.net/a7055117a/category_3152877.html
https://blog.csdn.net/a7055117a/c.html

ubuntu:Linux下C++编译生成自定义静态库/动态库

如何将静态库打包成动态库?请使用ar命令

ar -x libauthoal.a
gcc -shared *.o -o test.so

将静态库制作成动态库

GCC编译步骤及静态库动态库制作

编译动态库:GCC编译器,静态库,动态库
动态库又称为共享库或者动态链接库,现代程序中大量地使用动态链接库。例如,Windows 环境中的dll文件和Linux环境下的 so文件。动态库是在程序启动时被装载的。当一个程序装载了一个动态库后,其他应用程序仍然可以装载同一个动态库。

Makefile链接静态库.a编译成动态库.so

调用静态库生成动态库并使用

多个静态库连接成一个动态库例子

使用 dlopen() 调用动态库SO
https://www.ibm.com/docs/en/zos/2.1.0?topic=functions-dlopen-gain-access-dynamic-link-library

采用dlopen、dlsym、dlclose加载动态链接库【总结】
https://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html

二、如何制作插件dlopen?

动态库,如/usr/lib/system/libsystem_c.dylib,通常在程序运行之前加载。MacOS 的execve系统调用知道如何从 Mach-O 文件中提取对动态库的引用,并在继续之前将它们加载到内存中。但是动态库也可以在运行时显式加载。为了显式加载动态库,我们使用dlfcn.h(“动态加载函数”?)API。这就是“插件”的工作方式:插件是一个动态库!

提供的三个函数dlfcn.h是dlopen、dlclose和dlsym。该dlopen函数将动态库从文件加载到内存中。从内存中dlclose卸载它。在这两者之间,我们使用dlsym提取库中符号的引用。这些符号使我们可以访问库中的函数和其他内容。

这是一个例子。我们有main.c我们的主程序和plugin.c我们的插件。主程序希望插件定义plugin_func,这是一个不带参数并返回int. 主程序加载插件,调用该函数,然后退出。

// main.c
#include <dlfcn.h>
#include <stdio.h>
typedef int plugin_func();
int main() {
  void* handle = dlopen("plugin.so", RTLD_LAZY);
  if (handle == NULL) {
    fprintf(stderr, "Could not open plugin: %s\n", dlerror());
    return 1;
  }
  plugin_func* f = dlsym(handle, "plugin_func");
  if (f == NULL) {
    fprintf(stderr, "Could not find plugin_func: %s\n", dlerror());
    return 1;
  }
  printf("Calling plugin\n");
  int ret = f();
  printf("Plugin returned %d\n", ret);
  if (dlclose(handle) != 0) {
    fprintf(stderr, "Could not close plugin: %s\n", dlerror());
    return 1;
  }
  return 0;
}
// plugin.c
#include <stdio.h>
int plugin_func(void) {
  printf("Hello from the plugin!\n");
  return 42;
}

我们用 编译插件-shared,并将编译后的对象放在plugin.so(“共享库”)。

$ clang -shared -o plugin.so plugin.c
$ clang main.c
$ ./a.out

Calling plugin
Hello from the plugin!
Plugin returned 42

三、dlopen()函数详解动态库

参考:
https://blog.csdn.net/zhengqijun_/article/details/72540878
https://developpaper.com/loading-dynamic-libraries-using-dlopen/

通过一个例子来讲解dlopen系列函数的使用和操作。
主程序:

#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
 
//申明结构体
typedef struct __test {
    int i;
    void (* echo_fun)(struct __test *p);
}Test;
 
//供动态库使用的注册函数
void __register(Test *p) {
    p->i = 1;
    p->echo_fun(p);
}
 
int main(void) {
    void *handle = NULL;
    char *myso = "./mylib.so";
 
    if((handle = dlopen(myso, RTLD_NOW)) == NULL) {
        printf("dlopen - %sn", dlerror());
        exit(-1);
    }
 
    return 0;
}

动态库:

#include <stdio.h>
#include <stdlib.h>
 
//申明结构体类型
typedef struct __test {
    int i;
    void (*echo_fun)(struct __test *p);
}Test;
 
//申明注册函数原型
void __register(Test *p);
 
static void __printf(Test *p) {
    printf("i = %dn", p->i);
}
 
//动态库申请一个全局变量空间
//这种 ".成员"的赋值方式为c99标准
static Test config = {
    .i = 0,
    .echo_fun = __printf,
};
 
//加载动态库的自动初始化函数
void _init(void) {
    printf("initn");
    //调用主程序的注册函数
    __register(&config);
}

主程序编译:gcc test.c -ldl -rdynamic
动态库编译:gcc -shared -fPIC -nostartfiles -o mylib.so mylib.c

其他代码参考:c++较好的案例

https://github.com/xbanks/dynamic-loading-example可以在运行时从中导入函数的示例库:

//文件:greetings.cpp 
#include  
< iostream > extern

 "  C " { void
     say_hello  ( ) {
        std::cout << " Hello world? \n " ; 
    } void say_good_evening () {
        std::cout << " konbanwa! \n " ; 
    }
}

从上面的代码中得到的要点是extern "C"包装我们想要公开的函数。这是因为我们稍后将使用的工具需要 C 命名约定,并且由于 c++ 使用它的名称修饰做了一些有趣的事情,所以我们需要使用 C 命名约定导出这些函数。

这样做的一个副作用是我们不能在我们的extern块中重载函数,因为导出的符号名称将是相同的,因此会发生冲突。

较好的资料:
采用dlopen、dlsym、dlclose加载动态链接库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

源代码杀手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值