最近準備要把手邊用 python 做的小工具交給別人使用,如果可以直接給 code 是最簡單的,但有執行上的難度,所以用 PyInstaller 包成一個執行檔,避免一些安裝、環境、dependency 等等的問題,但 script 裡有用到 cx_Oracle,所以打包的方式有點不同,筆記一下。
目前 PyInstaller 3.5 用在 python 3.8 上好像有點問題,所以本機上的 python 裝的是 3.7.5。事前安裝 Oracle Instant Client 和 cx_Oracle 的部份可以參考 cx_Oracle 的安裝說明,不過我裝了文件裡提的 Visual Studio redistributable 還是沒辦法裝 cx_Oracle,最後是另外安裝 Build Tools for Visual Studio 2019 才行,詳見前篇。
一般要打包成單一一個可執行檔是用 -F 參數:
pyinstaller -F the_script.py
此時除了包好的 exe 檔在 dist/ 下外,還會有另一個 .spec 檔。修改 spec 文件,把 Oracle Instant Client 的 dll 檔加進去。
exe 區段裡的 a.binaries 要改成 a.binaries+[('oraociei19.dll','oraociei19.dll','BINARY')], 其中 oraociei19.dll 依據使用的 Oracle Instant Client 版本而定,以我的例子裝的是 v19。
改好的 spec 檔大概會長這樣:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['check-pcu-cr-status.py'],
pathex=['C:\\Users\\Administrator\\Documents\\linebot'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries+[('oraociei19.dll','oraociei19.dll','BINARY')],
a.zipfiles,
a.datas,
[],
name='check-pcu-cr-status',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False )
將 oraociei19.dll 檔 copy 到 script 所在目錄,接著執行 pyinstaller -F the_script.spec 即可。
參考:Pyinstaller: cx_Oracle.InterfaceError: Unable to acquire Oracle environment handle