使用自定义 C++ 库中的 MATLAB 对象供 MEX 函数使用

问题描述 投票:0回答:1

我当前的 MEX 文件正在正确编译,但是,我想创建几个 MEX 文件:

  • mex_a.cpp
  • mex_b.cpp
  • mex_c.cpp

此时,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 使用,基本上就是通用库的用途。

我的发现是:

  • 如果 mex_common_function 是静态的,则一切正常。
  • 否则,在使用 matlab 对象时它不起作用。

.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?-)...

有人可以给我线索吗?我真的很感激。

c++ matlab libraries mex
1个回答
0
投票

我在 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 上是这样。

© www.soinside.com 2019 - 2024. All rights reserved.