QQ登录

只需一步,快速开始

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

[ 复制链接 ]
我当前情况是,我第一次使用python,关于PYTHON的一切认识都为零。使用它是因为在网络通过一帖子介绍,使用三行就实现了视觉OCR识别。
经过测试效果杠杠的,所以想搞成DLL供WINDOWS下使用,因为我熟悉MFC。

经过我几天的摸索,是可以实现将PYTHON代搞成DLL或EXE文件的,
并且可以打包成在没有安装PYTHON环境下使用。
开始前自己得准备安装好三个编程软件。
0.VS2019.
40多GB大小,微软自家的工具,随处可下载;

1.pycharm.
python编程,我安装的IDE(编程软件)是pycharm-community-2021.1.1
这个软件到处都可以下载的到,就不贴网址了,小白都喜欢最新版本的,
我也是,所以下载了最新版本的。

2.Anaconda3.
这是个好工具,好比手机上APP商城,python用到的工具,都可以统一用此软件下载安装。
方便至极,比如后面要用到的pyinstaller,virtualenv 都可以直接在这工具上,通过界面操作,
下载与安装。网络能 找到的都是通过指令执行,小白很难理解与操作。
另外python有很多版本如版本2,版本3,各版本差别很大不兼容。
这样的话Anaconda3可以很方便创建任意版本的python环境。
官方下载网速不快,一会10KB,一会100kb的,可以在下边网址下载,网速满格。
Anaconda3各版本下载:
https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/

三个软件我都选择最新版本的下载。
三个软件都下载与安装好后,可以打开Anaconda3,
新建一个python环境,如下图easyocr。

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

python如何打包成动态库DLL与可执行程序EXE脱离环境运行


新建一个新的环境后,可以如上图,选择 ALL,再搜索想要安装的补助工具名称,
点击更新,实现下载与安装。
比如搜索pyinstaller或virtualenv,界面非常简洁很容易入手,自己多看看如何操作。
后面会用到这两工具,如果没安装的话,在pycharm内使用指令会不识别。
界面还是很简单的,第一次使用可多加操作。
主要要理解的是在创建一个python项目工程时,有个python环境要设置。
而Anaconda3就是可以创建任意python环境用。

Anaconda3我安装的目录是D:\ProgramData\Anaconda3,
这是默认的一个python环境。
刚才创建的python环境easyocr及以后创建的环境会生成保存在文件夹envs内。
如 D:\ProgramData\Anaconda3\envs。
以上都准备好后,来看一个如何将编程好的python文件打包成DLL动态库文件供外部调用。

一.python打包成动态库DLL并脱离环境调用。
python调包功能极其强大,印象深刻,但编写的程序想要独立运行。
也就是在其他没有安装PYTHON的电脑运行,操作起来特别麻烦,又是要这个工具,又是要那个文件的。
下面来看一个我摸索成功的过程,供会员与后期自己参考。

0.编写py文件实现程序功能。
pycharm新建一工程,工程使用先前创建的pycharm环境。

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

创建测试py文件run.py。
内容如下,实现两数值相加。
  1. def str_add(str1, str2):
  2.     return int(str1) + int(str2)
复制代码
python的py文件要生成dll动态库,是通过一个工具叫作cython来实现的,
cython网上介绍说,python其一个子集,可编写支持python与C语言代码。
也什么不能在pycharm上统一实现?第一次使用python,所以有点不理解。
这里直接给出上边代码对应的cython代码。
cython的语法我也不熟悉,下边的代码拿去套用也够用。
  1. cdef public str_add(str1,str2):
  2.          return int(str1) + int(str2)
复制代码

可以手动在上面文件run.py同级目录下创建一txt文件,手动复制内容,手动保存为run.pyx文件。
第一次使用pycharm? run.py文件在哪呢?
在pycharm界面,选中run.py文件,鼠标右键,可以看到open in菜单项,内有打开文件所以目录。
准备好上边的两文件后,就可以执行命令代码了cython run.pyx。
前提是cython工具事先要安装成功。
前面我们使用Anaconda3创建了一个python环境exayocr,
用pycharm创建的工程是基于此python环境。

