pyinstaller 打包报WARNING: lib not found: api-ms-win-core-path-l1-1-0.dll dependency of python39.dll

关于这个问题,在网上看了很多帖子,都无法解决我的问题,于是决定从源码入手,分析一波。

先罗列一下其它网友的解决方案,或许对某些朋友会有帮助,最后在写一下我自己的源码分析思路。如有不对的地方,还请各路大神指出。

原创不易,如转载请注明出处!

报错:

6058 WARNING: lib not found: api-ms-win-core-path-l1-1-0.dll dependency of C:\Users\lvliang\AppData\Local\Programs\Python\Python39\python39.dll

报错意思是python39.dll动态库依赖于api-ms-win-core-path-l1-1-0.dll动态库文件,但是本地计算机上缺少这个文件,我用everything工具本地搜索了一下,确实是没有这个文件。

于是从官网下载了一个

https://cn.dll-files.com/api-ms-win-core-path-l1-1-0.dll.html

1、将api-ms-win-core-path-l1-1-0.dll文件拷贝到python安装目录 

AppData\Local\Programs\Python\Python39和系统目录%windir%\SysWOW64下 

-- 重新执行pyinstaller打包操作,还是报lib not found

2、又试了下把文件拷贝到

C:\Windows\SysWOW64\downlevel

C:\windows\system32

C:\Windows\System32\downlevel

同时将AppData\Local\Programs\Python\Python39和以上目录加入path环境变量中

--重新执行pyinstaller打包操作,还是报lib not found

3、还有朋友提说,使用spec文件打包,我也试了下

3.1 首先使用pyinstaller -F xxx.py文件打下包,会生成一个xxx.spec文件

3.2 删掉build和dist目录,修改spec文件,在pathex中添加上api-ms-win-core-path-l1-1-0.dll文件所在的目录

3.3 使用pyinstaller -F xxx.spec 命令打包

--还是报lib not found

4、于是我想了下,是不是dll文件需要注册

使用regsrv32 xxx.dll命令执行了下发现注册失败

于是下载了一个depends.exe工具,打开这个dll文件看了下函数输出表,没有找到以下两个函数

DllRegisterServer

DllUnregisterServer

说明这个dll文件是不需要注册即可使用的

5、这就头疼了,网上已经找不到解决方案了,于是下面开始自己研究pyinstaller的代码

我使用的是python3.9

找到class

class Analysis(Target):

方法:

def assemble(self):

跳转到def Dependencies(lTOC, xtrapath=None, manifest=None, redirects=None):方法

pyinstaller 打包报WARNING: lib not found: api-ms-win-core-path-l1-1-0.dll dependency of python39.dll_第1张图片

selectImports这个方法中会去查到python39.dll所需要的所有动态库dll,而且这边出现了lib not found的报错

def selectImports(pth, xtrapath=None):

    rv = []

    if xtrapath is None:

        xtrapath = [os.path.dirname(pth)]

    else:

        assert isinstance(xtrapath, list)

        xtrapath = [os.path.dirname(pth)] + xtrapath  # make a copy

    dlls = getImports(pth)

    for lib in dlls:

        if lib.upper() in seen:

            continue

        if not compat.is_win:

            # all other platforms

            npth = lib

            lib = os.path.basename(lib)

        else:

            # plain win case

            npth = getfullnameof(lib, xtrapath)

            if lib == 'api-ms-win-crt-convert-l1-1-0.dll':

                print(npth)

        # now npth is a candidate lib if found

        # check again for excludes but with regex FIXME: split the list

        if npth:

            candidatelib = npth

        else:

            candidatelib = lib

        if not dylib.include_library(candidatelib):

            if (candidatelib.find('libpython') < 0 and

               candidatelib.find('Python.framework') < 0):

                # skip libs not containing (libpython or Python.framework)

                if npth.upper() not in seen:

                    logger.debug("Skipping %s dependency of %s",

                                 lib, os.path.basename(pth))

                continue

            else:

                pass

        if npth:

            if npth.upper() not in seen:

                logger.debug("Adding %s dependency of %s from %s",

                             lib, os.path.basename(pth), npth)

                rv.append((lib, npth))

        elif dylib.warn_missing_lib(lib):

            logger.warning("lib not found: %s dependency of %s", lib, pth)

    return rv

