使用PyInstaller打包自己写好的代码

零、需求

最近接到一个小单,需要批量修改文档内容,用Python做好后要打包成exe程序给客户的Win7电脑使用,此时需要用到PyInstaller打包自己的代码,想到还要有给用户试用的需求,所以还要加密打包。这里介绍一下如何打包并“加密”自己的Python程序。

壹、使用PyInstaller打包程序

建议:用Python开发程序时使用虚拟环境,打包也在虚拟环境中打包,这样减少项目之间的耦合性,方便管理。

一、安装PyInstaller

安装之前建议把pip的源改为国内的,这样安装速度快很多,具体怎样更改这边不再赘述,安装pyinstaller命令如下(目前是2023年10月,我安装的是PyInstaller 6.0的版本):

pip install pyinstaller

安装过程如下:

(venv) PS D:\project\modify_docx_xlsx_left_header> pip install pyinstallerLooking in indexes: http://mirrors.aliyun.com/pypi/simple/Collecting pyinstallerDownloading http://mirrors.aliyun.com/pypi/packages/a5/85/ddb59556f67ff274dd08201f0644a1715f245abc2d8b2faab7bd4e71b82d/pyinstaller-6.0.0-py3-none-win_amd64.whl (1.3 MB) ---------------------------------------- 1.3/1.3 MB 1.1 MB/s eta 0:00:00Collecting pywin32-ctypes>=0.2.1Downloading http://mirrors.aliyun.com/pypi/packages/a4/bc/78b2c00cc64c31dbb3be42a0e8600bcebc123ad338c3b714754d668c7c2d/pywin32_ctypes-0.2.2-py3-none-any.whl (30 kB)Collecting importlib-metadata>=4.6Downloading http://mirrors.aliyun.com/pypi/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl (22 kB)Collecting pyinstaller-hooks-contrib>=2021.4Downloading http://mirrors.aliyun.com/pypi/packages/66/6b/d1e3b2c8d306694d2d95c4886aa3057c6ca680a759700ae924de84c488bc/pyinstaller_hooks_contrib-2023.9-py2.py3-none-any.whl (284 kB) ---------------------------------------- 284.9/284.9 kB 2.9 MB/s eta 0:00:00Collecting pefile>=2022.5.30Downloading http://mirrors.aliyun.com/pypi/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl (71 kB) ---------------------------------------- 71.8/71.8 kB 232.3 kB/s eta 0:00:00Collecting altgraphDownloading http://mirrors.aliyun.com/pypi/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl (21 kB)Requirement already satisfied: setuptools>=42.0.0 in d:\project\modify_docx_xlsx_left_header\venv\lib\site-packages (from pyinstaller) (65.5.1)Collecting packaging>=20.0Downloading http://mirrors.aliyun.com/pypi/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl (53 kB) ---------------------------------------- 53.0/53.0 kB 2.9 MB/s eta 0:00:00Collecting zipp>=0.5Downloading http://mirrors.aliyun.com/pypi/packages/d9/66/48866fc6b158c81cc2bfecc04c480f105c6040e8b077bc54c634b4a67926/zipp-3.17.0-py3-none-any.whl (7.4 kB)Installing collected packages: altgraph, zipp, pywin32-ctypes, pyinstaller-hooks-contrib, pefile, packaging, importlib-metadata, pyinstallerSuccessfully installed altgraph-0.17.4 importlib-metadata-6.8.0 packaging-23.2 pefile-2023.2.7 pyinstaller-6.0.0 pyinstaller-hooks-contrib-2023.9 pywin32-ctypes-0.2.2 zipp-3.17.0WARNING: There was an error checking the latest version of pip.(venv) PS D:\project\modify_docx_xlsx_left_header>

出现Successfully installed pyinstaller即安装成功。安装成功后建议把命令行程序关掉,然后重新打开,重新载入一下环境。

若是成功安装PyInstaller,在命令行程序中执行pyinstaller命令即可看到PyInstaller的帮助信息:

