python应用越来越广泛,有时需要将python的project打包成二进制,到一个没有安装python解释器的环境中执行。Pyinstaller对这个功能提供了较好的支持。
Pyinstaller能够在Windows、Linux、 Mac OS X 等操作系统下将 Python 源文件打包,通过对源文件打包, Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个 独立文件方便传递和管理。
$ pip install pyinstaller
Babel (2.5.1)
PyInstaller (3.3)
代码:
# run.py
#!/usr/bin/env python
# encoding: utf-8
import babel
print babel.localedata.locale_identifiers()
$ pyinstall -F run.py
$ ./dist/run
Traceback (most recent call last):
File "pktest/run.py", line 6, in <module>
File "babel/localedata.py", line 76, in locale_identifiers
OSError: [Errno 2] No such file or directory: '/tmp/_MEISf3zGo/locale-data'
[100180] Failed to execute script run
指定需要的data路径:
$ pyinstaller -F run.py --add-data $(your_python_path)/babel/locale-data/:locale-data
也可以直接编辑.spec文件指定data
a = Analysis(['run.py'],
pathex=['$(your_code_path)/pktest'],
binaries=[],
datas=[('$(your_python_path)/babel/locale-data/', 'locale-data')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyinstaller 并非对所有的第三方库都能完美支持,参考支持的第三方库。其中,对babel的支持:
Fully supported, including “localedata” external data files (automatically handled).
不过Babel (2.5.1)已经没有localedata,而是用locale-data取代,并且在代码中对Pyinstaller做了兼容:
# babel/localedata.py
...
def get_base_dir():
if getattr(sys, 'frozen', False) and getattr(sys, '_MEIPASS', None):
# we are running in a |PyInstaller| bundle
basedir = sys._MEIPASS
else:
# we are running in a normal Python environment
basedir = os.path.dirname(__file__)
return basedir
_cache = {}
_cache_lock = threading.RLock()
_dirname = os.path.join(get_base_dir(), 'locale-data')
...
当环境为Pyinstaller,重新定义了basedir。我们需要重新指定locale-data路径,或者:
def get_base_dir():
return os.path.dirname(__file__)
Pyinstaller是一个很方便的库,功能强大,但是并不能完美支持所有第三方库。另外对于包含中文字符的场景也需要特别注意。