Linux

ubuntu pyinstaller 使用pyinstaller打包的坑

使用pyinstaller打包的坑,有需要的朋友可以参考下。

项目中用到pyinstaller将python打成.exe可执行文件:
结果发现如下问题:

由于需要获取命令执行的状态值及返回信息,因此放弃了os.system,os.popen等,commands.getstatusoutput在windows平台也不能使用,因此选择subprocess模块。 os.system还有个坑,当cmd有多个引号时,会解析cmd失败。

1.subprocess.Popen调用报异常:
当使用pyinstaller打成.exe文件安装后
使用p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
报WindowsError:[Error 6]异常
单独使用subprocess.check_output(cmd)同样报此异常。
奇怪的是,直接用源码测试执行时系统完全没有任何问题。
后来才发现,当使用pyinstaller打包时,Popen应该如下初始化:
p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
msg = ''
for line in p.stdout.readlines():
msg += line
status = p.wait()
这样就可以轻松获取指令执行返回的状态值和信息了。

2.Multiprocessing
系统在linux下多进程正常执行,但用pyinstaller打包后在windows下,pool.apply_async(...)多进程启动没有任何反应。在网上找了很久发现:
代码中直接使用标准库中的multiprocessing.Process和multiprocessing.Pool,在打包成可执行程序后会创建进程失败。对于pyinstaller的one-directory模式,只要再程序的最开始调用multiprocessing. freeze_support()就可以了,但对于one-file模式,还需要使用下面修改后的Process和Pool。

import multiprocessing.forking
import multiprocessing.pool
import os
import sys
class _Popen(multiprocessing.forking.Popen):
def __init__(self, *args, **kw):
if hasattr(sys, 'frozen'):
os.putenv('_MEIPASS2', sys._MEIPASS + os.sep)
try:
super(_Popen, self).__init__(*args, **kw)
finally:
if hasattr(sys, 'frozen'):
if hasattr(os, 'unsetenv'):
os.unsetenv('_MEIPASS2')
else:
os.putenv('_MEIPASS2', '')
class Process(multiprocessing.Process):
_Popen = _Popen
class Pool(multiprocessing.pool):
Process = Process

3.此外,pyinstaller只支持ascii,打包后可执行文件路径不能有中文。