所以先关闭pycharm,打开Anaconda3,选择python环境exayocr,如上边第一图片,搜索cython下载安装。
这里关闭pycharm,是因为其使用的环境有变化,要重启才生效。
重要的事说3遍吧,很多情况都没意识到这点。
pycharm重启生效。
pycharm重启生效。
pycharm重启生效。

第一个次pycharm?那么命令窗口又在哪打开执行呢?
pycharm窗口,最最最左下角,有个小下方形图标,点击可以看到一个terminal,选择就可以打开窗口执行命令。
和cmd相似。
run.py一般默认是在C盘,可以通过上面的方法打开其所在目录。
我测试时将两文件run.pyx,run.py放在C:\Users\baikhgmv\Desktop\222。
这样我在pycharm的命令窗口输入
C: 回车,
cd C:\Users\baikhgmv\Desktop\222 回车。
这样以命令方式打开文件夹C:\Users\baikhgmv\Desktop\222

命令窗口再输入cython run.pyx -3 回车。
表示用python 3版本库生成run.h和run.c两文件,也就是VS2019可以打开的cpp,h类型文件。
可以打开刚才的文件夹C:\Users\baikhgmv\Desktop\222查看

随后这个两个文件可通过调用python的C-API实现了run.py文件相同功能。
如何编写呢?下面是模板代码,
可自己新建一个CPP文件dllmain.c使用,放在run.h和run.c两文件一起。
  1. #include <Python.h>
  2. #include <Windows.h>
  3. #include "run.h"

  4. extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b) {
  5.     return PyLong_AsLong(str_add(PyUnicode_FromString(a),PyUnicode_FromString(b)));<br>
  6. }

  7. BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved) {
  8.     switch( fdwReason ) {
  9.         case DLL_PROCESS_ATTACH:
  10.             Py_Initialize();
  11.             PyInit_run();  #dll初始化的时候调用,这是python3的写法,python2改成,initrun()。参见生成的run.h
  12.             break;
  13.         case DLL_PROCESS_DETACH:
  14.             Py_Finalize();
  15.             break;
  16.     }
  17.     return TRUE;
  18. }
复制代码
上面部分是PYTHON库内函数,部分是C语言上熟悉的代码,主要关注自定义的导出函数_str_add名。

1.生成动态库DLL文件。
那么这个新建的文件dllmain.c如何生成动态库DLL呢?
网上介绍的一种方法是通过命令实现,也就是调用微软自家的程序cl.exe来实现。



先来看这种方法的实现,后面还会介绍如何通过VS2019来直接编译。
按上面一步步操作后,可在PYCHARM的命令操作继续输入
cl /LD dllmain.c run.c -ID:\ProgramData\Anaconda3\envs\easyocr\include D:\ProgramData\Anaconda3\envs\easyocr\libs\python38.lib 回车。
上边命令执行成功的前提是cl.exe路径必须在电脑系统的环境变量中,执行编译时用到的头文件/库路径,也得在环境变量中。
一般电脑系统环境变量都没有配置,所以不会成功,所以得自己手动配置环境变量。
繁琐的很哦。
D:\ProgramData\Anaconda3\envs\easyocr\include D:\ProgramData\Anaconda3\envs\easyocr\libs\python38.lib 首先这两路径应该可以找到吧。
前面用Anaconda3创建的python环境目录下有。
dllmain.c run.c两文件是刚才命令窗口打开的目录下的两文件。

那么如何给程序cl.exe配置系统环境变量呢?
可以参考我操作使用的路径,都选择64位版本的。
  1. PATH追加cl.exe路径
  2. D:\Program Files (x86)\vs2019\Enterprise\VC\Tools\MSVC\14.27.29110\bin\Hostx64\x64

  3. LIB 新添加
  4. C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64
  5. C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64
  6. D:\Program Files (x86)\vs2019\Enterprise\VC\Tools\MSVC\14.27.29110\lib\x64

  7. INCLUDE 新添加
  8. C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt
  9. C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\shared
  10. C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um
  11. D:\Program Files (x86)\vs2019\Enterprise\VC\Tools\MSVC\14.27.29110\include
