nuitka打包python程序
python打包的诟病一直是运行速度和反编译,而Nuitka直接将python编译成C++代码 ,再编译C++代码产生可执行文件,完全不存在反向解析的问题,非常安全,而且由于可执行文件由C++编译而来,运行速度也会获得提升
nuitka安装
直接使用pip install nuitka命令进行安装 安装完成后会在python根目录中的Scripts中放置一个nuitka.bat用于运行打包命令
显示版本及帮助信息
--version:显示nuitka及依赖软件的版本信息 -h/--help:显示帮助信息
nuitka依赖
nuitka默认使用depends来分析程序的依赖关系,gcc来编译,ccache来编译提速
为了保障编译的成功进行,nuitka不会信任我们已经安装的软件
当我们使用--version等命令时,会自动在"~\AppData\Local\Nuitka\Nuitka\Cache\downloads"目录中下载所需软件
但是由于一些不可名状的网络因素,下载可能会非常缓慢甚至失败,所以需要一些科技手段
编译时信息显示
--quiet:禁用所有信息输出,但显示警告 --show-scons:显示已执行的命令 --show-progress:显示进度提供进度信息和统计信息 --show-memory:显示内存提供内存信息和统计信息 --show-modules:显示模块提供所包含模块的最终摘要 --verbose:详细输出所采取行动的详细信息
编译设置
--module :将包/模块编译为供其他程序引入的pyd文件(扩展模块)而非可运行程序 打包pyd的时候不能指定入口文件,所以没有import可以follow,必须借助--include参数进行指定 打包完之后的文件名称不能修改,如num.py打包完之后变成num.cp39-win_amd64.pyd 不能使用--standalone启用独立模式 --standalone :启用独立模式 将整个运行时所需所有环境编译 可以随意传递软件给其他电脑而无需特定的运行环境 但也意味着编译后的程序变大 默认包含参数“--follow imports”和“--python flag=no_site” --onefile :生成单文件,必须配合--standalone参数使用 --onefile-tempdir-spec=path:单文件程序运行时的程序解压目录 默认为"{TEMP}\onefile_{PID}_{TIME}" 在指定路径时有一些特殊值可以使用以下替代 {TEMP} 用户临时文件目录,C:\Users\…\AppData\Locals\Temp {PID} 进程ID {TIME} 当前时间戳 {PROGRAM} 包含完整路径的可执行文件名(含文件名后缀) {PROGRAM_BASE} 包含完整路径的可执行文件名(不含文件名后缀) {CACHE_DIR} 或 {CACHE_} 用户的缓存目录,C:\Users\…\AppData\Locals {COMPANY} 公司名称,为--company-name参数的值 {PRODUCT} 产品名称,为--product-name参数的值 {VERSION} 版本,为--file-version 和 --product-version 的组合,如3.0.0.0-1.0.0.0 {HOME} 用户的家目录 --onefile-no-compression :在编译单文件程序时禁用压缩,程序体积会变大,主要用于在调试时用于加快编译 --onefile-as-archive :在编译单文件程序时的存档格式 默认使用程序本身来解压缩单文件程序 使用次选项会使用nuitka-onefile-unpack来解压缩单文件程序 --python-flag=FLAG:指定python运行的模式,常用值"no_site",即不加载site模块运行python --main=file :指定要编译的文件名 如果指定一次,它将取代位置参数,即要编译的文件名 当多次给定时,它会启用“multi-st” --prefer-source-code:重新编译拓展模块 当编译一个包或模块时,如果其中既有源文件又有编译好的pyd文件(扩展模块) 重新编译拓展模块会生成更加适合当前电脑环境的程序从而获得更高的性能 --no-prefer-source-code :不重新编译拓展模块,默认值 --include-data-files=localpath/file=softpath/file : 打包指定的文件到程序中 格式1 --include-data-files=localpath/diy.txt=softpath/softdiy.txt 打包本地的diy.txt文件到程序中,程序中使用路径"softpath/softdiy.txt"来获取文件 格式2 --include-data-files=localpath/*.txt=softpath/ 打包本地目录中的所有txt文件到程序中,程序中使用"softpath/come.txt"来获取文件 格式3 --include-data-files=localpath=folder_name=**/*.txt' 将整个目录中所有文件打包,程序中保留原目录结构 --noinclude-data-files=pattern :不打包的文件名 --noinclude-data-files=localpath/*test* 表示不打包文件名中含test的文件 --noinclude-data-files=localpath 表示整个目录都不打包 --include-data-dir=localpath=softpath :打包指定目录中的所有非代码文件 --run :在编译完成后立即执行编译的二进制文件 --user-package-configuration-file=file :指定编译的配置Yaml文件 --output-filename=FILENAME:指定生成可执行文件的文件名,在使用--module参数(生成pyd)的时候无法指定 --output-dir=DIRECTORY:指定编译中间产物及打包好的文件存放的目录,默认为当前目录 --remove-output :编译完成后会自动删除编译中间产物的build目录 --no-pyi-file:不生成pyi文件。pyi文件主要用于生成pyd文件时进行隐式import的检测 --low-memory :通过优化尽量减少程序运行时使用的内存 --warn-implicit-exceptions:为编译时检测到的隐式异常启用警告 --warn-unusual-code:为编译时检测到的异常代码启用警告 --clang:强制使用C语言进行编译, 需要电脑中有一个可用的Visual Studio来支持 --mingw64和--msvc :指定编译器,只能二选一,如果不是两种编译器都存在的情况,不需要设置这个参数,默认会调用系统中能用的编译器 --jobs=N :指定允许的并行C编译器作业数。默认为系统CPU计数 --disable-cache=name :禁用编译时的缓存 可选值"all","ccache","bytecode","compression","dll-dependencies" 可以多次使用次选项或使用逗号分割以指定多个值 如果仅仅禁用一个,name可以使用简化命令 --disable-bytecode-cache --disable-ccache --disable-dll-dependency-cache --force-dll-dependency-cache-update :强制更新dll-dependency缓存 --clean-cache=name :在编译之前清理指定的缓存 --pgo :使用C的PGO优化以提升性能,暂不能在独立模式中使用 --pgo-args=PGO_ARGS :指定使用PGO时使用的参数 --disable-console :隐藏控制台窗口 --enable-console :显示控制台窗口 --force-stdout-spec :重定向控制台的标准输出,用于隐藏控制台时的日志记录 --force-stderr-spec :重定向控制台的错误输出,用于隐藏控制台时的日志记录 --windows-icon-from-ico=ICON_PATH:从.ico文件指定软件图标 --windows-icon-from-exe=EXE_PATH:从.exe文件指定软件图标 --onefile-windows-splash-screen-image=image :指定在单文件或windows中的程序加载时的显示图片 --windows-uac-admin:编译的程序默认使用管理员运行 --windows-uac-uiaccess:请求Windows用户控制,强制运行远程桌面访问 --company-name=COMPANY_NAME:公司名称 --product-name=PRODUCT_NAME:产品名称 --file-version=:文件版本,最多可以用点连接4个数字 --file-description=FILE_DESCRIPTION:软件说明文本 --copyright=TEXT :版权信息 --trademarks=TRADEMARK_TEXT :版本信息中使用的商标 --product-version=FILE_VERSION:产品版本,最多可以用点连接4个数字
模块打包设置
编译时会根据py文件中的import语句找到所有引用的库,然后将这些库文件打包进二进制文件中
为了尽可能减小编译后的体积,会仅仅打包引入的包中使用到的功能
--follow-imports:打包所有import引入的模块,默认关闭 --follow-import-to=MODULE/PACKAGE:仅打包指定的模块 --nofollow-imports:不打包任何模块,会覆盖其他递归选项 --nofollow-import-to=MODULE/PACKAGE:不打包指定模块,会覆盖其他递归选项 --follow-stdlib:打包标准库中的包,默认不打包,开启将会大大加长编译的时间
如果某些模块没有被打包,程序会试图通过pythonXX.dll去搜索路径中查找这些库,然后进行调用,调用方式跟py文件一样
nuitka打包模块或包相对来说是比较耗费时间的,特别是像pandas这类
所以在开发测试时,可以暂时不对这些库进行打包,而是将这些库手动拷贝到搜索路径中(如exe同级目录)
模块预打包
将指定的模块或包打包进exe,用于程序后期可能的调用,如:
mod_name = input("请输入需要的模块名:") mod = __import__(mod_name) 如果在程序运行中可能会输入request,那么就需要提前把该模块打包 --include-package=package :打包指定的模块 会将指定的包所有功能完整的进行打包编译 但大多数时候我们仅仅是使用了包中的某些功能 我们没有使用的功能也打包会加大编译后的程序体积 为了避免不需要的子包,可以使用--nofollow-import-to指定 如:--nofollow-import-to=*test*.py --include-module=MODULE:打包指定的包 --include-plugin-directory=MODULE/PACKAGE:指定一个目录,打包里面包含的所有包和模块(覆盖其他递归选项) --include-plugin-files=PATTERN:与pattern匹配的所有文件都会被打包(覆盖其他递归选项)
开启三方库支持
--enable-plugin=PLUGIN_NAME:开启对某些第三方库或者python功能的支持,可以多次使用该参数以启用多个插件 --disable-plugin=PLUGIN_NAME:禁止对某些第三方库或者python功能的支持 --plugin-no-detection:禁用插件自动检测功能 编译时会自动检测需要启用的第三方库或功能,没有设置会警告 当确定了要启用的插件并通过--enable-plugin指定后可以禁用自动检测功能以提高编译速度 --disable-plugin=plugin-that-warned :禁用自动检测插件时的警告信息 --plugin-list:显示所有可用的插件列表 --user-plugin=PATH:指定用户插件的文件名
nuitka编译参数写入python文件
nuitka的编译参数这么多,如果每次编译都写一遍很不方便,nuitka还支持一种更为简单的方式来指定编译参数
就是在要编译的python文件中使用注释的方式,例如我们有一个名为demo.py的文件,内容如下
# -*- coding: utf-8 -*- #nuitka-project: --onefile #nuitka-project: --standalone #nuitka-project: --onefile-tempdir-spec="D:\code\python\click\tmp" #nuitka-project: --windows-icon-from-ico=logo.ico #nuitka-project: --windows-file-description="软件说明文本文字软件说明文本文字软件说明文本文字" #nuitka-project: --windows-file-version=1.1.1.1 #nuitka-project: --windows-product-version=2.2.2.2 #nuitka-project: --windows-product-name="软件名称软件名称" #nuitka-project: --copyright="版权信息" #nuitka-project: --remove-output #nuitka-project: --disable-console #nuitka-project: --output-filename=soft.exe #nuitka-project: --output-dir=mydest #nuitka-project: --plugin-no-detection #nuitka-project: --enable-plugin=pyside6 #nuitka-project: --enable-plugin=upx import time for i in range(20): print(i+1) time.sleep(0.5)
上面的示例中每行以#nuitka-project:
开头,后面写上编译的参数
这样一行一个将我们用到的编译参数全部写入到python文件中,当我们使用命令nuitka demo.py
来编译时,会自动使用这些编译参数
需要注意的是在指定编译参数的行之上不能存在实际的代码