(venv) PS D:\project\modify_docx_xlsx_left_header> pyinstallerusage: pyinstaller [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME] [--contents-directory CONTENTS_DIRECTORY] [--add-data SOURCE:DEST] [--add-binary SOURCE:DEST] [-p DIR] [--hidden-import MODULENAME] [--collect-submodules MODULENAME] [--collect-data MODULENAME] [--collect-binaries MODULENAME] [--collect-all MODULENAME] [--copy-metadata PACKAGENAME] [--recursive-copy-metadata PACKAGENAME] [--additional-hooks-dir HOOKSPATH] [--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES] [--splash IMAGE_FILE] [-d {all,imports,bootloader,noarchive}] [--python-option PYTHON_OPTION] [-s] [--noupx] [--upx-exclude FILE] [-c] [-w] [--hide-console {hide-late,minimize-early,minimize-late,hide-early}] [-i <FILE.ico or FILE.exe,ID or FILE.icns or Image or "NONE">] [--disable-windowed-traceback] [--version-file FILE] [-m <FILE or XML>] [-r RESOURCE] [--uac-admin] [--uac-uiaccess] [--argv-emulation] [--osx-bundle-identifier BUNDLE_IDENTIFIER] [--target-architecture ARCH] [--codesign-identity IDENTITY] [--osx-entitlements-file FILENAME] [--runtime-tmpdir PATH] [--bootloader-ignore-signals] [--distpath DIR] [--workpath WORKPATH] [-y] [--upx-dir UPX_DIR] [--clean] [--log-level LEVEL] scriptname [scriptname ...]pyinstaller: error: the following arguments are required: scriptname(venv) PS D:\project\modify_docx_xlsx_left_header>

二、PyInstaller参数

主要参数如下:

参数说明
–distpath 目录应用程序包的存放位置(默认值:./dist)
–workpath 工作路径所有临时文件(.log和.pyz等)的存放位置(默认值:./build)
-D, –onedir创建一个包含可执行文件的单文件夹捆绑包,也就是打包成多个文件,适合以框架的形式编写工具代码,代码易于维护。(默认)
-F, –onefile打包成一个可执行文件,所有代码打包进一个文件中,方便分发使用。
-n 名字, –name 名字程序包和配置文件的名称(默认值:第一个脚本的名称,不含后缀)
–contents-directory 内容目录仅对于onedir构建(多文件打包)有效,指定所有支持文件(即除可执行文件本身之外的所有文件,依赖文件)将放置在其中的目录的名称。
–clean在生成之前,清理PyInstaller缓存并删除临时文件。
–add-data SOURCE:DEST包含要添加到应用程序的数据文件的其他数据文件或目录。参数值应采用“source:dest_dir”的形式,其中source是要收集的文件(或目录)的路径,dest_dir是相对于顶级应用程序目录的目标目录,两个路径都用冒号(:)分隔。要将文件放在顶级应用程序目录中,请使用(.)作为dest_dir。此选项可以多次使用。
–add-binary SOURCE:DEST要添加到可执行文件中的其他二进制文件。请参见–add-data格式选项。此选项可以多次使用
-p 目录, –paths 目录搜索导入的路径(比如使用PYTHONPATH)。允许使用多个路径、由分隔或多次使用此选项。相当于在配置文件中提供参数。“:”pathex
–hidden-import 模块名称, –hiddenimport 模块名称在脚本代码中不可见的模块名称导入。此选项可以多次使用。
-w, –windowed, –noconsoleWindows和Mac OS X:不提供标准i/o的控制台窗口。在Mac操作系统上,这也会触发构建MacOS.app捆绑包。在Windows上,如果第一个脚本是“.pyw”文件,则会自动设置此选项。此选项在*NIX系统上被忽略。
-i , –iconico文件:将图标应用于Windows可执行文件。exe文件,编号:从exe中提取对应编号的图标。icns文件:将图标应用于Mac OS上的.app捆绑包。如果输入的图像文件不是平台格式(Windows上为ico,Mac上为icns),PyInstaller会尝试使用Pillow将图标转换为正确的格式(如果安装了Pillow)。使用“NONE”不应用任何图标,从而使操作系统显示一些默认值(默认值:应用PyInstaller的图标)。此选项可以多次使用。

其他相关参数可以参考PyInstaller官网文档:PyInstaller参数说明。我们待会儿打包程序使用到的最多就是上面这些参数。

三、基本程序打包

因为我程序相对来讲比较小,不需要过多的依赖文件,故选择打成单文件包,打包成多文件一样的操作,就把参数-F改为-D即可。
我的程序目录如下:

MODIFY_DOCX_XLSX_LEFT_HEADER│app.py│config.py│gui.py│log.py│run.py│└─imagesicon.ico

其中run.py是入口文件。

使用如下命令将项目中所有代码打包成单文件:

pyinstaller -F run.py

打包过程如下:

