使用命令行发现缺失的模块(“DLL load failed”错误)

5
在Windows上,当我们尝试导入一个.pyd文件时,如果找不到.pyd依赖的DLL文件,就会出现以下回溯信息:
Traceback (most recent call last):
  ...
ImportError: DLL load failed: The specified module could not be found.

当出现这种情况时,通常需要借助图形工具(例如Dependencies)来确定缺失模块的名称。

如何通过命令行获取缺失模块的名称?

背景:通常在 CI 中会遇到此错误,使用 SSH 登录以查找缺少的模块名称要比通过 GUI 登录更容易。

1个回答

4
首先,让我们选择一个具体的例子:NumPy_multiarray_umath*.pyd(来自Python 3.9pc064))。请注意,我将重复使用此控制台:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q074877580]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe"
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import os
>>>
>>> os.getpid()
12788
>>>
>>> from numpy.core import _multiarray_umath as _mu
>>>
>>> _mu
<module 'numpy.core._multiarray_umath' from 'e:\\Work\\Dev\\VEnvs\\py_pc064_03.09_test0\\lib\\site-packages\\numpy\\core\\_multiarray_umath.cp39-win_amd64.pyd'>
>>> ^Z


[prompt]>
[prompt]> :: Backup %PATH%
[prompt]> set _PATH=%PATH%
为了尽可能地使事情通用化,.pyd依赖于自定义的.dllOpenBLAS):

Img0

以下是上述(Python)过程的快照:

Img1

注意依赖的.dll是从哪里加载的(在我们选择的.pyd下面的2行)。

现在,回到问题:有很多工具可以做到这一点。
但是需要注意的是,无论使用什么工具,都(很可能)取决于PATH环境变量的内容(在第1张图片中,找不到依赖的.dll(和其他文件))。请查看[MS.Learn]: Dynamic-Link Library Search Order以获取有关.dll的更多详细信息。

作为一个注释,由于(某些)工具会生成大量输出,我将使用像FindStrGrep)之类的命令进行过滤,只显示相关部分,以避免在答案中填充垃圾信息。

1. [GitHub]: lucasg/Dependencies

除了你提到的GUI应用程序 (DependenciesGui.exe),旁边还有一个命令行工具: Dependencies.exe:

[prompt]>
[prompt]> :: Restore %PATH%
[prompt]> set PATH=%_PATH%

[prompt]>
[prompt]> "f:\Install\pc064\LucasG\DependencyWalkerPolitistTexan\Version\Dependencies.exe" -h
Dependencies.exe : command line tool for dumping dependencies and various utilities.

Usage : Dependencies.exe [OPTIONS] <FILE>

Options :
  -h -help : display this help
  -json : activate json output.
  -cache : load and use binary cache in order to prevent dll file locking.
  -depth : limit recursion depth when analysing loaded modules or dependency chain. Default value is infinite.
  -apisets : dump the system's ApiSet schema (api set dll -> host dll)
  -apisetsdll : dump the ApiSet schema from apisetschema <FILE> (api set dll -> host dll)
  -knowndll : dump all the system's known dlls (x86 and x64)
  -manifest : dump <FILE> embedded manifest, if it exists.
  -sxsentries : dump all of <FILE>'s sxs dependencies.
  -imports : dump <FILE> imports
  -exports : dump <FILE> exports
  -modules : dump <FILE> resolved modules
  -chain : dump <FILE> whole dependency chain

[prompt]>
[prompt]> "f:\Install\pc064\LucasG\DependencyWalkerPolitistTexan\Version\Dependencies.exe" -modules "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd" | findstr "libopenblas"
[NOT_FOUND] libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll :

[prompt]>
[prompt]> set PATH=%_PATH%;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\.libs

[prompt]>
[prompt]> "f:\Install\pc064\LucasG\DependencyWalkerPolitistTexan\Version\Dependencies.exe" -modules "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd" | findstr "libopenblas"
[Environment] libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll : e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\.libs\libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll

附注 - 如[SO]:如何使用ctypes运行Fortran脚本?(@CristiFati的答案)所示,有时(原因未知)它不会显示exports(至少是GUI)。

2. Dependency Walker

虽然它已经不再维护了,但它是一个非常好的工具,在Dependencies之前是我能找到的最好的工具。我还用它来做[SO]:如何构建libjpeg 9b的DLL版本?(@CristiFati的答案)(在末尾某处)。
缺点是它将输出吐出到文件中,因此需要额外的步骤:

