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)
opencv_world420d.lib
(it's just an import library, at runtime use opencv_world420d.dll)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:
Project2.lib
opencv_world420d.lib
Solution 2
Turn the Project3 /clr off, make it a pure C++ project
Solution 3
MakeClassB::FuncB
inline:
// 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:
- Why solution 1 works, by just swapping the input libs order?
- Why solution 2 works, by just switching off /clr for Project3 whose output target is dll?
- OpenCV puts inline implementation in their hpp file, I wonder if it is a safe and good way to do so?