(venv) PS D:\project\modify_docx_xlsx_left_header> pyinstaller -F run.py608 INFO: PyInstaller: 6.0.0608 INFO: Python: 3.8.10624 INFO: Platform: Windows-7-6.1.7601-SP1624 INFO: wrote D:\project\modify_docx_xlsx_left_header\run.spec639 INFO: Extending PYTHONPATH with paths['D:\\project\\modify_docx_xlsx_left_header']1154 INFO: checking Analysis1154 INFO: Building Analysis because Analysis-00.toc is non existent1154 INFO: Initializing module dependency graph...1170 INFO: Caching module graph hooks...1185 INFO: Analyzing base_library.zip ...2854 INFO: Loading module hook 'hook-heapq.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...3120 INFO: Loading module hook 'hook-encodings.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...5226 INFO: Loading module hook 'hook-pickle.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...6427 INFO: Caching module dependency graph...6614 INFO: Running Analysis Analysis-00.toc6614 INFO: Looking for Python shared library...6676 INFO: Using Python shared library: C:\Program Files\Python38\python38.dll6676 INFO: Analyzing D:\project\modify_docx_xlsx_left_header\run.py7800 INFO: Loading module hook 'hook-charset_normalizer.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8205 INFO: Loading module hook 'hook-certifi.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8377 INFO: Loading module hook 'hook-docx.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8548 INFO: Loading module hook 'hook-lxml.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...9859 INFO: Loading module hook 'hook-openpyxl.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...10545 INFO: Loading module hook 'hook-xml.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...10561 INFO: Loading module hook 'hook-xml.etree.cElementTree.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...11606 INFO: Processing module hooks...11622 INFO: Loading module hook 'hook-lxml.etree.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...11746 INFO: Loading module hook 'hook-difflib.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...12012 INFO: Loading module hook 'hook-platform.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...12043 INFO: Loading module hook 'hook-sysconfig.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...12542 INFO: Loading module hook 'hook-multiprocessing.util.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...13603 INFO: Loading module hook 'hook-lxml.isoschematron.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...13665 INFO: Loading module hook 'hook-_tkinter.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...13681 INFO: checking Tree13681 INFO: Building Tree because Tree-00.toc is non existent13681 INFO: Building Tree Tree-00.toc13743 INFO: checking Tree13743 INFO: Building Tree because Tree-01.toc is non existent13743 INFO: Building Tree Tree-01.toc13759 INFO: checking Tree13759 INFO: Building Tree because Tree-02.toc is non existent13759 INFO: Building Tree Tree-02.toc13759 INFO: Loading module hook 'hook-lxml.objectify.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...14851 INFO: Looking for ctypes DLLs14851 INFO: Analyzing run-time hooks ...14851 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth__tkinter.py'14866 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py'14866 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py'14866 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py'15007 INFO: Looking for dynamic libraries16738 INFO: Extra DLL search directories (AddDllDirectory): []16738 INFO: Extra DLL search directories (PATH): []18267 INFO: Warnings written to D:\project\modify_docx_xlsx_left_header\build\run\warn-run.txt18408 INFO: Graph cross-reference written to D:\project\modify_docx_xlsx_left_header\build\run\xref-run.html18470 INFO: checking PYZ18470 INFO: Building PYZ because PYZ-00.toc is non existent18470 INFO: Building PYZ (ZlibArchive) D:\project\modify_docx_xlsx_left_header\build\run\PYZ-00.pyz19827 INFO: Building PYZ (ZlibArchive) D:\project\modify_docx_xlsx_left_header\build\run\PYZ-00.pyz completed successfully.20046 INFO: checking PKG20046 INFO: Building PKG because PKG-00.toc is non existent20046 INFO: Building PKG (CArchive) run.pkg26739 INFO: Building PKG (CArchive) run.pkg completed successfully.26770 INFO: Bootloader D:\project\modify_docx_xlsx_left_header\venv\lib\site-packages\PyInstaller\bootloader\Windows-64bit-intel\run.exe26770 INFO: checking EXE26770 INFO: Building EXE because EXE-00.toc is non existent26770 INFO: Building EXE from EXE-00.toc26770 INFO: Copying bootloader EXE to D:\project\modify_docx_xlsx_left_header\dist\run.exe26786 INFO: Copying icon to EXE26801 INFO: Copying 0 resources to EXE26801 INFO: Embedding manifest in EXE26801 INFO: Appending PKG archive to EXE26879 INFO: Fixing EXE headers27379 INFO: Building EXE from EXE-00.toc completed successfully.(venv) PS D:\project\modify_docx_xlsx_left_header>

