来自 MATLAB Mex 库的链接错误

Posted

技术标签:

【中文标题】来自 MATLAB Mex 库的链接错误【英文标题】:Linking errors from MATLAB Mex library 【发布时间】:2013-03-08 16:23:42 【问题描述】:

我在编译 MATLAB Mex 库时遇到了麻烦 - 特别是来自 this website 的“相关聚类优化”代码。

我正在尝试在 OSX 机器上编译,并且正在使用提供的 mexall 函数。这运行以下行:

mex -O -largeArrayDims CXXFLAGS="\$CXXFLAGS -Wno-write-strings" QPBO.cpp QPBO_extra.cpp QPBO_maxflow.cpp QPBO_wrapper_mex.cpp QPBO_postprocessing.cpp -output QPBO_wrapper_mex

错误发生在链接时与 MATLAB 命令行的以下输出:

ld: duplicate symbol QPBO<int>::GetMaxEdgeNum()    in QPBO_extra.o and QPBO.o
collect2: ld returned 1 exit status

    mex: link of ' "QPBO_wrapper_mex.mexmaci64"' failed.

由此判断,GetMaxEdgeNum 函数同时出现在QPBO_extra.oQPBO.o 中。但是,它实际上只是在头文件QPBO.h 中定义。因此,我怀疑包含它的两个源文件都将它作为符号包含在其目标文件中,从而导致链接时出现问题。

(更多信息:每个源文件还在文件的最结尾处包含一个文件#include "instances.inc"instances.inc 显然似乎包含模板化QPBO 的一些特定实例。)

我在这里犯了一个明显的错误吗?我可以做些什么来增加编译这段代码的机会?

编辑

这是QPBO.h中有问题的GetMaxEdgeNum函数的定义:

template <typename REAL> 
    inline int QPBO<REAL>::GetMaxEdgeNum() 

    return (int)(arc_max[0]-arcs[0])/2;

编辑 2

关于我的机器的更多细节:

OSX 10.6.8 MATLAB R2012a(也有 R2011b) g++ 4.2 或 g++ 4.0(或通过 MacPorts 的 g++ 4.6)

我在下面的“赏金描述”中添加了一些关于我真正想要的答案的详细信息。

编辑 3

大家一致认为instances.inc 可能是造成问题的原因。这包含在每个cpp 文件的末尾,它包含以下内容:

#include "QPBO.h"

#ifdef _MSC_VER
#pragma warning(disable: 4661)
#endif

// Instantiations

template class QPBO<int>;
template class QPBO<float>;
template class QPBO<double>;

template <> 
    inline void QPBO<int>::get_type_information(char*& type_name, char*& type_format)

    type_name = "int";
    type_format = "d";


template <> 
    inline void QPBO<float>::get_type_information(char*& type_name, char*& type_format)

    type_name = "float";
    type_format = "f";


template <> 
    inline void QPBO<double>::get_type_information(char*& type_name, char*& type_format)

    type_name = "double";
    type_format = "Lf";

【问题讨论】:

有趣的是,它来自@Shai 的网站,所以你有自己的第一手支持来源:) 是的,我直接联系了他,但他说他没有在 OSX 上编译的经验。失败的部分实际上是第三方库,所以正如我在下面所说的,我认为理想情况下我应该有 OSX 的人来帮助解决这个问题...... 如果您能粘贴instances.inc 中的 QPBO 模板的特化,这可能会有所帮助。 (只是这些函数的原型应该没问题,我其实不需要看它们的代码内容。) @BillCheatham - 我怀疑问题与instaces.inc 文件有关。你能把它和qbpo.*中的save方法去掉吗(它不用于大规模CC)。 谢谢@Shai 我试了一下,但现在我发现链接失败是因为从 QPBO_wrapper 引用的未定义符号:Undefined symbols: "QPBO&lt;int&gt;::Solve()", referenced from: void QPBO_wrapper... 等。我同意我认为instances.inc 很麻烦! 【参考方案1】:

问题似乎是某些模板代码位于 .cpp 文件中。

    .cpp 文件中删除#include instances.inc 声明。 从 QPBO.cppQPBO_extra.cppQPBO_maxflow.cppQPBO_postprocessing.cpp 中移动所有代码到头文件qpbo.h。 您现在将拥有一个 .cpp 文件 qpbo_wrapper_mex.cpp 和一个标头 qpbo.h

    mex 文件(在 matlab 中)使用:

    >> mex -O -largeArrayDims qpbo_wrapper_mex.cpp
    

应该可以...

【讨论】:

太好了,这行得通。感谢您的工作......在图书馆和为我解决这个问题! @Shai +1 给你,先生,以及当之无愧的赏金。我毫不怀疑你能解决这个问题:)【参考方案2】:

GetMaxEdgeNum 更改为静态函数,或将其放入匿名命名空间可能会解决您的问题。

正如您所建议的,原因是它在两个目标文件中都有外部链接,这会导致名称冲突。我建议的解决方案为其提供了内部链接。

修改后:

如果您在类定义中定义方法,它会改变什么吗? 像这样:

template <typename REAL>
class QPB0 
    ...
public:
    inline int GetMaxEdgeNum() 
    
        return (int)(arc_max[0]-arcs[0])/2;
    
    ...
;

【讨论】:

谢谢,我试了一下(在函数中 int 之前添加了单词 static - 请参阅问题编辑)。但是,我收到了一些关于cannot declare member function 'int QPBO&lt;REAL&gt;::GetMaxEdgeNum()' to have static linkage 的错误。我不确定这意味着什么。 这意味着我的回答只有在你的函数不是成员函数时才有效,我认为它不是。 inline 关键字应该有同样的作用,所以我不知道为什么会出现链接器错误。 谢谢,我已经尝试过了,它绝对应该可以工作——只是不行。我仍然收到相同的链接器错误。不太确定下一步该做什么,但我会尝试一些不同的包含或编译器选项。我认为问题的一部分是每个源文件底部包含的奇怪的instances.inc...

以上是关于来自 MATLAB Mex 库的链接错误的主要内容,如果未能解决你的问题,请参考以下文章

编译 mex 文件时出现链接错误

MATLAB + Mex + OpenCV:链接和编译正确,但在运行时找不到库

使用 mingw-w64 编译 mex 的链接器错误

Matlab 缺少依赖项 MEX 文件

Fortran Mex 文件 - 传回 Matlab 的值不正确

链接 Matlab 生成的 C++ 库的问题