问题描述
我自己编译了我下载的一个开源软件pyuvc,编译出whl文件后使用delvewheel进行repair,也就是把它依赖库dll库拷贝到whl文件中。等效的的执行命令是:
python.exe -m delvewheel repair -w .\wheelhouse\ dist\pupil_labs_uvc-1.0.0rc2.dev0+g9e8ea60.d20240103-cp311-cp311-win_amd64.whl --add-path 'C:\\Users\\xxxx\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\pupil_pthreads_win\\data\\lib\\x64;.\\tmp\\libjpeg-turbo-install/bin;.\\tmp\\libusb-install/libusb-1.0.26-binaries/VS2015-x64/dll'
命令行报错是:
raise FileNotFoundError(f'Unable to find library: {dll_name}')
FileNotFoundError: Unable to find library: msvcr100.dll
如何解决
网上各种修复方法,试了都不靠谱,还是下载了delvewheel源码一点点加打印分析,发现是dll和whl的CPU位宽类型不一样导致的。
我系统是64位的windows,我系统上在C:\Windows\SysWOW64这个目录下是存在msvcr100.dll这个文件的,但是它是32位的,delvewheel 把它忽略了。delvewheel 要求whl和dll的CPU位宽是一致的。如果whl是64位CPU,则要求dll也要是64位的。
解决办法就是拷贝一个64位的msvcr100.dll到–add-path 参数后面的任意一个目录下就行。
如何区分dll文件的位宽
使用二进制方式直接打开msvcr100.dll,则可以看到,64位dll中,第一个PE后面跟着一个字母d:
32位的dll,第一个PE后面跟着一个L:
delvewheel如何判断dll是否匹配
在_dll_utils.py中,find_library()函数中可以看到判断dll是否匹配的逻辑。
dll_path = None
for item in contents:if name == item.lower():path = os.path.join(directory, item)if os.path.isfile(path) and get_arch(path) == arch:dll_path = pathbreak
除了判断dll的名字,还要判断dll文件的位宽是否匹配。
判断dll位宽的核心的逻辑如下(判断PE后面两个字节的内容):
def machine_field_to_type(cls, machine_field: int) -> typing.Optional['MachineType']:"""Given the Machine field of a PE file, return the machine type orNone if the machine type is unsupported."""if machine_field == 0x14c:return cls.I386if machine_field == 0x8664:return cls.AMD64if machine_field == 0xaa64:return cls.ARM64return None
可以看到,这里的类型判断和上面截图里二进制内容是对应的,PE后面跟着0x8664就是64位,跟着0x14c就是32位。当然由于是小端模式,在二进制文件中低位在前。
msvcr100.dll下载链接
我上传了一个压缩包,里面有32位和64位版本的各一个:
百度网盘链接:https://pan.baidu.com/s/129EYri6OPq990qLPU4vMKw?pwd=u913
参考资料
https://github.com/adang1345/delvewheel
如何判断一个dll/exe是32位还是64位?
完美解决msvcr100.dll找不到!