When exporting STL std::basic_string template from DLL, I get a LNK2005 error
Solution 1
It looks like you are seeing the issue described on connect.microsoft.com.
There is a workaround suggested there, but it seems a bit nasty.
Other options that might help:
- Don't export std::string, instead use const char * in the DLL interface (see https://stackoverflow.com/a/5340065/12663)
- Ensure the _ITERATOR_DEBUG_LEVEL matches for all your projects
Solution 2
Link to MS article that you presented says that some STL classes "...are already exported by the C Runtime DLL. Therefore, you cannot export them from your DLL. ". Including basic_string. And your link error says that basic_string symbol "...already defined in OtherClass.obj". Because linker sees two equal symbols in two different places.
JPhi1618
Updated on June 04, 2022Comments
-
JPhi1618 almost 2 years
OK, so I've read several question and articles about this topic, and I feel like I understand the basics, but I'm still having trouble.
I have a DLL that exports a class that has a std::string as a member. My main program contains classes that also have strings, and it uses the DLL.
If I compile the DLL in VS2010, I get the following warnings:
warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass'
When I compile the EXE, I get the same warnings, but there are no errors, and the program compiles and runs. In reality, it's a large project, so I get like 40 warnings, and I'm not too keen on that. (As a side-observation, these warnings are not present when compiled with VS2008)
So, I read about that warning, and it lead me to this MS article: http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958 which tells how to export a STL template from a DLL to satisfy the warnings I was getting.
The problem is, when I add the following lines to remove the warnings:
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>; EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
the DLL compiles with no warnings, but when I compile my EXE, the linker throws a fit:
2>SampleDLL.lib(SampleDLL.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 OtherClass.obj 2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::size(void)const " (?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) already defined in OtherClass.obj
Both the DLL and the EXE are compiled with the same code generation options. I can use MT on both or MD, and the results are the same.
I am including the code from a minimized sample program in case I left anything out above.
My main question: Can I fix the LNK2005 errors, or is it safe to just ignore the C4251 warnings?
Edit: So I've read a little more, and it looks like if the std::string that the DLL class uses is a private variable that is only accessed by member functions, it may be safe to ignore the warning... Any comments on this? Is this a step in the right direction?
DLL code:
#pragma once #include <exception> #include <string> #ifdef SAMPLEDLL_EXPORTS # define DECLSPECIFIER __declspec(dllexport) # define EXPIMP_TEMPLATE #else # define DECLSPECIFIER __declspec(dllimport) # define EXPIMP_TEMPLATE extern #endif //disable warnings on extern before template instantiation (per MS KB article) #pragma warning (disable : 4231) //std::basic_string depends on this allocator, so it must also be exported. EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>; //std::string is a typedef, so you cannot export it. You must export std::basic_string EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >; #pragma warning (default : 4231) class DECLSPECIFIER MyClass { public: std::string getData(); //returns 'data', body in CPP file private: std::string data; int data2; }; //in SampleDLL.cpp file... std::string MyClass::getData() { return data; }
EXE code:
#include <iostream> #include "SampleDLL.h" using namespace std; void main() { MyClass class1; cout << class1.getData() << endl; }
-
JPhi1618 over 11 yearsThanks. That certainly seems to be the issue I was running into. Way to dig up a dead thread, but an answer is an answer, and this is the first good explanation I've found. Hope it helps others!
-
bowman han about 8 yearsSo Could you please describe how to handle with basic_string