这是一个例子,它实际上是有效的,所以它实际上并不能说明我的问题,只是为了奠定讨论基础:
mkdir C:/test/testpyinst
cd C:/test/testpyinst
这里有
main.py
:
#!/usr/bin/env python3
import sys, os
from lib import relative_path2
def relative_path(relative_path): # https://stackoverflow.com/q/58487122
try:
base_path = sys._MEIPASS
print("_MEIPASS OK {}".format(base_path))
except Exception:
base_path = os.path.abspath(".")
print("_MEIPASS exception {}".format(base_path))
return os.path.join(base_path, relative_path)
def main():
print("Hello from main")
print("relative_path {}".format(relative_path(".")))
print("relative_path2 {}".format(relative_path2(".")))
if __name__ == '__main__':
main()
...和
lib.py
:
import sys, os
def relative_path2(relative_path): # https://stackoverflow.com/q/58487122
try:
base_path = sys._MEIPASS
print("_MEIPASS OK {}".format(base_path))
except Exception:
base_path = os.path.abspath(".")
print("_MEIPASS exception {}".format(base_path))
return os.path.join(base_path, relative_path)
我使用这个 -
pyinstaller
通过python3 -m pip install pyinstaller
安装:
$ uname -s
MINGW64_NT-10.0-19045
$ python3 --version
Python 3.11.8
$ pyinstaller --version
6.5.0
当我直接从 python 运行此代码时,
_MEIPASS
正如预期不可访问:
$ python3 main.py
Hello from main
_MEIPASS exception C:/test/testpyinst
relative_path C:/test/testpyinst/.
_MEIPASS exception C:/test/testpyinst
relative_path2 C:/test/testpyinst/.
然后我使用 PyInstaller 创建一个
.exe
:
pyinstaller --onefile main.py
...当我运行 .exe 时,正如预期的那样,
_MEIPASS
有效:
$ ./dist/main.exe
Hello from main
_MEIPASS OK D:\msys64\tmp\_MEI199762
relative_path D:\msys64\tmp\_MEI199762/.
_MEIPASS OK D:\msys64\tmp\_MEI199762
relative_path2 D:\msys64\tmp\_MEI199762/.
所以,这是我的问题 - 在我的实际(pyqt5)项目中,
sys._MEIPASS
不起作用 - 从某种意义上说,当我尝试读取 relative_path()
运行时,我总是
在
sys._MEIPASS
中遇到异常最终 .exe
由 PyInstaller 创建 !?
由 pyinstaller 生成的 exe 在运行任何 python 代码之前设置。我可以想到一些不被设置的原因:sys._MEIPASS
- 执行代码reload(sys)
- 您使用的是 3.0 之前的 PyInstaller 版本
- PyInstaller 安装不正确并且正在使用旧的 2.1 引导加载程序文件
我尝试运行
python3 -m trace --trace myprogram.py | grep reload
,显然我的程序中从未调用过 reload(sys) ...
所以,我仍然不知所措:我可以在我的项目中做什么,让
sys._MEIPASS
按预期工作?
一般解决方案:将
def relative_path
尽可能靠近主文件的顶部(主文件将是提供给 PyInstaller 的文件,例如 __init__.py
),可能在第一个 import sys, os
之后 - 一开始, sys._MEIPASS
应该可以正常工作(这可以帮助您稍后确定导致问题的确切库)。