[prompt]>
[prompt]> :: Restore %PATH%
[prompt]> set PATH=%_PATH%

[prompt]>
[prompt]> dir /b

[prompt]>
[prompt]> :: Help not available in console (/? will open GUI)
[prompt]>
[prompt]> "c:\Install\pc064\Depends\DependencyWalkerPolitistTexan\Version\depends.exe" /c /ot:_mu0.txt "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd"

[prompt]> type _mu0.txt | findstr -i "libopenblas"
     [ ? ] LIBOPENBLAS.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.GFORTRAN-WIN_AMD64.DLL
[ ? ]  LIBOPENBLAS.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.GFORTRAN-WIN_AMD64.DLL                                       Error opening file. The system cannot find the file specified (2).

[prompt]>
[prompt]> set PATH=%_PATH%;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\.libs

[prompt]>
[prompt]> "c:\Install\pc064\Depends\DependencyWalkerPolitistTexan\Version\depends.exe" /c /ot:_mu1.txt "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd"

[prompt]> type _mu1.txt | findstr -i "libopenblas"
     [  6] e:\work\dev\venvs\py_pc064_03.09_test0\lib\site-packages\numpy\.libs\LIBOPENBLAS.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.GFORTRAN-WIN_AMD64.DLL
[  6]  e:\work\dev\venvs\py_pc064_03.09_test0\lib\site-packages\numpy\.libs\LIBOPENBLAS.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.GFORTRAN-WIN_AMD64.DLL  2022/11/30 14:57  2022/11/20 00:44  35,695,412  A      0x0220BC27     0x0220BC27     x64  Console    None        0x00000000622C0000  Unknown      0x01E88000    Not Loaded  N/A              N/A              0.0        2.30        4.0     5.2

3. [MS.Learn]: DUMPBIN 参考

VStudio 的一部分。我只列举它作为一个参考,因为它可以显示 .dll 的依赖项,但不能确定它们是否可以被加载(如果可以,从哪里加载):

[prompt]>
[prompt]> :: Restore %PATH%
[prompt]> set PATH=%_PATH%

[prompt]>
[prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul

[prompt]>
[prompt]> dumpbin /DEPENDENTS "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd"
Microsoft (R) COFF/PE Dumper Version 14.29.30147.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Lib\site-packages\numpy\core\_multiarray_umath.cp39-win_amd64.pyd

File Type: DLL

  Image has the following dependencies:

    libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll
    python39.dll
    KERNEL32.dll
    VCRUNTIME140.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-string-l1-1-0.dll
    api-ms-win-crt-environment-l1-1-0.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-convert-l1-1-0.dll
    api-ms-win-crt-time-l1-1-0.dll
    api-ms-win-crt-utility-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll

  Summary

       40000 .data
       18000 .pdata
       64000 .rdata
        3000 .reloc
        1000 .rsrc
      1F3000 .text

4. Nix仿真器

调用[Man7]: LDD(1)
我猜这可能是一个喜欢的选择,因为它倾向于Nix世界(在这种情况下这些事情更容易),而且您还提到了SSH连接。
我将以MSYS2为例,但其他工具(如Cygwin,也许是MinGW等)也可以实现同样的功能。

[cfati@cfati-5510-0:/e/Work/Dev/StackOverflow/q074877580]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[064bit prompt]>
[064bit prompt]> uname -a
MSYS_NT-10.0-19045 cfati-5510-0 3.4.3-dirty.x86_64 2022-12-19 20:20 UTC x86_64 Msys
[064bit prompt]>
[064bit prompt]> _PATH="${PATH}"
[064bit prompt]>
[064bit prompt]> ls "/e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/core/_multiarray_umath.cp39-win_amd64.pyd"
/e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/core/_multiarray_umath.cp39-win_amd64.pyd
[064bit prompt]>
[064bit prompt]> ldd "/e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/core/_multiarray_umath.cp39-win_amd64.pyd"
ldd: /e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/core/_multiarray_umath.cp39-win_amd64.pyd: Bad file descriptor
[064bit prompt]>
[064bit prompt]> # Change extension
[064bit prompt]> cp "/e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/core/_multiarray_umath.cp39-win_amd64.pyd" ./_mu.dll
[064bit prompt]> ls
_mu.dll  _mu0.txt  _mu1.txt
[064bit prompt]> file _mu.dll
_mu.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
[064bit prompt]>
[064bit prompt]> ldd _mu.dll
        ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ff8ba930000)
        KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ff8ba320000)
        KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ff8b8070000)
        msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ff8b8f40000)
        _mu.dll => /e/Work/Dev/StackOverflow/q074877580/_mu.dll (0x7ff86ab50000)
        ucrtbase.dll => /c/Windows/System32/ucrtbase.dll (0x7ff8b8840000)
        vcruntime140.dll => /c/Windows/System32/vcruntime140.dll (0x7ff8a0980000)
        libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll => not found
        python39.dll => not found
        api-ms-win-crt-math-l1-1-0.dll => not found
        api-ms-win-crt-heap-l1-1-0.dll => not found
        api-ms-win-crt-stdio-l1-1-0.dll => not found
        api-ms-win-crt-string-l1-1-0.dll => not found
        api-ms-win-crt-environment-l1-1-0.dll => not found
        api-ms-win-crt-runtime-l1-1-0.dll => not found
        api-ms-win-crt-convert-l1-1-0.dll => not found
        api-ms-win-crt-time-l1-1-0.dll => not found
        api-ms-win-crt-utility-l1-1-0.dll => not found
        api-ms-win-crt-locale-l1-1-0.dll => not found
