Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking errors from MATLAB Mex library

I am having troubling compiling a MATLAB Mex library - specifically, the 'Correlation Clustering Optimization' code from this website.

I am trying to compile on an OSX machine, and am using the supplied mexall function. This runs the following line:

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

The error occurs at linking time with the following output to the MATLAB command line:

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.

Judging from this, the function GetMaxEdgeNum is appearing in both QPBO_extra.o and QPBO.o. However, it is only actually defined in a header file, QPBO.h. I therefore suspect that both source files which include it are including it as a symbol in their object files, causing a problem at link time.

(Further information: Each source file also includes a file #include "instances.inc" at the very end of the file. instances.inc apparently seems to include some specific instantiations of the templated QPBO.)

Is there an obvious mistake I am making here? What can I do to increase my chances of being able to compile this code?

EDIT

This is the definition of the problematic GetMaxEdgeNum function in QPBO.h:

template <typename REAL> 
    inline int QPBO<REAL>::GetMaxEdgeNum() 
{
    return (int)(arc_max[0]-arcs[0])/2;
}

EDIT 2

Some more details about my machine:

  • OSX 10.6.8
  • MATLAB R2012a (also have R2011b)
  • g++ 4.2 or g++ 4.0 (or g++ 4.6 via MacPorts)

I've added some details on what I really want from an answer in my 'bounty description' below.

EDIT 3

There's a bit of consensus that instances.inc may be causing the trouble. This is included at the end of each cpp file, and it contains the following:

#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";
}
like image 527
Bill Cheatham Avatar asked Feb 20 '26 21:02

Bill Cheatham


2 Answers

It seems like the issue is that some template code is in .cpp files.

  1. Remove the #include instances.inc declarations from the .cpp files.
  2. Move all code from QPBO.cpp, QPBO_extra.cpp, QPBO_maxflow.cpp and QPBO_postprocessing.cpp to the header file qpbo.h.
  3. You'll have now a single .cpp file qpbo_wrapper_mex.cpp and a single header qpbo.h
  4. mex the file (in matlab) using:

    >> mex -O -largeArrayDims qpbo_wrapper_mex.cpp
    

Should work...

like image 86
Shai Avatar answered Feb 22 '26 09:02

Shai


Changing GetMaxEdgeNum to a static function, or putting it in an anonymous namespace will probably fix your problem.

The reason is, as you suggest, that it has external linkage in both object files, which results in a nameclash. My suggested solutions gives it internal linkage.

After edit:

Does it change anything if you define the method inside the class definition? Like this:

template <typename REAL>
class QPB0 {
    ...
public:
    inline int GetMaxEdgeNum() 
    {
        return (int)(arc_max[0]-arcs[0])/2;
    }
    ...
};
like image 20
Kleist Avatar answered Feb 22 '26 09:02

Kleist



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!