复制代码

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

python如何打包成动态库DLL与可执行程序EXE脱离环境运行


电脑的系统环境变量如何设置如何添加就不介绍了,到处都是。
可多次执行上边的编译命令,遇到什么lib库文件找不到,什么h头文件找不到。
那就在库或头文件上一级/上上一级等等,查找文件名称,
再将其所在路径配置到系统环境变量,重新执行就好。
操作时一定要注意cl.exe及库文件都有32、64位之分,不要混合了。
操作时一定要注意cl.exe及库文件都有32、64位之分,不要混合了。
操作时一定要注意cl.exe及库文件都有32、64位之分,不要混合了。

命令执行成功会在文件dllmain.c同级目录生成多个文件如dllmain.dll,dllmain.lib等。
这就是我们想要的文件。

上面是通过程序cl.exe,配合命令来编译生成动态库方法。
非常繁琐,过两天什么是python我都不记得了,
鬼记得这玩意是什么,命令又是什么?

那么有没通过界面方式来生成动态库呢?
所以我还尝试了使用VS2019来编译dllmain.c,run.c,run.h三个文件,生成动态库。
打开VS2019,创建动态库工程,只为测试用所以一切保持默认,最终生成工程Dll1。
工程文件夹内的dllmain.cpp对应dllmain.c,
我直接复制dllmain.c内容覆盖dllmain.cpp的,再添加库python38.lib的引用,内容如下
  1. #include <Python.h>
  2. //#include <Windows.h>
  3. #include "pch.h"
  4. #include "run.h"
  5. #pragma comment(lib,"python38.lib")

  6. extern __declspec(dllexport) int __stdcall _str_add(const char* a, const char* b) {
  7.     return PyLong_AsLong(str_add(PyUnicode_FromString(a), PyUnicode_FromString(b)));
  8. }

  9. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
  10.     switch (fdwReason) {
  11.     case DLL_PROCESS_ATTACH:
  12.       //  Py_SetPythonHome(L"D:\\ProgramData\\Anaconda3" );
  13.         Py_Initialize();
  14.         PyInit_run();
  15.         break;
  16.     case DLL_PROCESS_DETACH:
  17.         Py_Finalize();
  18.         break;
  19.     }
  20.     return TRUE;
  21. }
复制代码
再将文件run.h,run.c导入到工程。
其次是python头文件,库文件路径在工程的设置。
看代码中你应该有注意到,有用到Python.h,python38.lib,所以还得设置其路径。
如何设置就不用多说了,极为常见问题,到处都有教程。
路径很多,Anaconda3所建立的每个python环境下的都可以用。
我用的如下,
D:\ProgramData\Anaconda3\envs\easyocr\include
D:\ProgramData\Anaconda3\envs\easyocr\libs

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

python如何打包成动态库DLL与可执行程序EXE脱离环境运行


都准备好后,编译发现还有预编译头文件相关问题。
也就是pch.h这个文件再捣鬼,它的目的主要是提升编译速度。
我就这点东西,不需要它提升,直接选择不用:项目属性--C/C++--预编译头--不使用预编译头。
这一步步操作,我都是选择64位,编译也是64位release版本。
python默认没安装debug版本,所以注意。
一切顺利编译便可生成动态库文件dll.

2.那么生成的动态库那如何使用呢?
动态库的调用就很简单了,熟悉窗口编程的朋友,这都是小问题,
有种回到自家地盘的感觉。
在VS2019创建dos的空工程,刚才生成的动态库文件记得复制过来Dll1.lib,Dll1.dll
新建源文件,复制下面代码测试效果。
  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. extern __declspec(dllexport) int __stdcall _str_add(const char* a, const char* b);
  4. #pragma comment(lib,"Dll1.lib")
  5. int main()
  6. {
  7.         printf("%d \n", _str_add("123", "456"));
  8.         getchar();
  9.         return 0;
  10. }
