使用Armadillo和MKL库构建x86(win32)

Building with Armadillo and MKL libraries for x86 (win32)

本文关键字:x86 win32 构建 Armadillo MKL 使用      更新时间:2023-10-16

在Visual Studio C++2017中,根据x64相应指南中描述的步骤(以及相应的x64->x86更改),基于armadillo头文件的某些代码部分显示了链接错误。

我已经从他们的官方网站下载了Armadillo最新的稳定版本(Armadillo-9200.6.tar)。我还从英特尔网站下载了在英特尔i5处理器上运行的64位WIndows 10的MKL库。我在Visual Studio 2017中将它们链接如下:

Project>Properties>Configuration Properties>VC++ Directories>Include Directories:(注意:前缀为星号()的行包含在armadillo设置中*)

* C:Program Files (x86)Microsoft Visual StudioSharedarmadillo-9.200.6include
* C:Program Files (x86)IntelSWToolscompilers_and_libraries_2019.1.144windowsmklinclude
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.16.27023include
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.16.27023atlmfcinclude
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCAuxiliaryVSinclude
C:Program Files (x86)Windows Kits10Include10.0.17763.0ucrt
C:Program Files (x86)Windows Kits10Include10.0.17763.0um
C:Program Files (x86)Windows Kits10Include10.0.17763.0shared
C:Program Files (x86)Windows Kits10Include10.0.17763.0winrt
C:Program Files (x86)Windows Kits10Include10.0.17763.0cppwinrt
C:Program Files (x86)Windows KitsNETFXSDK4.6.1Includeum

Project>Properties>Configuration Properties>VC++ Directories>Library Directories:(注意:前缀为星号()的行包含在armadillo设置中*)

* C:Program Files (x86)Microsoft Visual StudioSharedarmadillo-9.200.6exampleslib_win64
* C:Program Files (x86)IntelSWToolscompilers_and_libraries_2019.1.144windowsmkllibintel64_win
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.16.27023libx86
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.16.27023atlmfclibx86
C:Program Files (x86)Microsoft Visual Studio2017CommunityVCAuxiliaryVSlibx86
C:Program Files (x86)Windows Kits10lib10.0.17763.0ucrtx86
C:Program Files (x86)Windows Kits10lib10.0.17763.0umx86
C:Program Files (x86)Windows KitsNETFXSDK4.6.1libumx86
C:Program Files (x86)Windows KitsNETFXSDK4.6.1Libumx86

Project>Properties>Configuration Properties>C/C++>General>Additional Include Directories:

* C:Program Files (x86)IntelSWToolscompilers_and_libraries_2019.1.144windowsmklinclude
* C:Program Files (x86)Microsoft Visual StudioSharedarmadillo-9.200.6include
C:Python36_86include

Project>Properties>Configuration Properties>Linker>General>Additional Library Directories:

* C:Program Files (x86)IntelSWToolscompilers_and_libraries_2019.1.144windowsmkllibia32_win
C:Python36_86libs

Project>Properties>Configuration Properties>Linker>Input>Additional Dependencies:(注意:前缀为星号()的行包含在armadillo设置中*)

* mkl_core.lib
* mkl_sequential.lib
* mkl_intel_lp64.lib
* lapack_win64_MT.lib
* blas_win64_MT.lib

