犰狳 + Matlab Mex 段错误

Armadillo + Matlab Mex segfault

我折腾了一整天,所以我想我的经验可能会让大家受益,请看下面我的回答。

我首先遇到了在 Matlab 中 运行 编译的 Mex 文件的问题,因为 Matlab 抱怨它无法打开共享库 libarmadillo。我 使用环境变量 LD_LIBRARY_PATHLD_RUN_PATH(osx 中的 DYLD_LIBRARY_PATHLYLD_RUN_PATH)。

然而,问题仍然存在,一个简单的测试文件会在 运行 时间发生段错误,即使完全相同的代码可以编译并且 运行 在 Matlab 之外(不是 Mex'd)很好。

段错误似乎是由 Matlab 在其捆绑的 LAPACK 和 BLAS 库中使用 64 位整数(long longint64_t)引起的。另一方面,犰狳默认使用 32 位整数(64 位平台上的常规 int,或 int32_t)。

有两种解决方法;第一个涉及强制 Matlab 改为 link 到系统库(使用 ints),第二个涉及更改 Armadillo 的配置文件以使用 BLAS 启用 long longs。我倾向于认为第一种比较靠谱,因为没有黑盒效应,但是也比较麻烦,需要手动安装,记住你的BLAS和LAPACK库的路径。

这两种解决方案都要求我停止使用 Armadillo 的共享库并linked/included 手动获取源代码。 为此,您必须简单地在您的系统上安装 LAPACK 和 BLAS(如果它们还没有,在 Ubuntu 中就是 libblas-devliblapack-dev),然后复制整个 includes 目录在某个合理的地方,例如 $HOME/.local/arma


解决方案 1:link访问系统库

在 matlab 控制台中,将环境变量 BLAS_VERSIONLAPACK_VERSION 设置为指向您系统的库。在我的例子中(Ubuntu 14.04,Matlab R2014b):

setenv('BLAS_VERSION','/usr/lib/libblas.so');
setenv('LAPACK_VERSION','/usr/lib/liblapack.so');

然后就可以正常编译了:

mex -compatibleArrayDims -outdir +mx -L/home/john/.local/arma -llapack -lblas -I/home/john/.local/arma test_arma.cpp

或者如果您在 includes/armadillo_bits/config.hpp 中定义标志 ARMA_64BIT_WORD,则可以删除选项 -compatibleArrayDims


解决方案 2:更改 Armadillo 的配置

第二种解决方案是在 Armadillo 的配置文件 includes/armadillo_bits/config.hpp 中取消注释标志 ARMA_BLAS_LONG_LONG。 Matlab 将 link 到其捆绑的 LAPACK 和 BLAS 库,但这次 Armadillo 不会出现段错误,因为它使用了正确的字长。和以前一样,如果你想删除 -compatibleArrayDims.

,你也可以取消注释 ARMA_64BIT_WORD

编译为

mex -larmadillo -DARMA_BLAS_LONG_LONG armaMex_demo2.cpp

(在 Matlab 中)

armaMex_demo2(rand(1))

没有段错误。

但是,用

编译
mex -larmadillo  armaMex_demo2.cpp

(在 Matlab 中)

armaMex_demo2(rand(1))

导致段错误。

在这里,armaMex_demo2.cpp是

/* ******************************************************************* */
// armaMex_demo2.cpp: Modified from armaMex_demo.cpp copyright Conrad Sanderson and George Yammine.
/* ******************************************************************* */
// Demonstration of how to connect Armadillo with Matlab mex functions.
// Version 0.2
// 
// Copyright (C) 2014 George Yammine
// Copyright (C) 2014 Conrad Sanderson
// 
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/////////////////////////////
#include "armaMex.hpp"


void
mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  /* 
     Input:   X (real matrix)
     Output:  Eigenvalues of X X.T
  */


  if (nrhs != 1)
    mexErrMsgTxt("Incorrect number of input arguments.");


  // Check matrix is real
  if( (mxGetClassID(prhs[0]) != mxDOUBLE_CLASS) || mxIsComplex(prhs[0]))
    mexErrMsgTxt("Input must be double and not complex.");


  // Create matrix X from the first argument.
  arma::mat X = armaGetPr(prhs[0],true);


  // Run an arma function  (eig_sym)
  arma::vec eigvals(X.n_rows);
  if(not arma::eig_sym(eigvals, X*X.t()))
    mexErrMsgTxt("arma::eig_sym failed.");    


  // return result to matlab
  plhs[0] = armaCreateMxMatrix(eigvals.n_elem, 1);
  armaSetPr(plhs[0], eigvals);

  return;
}