使用命令行发现丢失的模块(“DLL 加载失败”错误)

Bru*_*ira 5 python windows dll pyd

在 Windows 上,当我们尝试导入一个文件,但找不到所依赖的.pydDLL 时,我们会得到以下回溯:.pyd

Traceback (most recent call last):
  ...
ImportError: DLL load failed: The specified module could not be found.
Run Code Online (Sandbox Code Playgroud)

发生这种情况时,通常必须求助于依赖关系等图形工具来找出丢失模块的名称。

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

上下文:我们经常在 CI 中遇到此错误,通过 SSH 登录来查找丢失的模块名称会更容易,而不是通过 GUI 登录。

Cri*_*ati 4

首先,我们选择一个具体的示例:NumPy_multiarray_umath*.pyd(来自Python 3.9 ( pc064 ))。请注意,我将重用此控制台:

[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%
Run Code Online (Sandbox Code Playgroud)

为了使事情尽可能通用,该.pyd依赖于自定义.dll ( OpenBLAS ):

图像0

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

图像1

请注意从属.dll 的加载位置(我们的(选定的).pyd下面 2 行)。

现在,回到问题:有很多工具可以做到这一点。
但值得一提的是,无论您使用什么工具,都将(很可能)依赖于PATH环境变量内容(在第一个图像中,未找到依赖的.dll (和其他))。有关.dll的更多详细信息,请检查[MS.Learn]:动态链接库搜索顺序

请注意,由于(某些)工具会生成大量输出,因此我将对其进行过滤(使用FindStr ( Grep ) 等命令),仅显示相关部分,以避免用垃圾填充答案。

1. [GitHub]: lucasg/依赖项

除了您提到的GUI应用程序 ( DependencyGui.exe ) 之外,它旁边还有一个命令行工具:Dependency.exe

[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%
Run Code Online (Sandbox Code Playgroud)

旁注 - 如[SO]: How to run a fortran skript with ctypes?中所示 (@CristiFati 的回答),有时(出于某种我不知道的原因)它不显示导出至少是GUI)

2.依赖步行者

虽然它不再维护,但它是一个非常好的工具,在依赖项之前它是我能找到的最好的工具。我也将它用于[SO]:How to build a DLL version of libjpeg 9b? (@CristiFati 的回答)(在最后的某个地方)。
缺点是它将输出吐入文件中,因此需要一个额外的步骤:

[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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

4.Nix模拟器

调用[Man7]: LDD(1)
我想这可能是一个最喜欢的,因为它倾向于Nix世界(其中此类事情更容易)并且您还提到了SSH连接。
我将以MSYS2为例,但其他人也可以实现同样的效果(Cygwin,也许MinGW,...)。

[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
Run Code Online (Sandbox Code Playgroud)

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

相关(或多或少):