我正在开发C++模块作为Python的扩展,因此我使用Win32的目标平台。幸运的是,armadillo代码的某些部分工作正常,而对于一些部分,它在问题声明中显示了如下所示的错误。这是我正在尝试构建的代码。它基本上是导入numpy数组,将它们相乘并将其作为Python对象返回。我正在做两次试验。试验1:使用三个for循环将其正常相乘(此处对此进行了评论),这是成功的。试验2使用了armadillo(错误来源的行通过注释指示)。代码为:

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <Python.h>
#include <Windows.h>
#include <cmath>
#include <vector>
#include <string>
#include <iostream>
#include <armadillo>
#define PyTuple_GET_ITEM PyTuple_GetItem
#define PyTuple_GET_SIZE PyTuple_Size
#define PyArray_FLOAT NPY_FLOAT
#include <numpy/arrayobject.h>
using namespace std;
using namespace arma;
//Taking two numpy array as arguments, multiplying the two numpy arrays and
// returning it back as python object
static PyArrayObject *mmult(PyObject *self, PyObject *args)
{
PyObject *vec1, *vec2;  
(PyArg_ParseTuple(args, "OO", &vec1, &vec2));
PyArrayObject *cvec1, *cvec2;
cvec1 = (PyArrayObject*) PyArray_FROM_OTF(vec1, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
cvec2 = (PyArrayObject*) PyArray_FROM_OTF(vec2, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
npy_intp *shape1 = PyArray_DIMS(cvec1);
npy_intp *shape2 = PyArray_DIMS(cvec2);
npy_intp shape3[2] = { shape1[0], shape2[1] };
PyArray_Descr* cvec3_type = PyArray_DescrFromType(NPY_DOUBLE);
PyArrayObject* cvec3 = (PyArrayObject *) PyArray_Zeros(2, shape3, cvec3_type,0);
double *v1, *v2, *v3;
v1 = (double*)PyArray_DATA(cvec1);
v2 = (double*)PyArray_DATA(cvec2);
v3 = (double*)PyArray_DATA(cvec3);

/* TRIAL 1 : SUCCESSFUL
for (int i = 0; i < shape1[0]; i++) {
for (int j = 0; j < shape2[1]; j++) {
for (int k = 0; k < shape2[0]; k++) {
v3[shape3[1]*i+j] += v1[shape1[1] * i + k] *v2[shape2[1] * k + j];
}
}
}
*/
//TIRAL 2: Wih Armadillo
arma::Mat<double> A1(shape1[0], shape1[1]);  //Successful
arma::Mat<double> A2(shape2[0], shape2[1]);
arma::Mat<double> A3(shape1[0], shape2[1]);
for (int i = 0; i < shape1[0]; i++) {
for (int j = 0; j < shape1[1]; j++) {   
A1(i, j) = v1[shape1[1] * i + j];   //Successful
}
}
for (int i = 0; i < shape2[0]; i++) {
for (int j = 0; j < shape2[1]; j++) {  //Successful
A2(i, j) = v2[shape2[1] * i + j];
}
}
A3 = A1 * A2;  // -----> This is the line that is creating the errors
for (int i = 0; i < shape1[0]; i++) {
for (int j = 0; j < shape2[1]; j++) {
v3[shape3[1] * i + j] = A3(i, j);
}
}

// This piece of the code also do not work with armadillo. I took this from a demo code.
// Create a 4x4 random matrix and print it on the screen
arma::Mat<double> A = arma::randu(4, 4);
std::cout << "A:n" << A << "n";
// Multiply A with his transpose:
std::cout << "A * A.t() =n";
std::cout << A * A.t() << "n";
return cvec3;
}
//Structure: Defines how C++ function is presented to Python
static PyMethodDef mhps_methods[] = {
{ "mmult", (PyCFunction)mmult, METH_VARARGS, nullptr },
{ nullptr, nullptr, 0, nullptr }
};
//Structure: Defines module as you want it to be referred to in your Python code.
static PyModuleDef mhps_module = {
PyModuleDef_HEAD_INIT,
"mhps",
"faster codes for research modules",
0,
mhps_methods
};
//Method: Python calls this method when it loads the module using "import mhps"
PyMODINIT_FUNC PyInit_mhps() {
import_array();
return PyModule_Create(&mhps_module);
}

这是正在生成的错误:

module1.obj : error LNK2001: unresolved external symbol _sposv_
module1.obj : error LNK2001: unresolved external symbol _cgemv_
module1.obj : error LNK2001: unresolved external symbol _sdot_
module1.obj : error LNK2001: unresolved external symbol _sgemv_
module1.obj : error LNK2001: unresolved external symbol _zgemv_
module1.obj : error LNK2001: unresolved external symbol _dgemm_
module1.obj : error LNK2001: unresolved external symbol _sgesv_
module1.obj : error LNK2001: unresolved external symbol _zgesv_
module1.obj : error LNK2001: unresolved external symbol _sgemm_
module1.obj : error LNK2001: unresolved external symbol _dposv_
module1.obj : error LNK2001: unresolved external symbol _dgemv_
module1.obj : error LNK2001: unresolved external symbol _zposv_
module1.obj : error LNK2001: unresolved external symbol _cposv_
module1.obj : error LNK2001: unresolved external symbol _cgemm_
module1.obj : error LNK2001: unresolved external symbol _dsyrk_
module1.obj : error LNK2001: unresolved external symbol _ssyrk_
module1.obj : error LNK2001: unresolved external symbol _ddot_
module1.obj : error LNK2001: unresolved external symbol _zgemm_
module1.obj : error LNK2001: unresolved external symbol _dgesv_
module1.obj : error LNK2001: unresolved external symbol _cgesv_

在以下位置输入输入时,我犯了一个小错误:

Project>Properties>Configuration Properties>Linker>Input>Additional Dependencies:

mkl_intel_c.lib
mkl_sequential.lib
mkl_core.lib

我完全用上面的文件名替换了它。它实际上是mkl文件夹中32位文件夹的库中的文件。根据这篇题为"Armadillo入门——Windows、Mac和Linux上的C++线性代数库"的文章的说明,作者认为大多数人都会将其用于64位,因此没有指定链接器输入列表中要包含的特定文件。