我当前的 MEX 文件正在正确编译,但是,我想创建几个 MEX 文件:
此时,mex_a.cpp 包含了典型的函数定义:
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...");
}
}
在
mex_aux
中,我们可以找到mex_common_function
的定义和实现。该对象的用途是供 mex_a.cpp、mex_b.cpp 和 mex_c.cpp 使用,基本上就是通用库的用途。
我的发现是:
.hpp 文件如下所示:
#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();
我现在正在做的事情,因此在 MATLAB 中出现以下错误(不是在构建期间):
matlabPtr
设置为 mex_aux
中的内部指针。factoryPtr
。这两者都来自构建后的主 mex 函数文件(即 mex_a.cpp)
mex_aux
,使用了设置器。
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(...);
我的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 ()
我猜想内存中发生了一些错误,因为来自
mex_aux
的指针可能指向内存中不可访问的位置(仅作用于 mex 文件 -mex_a.cpp?-)...
有人可以给我线索吗?我真的很感激。
我在 MEX 文件中使用了共享库,其中多个 MEX 文件需要访问同一个 C++ 对象。然后,您在共享库中创建该对象,并可以在链接到它的所有 MEX 文件中使用它。
但是如果共享库需要调用 MATLAB 函数,那么构建起来就会变得更加复杂。我会将 MATLAB 交互保留在共享库之外。
考虑到您的用例,“它们主要是转换函数,例如
std::vector<doubles>
到 matlab::arrays
”,我要么将其设为仅标头库,要么设为静态库。您不需要在 MEX 文件之间共享 C++ 对象,您实际上不需要将其作为共享库。而且转换函数通常不会是大型、复杂的代码,这些代码会通过静态链接来不必要地使 MEX 文件膨胀。
但是,如果您确实想要构建一个调用 MATLAB 的共享库,那么您需要像构建 MEX 文件一样构建它,只是它没有标准的 MEX 文件入口点或 MEX 文件扩展名。但您确实需要链接所有相同的 MATLAB 库,并设置所有相同的预处理器定义。
当您在 CMake 文件中调用
matlab_add_mex
时,您将运行 此 CMake 代码。这显示了构建 MEX 文件的复杂性。如果您想编写适用于所有版本的 MATLAB 和所有平台的 CMake 脚本,您必须基本上复制该函数的大部分功能。但您使用的是 C++ API,因此请仅遵循适用于 MATLAB 9.4 (R2018a) 及更高版本的路径。这包括设置 Matlab_HAS_CPP_API
和 Matlab_DATAARRAY_LIBRARY
时运行的所有位。
它看起来像这样(未经测试!):
add_library(${LIBRARY_MEX_AUX} SHARED
src/core/tools/mex_aux.cpp)
"${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp"
)
target_include_directories(${LIBRARY_MEX_AUX} SYSTEM PRIVATE ${Matlab_INCLUDE_DIRS})
target_link_libraries(${LIBRARY_MEX_AUX}
${Matlab_ENGINE_LIBRARY}
${Matlab_DATAARRAY_LIBRARY}
${Matlab_MEX_LIBRARY}
${Matlab_MX_LIBRARY}
)
target_compile_definitions(${LIBRARY_MEX_AUX} PRIVATE
"MATLAB_DEFAULT_RELEASE=R2018a"
MATLAB_MEX_FILE
)
if(WIN32)
set_property(TARGET ${LIBRARY_MEX_AUX} PROPERTY
DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)")
# (this is the same as `target_compile_definitions`, not sure why the CMake script uses this syntax)
else()
target_compile_options(${LIBRARY_MEX_AUX} PRIVATE "-fvisibility=default")
if(NOT APPLE) # Linux
# not sure if this is necessary?
target_compile_options(${LIBRARY_MEX_AUX} PRIVATE "-pthread")
endif()
endif()
请注意,此代码可能会针对 MATLAB 的未来版本而更改,它们会不断更改构建 MEX 文件的方式。因此,静态链接转换函数确实要方便得多。
当您构建
-fPIC
库时,您添加的 SHARED
选项已由 CMake 处理。但是您必须将其显式添加到您打算链接到共享库的静态库中,至少在 Linux 上是这样。