我自己编译了我下载的一个开源软件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 参数后面的任意一个目录下就行。
使用二进制方式直接打开msvcr100.dll,则可以看到,64位dll中,第一个PE后面跟着一个字母d:
32位的dll,第一个PE后面跟着一个L:
在_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 = path
break
除了判断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 or
None if the machine type is unsupported."""
if machine_field == 0x14c:
return cls.I386
if machine_field == 0x8664:
return cls.AMD64
if machine_field == 0xaa64:
return cls.ARM64
return None
可以看到,这里的类型判断和上面截图里二进制内容是对应的,PE后面跟着0x8664就是64位,跟着0x14c就是32位。当然由于是小端模式,在二进制文件中低位在前。
我上传了一个压缩包,里面有32位和64位版本的各一个:
百度网盘链接:https://pan.baidu.com/s/129EYri6OPq990qLPU4vMKw?pwd=u913