复制代码
例程一跑,你会发现,又是一堆错误。
想想挺恶心的,一路走来多不容易,到最后还有一堆问题。

python如何打包成动态库DLL与可执行程序EXE脱离环境运行

python如何打包成动态库DLL与可执行程序EXE脱离环境运行


没办法,谁叫你要用它。
其实图片是有提示的 PYTHONHOME = (not set),还有PYTHONPATH。
也就是python的系统环境变量没有设置。
dll是生成了,但它运行还是得依赖python库啊。
平常我们用VS2019等编写的程序可在其他台电脑使用,那是因为微软默认每个系统都给你准备好了运行库。
python是没有的,解决这问题有多种方法,第一如上边屏蔽的代码
// Py_SetPythonHome(L"D:\\ProgramData\\Anaconda3" ); 设置python库所以位置(保证电脑内有安装了python)。
第二种也是通过系统环境变量来指定路径。
第三种就是打包程序用到的python库,放在一起使用。

上边两程序生成的Dll1.dll,Project1.exe复制到D:\\ProgramData\\Anaconda3是可以直接运行的。
这样我们就实现了py文件生成动态库dll,再调用这个库文件,正常执行程序。

但要真正发布程序呢?
这目录下的文件10个GB左右,一同发布是有点恐怖。
所以最后还涉及一个打包问题,减少发布的程序尺寸。
那么如何打包了呢?

3.脱离PYTHON环境,打包发布程序。
这里又要用到另外一个工具pyinstaller再配合工具virtualenv
经过测试全部文件共40MB左右,压缩一下再发布还是能接受的。
这里看到这些工具一个接一个的来,真有点受不了。
真有点跟菇凉谈恋爱,还得先认识她的七大姑八大姨。
好在Anaconda3很方便,如下图,搜索工具名称,下载安装就好。
工具安装了,接下来在python里使用的命令才可以识别。
注意安装工具后记得重启python。


先前我们编写的python文件run.py,已经转换成了dll。
如果想打包成exe发布也是可以的,用到的工具都是上面提到的。
不管是将run.py搞的DLL,或是EXE发布。
run.py,DLL,或EXE二者所依赖的python库文件是都相同的,
所以打包操作一样,打包生成的文件通用。

打开python界面,打开其命令窗口。
命令窗口默认是留在先前选择的目录C:\Users\baikhgmv\Desktop\222。
没有话,按上面介绍的再打开这个目录,因为这目录我们先前放置有run.py文件。
打包要用到。
依次在命令窗口执行如下指令: # 及后面的内容为注释,不是指令;

0.virtualenv envpack 回车  # 创建新的环境,python包依赖比较庞大,创建新环境可以减少最终引入的包。
1.cd envpack 回车 #进入刚创建的文件夹,即C:\Users\baikhgmv\Desktop\222\envpack ;
2. #手动将run.py复制进去。
3.Scripts\activate # 激活并切换到virtualenv环境。
4.pyinstaller run.py # 执行打包命令,或pyinstaller -F run.py;
5.Scripts\deactivate # 打包成功后,使用命令取消激活环境;
可以再次进入C:\Users\baikhgmv\Desktop\222\envpack。
里面所生成的全部文件就为你程序所依赖的,自己整理使用。

二.python生成exe,打包发布。
方法如上所述,一样。
帖子涉及的dll工程附件。
请点击此处下载

查看状态:需购买或无权限

您的用户组是:游客

文件名称:python如何打包成动态库DLL与可执行程序EXE脱离环境运行.rar 
文件大小:24.44 KB 
下载权限: 捐助会员 以上或 VIP会员   [购买捐助会员]   [充值积分]   有问题联系我




回复

使用道具 举报

点击查看
快速回复 返回列表 客服中心 搜索