打包完成后在项目目录下生成了一个配置文件run.spec、一个输出目录dist和一个临时缓存目录build,其中打包好的可执行文件在输出目录dist中,没有特别指定名字,则是根据打包的脚本名命名的,我的为run.exe

四、资源打包

尝试运行run.exe,很遗憾,报错了,在弹出的一闪而过的控制台中可以看出,是图片资源找不到了:

我们需要把资源打包进来。

这需要在刚刚生成的配置文件中修改,或者使用--add-data参数(其实本质也是修改了配置文件),我使用参数的方式添加打包资源,使用如下命令:

pyinstaller -F run.py --add-data 'images/*:images'

根据上面参数的介绍,这个命令的意思是在将以run.py为入口的Python程序打成单个可执行文件的同时把目前相对位置为images文件夹下的所有文件嵌入到在执行时相对位置为images的文件夹中。要是有更多的资源文件夹或文件可以在后面继续添加--add-data参数。

但是这样还不行,还是提示文件找不到,经过了解,我们代码运行时的相对路径是以可执行文件位置作为起始地址的,而单个的可执行文件在运行前会把相关内容解压到电脑的缓存目录中,这样的话资源文件的位置就跟可执行文件位置不一样,从而找不到资源文件。还好,PyInstaller给我们提供了一个环境变量(PyInstaller官方文档 – 运行时信息),我们可以通过这个环境变量找到资源文件的位置,代码如下:

def get_res(file_path):import osimport sysif hasattr(sys, '_MEIPASS'):return os.path.join(getattr(sys, '_MEIPASS'), file_path)return file_path

通过这个函数获取到文件位置,然后再使用。

例如:
可以把

with open('res/a.txt', 'r', encoding='utf-8') as f:txt = f.read()

改写成

with open(get_res('res/a.txt'), 'r', encoding='utf-8') as f:txt = f.read()

这样就不会报错了。

注意:打包前需要把上次打包好的程序关掉,否则覆盖不了。

五、关闭控制台

发现序运行时会顺带开启一个控制台窗口,但是我的是图形化界面,不需要显示额外的控制台界面来调试。

使用-w参数关掉控制台:

pyinstaller -F run.py -w

合并参数如下:

pyinstaller -F run.py --add-data 'images/*:images' -w

重新打包后没有控制台界面了。

六、修改图标

我对默认的应用程序图标不太满意,我想使用我自己的图标,图标是项目的images文件夹下的icon.ico文件,可以使用-i参数指定可执行文件的图标:

pyinstaller -F run.py -i 'images/icon.ico'

-i后面跟着的是图标的路径,可以使用相对路径,也可以使用绝对路径。

合并参数如下:

pyinstaller -F run.py --add-data 'images/*:images' -w -i 'images/icon.ico'

运行此命令重新生成可执行文件后修改成功:

到这里,基本的打包需求就都满足了。

贰、使用Cython配合加密打包程序

除了正常的打包外,我们还有另外的需求,有些时候我们需要防止用户反编译我们的代码,此时,就需要用到一定的反编译技巧了。原本在PyInstaller 6.0版本之前是有一个加密的选项的,但是这个加密选项是会把密码打包进代码中的(密码必须被可执行程序读取到,否则无法运行代码),有很多分析工具可以直接获取这个密码,所以这个加密就变得毫无用处了,具体看这个:Remove the –key/cipher bytecode encryption. #6999。
PyInstaller不支持加密了,我们得找其他的路子。
我们知道Python被打包时或者为了加快运行速度是会生成一些.pyc文件的,类似于Java的.class文件,.pyc文件可以被轻易的反编译为.py文件:python反编译 – 在线工具。另外我们知道,相对于.pyc文件和.class文件,编译C语言生成的机器码更难被反编译(完全不被反编译几乎做不到),或者说机器码反编译后就是汇编代码或者可读性差的C语言代码,目前还没有直接把机器码转成Python代码的方法。故我们可以使用这种方式来“加密”我们的代码。
Cython是一个将Cython源代码转换为高效的C或C ++源代码的编译器。然后可以将此源代码编译为Python扩展模块或独立可执行文件。
我们可以利用Cython把我们的代码转成C或C ++后编译,这样大大增加了反编译的难度。

注意:可能不支持Python的魔法函数。

一、Cython 安装

安装命令:

pip install cython

安装过程如下:

