使用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)));
} 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。具体步骤简介如下:
- virtualenv envpack # 创建新的环境,python包依赖比较复杂,创建新环境可以减少最终引入的包
- cd envpack # 进入目录
- #复制run.py到这个目录,run.py运行需要的包,和最终dll需要的包是一样的
- Scripts\activate # 激活并切换到virtualenv环境
- pip install pyinstaller # 安装打包工具pyinstaller
- pip install numpy # 安装numpy等脚本需要的库,查看你的import
- pyinstaller run.py # 打包命令
- Scripts\deactivate # 打包成功后,使用命令取消激活环境
- 需要打包的文件在envpack\dist, 包括很多.dll和.pyd文件,把这些文件和dll一起发布即可。
使用python创建生成动态链接库dll的更多相关文章
- 创建一个动态链接库 (DLL),使用VS2010
在本演练中,您将创建一个动态链接库 (DLL),其中包含可供其他应用程序使用的有用例程.使用 DLL 是一种重用代码的绝佳方式.您不必在自己创建的每个程序中重新实现这些例程,而只需对这些例程编写一次, ...
- MinGW gcc 生成动态链接库 dll 的一些问题汇总 (补充)
我以前写过一个小短文,介绍MinGW gcc 生成动态链接库 dll 的一些问题.当时写的并不全面.近期又遇到写新的问题.这里记录一下,做个补充. 通常情况下,dll 中的函数假设採用 _stdcal ...
- dll = MinGW gcc 生成动态链接库 dll 的一些问题汇总
MinGW gcc 生成动态链接库 dll 的一些问题汇总 https://blog.csdn.net/liyuanbhu/article/details/42612365 网络上关于用 MinGW ...
- MinGW gcc 生成动态链接库 dll 的一些问题汇总(由浅入深,很详细)
网络上关于用 MinGW gcc 生成动态链接库的文章很多.介绍的方法也都略有不同.这次我在一个项目上刚好需要用到,所以就花了点时间将网上介绍的各种方法都实验了一遍.另外,还根据自己的理解试验了些网上 ...
- 动态链接库DLL的创建生成及调用
一.背景 最近在做CANTOUSB底层驱动的调用,是调用别人已经封装好的库,看不到别人写的源程序.程序中调用的是隐式调用即 x.h+x.lib+x.dll,其中DLL即是动态链接库(Dynamic L ...
- vs2010创建和使用动态链接库(dll)
本文将创建一个简单的动态链接库,并编写一个应用台控制程序使用该动态链接库,并提出了与实现相关的几个问题,供初学者交流. 本文包含以下内容: 创建动态链接库项目 向动态链接库添加类 创建引用动态链接库的 ...
- MFC创建动态链接库DLL并调用方法详解
实例一: 1.创建一个动态链接库工程,如login_dll. 2.在原工程头文件或者新建头文件如showdlg.h定义动态链接库的导出函数,代码如下: #include "stdafx.h& ...
- vs2010 C++创建和使用动态链接库(dll)
一.用C++创建动态链接库项目: 1.打开Microsoft Visual Studio 2010,选择File->New->Project. 2.在NewProject中选择Inst ...
- C# 创建和引入动态链接库dll文件
一.创建动态链接库dll文件 新建 -> 项目->类库 名称为:dlltest 添加函数:消息框弹出消息 using System.Collections.Generic; using S ...
随机推荐
- 51nod 1012 最小公倍数LCM
输入2个正整数A,B,求A与B的最小公倍数. 收起 输入 2个数A,B,中间用空格隔开.(1<= A,B <= 10^9) 输出 输出A与B的最小公倍数. 输入样例 30 105 输出 ...
- 20165222 预备作业3 Linux安装及学习
一,安装Linux操作系统 一开始下载ubuntu的时候比较麻烦,然后用同学发给我的,才得以安装.根据教程,也没出现什么问题,只是下载的比较麻烦. 二,关于Linux的学习 1,Linux系统简介和 ...
- loj #6136. 「2017 山东三轮集训 Day4」Left
题目: 题解: 我们可以发现所有的交换器都是一个位置连接着下一层左侧的排序网络,另一个位置连着另一侧的排序网络. 而下一层是由两个更低阶的排序网络构成的. 两个网络互不干扰.所以我们可以通过第一行和最 ...
- tornado日志管理
默认数据格式 默认情况下,采用tornado的web框架运行起来之后,任何访问都会直接在控制台输出日志信息,格式如下: [I 160807 09:27:17 web:1971] 200 GET / ( ...
- yield关键字用法与解析(C# 参考)
yield 关键字向编译器指示它所在的方法是迭代器块. 编译器生成一个类来实现迭代器块中表示的行为. 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值. 这是一个返 ...
- HttpClient超时设置
场景:最近并发较高,看到响应时间6s的时候,心里咯噔一下,我记得我设置的超时时间是5s啊. 原来读取超时时间没生效,只生效了连接超时时间. ConnectionPoolTimeoutExcepti ...
- lbypmall系统备份恢复
打开phpmyadmin 1.数据库创建,在服务器上创建lbypmall数据库,排序规则utf8_general_ci 2.mysqldump -u root -p lbypmall > lby ...
- 参数化防SQL注入
private void AddStudent(){ string strName =txtName.Text.Trim(); string strPwd = txtPwd.Text.Trim(); ...
- 字符串(二)(PHP)
1.大段文本在PHP中应该如果表示? 答: <?php $str = <<<aaa hello word; fjasdflj fjslad aaa;date_sub() aaa ...
- 【转】配置Jmeter的自定义参数
配置Jmeter的自定义参数 User Defined Variables 在这个控件中,定义你所需要的参数,如 在对应的需要使用参数的位置,使用${host}替代. 应用场景: 当测试环境变化时,我 ...