My current MEX file is properly compiling, however, I would like to create let's say several MEX files:
- mex_a.cpp
- mex_b.cpp
- mex_c.cpp
At this moment, mex_a.cpp contains the typical function definition:
class MexFunction : public matlab::mex::Function {
private:
// Get pointer to engine
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
// Get array factory
std::shared_ptr<matlab::data::ArrayFactory> factoryPtr;
private:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) override
{
try
{
// Parse inputs..
mex_aux->mex_common_function(...)
// Parse outputs..
}
catch (int)
{
std::fprintf(stdout, "ERROR: Something unexpected happened...");
}
}
In mex_aux, we can find the definition and implementation of mex_common_function. The purpose of this object is to be used by mex_a.cpp, mex_b.cpp and mex_c.cpp, basically what a common library do.
My findings are:
- If mex_common_function is static, everything works.
- Otherwise, it doesn't work while using matlab objects.
The .hpp file looks like:
#pragma once
// Include system libraries
# include <string>
# include <utility>
// MATLAB stuff
#include "mex.hpp"
class mex_aux
{
public:
// Constructor
mex_aux() = default;
// Destructor
~mex_aux() = default;
private:
// Get pointer to engine
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr;
// Get array factory
std::shared_ptr<matlab::data::ArrayFactory> factoryPtr;
public:
// Setters:
void set_matlab_ptr(std::shared_ptr<matlab::engine::MATLABEngine>& matlab_ptr) {this->matlabPtr = matlab_ptr; }
void set_factory_ptr(std::shared_ptr<matlab::data::ArrayFactory>& factory_ptr) {this->factoryPtr = factory_ptr; }
public:
// The used function, if this one is set as static (hence not using members of the class) it works.
void mex_common_function();
What I am doing now, and hence getting the following error in MATLAB (not during building time) is:
- Setting
matlabPtras an internal pointer inmex_aux. - Same for
factoryPtr.
This both from the main mex function file (i.e., mex_a.cpp) after building mex_aux, the setters are used.
Error in MATLAB:
Invalid MEX-file
'/path/to/mex/mexfunction.mexa64':
/path/to/external/libextern.so:
undefined symbol:
_ZN6matlab6engine12MATLABEngine5fevalERKNSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEiRKSt6vectorINS_4data5ArrayESaISC_EERKSt10shared_ptrISt15basic_streambufIDsS5_EESM_
Error in mex_vsod (line 50)
b(:,:,i) = mexfunction(...);
My CMakeLists.txt:
# MEX AUX Library
set(LIBRARY_MEX_AUX "mex_aux")
add_library(${LIBRARY_MEX_AUX} SHARED
src/core/tools/mex_aux.cpp)
target_link_libraries(${LIBRARY_MEX_AUX}
${Matlab_MEX_LIBRARY}
${Matlab_MX_LIBRARY})
set_target_properties(${LIBRARY_MEX_AUX} PROPERTIES
COMPILE_FLAGS "-fPIC"
LINK_FLAGS "-Wl,-rpath,./") # To use relative paths in shared libs
# MEX FILES
if (BUILD_WITH_MATLAB)
# MEX functions files
matlab_add_mex(NAME mex_vsaod
SRC src/main/mex_cpp/mex_a.cpp
LINK_TO ${LIBRARY_target1} ... ${LIBRARY_targetN} ${LIBRARY_MEX_AUX})
endif ()
I guess something wrong is happening within the memory due to a pointer from mex_aux pointing possibly to an un-accessible place in memory (only scoped to the mex file -mex_a.cpp?-)...
Can someone give me a clue? I would really appreciate it.
I have used a shared library in MEX-files where multiple MEX-files need access to the same C++ object. You then create the object in the shared library, and can use it in all the MEX-files that link to it.
But if the shared library needs to call MATLAB functions, it becomes much more complicated to build. I would keep the MATLAB interaction outside the shared library.
Given your use case, "they are mostly conversion functions, like
std::vector<doubles>tomatlab::arrays", I would either make this a header-only library or a static library. You don't need to share a C++ object across MEX-files, you don't really need this to be a shared library. And the conversion functions would typically not be large, complex code that unnecessarily bloats the MEX-files by linking them statically.However, if you really want to build a shared library that calls MATLAB, then you need to build it like you would a MEX-file, except it doesn't have the standard MEX-file entry point or the MEX-file extension. But you do need to link all the same MATLAB libraries, and set all the same preprocessor defines.
When you call
matlab_add_mexin your CMake file, you run this CMake code. This shows the complexity of building a MEX-file. If you want to write a CMake script that works for all versions of MATLAB and for all platforms, you'll have to basically copy over most of what that function does. But you're using the C++ API, so follow only the paths that apply to MATLAB 9.4 (R2018a) and newer. This includes all the bits that are run whenMatlab_HAS_CPP_APIandMatlab_DATAARRAY_LIBRARYare set.It would look something like this (not tested!):
Note that this code might change for future versions of MATLAB, they keep changing how one builds MEX-files. So it really is much more convenient to link your conversion functions statically.
The
-fPICoption you add is already handled by CMake when you build aSHAREDlibrary. But you'd have to explicitly add it to a static library that you intend to link into a shared library, at least on Linux.