It started with a seemingly minor problem that I encountered when I integrated my small exception handling library into a code base consisting of ~ 200 Visual C ++ projects in one Visual Studio solution.
I have a linker problem expressed by this message
3>B_Utils.lib(B_Utils.dll) : error LNK2005: "public: __cdecl ExceptionBase<class std::runtime_error>::ExceptionBase<class std::runtime_error>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (??0?$ExceptionBase@Vruntime_error@std@@@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in TranslationUnit_2.obj
3>B_Utils.lib(B_Utils.dll) : error LNK2005: "public: virtual __cdecl ExceptionBase<class std::runtime_error>::~ExceptionBase<class std::runtime_error>(void)" (??1?$ExceptionBase@Vruntime_error@std@@@@UEAA@XZ) already defined in TranslationUnit_2.obj
3>B_Utils.lib(B_Utils.dll) : error LNK2005: "public: __cdecl ExceptionBase<class std::runtime_error>::ExceptionBase<class std::runtime_error>(class ExceptionBase<class std::runtime_error> const &)" (??0?$ExceptionBase@Vruntime_error@std@@@@QEAA@AEBV0@@Z) already defined in TranslationUnit_2.obj
At first glance, this looked like another typical problem, which can be solved with the help of a typical advice “try changing the order of #include files” or “deducing the implementation from the header file”, but this is not so.
I have studied a number of similar questions, such as this or this , but none of them suit my business. At least the suggested recipes do not help in my problem.
In addition, long-standing people in our company encountered another problem related to the Visual Studio linker during the migration to VS2010, which turned out to be a linker error, see here . In any case, none of them matched my scenario.
So, this tiny question ended with a whole mini-exploration. You can find details and an example of toys that reproduce the problem here on github . In the meantime, I will try to describe the situation below as briefly as possible.
The key components that cause the assembly to fail are:
- 3 ( A, B, C) : B- > A, C- > B, C- > A.
- A . A.
- DLL- B, 2).
- C , 2), 3).
:
A_SDK
(ExceptionBase.h)
template<typename T>
class ExceptionBase;
--
(foo.h)
#include "ExceptionBase.h"
inline void foo()
{
throw ExceptionBase<std::runtime_error>("Problem");
}
B_Utils
(Error.h)
#include "ExceptionBase.h"
#if defined(B_EXPORTS)
#define _B_UTILS_EXPORTS_CLASS __declspec(dllexport)
#else
#define _B_UTILS_EXPORTS_CLASS __declspec(dllimport)
#endif
struct _B_UTILS_EXPORTS_CLASS Error : public ExceptionBase<std::runtime_error>
{ Error(std::string&& s); }
C_Client
(TranslationUnit_1.cpp)
#include "A_SDK/foo.h"
#include "B_Utils/Error.h"
void TranslationUnit_1() {
foo();
}
(TranslationUnit_2.cpp)
#include "A_SDK/foo.h"
void TranslationUnit_2() {
foo();
}
, // !!!. , . , github.
- , ?
, :
P.S. , . . github README. .