问题
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).
回答1:
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
.
回答2:
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;
}
来源:https://stackoverflow.com/questions/28421934/armadillo-matlab-mex-segfault