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

iaqfqrcu  于 4个月前  发布在  Matlab
关注(0)|答案(1)|浏览(86)

我当前的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后,使用的setters。
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?-)...
谁能给予我点提示吗?我会很感激的。

hlswsv35

hlswsv351#

我在MEX文件中使用了一个共享库,其中多个MEX文件需要访问同一个C对象。然后在共享库中创建对象,并可以在链接到它的所有MEX文件中使用它。
但是如果共享库需要调用MATLAB函数,那么构建起来就变得复杂得多。
考虑到你的用例,“* 它们主要是转换函数,比如std::vector<doubles>matlab::arrays *",我会把它做成一个只有头文件的库或静态库。你不需要在MEX文件中共享一个C
对象,你不需要把它变成一个共享库。而且转换函数通常不会很大,通过静态链接MEX文件而不必要地使MEX文件膨胀的复杂代码。
但是,如果你真的想构建一个调用MATLAB的共享库,那么你需要像构建MEX文件一样构建它,除了它没有标准的MEX文件入口点或MEX文件扩展名。但是你确实需要链接所有相同的MATLAB库,并设置所有相同的预处理器定义。
当你在CMake文件中调用matlab_add_mex时,你会运行这个CMake代码。这显示了构建MEX文件的复杂性。如果你想编写一个适用于所有版本的MATLAB和所有平台的CMake脚本,你基本上必须复制该函数的大部分功能。但是你使用的是C++ API,因此,仅遵循适用于MATLAB 9.4(R2018 a)及更新版本的路径。这包括设置Matlab_HAS_CPP_APIMatlab_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文件的方式。因此,静态链接转换函数确实要方便得多。
在构建SHARED库时,您添加的-fPIC选项已经由CMake处理。但是您必须显式地将其添加到您打算链接到共享库的静态库中,至少在Linux上是这样。

相关问题