Linux下编译WindowsC++⽣成动态链接库(libxxx.so)
1. 简介
在python、java等语⾔中某些时候需要C做效率上的补充,在实际应⽤中,需要做部分数据的交互。因此就需要使⽤到链接库(动态库和静态库,注:这⾥只介绍动态库)。⽽本⽂主要介绍的是跨平台编译:针对windows系统中的C++程序在linux编译成动态链接库的过程。
2. .so及.dll介绍
2.1 .dll
Windows下动态链接库以 .DLL 事实上和 EXE ⽂件⼀样,同属 PE 格式的执⾏⽂件。对于隐式的引⽤外部符号,需要把外部符号所在的位置写在 PE 头上。PE 加载器将从 PE 头上到依赖的符号表,并加载依赖的其它 DLL ⽂件。
windows 可以存在⼀个dll 对另⼀个 dll 的隐式依赖。windows的这种dll机制在著名教科书《程序员的⾃我修养》⾥仔细分析过。windows 搞的这么⿇烦,其实就是考虑到调⽤dll接⼝时的效率。
2.2 .so
在Linix 下,.so 为共享库,是shared object,⽤于动态连接的(通常还以 lib 开头)。so ⽂件⼤多为 elf 执⾏⽂件格式。当它们需要的外部符号,可以不写明这些符号所在的位置。即通常so ⽂件并不知道它依赖的那些符号在哪些 so ⾥⾯。这些符号是由调⽤ dlopen 进程运⾏时提供的。dlopen 把这些符号通报给 dlopen 加载的 .so ⽂件,最终完成动态链接。
Linix 下⼀般不需要让 so和 so 有隐式依赖关系。效率⽅⾯linux也⽀持另⼀种so机制,编译so时不加 -fPIC 的,可以⽤内存空间换调⽤时间。
2.3 .so和.dll⽐较分析
由于操作系统的不同,他们在许多⽅⾯还是不尽相同,下⾯从以下⼏个⽅⾯进⾏阐述。
(1) 动态库程序编写,在Windows系统下的执⾏⽂件格式是PE格式,动态库需要⼀个DllMain函数作为初始化的⼈⼝,通常在导出函数的声明时需要有 _declspec(dllexport)关键字。Linux下的gcc编译的执⾏⽂件默认是ELF格式,不需要初始化⼊⼝,亦不需要到函数做特别声明,编写⽐较⽅便。
(2)动态库编译,在windows系统下⾯,有⽅便的调试编译环境,通常不⽤⾃⼰去编写makefile⽂件,但在linux下⾯,需要⾃⼰动⼿去编写makefile⽂件。
(3)动态库调⽤⽅⾯,Windows和Linux对其下编制的动态库都可以采⽤显式调⽤或隐式调⽤,但具体的
调⽤⽅式也不尽相同。
(4) 动态库输出函数查看,在Windows中,有许多⼯具和软件可以进⾏查看DLL中所输出的函数,例如命令⾏⽅式的dumpbin以及VC++⼯具中的 DEPENDS程序。在Linux系统中通常采⽤nm来查看输出函数,也可以使⽤ldd查看程序隐式链接的共享对象⽂件。linux下gcc编译的四个步骤
(5)对操作系统的依赖,这两种动态库运⾏依赖于各⾃的操作系统,不能跨平台使⽤。因此,对于实现相同功能的动态库,必须为两种不同的操作系统提供不同的动态库版本。
3. Linux下编译.so
3.1  附加库
由于编译的是Windows上的C++代码,其中使⽤了附加的mysql、opencv及ffmpeg库,因此在Linux上重新编译配置了相应版本的库。将相应编译好的库下⾯lib和include路径记录下来在makefile中使⽤。
3.2  Linux下C/C++及附加库安装配置
1)安装C/C++编译器:
2)C/C++程序编译 与 调试
注:使⽤ ”-tui “ 选项可以将代码显⽰在⽂本⽤户界⾯TUI。可⽤光标操控同时在下⾯的GDB shell中输⼊命令: $ gdb -tui [可执⾏程序名]
3)安装eclipse进⾏C/C++开发
4)安装ffmpeg
5)安装opencv3.3
6)安装mysql
注:python导⼊mysql库:$ sudo yum install MySQL-python
3.3  Makefile⽂件
⽬标+依赖+命令。Makefile ⽂件描述了整个⼯程的编译、Makefile是类unix环境下(⽐如Linux)的类似于批处理的"脚本"⽂件。其基本语法是: ⽬标+依赖+命令。
连接等规则。有⾃⼰的书写格式、关键字、函数。像C 语⾔有⾃⼰的格式、关键字和函数⼀样。
1) 规则:
Makefile⽂件由⼀系列规则(rules)构成。每条规则的形式如下,上⾯第⼀⾏冒号前⾯的部分,叫做"⽬标"(target),冒号后⾯的部分叫做"前置条件"(prerequisites);第⼆⾏必须由⼀个tab键起⾸,后⾯跟着"命令"(commands)。
2)语法:
包括:注释、回声、通配符、模式匹配、变量和赋值符、变量和赋值符、⾃动变量、判断和循环、函数等。
3)⽰例:
3.4  注意的问题
将windows下的C++代码放在linux上编译时除了⼀些头⽂件导⼊路径稍作修改外还有⼀些函数的修改如:
1)windows C++中的sprintf_s()  ->  Linux下的sprintf():
那么⼀举两得的⽅法是既能在Windows的C++中编译也可以在linux上编译的⽅法是:
在C++代码中加⼊定义:
#ifdef _WIN64
#define _CRT_SECURE_NO_WARNINGS
#endif
2. windows C++中的_itoa_s()  -> Linux未定义:
我们可以使⽤sprintf()函数实现该功能:
char buffer[20]
int n = 123456;
sprintf(buffer,"%d",n);
4. 应⽤
4.1 python调⽤.so
当需要采⽤调⽤c++的程序的时候,需要对原有的数据加⼀个extern "C"封装⼀下即可。采⽤g++编译的代码也需要的,原因可能是因为c++编译器编译后的⼆进制so⽂件中,对c++的函数进⾏了重新的命名导致的。
4.2 ctypes库
ctypes使得python能够直接调⽤c语⾔开发的动态链接库,⾮常强⼤。
为了使⽤ctypes,须依次完成以下步骤:
* 编写动态连接库程序
* 载⼊动态连接库
* 将Python的对象转换为ctypes所能识别的参数
* 使⽤ctypes的参数调⽤动态连接库中的函数
1)导⼊.so
import ctypes
so=ctypes.CDLL('/root/VideoCompute/libKeyFrame.so')
<_hashfamily()
2) 数据类型
ctypes 提供了⼀些原始C语⾔兼容的数据类型。第⼀列是在ctypes库中定义的变量类型,第⼆列是C定义的变量类型,第三列是Python在不使⽤ctypes时定义的变量类型。
5. 总结
参考连接:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。