报错现象
本人基于 llama-cpp-python 构建了一个领域知识问答程序,并通过 Pyinstaller 打包成一个包含 .exe
运行文件的文件夹(记为 D
)。
该 .exe
在本机(打包用的电脑,Windows 11)上运行正常,在把文件夹 D
拷贝到另外五台电脑(Windows 10)上后, .exe
在其中三台电脑上运行正常,但另两台报如下错误:
RuntimeError: Failed to load shared library 'D:\PPLocalChatbot\_internal\llama_cpp\llama.dll':
Failed to load dynlib/dll 'D:\\PPLocalChatbot\\_internal\\llama_cpp\\llama.dll'.
Most likely this dynlib/dll was not found when the application was frozen.
本机配置
- Windows 11
- Python 3.8
- llama-cpp-python 0.2.73
- Pyinstaller 6.6.0
- kernel32.dll 10.0.22621.3527
问题分析
- 如这里所示,通常 Pyinstaller 打包后的程序报错无法找到/加载 xx 文件,大概率是该文件在打包时未被 Pyinstaller 自动加入到指定文件夹引发的。然而这次不是,我已在打包配置文件
.spec
中通过Analysis.binaries
将llama.dll
加入到了正确文件夹;此外,其他三台电脑能正常运行也表明了llama.dll
其实正位于正确的文件夹下。 - 考虑到有些电脑能跑,有些不行,那可能与电脑版本或环境有关;
- 在这里看到,该类报错也有可能是
.dll
所依赖其它.dll
未在目标电脑上找到,可以采用 Dependencies 软件来检测 DLL 文件的依赖情况。 - 下图是本机使用 Dependencies 检测出的
llama.dll
的依赖情况,通过查找,发现除了kernel32.dll
,其它 DLL 文件均在打包后的文件夹D
中存在。所以在运行.exe
文件时,被调用的llama.dll
会从目标电脑的C:\Windows\System32
中调用kernel32.dll
。而这个kernel32.dll
的版本在各电脑中都有所不同,因此kernel32.dll
大概率就是问题所在。
问题解决
- 本机的
kernel32.dll
的版本为10.0.22621.3527
,再查看五台测试电脑上的kernel32.dll
的版本,发现正常运行的电脑的kernel32.dll
的版本均在10.0.17***.****
以上,而报错的电脑的kernel32.dll
的版本均在10.0.16***.****
以下;
报错电脑的 kernel32.dll 版本(旧)
正常运行电脑的 kernel32.dll 版本
- Google 后了解到
kernel32.dll
与 Windows 版本直接关联,所以不能直接通过复制粘贴来更新。因此我不考虑更改kernel32.dll
,而是更改llama.dll
让其适配旧版的kernel32.dll
; - 为了让
llama.dll
适配旧版的kernel32.dll
,最直接的方法就是:在旧版的 Windows 系统(即kernel32.dll
版本低于10.0.16***.****
)中配置 Python 环境,安装 llama-cpp-python(这一步需要 cmake 等环境,可参考官方文档),并对程序进行打包; - 经测试,在旧版 Windows 上打包的程序同时也可在新版 Windows 上正常运行(新版向下兼容)。