3
18
2013
16

使用 cx_freeze 打包 Python 程序

本文来自依云's Blog,转载请注明。

首先,当然是给一个目标系统安装 cx_freeze。虽然 cx_freeze 是跨平台的,但没发现它支持在一个平台上打包出另一个平台的二进制文件,而且那样还得准备那个平台上的库文件。我的目标平台是 Windows XP,所以还要准备一个 Dependency Walker

其次,使用cxfreeze-quickstart向导生成配置文件setup.py。当然,如果已经有setup.py文件的话直接修改就是了。下边是一个示例:

import sys

from cx_Freeze import setup, Executable

# Dependencies are automatically detected, but it might need
# fine tuning.
buildOptions = dict(
  packages = [], excludes = [],
  include_files = ['images', 'data.sqlite'],
)

name = 'example'

if sys.platform == 'win32':
  name = name + '.exe'

base = None
if sys.platform == "win32":
    base = "Win32GUI"

executables = [
  Executable('main.py', base = base, targetName = name,
             compress = True,
            )
]

setup(name='Example',
      version = '1.0',
      description = 'An example program',
      options = dict(build_exe = buildOptions),
      executables = executables)

当然,这里有不少我改过的地方。在buildOptions变量中我加了data.sqlite文件和images目录到include_files中去。它们会被放到生成的二进制文件相同的目录。

cx_freeze 在打包 Windows 可执行文件时并不会像 gcc 那样自动添加.exe后缀,所以我要手动加上。

Executable的调用中,要写成base='Win32GUI'这样子。cxfreeze-quickstart目前直接写在第二个参数的位置上的方法是不对的。base的默认值是Console,在 Windows 下运行时是会出现黑色的cmd.exe窗口的。参见StackOverflow: Hide console window with wxPython and cxFreeze

这样还没有完成。打包后测试发现PyQt4.QtNetwork的库文件没有打包进去,可能是因为它是从共享库中引用的,cx_freeze 没有检测到这个依赖。在程序中 import 一下就可以了。另外一个问题是,在没有安装相关库的干净的目标系统上执行时还遇到以下错误信息:

DLL load failed: 找不到指定的模块
DLL load failed: The specified module could not be found.

其上还有一个 Traceback。这是因为有些(据说主要是 Microsoft Visual C++ Redistributable 的) DLL (非 Python 模块)没有被打包进去。从 Traceback 中找到引发这个错误的 DLL(或者 pyd)文件名,将其在打包系统中使用前边提到的 Dependency Walker 打开,在左边的树形库列表中找到目标系统上可能没有的库文件,将其复制到 cx_freeze 生成二进制文件的目录中即可。比如我这里需要手动添加msvcr100.dllmsvcp100.dll

最后,打包过的程序执行时__main__模块是没有__file__属性的,所以无法通过这个变量来切换到程序所在的目录,进而读取自己的数据文件。但是,打包过的程序有sys.frozen属性,程序自身的路径存放在sys.executable中,所以程序中需要作下判断:

import os
import sys

if hasattr(sys, 'frozen'):
  me = sys.executable
else:
  me = __file__
mydir = os.path.dirname(me)

参见StackOverflow: How do I get the path of the current executed file in python?

最终打出来的可执行文件和库文件比较大,PyQt 程序总共有 40M 之多。使用 7z 压缩之后能减小到 10M 多。

Category: python | Tags: python windows | Read Count: 37642
Avatar_small
tisyang 说:
Mar 19, 2013 02:09:06 PM

copy 一下右侧的权利声明 ⊙▽⊙

JackPhil 说:
Mar 22, 2013 01:13:03 PM

题外话,用feedly订阅这个博客出错,不知是feedly的问题还是博客的问题

Avatar_small
依云 说:
Mar 22, 2013 04:37:23 PM

我这里订阅正常。能说一下发生了什么使你认为出错了吗?能说一下你的操作流程吗?如果能够使用 Firebug 或者 httpfox 查看网络流就更好了。

JackPhil 说:
Mar 22, 2013 04:42:55 PM

feedly显示错误信息如下:

Feedly was not able to load feed:
feed/http%3A%2F%2Flilydjwg.is-programmer.com%2Fposts.rss

Why?

Access to this feed might require a username and password (feedly does not know yet how to access and load authenticated feeds).
The specified URL does not point to a valid RSS or ATOM feed (in which case you might want to contact the owner of the website you are trying to subscribe to and let them know about the problem).
You are running into a feedly bug. Please open a ticket so that we can track it down.

