Search code examples
c++visual-c++stlbuildlinker

VS linker fails with "object already exists" error for std::string methods


First of all I must stress that I'm trying for quite some time to solve it, and I don't know what I am missing (or more precisely, what I don't understand). Any help will be greatly appreciated!

I have a project called *static_tools* that compiles to a static lib which is called static_tools.lib and it uses STL. I compile that project with /MD, and it compiles successfully.

Another project called system compiles to a DLL which is called system.dll also uses STL and links with static_tools.lib. I compile that project with /MD and it compiles successfully.

Here is the problem: Another (3rd) project called systemclient compiles to a DLL which is called systemclient.dll also uses STL and links with system.dll and static_tools.lib. I compile that project with /MD and the linker fails :-( .

The error is that methods of std::string already exists in system.dll. I think it happens because system.dll got the objects from static_tools.lib, but if it is true, it sounds like it is impossible to use static lib, which doesn't make sense.

UPDATE - some extra details requested:

  • I am using VS2013, but it also happened in VS2010
  • The error I am getting from the linker:

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >(wchar_t const *)" (??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@PEB_W@Z) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >::~basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >(void)" (??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@XZ) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > & __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::operator+=(class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > const &)" (??Y?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV01@AEBV01@@Z) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > & __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::append(class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>const &)"(?append@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@AEBV12@@Z) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > & __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::assign(wchar_t const *,unsigned __int64)" (?assign@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAAAEAV12@PEB_W_K@Z) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: wchar_t const * __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::c_str(void)const " (?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBAPEB_WXZ) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: bool
__cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::empty(void)const " (?empty@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBA_NXZ) already defined in system.lib(system.dll)

2>static_tools.lib(pipe_client.obj) : error LNK2005: "public: unsigned
__int64 __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::size(void)const " (?size@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBA_KXZ) already defined in system.lib(system.dll)

2>static_tools.lib(error_tracer.obj) : error LNK2005: "public: __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >(void)" (??0?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@XZ) already defined in system.lib(system.dll)

2>static_tools.lib(error_tracer.obj) : error LNK2005: "public: __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >::~basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >(void)" (??1?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEAA@XZ) already defined in system.lib(system.dll)

2>static_tools.lib(error_tracer.obj) : error LNK2005: "public: wchar_t const * __cdecl std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t>>::c_str(void)const " (?c_str@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@QEBAPEB_WXZ) already defined in system.lib(system.dll)

I have explicitly instantiate std::basic_string in stdafx.h, but it didn't work :-(.

Can anyone help me out here? Also a small explanation would be nice :-).


Solution

  • Based on comments, your problem seems to be that you're explicitly instantiating std::string in the DLL and implicitly instantiating it in the staic library - these two instantiations will then cause a linker error.

    The cleanest solution would be to not explicitly instantiate the template in the DLL. You mentioned you're doing it because your class is derived from std::string. It's generally a bad idea to (publically) derive from standard library containers, because they don't have a virtual destructor. So I'd look for ways to change your design accordingly, which would remove the need for explicit instantiation and the problem would disappear.

    If that is not possible for one reason or another, you have a few other options. You mentioned VS2013, which should have support for the extern template feature of C++11. You could use that to provide an explicit instantiation declaration in the static library (so that it won't generate its own implicit instantiation) - it would then satisfy its link dependencies by the explicit instantiation in the DLL. Of course, that would mean all users of the static lib would have to supply the explicit instantation.

    Another option would be to actually explicitly instantiate std::string in the static library; the DLL would then use that explicit instantiation as well.

    EDIT

    One more option I can think of: create a new DLL (e.g. string.dll) which will only contain the explicitly instantiated std::string. Use extern template in the other two DLLs and the static lib, and link string.dll to the other two DLLs.