Reputation: 7982
I recently installed Visual Studio 2010 and used CMake to generate the solution files for my project. This process had previously worked fine on VS2005.
The first issue I encountered was because of the new "move constructors", so I had to remove some implicit conversions from my code — fair enough, that works now.
My current situation is as follows: I am compiling DLL 1, which is dependent only on some system libraries (Kernel32, etc) and the CRT, and DLL 2, which links to DLL 1, as well as some third party libraries.
The errors I get are along the lines of:
DLL1.lib(DLL1.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in objFromDLL2.obj
This appears to be exactly the problem described here.
However, nothing in this thread solves my problem.
What am I missing? Please let me know if I need to provide more information and I will edit the question as best I can.
update: It's been a while and I still have no solution. I've been updating the question with responses to comments, and I'm currently working on a different codebase which does work - I'm starting to think that the backwards compatibility for older code has finally started to dry up, and I should just move on.
more update: I've found what's probably a very undesirable linker flag, /FORCE:MULTIPLE, which turns the errors into warnings by ignoring all but the first definition of the symbols. There must be bad side-effects of doing this. A test of this flag highlighted an LNK2001: unresolved std::string::npos, which was buried in all the previous LNK2005 errors. The torment never ends.
Upvotes: 11
Views: 2736
Reputation: 4416
I have used /FORCE:MULTIPLE
successfully. It is sometimes inevitable when using a mixed bag of libraries. As long as the linker uses the one & same address to consistently resolve the reference, it works. The other definitions are ignored.
Upvotes: 2
Reputation: 179779
It seems that the problem is that DLL1 does export std::string
(probably implicitly, because it's used in a class that's also exported), but the headers of DLL1 don't declare that. Therefore, when DLL2 is compiled, it's not noted as an import. This is no problem, because it's a template: the compiler just instantiates another copy. But then the linker stumbles, because DLL2 really should have imported std::string
.
Solution: explicitly export/import std::string
; you probably already have an appropriate macro for the _declspec( )
in your DLL1 header(s).
Upvotes: 0
Reputation: 179779
I'm inclined to think that your stated assumptions are incorrect. In particular, "DLL 1, which is dependent only on some system libraries (Kernel32, etc)" can't be right if it's compiled with /MD and refers to std::string::~string
. That would obviously cause a dependency on the CRT.
Aslo, if DLL1 doesn't depend on DLL2, how in the world is the linker aware of files from DLL2?! Have you managed to set up a cyclic dependency by any chance?
Between VS2008 and VS2010, it seems that std::string::~string
was removed from the CRT. Therefore, it's no longer a DLLimport for your own code. That could explain the difference in behavior. A cyclic dependency between DLL1 and DLL2 wouldn't have mattered to std::string::~string
since both would get it from the CRT, and that obviously wouldn't be part of the cycle.
Upvotes: 0