cython - 在 cython 中使用 MKL 失败,在来自 MKL 的共享对象中有未定义的符号,但直接执行没问题
问题描述
我正在使用 Intel Math Kernel Library (MKL) 在 C 中编写物理模拟,并希望使用 cython 从 python 代码中直接调用它。cython 编译本身可以工作(如果示例中不包含 MKL,则程序运行无错误)并且如果我直接在 gcc 中编译我的 C 代码
gcc -O3 -Wall -m64 -I"${MKLROOT}/include" bar.c -L${MKLROOT}/lib/intel64 -Wl,--no-as-needed -lmkl_intel_lp64 -lmkl_sequential -lmkl_core -lpthread -lm -ldl
它运作良好。编译器标志由MKL Link line Advisor生成。但是如果我现在尝试用 cython 编译相同的代码,我会收到错误消息
INTEL MKL ERROR: /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_avx2.so.1: undefined symbol: mkl_sparse_optimize_bsr_trsm_i8. Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so.1 or libmkl_def.so.1.
我还尝试将我的程序(没有主程序)编译到一个共享库.so
(LD_LIBRARY_PATH
知道如何使链接正确吗?
我可以将使用过的cblas_
功能换成不同的功能(例如cblas_drot
,还有一些尝试过的功能)并得到相同的错误。
我已经阅读了很多其他问题(许多关于 anaconda 中的 MKL,我的 MKL 是手动安装的,/opt
如上面的路径所示),包括这个试图在 java 中使用 MKL 并得到相同错误的问题。我可以重现关于nm
语句的相同结果(在 中未定义libmkl_avx2.so.1
,但在 中定义libmkl_gnu_thread.so
),但我未能将该问题的答案应用于我的问题。如果我尝试-lmkl_gnu_thread
在下面显示的setup.py
脚本中添加,我会得到不同的未实现的依赖项,通过还包括-fopenmp
返回到旧错误来修复...
更多信息和使用的文件
LD_LIBRARY_PATH=/opt/intel/oneapi/mkl/latest/lib/intel64:/opt/intel/oneapi/compiler/2021.1.1/linux/lib:/opt/intel/oneapi/compiler/2021.1.1/linux/lib/x64:/opt/intel/oneapi/compiler/2021.1.1/linux/lib/emu:/opt/intel/oneapi/compiler/2021.1.1/linux/compiler/lib/intel64_lin:/opt/intel/oneapi/compiler/2021.1.1/linux/compiler/lib:/opt/intel/oneapi/tbb/2021.1.1/env/../lib/intel64/gcc4.8
(由 mkl setvars 脚本设置,由 获得echo $LD_LIBRARY_PATH
)python 可能对这个变量做一些奇怪的事情吗?
readelf -d $MKLROOT/lib/intel64/libmkl_avx2.so.1 | grep NEEDED 0x0000000000000001 (NEEDED)
返回Shared library: [libdl.so.2]
,表明它声称只依赖于libdl
(我没有找到我从哪里得到该命令的问题,但它也是这个主题,只是文件名中缺少 .1)
用过的文件
安装程序.py
(包含第二个版本作为命令,可以像这样运行)
from Cython.Distutils import build_ext
#from Cython.Build import cythonize
from distutils.extension import Extension
from distutils.core import setup
import numpy
extensions = [
Extension("foo", ["foo.pyx"],
include_dirs=[numpy.get_include()],
extra_compile_args=["-Wall", "-m64", "-I\"${MKLROOT}/include\""],
extra_link_args=["-fopenmp", "-L${MKLROOT}/lib/intel64", "-Wl,--no-as-needed", "-lmkl_gnu_thread", "-lmkl_intel_lp64",
"-lmkl_sequential", "-lmkl_core", "-lpthread", "-lm", "-ldl"])
]
for e in extensions:
e.cython_directives = {'language_level': "3"} #all are Python-3
# produce the same behaviour, first:
setup(ext_modules=cythonize(extensions))
#second
#setup(ext_modules=cythonize(extensions),
# cmdclass = {'build_ext':build_ext})
与
python setup.py build_ext --inplace
根据评论,编辑另一个更好地使用关键字的版本。它给出了同样的错误。
from Cython.Build import cythonize
from distutils.extension import Extension
from distutils.core import setup
import numpy
extensions = [
Extension("foo", ["foo.pyx"],
include_dirs=[numpy.get_include(), "\"${MKLROOT}/include\""],
libraries=["mkl_intel_lp64", "mkl_sequential", "mkl_core", "pthread", "m", "dl"],
library_dirs=["${MKLROOT}/lib/intel64"],
extra_compile_args=["-Wall", "-m64"],
extra_link_args=["-Wl,--no-as-needed", ])
]
for e in extensions:
e.cython_directives = {'language_level': "3"} #all are Python-3
setup(ext_modules=cythonize(extensions))
foo.pyx
cimport numpy as np
import numpy as np
import ctypes
cdef extern from "bar.c":
void double_elements(int n, double* vec_y)
def func(np.ndarray[np.double_t, ndim=1] y not None):
double_elements(<int> y.size//2, <double*> <size_t> y.__array_interface__['data'][0])
return y
酒吧.c
#include <mkl.h>
#include <stdio.h>
void double_elements(int n,
double* x) {
cblas_dscal(n, 2., x, 1);
}
#ifndef PY_VERSION_HEX // compile the main only, if not using cython
int main() {
double x[2] = {1., 2.};
double_elements(2, x);
printf("%g %g\n", x[0], x[1]);
return 0;
}
#endif
运行.py
(用于测试,比较无聊,只调用函数)
import numpy as np
import foo
x = np.array([1., 2.])
y = foo.func(x)
print(x)
print(y)
解决方案
我已经通过使用 MKL 的静态链接解决了这个问题。因为我也未能在 setup.py 脚本中应用来自静态链接(它使用组)的所有命令,所以我已经切换到完全自己编译它
gcc -O3 -Wall -m64 -I"${MKLROOT}/include" -c bar.c -o build/bar.o
cythonize foo.pyx
# exchange /path/to/numpy/ by value given by numpy.get_include()
gcc -Wall -O2 -fstack-protector-strong -fwrapv -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIC -I/path/to/numpy/core/include -I/usr/include/python3.8 -c foo.c -o build/foo.o -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
gcc -shared build/foo.o build/bar.o -o foo.cpython-38-x86_64-linux-gnu.so -Wl,--start-group ${MKLROOT}/lib/intel64/libmkl_intel_lp64.a ${MKLROOT}/lib/intel64/libmkl_sequential.a ${MKLROOT}/lib/intel64/libmkl_core.a -Wl,--end-group -lpthread -lm -ldl
这对应于安装脚本完成的编译步骤(不检查更改日期)并删除了一些编译标志(它使用了许多重复项)。
推荐阅读
- php - 为什么我收到所有 Stripe Webhook 请求的错误 401?
- flutter - 容器性能对比 应用程序中的自定义画家可能大于 100 万个正方形
- android - Android 应用程序抛出 java.lang.NoSuchMethodError:调用 setStateDescription 方法时没有超级方法
- css - Vue 中未使用 vue.config.js 加载的全局样式表
- r - 循环创建栅格
- google-cloud-platform - Cloud Run 缩减到零对长时间计算作业或外部 API 请求有何影响?
- python - 如何在centos 8上静态编译python?
- javascript - reCAPTCHA:JavaScript 方法不适用于属性
- rust - 是否可以从将引用作为参数的 rust dll 导出函数
- reactjs - 在 React.js 中使用 new Array() 命令。将 typeof() 应用于变量时,结果是“对象”