简体   繁体   中英

Armadillo + Matlab Mex segfault

I fiddled with this the whole day, so I thought I might make everyone benefit from my experience, please see my answer below.

I first had a problem with running a compiled Mex file within Matlab, because Matlab complained that it couldn't open the shared library libarmadillo . I solved this using the environment variables LD_LIBRARY_PATH and LD_RUN_PATH ( DYLD_LIBRARY_PATH and LYLD_RUN_PATH in osx).

The problem remained however, that a simple test file would segfault at runtime even though the exact same code would compile and run fine outside Matlab (not Mex'd).

The segfault seems to be caused by the fact that Matlab uses 64bits integers ( long long or int64_t ) in its bundled LAPACK and BLAS libraries. Armadillo on the other hand, uses 32bits integers (regular int on a 64bits platform, or int32_t ) by default.

There are two solutions; the first one involves forcing Matlab to link to the system's libraries instead (which use int s), the second involves changing Armadillo's config file to enable long long s with BLAS. I tend to think that the first is more reliable, because there is no black-box effect, but it's also more troublesome, because you need to manually install and remember the path of your BLAS and LAPACK libs.

Both solutions required that I stopped using Armadillo's shared libraries and linked/included manually the sources. To do this, you must simply install LAPACK and BLAS on your system (if they are not already there, in Ubuntu that's libblas-dev and liblapack-dev ), and copy the entire includes directory somewhere sensible like in $HOME/.local/arma for example.


Solution 1: linking to system's libraries

From the matlab console, set the environment variables BLAS_VERSION and LAPACK_VERSION to point to your system's libraries. In my case (Ubuntu 14.04, Matlab R2014b):

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

You can then compile normally:

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

or if you define the flag ARMA_64BIT_WORD in includes/armadillo_bits/config.hpp , you can drop the option -compatibleArrayDims .


Solution 2: changing Armadillo's config

The second solution involves uncommenting the flag ARMA_BLAS_LONG_LONG in Armadillo's config file includes/armadillo_bits/config.hpp . Matlab will link to its bundled LAPACK and BLAS libraries, but this time Armadillo won't segfault because it's using the right word-size. Same than before, you can also uncomment ARMA_64BIT_WORD if you want to drop the -compatibleArrayDims .

Compiled with

mex -larmadillo -DARMA_BLAS_LONG_LONG armaMex_demo2.cpp

(In Matlab)

armaMex_demo2(rand(1))

works without segfault.

However, compiled with

mex -larmadillo  armaMex_demo2.cpp

(In Matlab)

armaMex_demo2(rand(1))

causes a segfault.

Here, armaMex_demo2.cpp is

/* ******************************************************************* */
// 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM