Shiv生成的可执行文件找不到app模块,设置PATH后恢复正常原因咨询
构建配置
我使用shiv结合以下Makefile构建Python可执行文件:
benv: python3.11 -m venv bvenv . bvenv/bin/activate; pip install myapplication/ . bvenv/bin/activate; pip install shiv build: benv . bvenv/bin/activate; shiv --site-packages bvenv --compressed -p '/usr/bin/env python3.11' -o mycompiled-app -e app.main.py
报错信息
在其他机器运行该可执行文件时,始终抛出如下异常:
/opt/myappdirectory-app/mycompiled-app run Traceback (most recent call last): File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 76, in import_string ModuleNotFoundError: No module named 'app' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 76, in import_string ModuleNotFoundError: No module named 'app' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<frozen runpy>", line 198, in _run_module_as_main File "<frozen runpy>", line 88, in _run_code File "/opt/myappdirectory-app/mycompiled-app/__main__.py", line 3, in <module> File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 253, in bootstrap File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 81, in import_string File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 81, in import_string File "/opt/myappdirectory-app/mycompiled-app/_bootstrap/__init__.py", line 59, in import_string File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<frozen importlib._bootstrap>", line 1204, in _gcd_import File "<frozen importlib._bootstrap>", line 1176, in _find_and_load File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked ModuleNotFoundError: No module named 'app'
现象确认
- 解压shiv生成的
mycompiled-app后,确认存在app模块及main.py文件 - 将构建时使用的虚拟环境
bvenv/bin目录添加到系统PATH后,可执行文件能正常运行
原因分析及解决办法
1. 入口点参数错误(最直接原因)
你的shiv命令中-e app.main.py是错误写法:Python模块名不包含.py后缀,正确的入口点应该是-e app.main(表示导入app.main模块并执行其__main__逻辑),或者指定模块内的具体函数(比如-e app.main:main)。
当你写-e app.main.py时,shiv会尝试导入名为app.main.py的模块,而实际你的模块是app.main,这会导致导入路径解析错误,最终抛出找不到app模块的异常。
2. 虚拟环境开发模式安装导致打包不完整
如果pip install myapplication/是使用开发模式(比如添加了-e参数,即使Makefile没写但实际操作时加了),虚拟环境的site-packages里只会生成一个指向源码目录的.egg-link文件,而非实际的模块文件。shiv打包时会把这个.egg-link文件包含进去,但在其他机器上,该链接指向的本地源码路径不存在,自然找不到app模块。
而当你把虚拟环境bin目录加到PATH后,/usr/bin/env python3.11会优先调用虚拟环境内的Python,该Python会通过.egg-link找到本地源码中的app模块,因此能正常运行。
3. Shiv打包路径配置问题
虽然你解压后能看到app模块,但可能它被打包到了shiv bootstrap脚本未添加到sys.path的子目录中。可以修改shiv命令,显式指定要打包的模块目录,而不是依赖--site-packages bvenv:
shiv --compressed -p '/usr/bin/env python3.11' -o mycompiled-app -e app.main myapplication/
这种方式会直接把myapplication/下的app模块打包进去,避免依赖虚拟环境的site-packages配置。
内容的提问来源于stack exchange,提问作者asdf

