3

我在编译 MATLAB Mex 库时遇到了麻烦——特别是来自这个网站的“相关聚类优化”代码。

我正在尝试在 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。)

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

编辑

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

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";
}
4

2 回答 2

5

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

  1. 从文件中删除#include instances.inc声明。.cpp
  2. 将QPBO.cppQPBO_extra.cppQPBO_maxflow.cppQPBO_postprocessing.cpp中的所有代码移动到头文件qpbo.h中。
  3. 您现在将拥有一个 .cpp 文件qpbo_wrapper_mex.cpp和一个头文件qpbo.h
  4. 使用以下命令混合文件(在 matlab 中):

    >> mex -O -largeArrayDims qpbo_wrapper_mex.cpp
    

应该管用...

于 2013-03-11T11:43:00.333 回答
3

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

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

编辑后:

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

template <typename REAL>
class QPB0 {
    ...
public:
    inline int GetMaxEdgeNum() 
    {
        return (int)(arc_max[0]-arcs[0])/2;
    }
    ...
};
于 2013-03-08T16:30:27.380 回答