[064bit prompt]>
[064bit prompt]> PATH="${_PATH}:/e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/.libs"
[064bit prompt]>
[064bit prompt]> ldd _mu.dll
        ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ff8ba930000)
        KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ff8ba320000)
        KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ff8b8070000)
        msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ff8b8f40000)
        _mu.dll => /e/Work/Dev/StackOverflow/q074877580/_mu.dll (0x7ff86ab50000)
        ucrtbase.dll => /c/Windows/System32/ucrtbase.dll (0x7ff8b8840000)
        vcruntime140.dll => /c/Windows/System32/vcruntime140.dll (0x7ff8a0980000)
        libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll => /e/Work/Dev/VEnvs/py_pc064_03.09_test0/Lib/site-packages/numpy/.libs/libopenblas.FB5AE2TYXYH2IJRDKGDGQ3XBKLKTF43H.gfortran-win_amd64.dll (0x622c0000)
        user32.dll => /c/Windows/System32/user32.dll (0x7ff8b92f0000)
        win32u.dll => /c/Windows/System32/win32u.dll (0x7ff8b8940000)
        gdi32.dll => /c/Windows/System32/gdi32.dll (0x7ff8b94a0000)
        gdi32full.dll => /c/Windows/System32/gdi32full.dll (0x7ff8b8400000)
        msvcp_win.dll => /c/Windows/System32/msvcp_win.dll (0x7ff8b8610000)
        python39.dll => not found
        api-ms-win-crt-math-l1-1-0.dll => not found
        api-ms-win-crt-heap-l1-1-0.dll => not found
        api-ms-win-crt-stdio-l1-1-0.dll => not found
        api-ms-win-crt-string-l1-1-0.dll => not found
        api-ms-win-crt-environment-l1-1-0.dll => not found
        api-ms-win-crt-runtime-l1-1-0.dll => not found
        api-ms-win-crt-convert-l1-1-0.dll => not found
        api-ms-win-crt-time-l1-1-0.dll => not found
        api-ms-win-crt-utility-l1-1-0.dll => not found
        api-ms-win-crt-locale-l1-1-0.dll => not found

当然,可能还有我不知道的更多工具(或者涉及到来自.NET的.dll文件)。

相关(或多或少):


1
谢谢,非常好的答案!我知道依赖于%PATH%,忘了提到它。Dependencies.exe似乎是这里最好的建议,再次感谢。 - Bruno Oliveira
这个回答甚至与我的问题无关,但是我还是点赞了,因为回答得太好了,哈哈。 - undefined
@WilliamBrochensquejunior:谢谢你,你能分享一下你的问题吗?也许我们可以改进来回答你的问题,或者可能有其他答案可以解决它(考虑到你的问题与此类似)。请注意,这个例子说明了调查这类问题的过程。 - undefined
我觉得我可以在类似的问题上找到解决办法,所以不是什么大问题!不管怎样,还是谢谢你。如果没有其他办法,我会创建一个关于这个问题的提问! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接