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

12,831

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:

  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

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.

Share:
12,831
JPhi1618
Author by

JPhi1618

Updated on June 04, 2022

Comments

  • JPhi1618
    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
    JPhi1618 over 11 years
    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!
  • bowman han
    bowman han about 8 years
    So Could you please describe how to handle with basic_string