当前位置: 首页 > news >正文

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加载动态链接库

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 张越:智慧要包括一种向善之心
  • C++使用技巧(十一):函数返回一个数组
  • 张越:每张脸背后都有故事
  • C++使用技巧(十三):Google-GTest测试框架的安装与使用(demo源码实现)
  • C++使用技巧(十四):ubuntu16.04--C++ (Cpp) PCM示例与pcm及音频算法的参考资料
  • 熊节:谁震撼了世界——第14届Jolt奖点评
  • C++使用技巧(十五):类构造函数 与 析构函数
  • 刘江:国外计算机图书月旦评(2004.4)
  • C++使用技巧(十六):智能指针
  • 聚合页面更新
  • C++使用技巧(十七):虚函数
  • C++使用技巧(十八):多肽
  • 关于“滚动的一天”潜在危险
  • C++使用技巧(十九):内存管理
  • 一个类似“作者主页平台”的地方
  • chrome扩展demo1-小时钟
  • Git初体验
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • JavaScript HTML DOM
  • Linux CTF 逆向入门
  • magento 货币换算
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue实战(四)登录/注册页的实现
  • Web设计流程优化:网页效果图设计新思路
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 汉诺塔算法
  • 老板让我十分钟上手nx-admin
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 小程序开发之路(一)
  • 用jQuery怎么做到前后端分离
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 主流的CSS水平和垂直居中技术大全
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​14:00面试,14:06就出来了,问的问题有点变态。。。
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ​香农与信息论三大定律
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (javaweb)Http协议
  • (六)DockerCompose安装与配置
  • (生成器)yield与(迭代器)generator
  • (四)linux文件内容查看
  • (五)关系数据库标准语言SQL
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (转)LINQ之路
  • .Net FrameWork总结
  • .NET面试题(二)
  • ?.的用法
  • @Value获取值和@ConfigurationProperties获取值用法及比较(springboot)
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)