使用python创建生成动态链接库dll
如今,随着深度学习的发展,python已经成为深度学习研究的第一语言。大多数深度学习工具包都有python版本,很多重要的算法都有python版本。为了将这些算法应用到具体的项目中,这些工具包还提供了不同类型的接口。
动态链接库(.dll、.so)是系统开发中一种非常重要的跨语言协作方式。将python语言编写的算法编译成动态库,可以被其他语言调用,可以大大提高算法的开发效率。
但是,虽然python可以调用其他语言生成的动态库,但是作为脚本语言,python本身并不能直接编译生成动态库。为了生成动态库,我们使用cython将python脚本转成c语言文件。具体过程通过一个简单的例子来说明。
def str_add(str1,str2):
return int(str1) + int(str2)
此代码将两个数字的字符串转换为数字并将它们相加。我们将此代码保存为 run.py 以进行备份。根据cython语法,我们给出函数的cython版本:
cdef public str_add(str1,str2):
return int(str1) + int(str2)
与之前的python版本相比,cdef替换了def,增加了public关键字,表示这个函数是要导出的。将此代码保存为 pyx 文件,例如 run.pyx。
接下来,我们执行以下命令,将这段代码变成C语言版本:
cython run.pyx
此时目录下会生成两个文件run.h和run.c。这两个文件通过调用python的C-API实现run.py代码的功能。
接下来,我们编写动态库的主文件dllmain.c:
#include <Python.h>
#include <Windows.h>
#include "run.h"
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b) {
return PyLong_AsLong(str_add(PyUnicode_FromString(a),PyUnicode_FromString(b)));<br>
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved) {
switch( fdwReason ) {
case DLL_PROCESS_ATTACH:
Py_Initialize();
PyInit_run(); #dll初始化的时候调用,这是python3的写法,python2改成,initrun()。参见生成的run.h
break;
case DLL_PROCESS_DETACH:
Py_Finalize();
break;
}
return TRUE;
}
该文件定义了导出函数_str_add。在python中,所有数据都存储在pyobject中。该函数通过PyUnicode_FromString将两个字符串转换为python对象类型,调用run.h中的函数str_add进行求和,通过PyLong_AsLong函数将结果从python对象转换为整数。
我们可以通过如下命令,将这个代码编译生成dll:
cl /LD dllmain.c run.c -IC:\python36\include C:\python36\libs\python36.lib
这里python的路径是根据python在不同电脑上的安装位置来调整的。
生成的dll,我们写个简单调用,测试一下:
#include "stdio.h"
#include "stdlib.h"
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b);
#pragma comment(lib,"dllmain.lib")
int main()
{
printf("%d \n", _str_add("123","456"));
return 0;
}
输出结果: 579,正好等于123+456。
通过以上步骤,我们已经能够将python代码实现的功能封装成动态库了。但是,这个动态库不能在没有安装 python 的机器上运行。事实上,python代码通常需要很多依赖才能运行。而且,每段代码所需要的依赖都是不同的。为了找到这些包,我们使用了另一个工具,pyinstaller。具体步骤如下:
(1) virtualenv envpack #新建环境,python包依赖比较复杂,新建环境可以减少最后引入包;
(2)cd envpack # 进入目录;
(3)#将run.py复制到该目录下,run.py运行所需的包与最终dll所需的包相同;
(4)Scripts\activate # 激活并切换到virtualenv环境;
(5)pip install pyinstaller # 安装打包工具pyinstaller;
(6)pip install numpy # 安装numpy等脚本需要的库,查看你的import;
(7)pyinstaller run.py # 打包命令;
(8)Scripts\deactivate # 打包成功后,使用命令取消激活环境;
(9) 需要打包的文件在envpack\dist中,包括很多.dll和.pyd文件,可以和dll一起发布。
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 如何卸载python3.610/24
- ♥ python pprint.pformat()函数的使用11/13
- ♥ 如何在python中转换日期和字符串?09/22
- ♥ 如何使用python的dir()函数11/30
- ♥ 如何在python中格式化纬度和经度10/15
- ♥ 如何使用python算法解决变化问题?10/25
内容反馈