(venv) PS D:\project\modify_docx_xlsx_left_header> pip install cythonLooking in indexes: http://mirrors.aliyun.com/pypi/simple/Collecting cythonUsing cached http://mirrors.aliyun.com/pypi/packages/78/4c/b6b9ad587955e2fc0e4ca3bdf5cc6ccd56877c9683a4016cdb0bd4cce7c5/Cython-3.0.3-cp38-cp38-win_amd64.whl (2.8 MB)Installing collected packages: cythonSuccessfully installed cython-3.0.3WARNING: There was an error checking the latest version of pip.(venv) PS D:\project\modify_docx_xlsx_left_header>

出现Successfully installed cython即安装成功。

二、Cython编译配置文件

建议文件名:build_pyd.py,内容如下:

from distutils.core import setupfrom Cython.Build import cythonizesetup(name='一个名字',ext_modules=cythonize(["Python脚本文件.py","Python脚本文件夹/*.py",# ...],language_level=3),)

其中,setup中的name是自己给程序取的名字,名字可以随意,ext_modules中的列表是自己要转成C/C++编译的Python脚本或Python脚本所在的目录,language_level是Python的版本,我用的Python3,故为3。

我的是这样的:
build_pyd.py

from distutils.core import setupfrom Cython.Build import cythonizesetup(name='MoDoXlLeHe',ext_modules=cythonize(['app.py','config.py','gui.py','log.py'],language_level=3),)

写好后转C/C++并编译,执行如下命令:

python build_pyd.py build_ext --inplace

其中build_pyd.py是配置文件文件名。

运行后会发现,生成了一些.c文件,但是会报如下错误:

(venv) PS D:\project\modify_docx_xlsx_left_header> python build_pyd.py build_ext --inplaceCompiling app.py because it changed.Compiling config.py because it changed.Compiling gui.py because it changed.Compiling log.py because it changed.[1/4] Cythonizing app.py[2/4] Cythonizing config.py[3/4] Cythonizing gui.py[4/4] Cythonizing log.pyrunning build_extbuilding 'app' extensionerror: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/(venv) PS D:\project\modify_docx_xlsx_left_header>

需要Microsoft Visual C++14.0或更高版本。

三、安装编译程序 Microsoft Visual C++

1. 下载

可以下载单独的生成工具,也可以下载Visual Studio集成开发环境,只要勾选了C++工具中的MSVCWindowsSDK就可以了,其中已知Win7单独下载生成工具比较困难。

Win10、Win11 下载位置:Microsoft C++ 生成工具
Win7、Win8下载位置:Visual Studio 较旧的下载 – 2019、2017、2015 和以前的版本

2. 安装

下载好后运行,会出来一个这样的界面,重点:勾选上“使用C++的桌面开发”中的“MSVC组件”和“Windows SDK组件”,然后点安装就行(安装位置可以更改)。Visual Studio 2022不支持Windows7系统,Windows7需要使用Visual Studio 2019的版本,也是勾选上“使用C++的桌面开发”中的“MSVC组件”和“Windows SDK组件”。

下载大概需要1.5GB流量,下载后会自己安装,下载安装好后即可把这个界面关掉了。

四、编译Py文件

下载安装好后我们继续尝试编译,在虚拟环境控制台中再次执行之前的命令:

python build_pyd.py build_ext --inplace

执行过程如下:

(venv) PS D:\project\modify_docx_xlsx_left_header> python build_pyd.py build_ext --inplacerunning build_extbuilding 'app' extension"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -ID:\project\modify_docx_xlsx_left_header\venv\include "-IC:\Program Files\Python38\include" "-IC:\Program Files\Python38\Include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt" /Tcapp.c /Fobuild\temp.win-amd64-cpython-38\Release\app.objapp.ccreating D:\project\modify_docx_xlsx_left_header\build\lib.win-amd64-cpython-38"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\link.exe" /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\libs "/LIBPATH:C:\Program Files\Python38\libs" "/LIBPATH:C:\Program Files\Python38" /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" /EXPORT:PyInit_app build\temp.win-amd64-cpython-38\Release\app.obj /OUT:build\lib.win-amd64-cpython-38\app.cp38-win_amd64.pyd /IMPLIB:build\temp.win-amd64-cpython-38\Release\app.cp38-win_amd64.lib正在创建库 build\temp.win-amd64-cpython-38\Release\app.cp38-win_amd64.lib 和对象 build\temp.win-amd64-cpython-38\Release\app.cp38-win_amd64.exp正在生成代码已完成代码的生成building 'config' extension"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -ID:\project\modify_docx_xlsx_left_header\venv\include "-IC:\Program Files\Python38\include" "-IC:\Program Files\Python38\Include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt" /Tcconfig.c /Fobuild\temp.win-amd64-cpython-38\Release\config.objconfig.c"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\link.exe" /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\libs "/LIBPATH:C:\Program Files\Python38\libs" "/LIBPATH:C:\Program Files\Python38" /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" /EXPORT:PyInit_config build\temp.win-amd64-cpython-38\Release\config.obj /OUT:build\lib.win-amd64-cpython-38\config.cp38-win_amd64.pyd /IMPLIB:build\temp.win-amd64-cpython-38\Release\config.cp38-win_amd64.lib正在创建库 build\temp.win-amd64-cpython-38\Release\config.cp38-win_amd64.lib 和对象 build\temp.win-amd64-cpython-38\Release\config.cp38-win_amd64.exp正在生成代码已完成代码的生成building 'gui' extension"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -ID:\project\modify_docx_xlsx_left_header\venv\include "-IC:\Program Files\Python38\include" "-IC:\Program Files\Python38\Include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt" /Tcgui.c /Fobuild\temp.win-amd64-cpython-38\Release\gui.objgui.c"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\link.exe" /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\libs "/LIBPATH:C:\Program Files\Python38\libs" "/LIBPATH:C:\Program Files\Python38" /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" /EXPORT:PyInit_gui build\temp.win-amd64-cpython-38\Release\gui.obj /OUT:build\lib.win-amd64-cpython-38\gui.cp38-win_amd64.pyd /IMPLIB:build\temp.win-amd64-cpython-38\Release\gui.cp38-win_amd64.lib正在创建库 build\temp.win-amd64-cpython-38\Release\gui.cp38-win_amd64.lib 和对象 build\temp.win-amd64-cpython-38\Release\gui.cp38-win_amd64.exp正在生成代码已完成代码的生成building 'log' extension"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -ID:\project\modify_docx_xlsx_left_header\venv\include "-IC:\Program Files\Python38\include" "-IC:\Program Files\Python38\Include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt" /Tclog.c /Fobuild\temp.win-amd64-cpython-38\Release\log.objlog.c"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\link.exe" /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\libs "/LIBPATH:C:\Program Files\Python38\libs" "/LIBPATH:C:\Program Files\Python38" /LIBPATH:D:\project\modify_docx_xlsx_left_header\venv\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.37.32822\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" /EXPORT:PyInit_log build\temp.win-amd64-cpython-38\Release\log.obj /OUT:build\lib.win-amd64-cpython-38\log.cp38-win_amd64.pyd /IMPLIB:build\temp.win-amd64-cpython-38\Release\log.cp38-win_amd64.lib正在创建库 build\temp.win-amd64-cpython-38\Release\log.cp38-win_amd64.lib 和对象 build\temp.win-amd64-cpython-38\Release\log.cp38-win_amd64.exp正在生成代码已完成代码的生成copying build\lib.win-amd64-cpython-38\app.cp38-win_amd64.pyd -> copying build\lib.win-amd64-cpython-38\config.cp38-win_amd64.pyd -> copying build\lib.win-amd64-cpython-38\gui.cp38-win_amd64.pyd -> copying build\lib.win-amd64-cpython-38\log.cp38-win_amd64.pyd -> (venv) PS D:\project\modify_docx_xlsx_left_header> 

然后会发现在原来已有.c文件的基础上再生成了一些.pyd文件,这是Windows的DLL文件,相对来说破解和反编译都比直接用.pyc文件要难一些,可以达到一定的加密效果。这是生成.pyd文件后的目录结构:

D:\PROJECT\MODIFY_DOCX_XLSX_LEFT_HEADER│app.c│app.cp38-win_amd64.pyd│app.py│build_pyd.py│config.c│config.cp38-win_amd64.pyd│config.py│gui.c│gui.cp38-win_amd64.pyd│gui.py│log.c│log.cp38-win_amd64.pyd│log.py│run.py│├─.idea│......省略......│ ├─build│......省略...... │ ├─images│icon.ico│├─logs│......省略......│ ├─venv│......省略......│└─__pycache__ ......省略...... 

这样便是编译好了。

五、打包

我们仍然使用之前的打包命令,PyInstaller会检测.pyd文件并打包进去的:

pyinstaller -F run.py --add-data 'images/*:images' -w -i 'images/icon.ico' --clean

这里需要加上--clean参数,因为我们没有更改代码,它检测不到变化,是直接用缓存文件生成的,我们需要让它重新检测一下。

打包完成后我们运行一下可执行程序,发现报如下错误:
Failed to execute script ‘run’ due to unhandled exception:No module named json’

找不到json模块?
我们把Python源文件编译成了.pyd文件,因为.pyd文件是二进制文件,所以当PyInstaller在查找需要导入的包的时候分析不了.pyd文件,导致PyInstaller不知道.pyd文件里边导入了什么模块。
因此我们需要通过--hidden-import参数告诉PyInstaller我们需要导入哪些模块。

经过分析,发现我的项目中导入了这些模块:jsontkintertkinter.filedialogrequestsdocxopenpyxllogguitkinter.ttkconfig
当然,如果你不知道你的项目导入了哪些模块,那你可以打包一次,然后运行打包好的可执行文件,它会告诉你少什么模块的,然后再添加上这个模块,反复这样,总能够在有限的打包次数中取得成功(记得打包前把报错窗口关掉)!

故打包命令如下:

pyinstaller -F run.py --hidden-import json --hidden-import tkinter --hidden-import tkinter.filedialog --hidden-import requests --hidden-import docx --hidden-import openpyxl --hidden-import log --hidden-import gui --hidden-import tkinter.ttk --hidden-import config

加上之前的参数:

pyinstaller -F run.py --add-data 'images/*:images' -w -i 'images/icon.ico' --clean --hidden-import json --hidden-import tkinter --hidden-import tkinter.filedialog --hidden-import requests --hidden-import docx --hidden-import openpyxl --hidden-import log --hidden-import gui --hidden-import tkinter.ttk --hidden-import config

打包过程如下:

(venv) PS D:\project\modify_docx_xlsx_left_header> pyinstaller -F run.py --add-data 'images/*:images' -w -i 'images/icon.ico' --clean --hidden-import json --hidden-import tkinter --hidden-import tkinter.filedialog --hidden-import requests --hidden-import docx --hidden-import openpyxl --hidden-import log --hidden-import gui --hidden-import tkinter.ttk --hidden-import config467 INFO: PyInstaller: 6.0.0468 INFO: Python: 3.8.10482 INFO: Platform: Windows-7-6.1.7601-SP1484 INFO: wrote D:\project\modify_docx_xlsx_left_header\run.spec485 INFO: Removing temporary files and cleaning cache in C:\Users\y17mm\AppData\Local\pyinstaller500 INFO: Extending PYTHONPATH with paths['D:\\project\\modify_docx_xlsx_left_header']962 INFO: Appending 'datas' from .spec963 INFO: checking Analysis964 INFO: Building Analysis because Analysis-00.toc is non existent965 INFO: Initializing module dependency graph...966 INFO: Caching module graph hooks...989 INFO: Analyzing base_library.zip ...2909 INFO: Loading module hook 'hook-encodings.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...4803 INFO: Loading module hook 'hook-pickle.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...5709 INFO: Loading module hook 'hook-heapq.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...6157 INFO: Caching module dependency graph...6338 INFO: Running Analysis Analysis-00.toc6339 INFO: Looking for Python shared library...6373 INFO: Using Python shared library: C:\Program Files\Python38\python38.dll6374 INFO: Analyzing D:\project\modify_docx_xlsx_left_header\run.py6381 INFO: Analyzing hidden import 'json'6408 INFO: Analyzing hidden import 'tkinter'6583 INFO: Analyzing hidden import 'tkinter.filedialog'6640 INFO: Analyzing hidden import 'requests'7515 INFO: Loading module hook 'hook-charset_normalizer.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8006 INFO: Loading module hook 'hook-certifi.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8155 INFO: Analyzing hidden import 'docx'8157 INFO: Loading module hook 'hook-docx.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...8345 INFO: Loading module hook 'hook-lxml.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...9495 INFO: Analyzing hidden import 'openpyxl'9508 INFO: Loading module hook 'hook-openpyxl.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...10186 INFO: Loading module hook 'hook-xml.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...10201 INFO: Loading module hook 'hook-xml.etree.cElementTree.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...11147 INFO: Analyzing hidden import 'log'11155 INFO: Analyzing hidden import 'gui'11156 INFO: Analyzing hidden import 'tkinter.ttk'11223 INFO: Analyzing hidden import 'config'11232 INFO: Processing module hooks...11240 INFO: Loading module hook 'hook-lxml.etree.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...11428 INFO: Loading module hook 'hook-difflib.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...11690 INFO: Loading module hook 'hook-platform.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...11714 INFO: Loading module hook 'hook-sysconfig.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...12140 INFO: Loading module hook 'hook-multiprocessing.util.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...13182 INFO: Loading module hook 'hook-lxml.isoschematron.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...13261 INFO: Loading module hook 'hook-_tkinter.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks'...13263 INFO: checking Tree13266 INFO: Building Tree because Tree-00.toc is non existent13267 INFO: Building Tree Tree-00.toc13323 INFO: checking Tree13337 INFO: Building Tree because Tree-01.toc is non existent13338 INFO: Building Tree Tree-01.toc13347 INFO: checking Tree13351 INFO: Building Tree because Tree-02.toc is non existent13353 INFO: Building Tree Tree-02.toc13355 INFO: Loading module hook 'hook-lxml.objectify.py' from 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...14089 INFO: Looking for ctypes DLLs14094 INFO: Analyzing run-time hooks ...14104 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py'14108 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py'14111 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py'14119 INFO: Including run-time hook 'D:\\project\\modify_docx_xlsx_left_header\\venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth__tkinter.py'14190 INFO: Looking for dynamic libraries15374 INFO: Extra DLL search directories (AddDllDirectory): []15375 INFO: Extra DLL search directories (PATH): []16683 INFO: Warnings written to D:\project\modify_docx_xlsx_left_header\build\run\warn-run.txt16833 INFO: Graph cross-reference written to D:\project\modify_docx_xlsx_left_header\build\run\xref-run.html16916 INFO: checking PYZ16917 INFO: Building PYZ because PYZ-00.toc is non existent16918 INFO: Building PYZ (ZlibArchive) D:\project\modify_docx_xlsx_left_header\build\run\PYZ-00.pyz18034 INFO: Building PYZ (ZlibArchive) D:\project\modify_docx_xlsx_left_header\build\run\PYZ-00.pyz completed successfully.18131 INFO: checking PKG18131 INFO: Building PKG because PKG-00.toc is non existent18132 INFO: Building PKG (CArchive) run.pkg24699 INFO: Building PKG (CArchive) run.pkg completed successfully.24742 INFO: Bootloader D:\project\modify_docx_xlsx_left_header\venv\lib\site-packages\PyInstaller\bootloader\Windows-64bit-intel\runw.exe24743 INFO: checking EXE24748 INFO: Building EXE because EXE-00.toc is non existent24749 INFO: Building EXE from EXE-00.toc24755 INFO: Copying bootloader EXE to D:\project\modify_docx_xlsx_left_header\dist\run.exe24765 INFO: Copying icon to EXE24771 INFO: Copying 0 resources to EXE24771 INFO: Embedding manifest in EXE24777 INFO: Appending PKG archive to EXE24795 INFO: Fixing EXE headers25093 INFO: Building EXE from EXE-00.toc completed successfully.(venv) PS D:\project\modify_docx_xlsx_left_header>

打包后同样的生成了一个可执行文件,并且能正常运行,经过测试,功能正常。

这样,我们就把我们的项目打包成了一个比较难被反编译的包,可以发给客户使用了(发之前要严格测试哦)~

叁、总结

上面我介绍了如何使用PyInstaller打包自己的Python项目发给别人用,有两种打包方式,一种是常规的方式,很容易被反编译,另外一种是使用Cython的方式,反编译难度较高,我们在打包自己项目时可以选择合适的方式打包。另外本文中全都是用参数的形式对PyInstaller提需求的,除此之外还可以通过修改配置文件(生成的.spec文件),然后使用pyinstaller 配置文件名的方式来打包自己的代码,两种方式各有好处,选择自己喜欢的方式即可。另外本文中难免存在疏漏,若有问题,可以评论。

肆、参考资料

  1. 【python第三方库】pyinstaller使用教程及spec资源文件介绍
  2. pyinstaller打包python应用之方法(含打包图片资源)
  3. python 将资源文件打包进exe
  4. 谈谈 Pyinstaller 的编译和反编译,如何保护你的代码
  5. VS2015安装包-下载
  6. pip错误“Microsoft Visual C++ 14.0 is required.”解决办法
  7. Remove the –key/cipher bytecode encryption. #6999
  8. Visual Studio 较旧的下载 – 2019、2017、2015 和以前的版本
  9. Cython+Pyinstaller Python编译与打包-踩坑
  10. Oxyry Python Obfuscator
  11. python反编译 – 在线工具
  12. PyInstaller 官方文档
  13. pyinstaller系列之五:使用 –add-data 打包额外资源。
  14. python高性能编程之Cython篇 第一章
  15. python .pyc .pyd .pyo文件的区别
  16. python编译后的pyd爆破
  17. 通过pyinstaller打包编译好的pyd文件到exe