8

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;

}
jeffm
  • 3,120
  • 1
  • 34
  • 57
JPhi1618
  • 783
  • 1
  • 11
  • 21
  • possible duplicate of [Exporting classes containing std:: objects (vector, map, etc) from a dll](http://stackoverflow.com/questions/767579/exporting-classes-containing-std-objects-vector-map-etc-from-a-dll) – mmmmmm Jan 23 '12 at 18:27
  • Mark: I did read that question, but it didn't seem to have an answer for the issue I'm seeing because it does not mention the additional LNK2005 problem I now have. – JPhi1618 Jan 23 '12 at 18:29

5 Answers5

4

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:

  1. Don't export std::string, instead use const char * in the DLL interface (see https://stackoverflow.com/a/5340065/12663)
  2. Ensure the _ITERATOR_DEBUG_LEVEL matches for all your projects
Community
  • 1
  • 1
danio
  • 8,548
  • 6
  • 47
  • 55
  • Thanks. 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! – JPhi1618 Sep 25 '12 at 19:04
1

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.

Vlad
  • 1,977
  • 19
  • 44
0

When exporting STL std::basic_string template from DLL, I get a LNK2005 error

Also see Microsoft's KB 168958 article How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object. From the article:

To Export an STL Class

  1. In both the DLL and the .exe file, link with the same DLL version of the C run time. Either link both with Msvcrt.lib (release build) or link both with Msvcrtd.lib (debug build).
  2. In the DLL, provide the __declspec specifier in the template instantiation declaration to export the STL class instantiation from the DLL.
  3. In the .exe file, provide the extern and __declspec specifiers in the template instantiation declaration to import the class from the DLL. This results in a warning C4231 "nonstandard extension used : 'extern' before template explicit instantiation." You can ignore this warning.
jww
  • 97,681
  • 90
  • 411
  • 885
0

I got a hack can fix this in temp

Open Project Options,Click Linker->Command Line, In the Additional Options Input Box,type

 /FORCE:MULTIPLE
bowman han
  • 1,097
  • 15
  • 25
0

To me the whole topic boiled down to

  • Don't export STL stuff. Ignore the warning. (At least up to MSVC2013.)
  • Of course make sure, that every party links to the C runtime in the same manner regarding debug/release, static/dynamic.

Always fixed the problem for me so far.

Unfortunately that is no answer if you have no control over the source code you would like to link to.

yau
  • 537
  • 6
  • 14