在Python中,可以使用第三方库PyInstaller将Python代码打包成独立的可执行文件(exe、dmg等.安装PyInstaller,可以通过pip安装PyInstaller:
pip install pyinstaller
安装完成后即可开始使用PyInstaller进行打包。
打包流程
- 在终端中进入Python代码所在目录,并执行以下命令:
pyinstaller --onefile filename.py
其中filename.py
是需要打包的Python代码文件名。--onefile
参数表示生成一个独立的可执行文件。
- 等待打包过程完成。完成后,在生成的
dist
目录中会生成一个可执行文件filename.exe
(Windows)或filename
(MacOS、Linux)。 - 将
filename.exe
和其他依赖文件拷贝到其他设备上,即可直接运行该应用程序。
其他常用参数
--name
:指定生成的可执行文件名称。--icon
:指定应用程序图标。--noconsole
:生成无控制台窗口版本的可执行文件。--windowed
:生成包含GUI界面的可执行文件.
例如,如果要生成名为my_app
,带有图标且没有控制台窗口的应用程序,则可以执行以下命令:
复制代码pyinstaller --onefile --name my_app --icon=my_icon.ico --noconsole filename.py
pyinstaller 对于特殊路径处理
当使用PyInstaller将Python应用程序打包成可执行文件时,有时会遇到特殊路径的问题,例如读取配置文件、log等。此时可以使用sys._MEIPASS
变量来解决路径问题。
sys._MEIPASS变量
PyInstaller在打包过程中会额外生成一个临时目录,其中包含了所有需要的依赖文件和Python解释器。当运行可执行文件时,PyInstaller会将这些文件解压缩到临时目录,并将sys.executable
指向解压后的Python解释器。同时,PyInstaller会设置sys._MEIPASS
变量,该变量指向临时目录。
因此,我们可以通过判断sys._MEIPASS
是否存在来处理路径问题,示例代码如下:
import sys
import os
if getattr(sys, 'frozen', False):
# 当前为打包后的exe/dmg文件
root_path = sys._MEIPASS # 临时目录
else:
# 当前为.py源码文件
root_path = os.path.dirname(os.path.abspath(__file__)) # 当前目录
上述代码中,getattr(sys, 'frozen', False)
用于判断当前是否是打包后的可执行文件。如果返回True,说明是打包后的可执行文件,此时可以通过sys._MEIPASS
获取临时目录;否则返回False,说明是.py源码文件,则可以通过__file__
获取当前文件的绝对路径来计算出根目录。
示例
例如,我们有以下代码:
import os
import configparser
config_path = os.path.join(os.getcwd(), 'config.ini')
config = configparser.ConfigParser()
config.read(config_path)
在打包时,如果不使用sys._MEIPASS
变量,则可能会出现找不到配置文件的情况。因此,我们可以将代码改为:
import sys
import os
import configparser
if getattr(sys, 'frozen', False):
# 当前为打包后的exe/dmg文件
root_path = sys._MEIPASS # 临时目录
else:
# 当前为.py源码文件
root_path = os.path.dirname(os.path.abspath(__file__)) # 当前目录
config_path = os.path.join(root_path, 'config.ini')
config = configparser.ConfigParser()
config.read(config_path)
这样,在打包后的可执行文件中,就可以正确读取配置文件了。
注意事项
- 如果应用程序所需文件较多,可能需要手动指定打包时需要打包的文件或目录。
- 使用
sys._MEIPASS
变量需要注意,在某些情况下可能会返回空值。建议在开发和测试环境中进行充分测试,确保在各种情况下程序能够正常运行。
py2app
安装py2app打包工具
安装py2app 需要注意,安装全局环境下还是安装到Vscode创建的项目下。(一般情况下建议py2app安装Vscode开发项目的编译环境下,需要的第三方包环境已经配置好。)
安装命令:
sudo pip install py2app
生成app的配置文件setup.py
在终端窗口执行:(xxx.py是app的启动文件,就像其他程序的main文件一样)
py2applet --make-setup xxx.py
执行完上方命令后:终端会输出一段文字
$xx: Wrote setup.py
配置app的setup.py,初始化的setup.py
"""
This is a setup.py script generated by py2applet
Usage:
python setup.py py2app
"""
from setuptools import setup
APP = ['xxx.py'] #APP启动的py文件
DATA_FILES = [] #自写模块放在DATA_FILES列表中
OPTIONS = {} # 第三方库放在OPTIONS下的includes对应的列表中
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
下方举一个实例:
1.启动文件为xxx.py
2.项目内其他文件:test.py、 test2.py
3.导入第三方库:requests
配置文件如下:
#第一种配置
from setuptools import setup
APP = ['xxx.py'] #APP启动的py文件
DATA_FILES = ['test.py', 'test2.py'] #自写模块放在DATA_FILES列表中
OPTIONS = {'includes' : ['requests']} # 第三方库放在OPTIONS下的includes对应的列表中
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
#第二种配置
from setuptools import setup
APP = ['xxx.py'] #APP启动的py文件
DATA_FILES = [] #自写模块放在DATA_FILES列表中
OPTIONS = {
'includes' : ['requests'], # 第三方库放在OPTIONS下的includes对应的列表中
'iconfile':'Icon.icns', #APP图标
'plist': {'CFBundleShortVersionString':'0.1.0'} # APP 版本
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
py_modules=['test', 'test2'] #项目modules内容
)
其中icns图标的生成可以,都配置完没问题,就可以打包app了
制作
1.准备一张1024x1024的png图片(MsgAppIcon.png)
2.创建一个临时目录存放不同大小的图片icons.iconset.(目录必须采用.iconset保存)
3.把原图片转为不同大小的图片,并放入上面的临时目录
sips -z 16 16 ./MsgAppIcon.png --out icons.iconset/icon_16x16.png
sips -z 32 32 ./MsgAppIcon.png --out icons.iconset/icon_16x16@2x.png
sips -z 32 32 ./MsgAppIcon.png --out icons.iconset/icon_32x32.png
sips -z 64 64 ./MsgAppIcon.png --out icons.iconset/icon_32x32@2x.png
sips -z 64 64 ./MsgAppIcon.png --out icons.iconset/icon_64x64.png
sips -z 128 128 ./MsgAppIcon.png --out icons.iconset/icon_64x64@2x.png
sips -z 128 128 ./MsgAppIcon.png --out icons.iconset/icon_128x128.png
sips -z 256 256 ./MsgAppIcon.png --out icons.iconset/icon_128x128@2x.png
sips -z 256 256 ./MsgAppIcon.png --out icons.iconset/icon_256x256.png
sips -z 512 512 ./MsgAppIcon.png --out icons.iconset/icon_256x256@2x.png
sips -z 512 512 ./MsgAppIcon.png --out icons.iconset/icon_512x512.png
sips -z 1024 1024 ./MsgAppIcon.png --out icons.iconset/icon_512x512@2x.png
4 通过iconutil生成icns文件 $ iconutil -c icns tmp.iconset -o Icon.icns,此时当前目录下生成icns图标
快速生成的Shell脚本
setIconImage(){
sips -z 16 16 ./MsgAppIcon.png --out icons.iconset/icon_16x16.png
sips -z 32 32 ./MsgAppIcon.png --out icons.iconset/icon_16x16@2x.png
sips -z 32 32 ./MsgAppIcon.png --out icons.iconset/icon_32x32.png
sips -z 64 64 ./MsgAppIcon.png --out icons.iconset/icon_32x32@2x.png
sips -z 64 64 ./MsgAppIcon.png --out icons.iconset/icon_64x64.png
sips -z 128 128 ./MsgAppIcon.png --out icons.iconset/icon_64x64@2x.png
sips -z 128 128 ./MsgAppIcon.png --out icons.iconset/icon_128x128.png
sips -z 256 256 ./MsgAppIcon.png --out icons.iconset/icon_128x128@2x.png
sips -z 256 256 ./MsgAppIcon.png --out icons.iconset/icon_256x256.png
sips -z 512 512 ./MsgAppIcon.png --out icons.iconset/icon_256x256@2x.png
sips -z 512 512 ./MsgAppIcon.png --out icons.iconset/icon_512x512.png
sips -z 1024 1024 ./MsgAppIcon.png --out icons.iconset/icon_512x512@2x.png
}
mkdir icons.iconset
setIconImage
iconutil -c icns icons.iconset -o icon.icns
Mac电脑生成icons就这样完成了。
生成app
如果Mac电脑上有多个版本的Python,需要注意打包时Python版本当前打包的环境是否包含app需要依赖的lib和frame。
# 打包速度快,需要依赖库(自己开发可以使用这种方式)
python setup.py py2app -A
#给其他没有sdk的电脑使用,包括lib库。(没有安装sdk的电脑使用,需要去掉-A,将把所有的依赖全部打包。)
python setup.py py2app