Я пишу физическое моделирование на C с использованием библиотеки Intel Math Kernel Library (MKL) и хочу вызвать его непосредственно из кода Python с помощью cython. Сама компиляция cython работает (программа работает без ошибок, если MKL не включен в пример), и если я скомпилирую свой код C непосредственно в gcc с помощью
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. Но если я сейчас попытаюсь скомпилировать тот же код с помощью 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
), чтобы выполнить привязку MKL за пределами cython, а затем просто связать с ней, но после того, как я поиграл с этой библиотекой в LD_LIBRARY_PATH
, я получил такое же поведение снова.
Есть идеи, как правильно установить связь?
Я могу поменять используемую функцию cblas_
на другую (например, cblas_drot
и еще несколько) и получить ту же ошибку.
Я прочитал несколько других вопросов (многие из них касаются MKL в anaconda, мой MKL устанавливается вручную в /opt
, как показано выше), включая this, который пытается использовать MKL в java и получает ту же ошибку. Я могу воспроизвести те же результаты относительно операторов 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)
используемые файлы
setup.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
бар.с
#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)
extra_link_args
может работать не так, как ожидалось (хотя не уверен, что это так, но может быть). Лучше использовать аргументыlibrary_dirs
иlibraries
, см. docs.python .org/3/distutils/ - person ead   schedule 14.02.2021-Wl,--no-as-needed
). Можете ли вы подтвердить, что результат соответствует вашим ожиданиям? Это дает ту же ошибку (как я и ожидал, потому что ранее я также пробовал полностью внешнюю компиляцию в качестве общей библиотеки) - person schetefan24   schedule 14.02.2021