1

Similar to LNK2005 Error in CLR Windows Form, yet this answer cannot explain what I've met.

My question is at the end of the description, thanks for the patience.

The project structure is as below (I simplify the situation to demonstrate the problem I met, which does not make any sense in real development):

Environment: Visual Studio 2019

Configuration: Debug/x86

OpenCV 420: I compile it to a dynamic library (.lib+.dll) myself because the x86 version is not provided officially.

Project2: pure C++, output type: lib

// ClassB.h
#pragma once
#include <opencv2/opencv.hpp>
class ClassB
{
public:
    void FuncB();
};
// ClassB.cpp
#include "ClassB.h"
void ClassB::FuncB() {
    cv::Mat mat;
}

Project3: C++ with /clr on, output type: dll for .NET Framework v4.6.1

// ClassC.h
#pragma once
#include <iostream>
#include <opencv2/opencv.hpp>
class __declspec(dllexport) ClassC
{
};
// ClassC.cpp
#include "ClassC.h"

Link against (the input libs order matters, will explain later)

  1. opencv_world420d.lib (it's just an import library, at runtime use opencv_world420d.dll)
  2. Project2.lib

And the compiler throws errors:

LNK2005 "public: __thiscall cv::MatSize::MatSize(int *)" (??0MatSize@cv@@QAE@PAH@Z) already defined in opencv_world420d.lib(opencv_world420d.dll)   Project3 (ClassB.obj)   1   
LNK2005 "public: __thiscall cv::MatStep::MatStep(unsigned int)" (??0MatStep@cv@@QAE@I@Z) already defined in  opencv_world420d.lib(opencv_world420d.dll) Project3 (ClassB.obj)   1   

After some digging, I suppose it is because there're some inline functions in mat.inl.hpp header file which is needed by class Mat and included byopencv.hpp(indirectly though), as below:

inline
MatStep::MatStep(size_t s)
{
    p = buf; p[0] = s; p[1] = 0;
}

Maybe the compiler decided not to inline the functions, but indexed them into Project2.lib, to assure, I dump the two libs:

// Project2.lib
8B6 00000000 SECT109 notype ()    External    | ??0MatSize@cv@@QAE@PAH@Z (public: __thiscall cv::MatSize::MatSize(int *))
// opencv_world420d.lib
??0MatSize@cv@@QAE@PAH@Z (public: __thiscall cv::MatSize::MatSize(int *))

As far as I know, SECT109 and External do mean that Project2.lib has complete definition of cv::MatSize::MatSize(int *), so do opencv_420world420d.lib

However, I explore 3 separate ways out to pass the compilation

Solution 1

swap the linking order to:

  1. Project2.lib
  2. opencv_world420d.lib

Solution 2

Turn the Project3 /clr off, make it a pure C++ project

Solution 3

MakeClassB::FuncBinline:

// ClassB.h
#pragma once
#include <opencv2/opencv.hpp>
class ClassB
{
public:
    void FuncB() {
        cv::Mat mat(100, 200, CV_8U);
    }
};
// ClassB.cpp
#include "ClassB.h"

For solution1/2, I don't even touch Project2, so obviously ??0MatSize@cv@@QAE@PAH@Z still exists in Project2.lib (so I don't understand how the compilation succeed).

For solution3, ??0MatSize@cv@@QAE@PAH@Z disappears in Project2.lib (again I dumped the lib file and search the function name), so this does make sense to me.

In conclusion, my questions are:

  1. Why solution 1 works, by just swapping the input libs order?
  2. Why solution 2 works, by just switching off /clr for Project3 whose output target is dll?
  3. OpenCV puts inline implementation in their hpp file, I wonder if it is a safe and good way to do so?
Tomingsun
  • 129
  • 1
  • 11

0 Answers0