【问题标题】:Dll dependencies missing when using ctypes with fortran dll compiled with intel fortran compiler and linking to intel's mkl library将 ctypes 与使用 intel fortran 编译器编译的 fortran dll 一起使用并链接到 intel 的 mkl 库时缺少 Dll 依赖项
【发布时间】:2021-05-27 01:20:17
【问题描述】:

我在窗户下。 mkl_example.f中的fortran代码:

    subroutine matmultmkl(M1, M2, M3, M, N, K) bind(c, name='matmultmkl')
        !DEC$ ATTRIBUTES DLLEXPORT :: matmultmkl
        use iso_c_binding, only: c_float, c_int
    
        integer(c_int),intent(in) :: M, N, K
        real(c_float), intent(in) :: M1(M, N), M2(N, K)
        real(c_float), intent(out):: M3(M, K)

        CALL DGEMM('N','N',M,K,N,1.,M1,M,M2,N,0.,M3,M)
    
    end subroutine 

我使用以下批处理文件通过命令行(在我之前运行 compilervars.bat 的 cmd 窗口中)编译它:

@Echo off

setlocal ENABLEDELAYEDEXPANSION
SET "IFORT_INITIAL_FLAGS=-c -fpp"
SET "IFORT_OPTIMIZATION_FLAGS=/O3"

ifort %IFORT_OPTIMIZATION_FLAGS% %IFORT_INITIAL_FLAGS% /I"C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2020.4.311\windows\mkl\include" -o mkl_example.obj mkl_example.f
ifort -dll -o mylib.dll mkl_example.obj /link /LIBPATH:"C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2020.4.311\windows\mkl\lib\intel64_win" mkl_intel_lp64.lib mkl_intel_thread.lib mkl_core.lib libiomp5md.lib 

然后我运行以下python脚本mkl_example.py

from ctypes import *
import time

import os
os.add_dll_directory("C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_2020.4.311/windows/mkl/lib/intel64_win")
os.add_dll_directory("C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_2020.4.311/windows/compiler/lib/intel64_win")

import numpy as np

mylib = CDLL('./mylib.dll')

mylib.matmultmkl.argtypes = [ POINTER(c_float), 
                                POINTER(c_float), 
                                POINTER(c_float),
                                POINTER(c_int),
                                POINTER(c_int),
                                POINTER(c_int) ]
mylib.matmultmkl.restype = None
M=1000
N=1000
K=1000

a = np.empty((M,N), dtype=c_float)
b = np.empty((N,K), dtype=c_float)
c = np.empty((M,K), dtype=c_float)

a[:] = np.random.rand(M,N)
b[:] = np.random.rand(N,K)

# Fortran mkl call
start = time.time()
mylib.matmultmkl( a.ctypes.data_as(POINTER(c_float)), 
                    b.ctypes.data_as(POINTER(c_float)), 
                    c.ctypes.data_as(POINTER(c_float)), 
                    c_int(M), c_int(N), c_int(K) )
stop = time.time()
print(f"Fortran mkl \t {stop - start}s")

输出是:

Traceback (most recent call last):
  File "path\to\mkl_example.py", line 14, in <module>
    mylib = CDLL('./mylib.dll')
  File "C:\PYTHON\3\3.8.2_64bits\lib\ctypes\__init__.py", line 373, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: path\to\mylib.dll' (or one of its dependencies). Try using 
the full path with constructor syntax.

如果你删除所有 mkl 的东西并自己编写一个函数,mylib.dll 会在运行时由 python 找到。因此,在我链接到 mkl 的情况下,该消息并不意味着即使 mylib.dll 位于正确的位置,由于某些奇怪的原因在运行时找不到它,但确实找不到它的依赖项之一。

除了找到 all 依赖项并将它们放在 fortran dll 和 python 文件旁边的同一个文件夹中之外,我没有看到我能做什么。但如果这是唯一的方式,也许我更喜欢绝对退出。

【问题讨论】:

    标签: python windows fortran ctypes intel


    【解决方案1】:

    添加到 Python 脚本中的 DLL 搜索路径的路径用于包含编译器和 MKL 的静态库和导入库的目录,而不是运行时 DLL。

    (英特尔编译器的安装通常将编译器运行时安装在 Common files 目录中,并将其添加到系统搜索路径 - 因此编译器运行时 DLL 很可能通过该路径找到 - 但这不适用于MKL 运行​​时 DLL。)

    os.add_dll_directory 调用中使用正确的目录。它类似于(您需要检查您的安装)C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_xxxx\windows\redist\intel64_win\mkl。根据您的需要,与版本无关的符号链接目录也可能更合适。

    (在没有安装编译器的情况下部署到另一台机器需要一个关于如何部署依赖项的策略,但这是一个更大的话题。)

    【讨论】:

    • 当我从我的.bat 文件的第二个编译行添加所有包含.lib 的目录时,它确实“工作”了。然后发生了一些奇怪的事情:什么都没有。然后在 python 中,我将大小从 1000 更改为 100,然后它就起作用了。我怀疑dgemm 会触发 1000*1000 方阵乘积的分割失败,但不会触发 100*100 矩阵。这真的很奇怪。
    • 我针对上述评论问题创建了一个问题:stackoverflow.com/questions/66387002/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多