如何将所有资源打包成一个可执行文件?
我用Python写了一个GTK应用程序。
这个程序的所有图形界面都在一个glade文件里,还有一些图片用到。我想把我的应用程序打包成一个可执行文件(EXE)。为此,我使用了PyInstaller这个编译工具和UPX这个压缩工具。
我按照说明书的步骤做了:
python Configure.py
python Makespec.py --onefile --windowed --upx /path/to/yourscript.py
python Build.py /path/to/yourscript.spec
PyInstaller工作得很好,生成了一个exe文件。但是为了让我的应用程序正常运行,我必须把我的glade文件和图片文件复制到exe的文件夹里。
有没有办法把这些文件直接编译进可执行文件里呢?
我尝试了多种方式修改我的spec文件,但始终达不到我想要的效果。下面的spec文件只是把文件复制到目录里,并没有把它们编译进可执行文件中。
# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'r:\\connection\\main.py'],
pathex=['C:\\Documents and Settings\\Lixas\\Desktop\\pyinstaller-1.5-rc1'])
pyz = PYZ(a.pure)
exe = EXE( pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name=os.path.join('dist', 'NetworkChecker.exe'),
debug=False,
strip=False,
upx=True,
console=False,
icon='r:\\connection\\ikona.ico' )
coll = COLLECT(
exe,
[('gui.glade', 'r:\\connection\\gui.glade', 'DATA')],
[('question16.png', 'r:\\connection\\question16.png', 'DATA')],
# a.binaries,
# strip=False,
upx=True,
name='distFinal')
我希望能得到一个包含所有内容的单一可执行文件。
3 个回答
有没有办法把这些文件编译成可执行文件呢?
严格来说,是没有的,因为编译的对象是源代码,而glade文件是XML格式的,图片则是二进制数据。通常你需要做的是创建一个安装程序(也就是一个自解压的压缩包,运行时会把不同的文件放到正确的目录里)。
补充:如果你只是想要一个单文件的可执行程序(所以其实不是在“编译”,而是关心文件在系统上占用的数量),你可以试试这个脚本,它是基于py2exe的。它的做法是每次运行程序时创建临时文件,执行完成后再删除这些文件。
补充2:显然,你想要的在PyInstaller下也是可以实现的。根据文档:
默认情况下,pyinstaller.py会创建一个包含主可执行文件和动态库的分发目录。选项--onefile表示你希望PyInstaller把所有内容打包成一个文件。
通过一些简单的修改,你可以把所有内容都放进你的源代码里,这样就能把它们打包进你的可执行文件里。
如果你在你的图片文件上运行 gdk-pixbuf-csource
,你可以把这些图片转换成字符串,然后用 gtk.gdk.pixbuf_new_from_inline()
来加载它们。
你还可以把你的 Glade 文件作为字符串包含在程序里,然后用 gtk.Builder.add_from_string()
来加载它。
PyInstaller 确实可以让你把所有资源打包进 exe 文件里,而不需要把数据文件转换成 .py 文件,这样就简单多了。你的 COLLECT 对象看起来是正确的,真正麻烦的是在运行时如何访问这些文件。PyInstaller 会把这些文件解压到一个临时目录,并通过 _MEIPASS2 变量告诉你它们的位置。为了在开发模式和打包模式下都能获取文件路径,我使用了以下代码:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
# in development
>>> resource_path("gui.glade")
"/home/shish/src/my_app/gui.glade"
# in deployment
>>> resource_path("gui.glade")
"/tmp/_MEI34121/gui.glade"