网络寻租

Programmer, Gamer, Hacker

Pyqt编写的程序如何发布

| Comments

2009年12月3号研究了一下如何发布pyqt的程序,整理内容如下:

pyqt是qt图形库对于python编程语言的一个绑定,qt是著名的跨平台图形开发库,专业,易用,以及企业级别支持,文档齐全。python是一个简单易用的解释语言。不过这篇文章是关于如何发布pyqt程序的,那么读者应该都知道这些,我就不多介绍了。

我们用pyqt开发完程序的时候,得到的是一堆python源代码,以及一些资源文件,比如用到的图片,声音什么的。程序在我们开发平台上可以运行,但是我们还需要想办法让客户机也能够用我们的代码。

我们需要做2件事情:一个是把源代码打包成可以放到任何电脑都能够执行的程序,另一个是做一个安装程序,好方便安装到客户机上。

我现在选择py2exe作为打包的工具,nsis作为生成安装程序的工具。

py2exe

nsis

nsis下载后文档中有详细的介绍,安装目录中含有许多的示例。

我写的示例在 这里

稍微解释一下: 比如,我写了一个新的专案,名称叫test_pyqt,新建了一个这样的文件夹。 里面有一个main.py源代码。同时还有一个res的资源目录。 为了能够利用py2exe打包,需要新建一个setup.py的设置文件。

几个难点整理如下: 根据py2exe里面说的,pyqt需要包含sip(我也不知道这是什么东西,估计是C++转python的时候要用到的。。),下面的脚本含有具体的设置。 编译好的文件还需要一些额外的dll文件(主要是针对没有加sp的XP版本运行时出现“程序出错”报错的状况),放在dll文件夹里面,打包的时候要加上(dll文件在上面的示例中)。我没有研究出如何把这些文件加到可执行文件里面的办法,如果你知道的话,就告诉我。

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# ---------------------------------
# 打包程序
from distutils.core import setup
import py2exe,glob

setup(windows=[{
                "script": 'main.py',
                #应用程序图标
                "icon_resources":[(1, "res/py.ico")] }],
      data_files=[
                  #资源文件
                  ("res", glob.glob("res/*.*")),
                  #因为客户机可能缺少部分开发文件造成无法运行程序,需要打包一些文件
                  (".",glob.glob("dlls/*.*")),
                  ],
      options={"py2exe":{"includes":["sip"],
                         "optimize":2,
                         #打包成一个文件,加快读取速度
                         "compressed":1,
                         "bundle_files":2,
                         #文件放在哪里
                         "dist_dir":"temp/dist",
                         #少了个文件,不管它
                         "dll_excludes":["MSVCP90.dll"],
                         },
               },
      zipfile=None,)#一个文件

#删除build临时目录
import shutil
shutil.rmtree('build')

执行:

python setup.py py2exe

以上语句需要把python的目录加到path里面去,或者你可以在python前加上完整的python安装目录. 我是加path的,因为这样使用python更方便。

之后,会生成temp/dist文件夹,里面就是一个main.exe可执行文件了,还有res文件夹。

之后是生成安装文件,新建一个installer.nsi文件,内容如下(因为比较长,放到最后)。

内容比较多。当时我在做的时候,看了很多的文档才知道具体怎么做。为了方便,你还是用我的示例吧。

下面的内容含有多语言,license页面,安装内容页面,安装目录页面,以及反安装页面。

如果你感兴趣的话可以自己研究,我是被nsis细节给累倒了。

这个文件你只需要改下面软件名称的部分,它会自动把dist打包安装到program files里面,生成执行文件链接到桌面以及菜单项中。

对了,主执行文件的入口是main.py这个源代码。

文件写好后,鼠标右键菜单中有一个compile nsis script的选项,点击就可以生成安装文件。

具体的细节可以看我上面示例的压缩文档。我写了一个makefile来方便快速执行操作(别告诉我你不会用make)。 该示例在windows xp,python2.6,nsis2.46,pyqt4.5,py2exe上测试通过。等以后考虑跨平台版本:

#coding:utf-8

;软件名称
!define NAME "test_pyqt"

;主执行文件
!define EXE "dist\main.exe"

;样式
XPstyle on

;输出的安装文件
OutFile "temp/${NAME}_installer.exe"

;默认目录
InstallDir $PROGRAMFILES\${NAME}

; 检查是否已经安装过
InstallDirRegKey HKLM "Software\${NAME}" "Install_Dir"

;需要管理员权限
RequestExecutionLevel admin

;--------------------------------

; 页面

Page license
Page components
Page directory
Page instfiles

UninstPage uninstConfirm
UninstPage instfiles

;--------------------------------

; 安装主目录
Section "main"

SectionIn RO

; Set output path to the installation directory.
SetOutPath $INSTDIR

; 需要安装的程序
File /r "temp\dist"

; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\${NAME} "Install_Dir" "$INSTDIR"

; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "DisplayName" "${NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "NoRepair" 1
WriteUninstaller "uninstall.exe"

SectionEnd

; 开始菜单
Section "开始菜单"

CreateDirectory "$SMPROGRAMS\${NAME}"
CreateShortCut "$SMPROGRAMS\${NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
SetOutPath $INSTDIR\dist
CreateShortCut "$SMPROGRAMS\${NAME}\${NAME}.lnk" "$INSTDIR\${EXE}" "" "$INSTDIR\${EXE}" 0

SectionEnd

; 桌面快捷方式
Section "桌面快捷方式"
SetOutPath $INSTDIR\dist
CreateShortCut "$DESKTOP\${NAME}.lnk" "$INSTDIR\${EXE}" "" "$INSTDIR\${EXE}" 0
SectionEnd

;--------------------------------

; Uninstaller

Section "Uninstall"

; Remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
DeleteRegKey HKLM SOFTWARE\${NAME}

; Remove directories used
Delete "$DESKTOP\${NAME}.lnk"
RMDir /r "$SMPROGRAMS\${NAME}"
RMDir /r "$INSTDIR"

SectionEnd

;--------------------------------
; 语言部分
; First is default
LoadLanguageFile "${NSISDIR}\Contrib\Language files\English.nlf"
LoadLanguageFile "${NSISDIR}\Contrib\Language files\SimpChinese.nlf"

; License data
; Not exactly translated, but it shows what's needed
LicenseLangString myLicenseData ${LANG_ENGLISH} "license.txt"
LicenseLangString myLicenseData ${LANG_SIMPCHINESE} "license.txt"
LicenseData $(myLicenseData)

; Set name using the normal interface (Name command)
; LangString Name ${LANG_ENGLISH} "English"
; LangString Name ${LANG_SIMPCHINESE} "Simplified Chinese"
; Name $(Name)

;--------------------------------
Function .onInit

;Language selection dialog

Push ""
Push ${LANG_ENGLISH}
Push English
Push ${LANG_SIMPCHINESE}
Push "Simplified Chinese"
Push A ; A means auto count languages
; for the auto count to work the first empty push (Push "") must remain
LangDLL::LangDialog "Installer Language" "Please select the language of the installer"

Pop $LANGUAGE
StrCmp $LANGUAGE "cancel" 0 +2
Abort
FunctionEnd
[/sourcecode]

2010/10/29修改: 其实现在pyinstaller用起来更方便, 直接build就可以了. python2.6以后的版本需要下载开发版本使用.

Comments