结合这段代码,跳转到getfullnameof函数中

def getfullnameof(mod, xtrapath=None):

    pywin32_paths = []

    if compat.is_win:

        pywin32_paths = [os.path.join(get_python_lib(), 'pywin32_system32')]

        if compat.is_venv:

            pywin32_paths.append(

                os.path.join(compat.base_prefix, 'Lib', 'site-packages',

                             'pywin32_system32')

            )

    epath = (sys.path +  # Search sys.path first!

             pywin32_paths +

             winutils.get_system_path() +

             compat.getenv('PATH', '').split(os.pathsep))

    if xtrapath is not None:

        if type(xtrapath) == type(''):

            epath.insert(0, xtrapath)

        else:

            epath = xtrapath + epath

    for p in epath:

        npth = os.path.join(p, mod)

        if os.path.exists(npth) and matchDLLArch(npth):

            return npth

    return ''

 

从getfullnameof函数中可以得到很多信息,python会优先去python39安装目录找dll文件

然后还会从以下目录去找

'C:\\Windows\\SysWOW64\\downlevel',

'C:\\Windows\\System32\\downlevel',

'C:\\windows\\system32',

'C:\\windows',

'D:\\Program Files\\JetBrains\\PyCharm 2021.2\\bin'

'C:\\Users\\lys4989\\AppData\\Local\\Programs\\Python\\Python39\\DLLs',

'C:\\Users\\lys4989\\AppData\\Local\\Programs\\Python\\Python39\\lib',

'C:\\Users\\lys4989\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages',

那说明前面第1,2两步的做法没错,既然文件存在,那就一定是matchDLLArch(npth)判断失败了

看一下matchDLLArch方法

def matchDLLArch(filename):

    # TODO: check machine type on other platforms?

    if not compat.is_win:

        return True

    global _exe_machine_type

    try:

        if _exe_machine_type is None:

            pefilename = compat.python_executable  # for exception handling

            exe_pe = pefile.PE(pefilename, fast_load=True)

            _exe_machine_type = exe_pe.FILE_HEADER.Machine

            exe_pe.close()

        pefilename = filename  # for exception handling

        pe = pefile.PE(filename, fast_load=True)

        match_arch = pe.FILE_HEADER.Machine == _exe_machine_type

        pe.close()

    except pefile.PEFormatError as exc:

        raise SystemExit('Can not get architecture from file: %s\n'

                         '  Reason: %s' % (pefilename, exc))

    return match_arch

在源码中添加一些打印代码,发现matchDLLArch返回为false,说明我的dll文件是32位的,而操作系统版本是64位的

到这边,已经找到了一直报lib not found的原因了,虽然dll文件确实存在但是文件版本和操作系统版本不匹配,python也是一样输出lib not found。(我觉得这一块是不是可以优化一下源代码,这报错信息太折磨人了。)

在网上下载一个64位dll文件

使用以下python脚本测试一下

import pefile
pefile.fast_load = True
exe_pe = pefile.PE('D:\\api-ms-win-core-path-l1-1-0.dll', fast_load=True)
_exe_machine_type = exe_pe.FILE_HEADER.Machine
exe_pe.close()
print(_exe_machine_type)

输出结果为34404(如果是32位的dll文件,会输出332),表明是64位的,再次执行pyinstaller打包,问题解决。

总结一下:

对于我的这个问题,python3.9 + 64位操作系统,我只需要下载一个64位的dll文件,放到python安装目录下,就可以了。

由于官网上只有32位的文件,我在个人资源中添加了一个64位的dll文件。

 原创不易,如转载请注明出处!

你可能感兴趣的:(python)