在 python 的 c 扩展中包括外部共享英特尔的 mkl 库

Posted

技术标签:

【中文标题】在 python 的 c 扩展中包括外部共享英特尔的 mkl 库【英文标题】:Including external shared intel's mkl library in c extension for python 【发布时间】:2016-06-16 00:06:38 【问题描述】:

我编写了一个 python c 扩展,它使用来自 Intel 的数学内核库 (mkl) 的例程。这是我第一次编写 c 扩展。我今天才知道。

编译的 c 扩展。但是当我在python中导入它时,它说未定义的符号,并且找不到在mkl中定义的函数。

如何在 python c 扩展中包含任何外部 c 库?

感谢您的帮助。

mkl_helper.c:

#include "Python.h"
#include "numpy/arrayobject.h"
#include "mkl.h"

static PyObject* test4 (PyObject *self, PyObject *args)

    // test4 (m, n,
    //        a, ja, ia,
    //        c, jc, ic)

    PyArrayObject *shape_array;
    PyArrayObject *a_array;   // csr_matrix.data
    PyArrayObject *ja_array;  // csr_matrix.indices
    PyArrayObject *ia_array;  // csr_matrix.indptr
    PyArrayObject *c_array;
    PyArrayObject *jc_array;
    PyArrayObject *ic_array;

    if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!", 
                            &PyArray_Type, &shape_array,
                            &PyArray_Type, &a_array,
                            &PyArray_Type, &ja_array,
                            &PyArray_Type, &ia_array,
                            &PyArray_Type, &c_array,
                            &PyArray_Type, &jc_array,
                            &PyArray_Type, &ic_array))
    
        return NULL;
    

    long  * ptr_int     = shape_array->data;
    int m               = ptr_int[0];
    int n               = ptr_int[1];
    int k               = n;

    float *  a_data_ptr =  a_array->data;
    float * ja_data_ptr = ja_array->data;
    float * ia_data_ptr = ia_array->data;
    float *  c_data_ptr =  c_array->data;
    float * jc_data_ptr = jc_array->data;
    float * ic_data_ptr = ic_array->data;

    char trans  = 'T';
    int sort    = 0;
    int nzmax   = n*n;
    int info    = -3;
    int request = 0;

    mkl_scsrmultcsr(&trans, &request, &sort,
       &m, &n, &k,
       a_data_ptr, ja_data_ptr, ia_data_ptr,
       a_data_ptr, ja_data_ptr, ia_data_ptr,
       c_data_ptr, jc_data_ptr, ic_data_ptr,
       &nzmax, &info);

    return PyInt_FromLong(info);



static struct PyMethodDef methods[] = 
    "test4", test4, METH_VARARGS, "test2(arr1)\n take a numpy array and return its shape as a tuple",
    NULL, NULL, 0, NULL
;

PyMODINIT_FUNC
initmkl_helper (void)

    (void)Py_InitModule("mkl_helper", methods);
    import_array();

setup.py:

from distutils.core import setup, Extension
import numpy as np

ext_modules = [ Extension('mkl_helper', sources = ['mkl_helper.c']) ]

setup(
        name = 'mkl_helper',
        version = '1.0',
        include_dirs = [np.get_include()], #Add Include path of numpy
        ext_modules = ext_modules
)

test.py:

import mkl_helper

test.py 运行结果:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: /home/rxu/local/lib/python2.7/site-packages/mkl_helper.so: undefined symbol: mkl_scsrmultcsr

2016 年 6 月 16 日更新:

这似乎很有用:

1.12。在https://docs.python.org/2/extending/extending.html 中为扩展模块提供 C API 表示,即使在另一个 c 扩展中包含一个 c 扩展,如果链接为共享库也会出现问题。所以,我想我必须将 mkl 链接为静态库?或者将 inlcude mkl.h 添加到 python.h 中?

但是,在 python 中(没有 c),我可以使用 ctypes.cdll.LoadLibrary("./mkl_rt.so") 加载 mkl 的共享库,然后使用共享库中的 c 函数没有问题(如here)。然而 Python/C api 不能在 c 中做同样的事情?

为了静态链接外部 c 库,setup.py 可能需要: 类 distutils.core.Extensions 中的额外对象 https://docs.python.org/2/distutils/apiref.html?highlight=include#distutils.ccompiler.CCompiler.add_include_dir

关于cython的相关问题没有答案:Combining Cython with MKL

这个似乎更有帮助:Python, ImportError: undefined symbol: g_utf8_skip

这个使用了已弃用的 dlopen:Undefined Symbol in C++ When Loading a Python Shared Library

【问题讨论】:

【参考方案1】:

oopcode 在Python, ImportError: undefined symbol: g_utf8_skip 中的回答有效。 通过以下方式改善了情况。

将c扩展导入python没有错误。 从 python 调用 c 扩展会出现以下错误: 英特尔 MKL 致命错误:无法加载 libmkl_mc.so 或 libmkl_def.so。

我记得当我使用 mkl 手动编译 numpy 时,site.cfg 文件要求提供库路径和英特尔 mkl 的包含路径。我想我还需要将库路径添加到 extra_link_args ......但这没有用。

像 here 一样,使用 anaconda 的人也有这个错误。 类似案例在英特尔论坛here。

这个***问题说extra_compile_args也是需要的:How to pass flag to gcc in Python setup.py script

setup.py

from distutils.core import setup, Extension
import numpy as np

extra_link_args=["-I", "(intel's dir)/intel/compilers_and_libraries_2016.3.210/linux/mkl/include", "-L", "(intel's dir)/intel/mkl/lib/intel64/libmkl_mc.so", "-mkl"] 
ext_modules = [ Extension('mkl_helper', sources = ['mkl_helper.c'], extra_link_args=extra_link_args) ]


setup(
        name = 'mkl_helper',
        version = '1.0',
        include_dirs = [np.get_include()], #Add Include path of numpy
        ext_modules = ext_modules
)

更新: 我终于让它像here一样工作了 但是 mkl 仍然只使用 12 个 cpu 中的一个。

【讨论】:

以上是关于在 python 的 c 扩展中包括外部共享英特尔的 mkl 库的主要内容,如果未能解决你的问题,请参考以下文章

在 c/c++ 中包括结构和编译

在 2 路频率/列联表中包括零频率

C#调用C/C++的dll,一个库中包括多个函数,每调用一个函数都要用DllImport加载吗?求大神

规则二:方案中包含扩展

Windows下Eclipse+PyDev安装Python开发环境

Python 中的 C++ 扩展“DLL 加载失败”