version
11.0.455

internal information
failed to get feed information for 'feed/http%3A%2F%2Flilydjwg.is-programmer.com%2Fposts.rss' because: 400 -- undefined. Hint Google Reader URL: !{google}/reader/api/0/stream/contents/feed%2Fhttp%253A%252F%252Flilydjwg.is-programmer.com%252Fposts.rss?r=n&n=10&client=feedly&ck=1363941681273

JackPhil 说:
Mar 22, 2013 04:46:31 PM

我是直接在FF中点击右侧的文章RSS,然后最后一步出错

又试了一下,直接用rss地址可以正常添加

Avatar_small
依云 说:
Mar 22, 2013 04:59:12 PM

你用的是 feedly 的火狐插件啊,去 feedly 官方报告 bug 吧。

直接复制博客地址或者其 RSS 地址并在 feedly 的网页中是能够正常添加的。

kk 说:
Apr 06, 2013 03:52:55 PM

您好 我是个python新手 在用cxfreeze打包的时候遇到个问题 google无果 能否向您请教下
程序用到了qtgui 和qtcore
打包后在我的电脑上运行正常 到别的机器上会出现下面的错误
i.imgur.com/RpuWOIh.png
这个有可能是什么地方出错了吗?。。。
非常感谢 <(ˉ▽ˉ;=)>

Avatar_small
依云 说:
Apr 07, 2013 01:41:45 PM

使用文中提到的 Dependency Walker 查询你的二进制所直接依赖的 DLL,把非 Windows 自带的全补上。

Avatar_small
依云 说:
Apr 07, 2013 01:43:21 PM

Dependency Walker 也可以告诉你哪些 DLL 没有找到,所以你也可以在有问题的系统上跑,看看缺少哪些 DLL。

如果是载入模块中抛出的异常,见文中所言。

kk 说:
Apr 08, 2013 01:22:20 PM

我又试了下 按在line6出错 代码正在import qtgui 来分析的话 我缺的是qtgui和qtcore 但它打包的文件夹中已经有Qt5Core.dll和Qt5Gui.dll了 好奇怪呀 用dependency在运行不了的机子上分析 提示“警告: 由于在延时加载依赖模块中丢失导入函数,至少有一个模块具有不能解析的导入。”
要打包程序 步骤就是修改setup.py 再build是吗

Avatar_small
依云 说:
Apr 08, 2013 01:55:44 PM

还可能要往生成 .exe 文件的目录里丢缺失的 .dll 文件。

kk 说:
Apr 11, 2013 12:11:35 PM

谢谢 偶然解决了这个问题,xp果然还是太老了 缺失D3DCompiler_43.dll,补上这个就没有这个错误,最终又添了两个dll才真正能运行 晕啊 打包能再傻瓜化就好了 (>_<)

Probe 说:
Jun 21, 2013 11:43:18 PM

谢谢博主的勤劳探索!
我遇到了类似问题,Python+Qt5在开发机器上打包exe运行良好,但在没有环境的Win7中怎么也无法运行。
折腾好几天了才搞定。

针对使用Qt5的Python程序,最后结论是:
msvcp100.dll
libEGL.dll
platforms/qwindows.dll
都必须放到最终生成的目录中(可以不使用setup.py配置这些文件,通过人肉复制进去即可)。

另外,这个Dependency Walker实在是作用不大啊,最重要的那些dll,如"libEGL.dll","msvcp100.dll",都没能检测出来。反倒检测出一些其他的毛病,结果花了好长时间去处理却发现不是它们的问题。

Avatar_small
依云 说:
Jun 22, 2013 12:00:33 AM

可能是 Dependency Walker 在 win7 下有些问题?不过 Windows 下我只找到这个了唉,不像 Linux/BSD 有 ldd 命令。

Avatar_small
danny 说:
Mar 22, 2014 08:44:06 PM

血的教训呃.
我花费了两个钟来检查问题. msvcr100.dll说是找不到...
win7 64位下打包,xp无法运行,提示找不到文件msvcr100.dll. 然而,当我下载好之后,又提示我这别的问题.
我就干脆在xp下安装个py然后在xp下打包.这下没事了.

Avatar_small
danny 说:
Mar 22, 2014 08:46:23 PM

如果快捷方式没有起码位置,将不会显示任务栏图标呃.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com