zoukankan      html  css  js  c++  java
  • 手把手教你将Python程序打包为DLL

    手把手教你将Python程序打包为DLL

    Python的数据类型和C的数据类型貌似是有某种“一一对应”的关系的,此外,由于Python(确切的说是CPython)本身是由C语言实现的,故Python数据类型之间的函数运算也必然与C语言有对应关系。那么,有没有可能“自动”的做替换,把Python代码直接变成C代码呢?答案是肯定的,这就是Cython主要解决的问题。
    本教程将介绍如何在Windows下借助Cython将Python代码打包为DLL供C/C++程序调用。

    编译环境

    Python 3 或 Python 2
    Visual Studio
    JetBrains PyCharm
    安装Cython

    Cython是结合了Python和C的语法的一种语言,可以简单的认为就是给Python加上了静态类型后的语法。
    如果已经安装过Cython可以跳过此步。安装Cython需要使用easy_install,Python 2.7.9 以上的版本已经自带easy_install。在Visual Studio的命令提示符下完成(注意配合Python版本使用32位还是64位的Visual Studio的命令提示符,有可能需要以管理员权限运行):

    easy_install -U cython
    1
    使用Cython编译

    在PyCharm中新建工程,然后新建一个py文件:great_module.py,在该文件中输入如下内容:

    def str_add(str1, str2):
      return int(str1) + int(str2)

    1
    2
    3
    这是一个简单的将字符串转换为int求和的函数。为了使该函数能够被Cython编译,需要新建一个run.pyx文件,并加入如下内容:

    cdef public int str_add(const char* str1,const char* str2):
      return int(str1) + int(str2)

    1
    2
    3
    这其中的cdef和public等都是cython关键字,这些关键字可以帮助函数可以被外部调用。然后在PyCharm中使用下面的命令编译,生成run.h和run.c两个文件。

    cython run.pxy
    1
    Cython是支持Python的动态类型特性的,如果后续步骤使用VS的命令行编译也可以生成DLL,但是我在实验时不知为何无法提取到DLL中的函数地址,所以这里统一使用静态类型,所有参数和返回值都使用Cython的静态类型关键字规定好数据类型。

    通过VS编译得到动态链接库

    在得到了.c和.h文件后,我们需要为其创建一个VS DLL工程。打开VS软件,新建win32项目,其中应用程序类型选择DLL,附加选项选择空项目。 将刚刚的.c和.h文件复制到项目存放代码的文件夹并添加到项目中。在项目中添加一个空的dllmain.cpp,并添加如下代码:

    #include <Python.h>
    #include <Windows.h>
    #include "run.h"
    extern "C"
    {
      __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b)
      {
        return str_add(a, b);
      }
    }

    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
    {
      switch (fdwReason)
      {
        case DLL_PROCESS_ATTACH:
          Py_Initialize();
          //dll初始化的时候调用,这是python3的写法,python2改成,initrun()。参见生成的run.h
          PyInit_run();
          break;
        case DLL_PROCESS_DETACH:
          Py_Finalize();
          break;
      }
      return TRUE;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    右键项目,属性,进入VC++目录标签页。在包含路径中添加Python的include路径,如“C:ProgramFilesPython36include”。在库目录中添加Python的lib,如“C:Program FilesPython36libs”。注意编译的版本选择Release,根据Python版本选择x64平台或x32平台。 编译后可以得到dll文件。

    DLL的动态调用

    建立另一个工程对刚生成的dll进行测试。打开VS新建Win32控制台应用程序,并添加如下代码:

    #include "stdafx.h"
    #include <Windows.h>
    #include <iostream>
    using namespace std;
    int main()
    {
      // 调用dll测试
      typedef int(*pAdd)(const char * a, const char * b);
      HINSTANCE hDLL = LoadLibrary(_T("MyDLL.dll"));
      cout << "hDLL:" << hDLL << endl;
      if (hDLL)
      {
        // 获取DLL中需要调用的函数的地址
        pAdd pFun = (pAdd)GetProcAddress(hDLL, "_str_add");
        cout << "pFun:" << pFun << endl;
        const char* stra= "12";
        const char* strb = "22";
        if (pFun)
        {
          int i = pFun(stra, strb);
          cout << "i = " << i << endl;
        }
      }
      system("pause");
      return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    根据dll选择x86或x64平台,进行release编译后可以得到输出结果“i = 34”。

    补充

    在通过Cython得到.h和.c文件后,可以通过vs命令提示符cl命令的方式对其编译。这种方法支持Python的动态数据类型,编译时需要注意x86/x64平台选择和管理员权限的问题。但是我在成功编译后得到的DLL无法被正确调用,目前仍不清楚具体原因。
    在Linux下的编译将更为方便,因为linux原生支持Python并带有C/C++编译器,环境的配置将更为简便

  • 相关阅读:
    第十五篇 -- 学习第十四天打卡20190702
    第三篇 -- 方向
    第十四篇 -- 学习第十三天打卡20190701
    yum更换阿里源
    Jenkins+sonar7.3集成
    xshell 5 书写汉字乱码
    zabbix 短信报警
    zabbix 微信报警
    zabbix邮件报警
    zabbix主动监测客户端设置
  • 原文地址:https://www.cnblogs.com/gdg87813/p/11790550.html
Copyright © 2011-2022 走看看