Python程序分发
Python是一个脚本语言,程序运行时需要依赖Python解释器,并且要安装相应的依赖库。对于我这种Python用户来说自然不是什么大问题,一个pip就完事了。但是如果是分发给其他windows用户,尤其是不熟悉Python的人来说,这样实在太麻烦。因此最好的办法是连同python解释器和python程序打包在一起,通过inno setup一次安装解决问题。
嵌入式Python处理
此嵌入式不是硬件的嵌入式,而是Python官方提供的免安装版解释器,可以从这里下载所需的版本:Python for Windows。
注意要下载embeddable的版本,不然无法用于制作安装程序。
下载完免安装版本后解压即可,然后从这里下载pip的get-pip.py放入解压的目录中,用cmd执行:
|
|
安装完会在根目录下生成Scripts子目录,用于存储安装后生成的exe:
安装完pip就可以安装所需的依赖库和主程序了,以我的同人志爬虫框架为例子,安装完后会在Scripts生成djsc.exe(见上图)。这样程序就部署完毕了。
但是目前的python整合包尚不能用于分发,因为pip在安装这些会生成exe的程序时会把python解释器的路径写死在这些exe中,需要手动删除那些绝对路径的内容,只保留python.exe:
制作Windows安装程序
在删除解释器的绝对路径之后,就可以用inno setup创建安装包,我建议用inno setup的QuickStart Pack,会自动安装Inno Script Studio,体验很好。下面是我的脚本文件(djscf.iss):
|
|
其中最重要的几点如下:
- 1#define MyAppExeName "Scripts\djsc.exe"
在用ISS的向导程序创建脚本时会让你填写主程序的路径,如下图:
但是我们的exe是在嵌入式python目录的子目录Scripts中,如果在向导中直接设置主程序为djsc.exe并没有修改上面的脚本的话,就会导致封包出来的安装程序在安装完会把djsc.exe从Scripts目录中提取到根目录并为它生成开始菜单快捷方式。
为了解决这个问题最好的办法是直接修改MyAppExeName,前面加上子目录。
- 12345678910111213141516171819[Code]function NeedsAddPath(Param: string): boolean;varOrigPath: string;beginif not RegQueryStringValue(HKEY_LOCAL_MACHINE,'SYSTEM\CurrentControlSet\Control\Session Manager\Environment','Path', OrigPath)then beginResult := True;exit;end;{ look for the path with leading and trailing semicolon }{ Pos() returns 0 if not found }Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;end;[Registry]Root: "HKLM";Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment";ValueType: expandsz;ValueName: "Path";ValueData: "{olddata};{app}";Check: NeedsAddPath('{app}')
上面的代码是用于安装时在PATH中写入安装路径,安装路径即’{app}’。把安装路径写入Path就可以直接在cmd中调用python。但是用户在安装完并不能直接使用,还需要下面的代码。
- 12[Setup]AlwaysRestart = yes
上面的代码可以让用户选择是否重启计算机,重启后就可以正常使用djsc.exe了。
- 1Name: "{group}\打开配置文件"; Filename: "{app}\Scripts\config.ini"
这个代码可以把配置文件的快捷方式一并加入开始菜单,免得用户手动打开目录编辑。
结语
通过上面的实践,就可以把python程序和解释器、依赖库一并打包分发给非专业用户,尤其是pyqt程序。如果依赖库使用了numpy等库,pyinstaller经常会打包失败,但是这样打包成安装包就提高了用户的使用体验。