简体   繁体   English

从DLL导出STL std :: basic_string模板时,出现LNK2005错误

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

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. 我有一个DLL,可导出具有std :: string作为成员的类。 My main program contains classes that also have strings, and it uses the DLL. 我的主程序包含也具有字符串的类,并且使用DLL。

If I compile the DLL in VS2010, I get the following warnings: 如果我在VS2010中编译DLL,则会收到以下警告:

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. 当我编译EXE时,我得到相同的警告,但是没有错误,并且程序可以编译并运行。 In reality, it's a large project, so I get like 40 warnings, and I'm not too keen on that. 实际上,这是一个大项目,所以我收到40条警告,但我对此不太感兴趣。 (As a side-observation, these warnings are not present when compiled with VS2008) (从侧面观察,使用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. 因此,我读到了该警告,并将其引导至这篇MS文章: http : //support.microsoft.com/default.aspx? scid=KB;EN-US;168958,其中介绍了如何从计算机上导出STL模板DLL可以满足我收到的警告。

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: DLL编译时没有任何警告,但是当我编译我的EXE时,链接器将抛出异常:

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. DLL和EXE都使用相同的代码生成选项进行编译。 I can use MT on both or MD, and the results are the same. 我可以同时在MT或MD上使用MT,结果相同。

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? 我的主要问题:我可以解决LNK2005错误,还是忽略C4251警告是否安全?

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? 编辑:因此,我已经阅读了更多内容,并且看起来如果DLL类使用的std :: string是仅由成员函数访问的私有变量,则可以安全地忽略警告...任何对此有何评论? Is this a step in the right direction? 这是朝正确方向迈出的一步吗?

DLL code: DLL代码:

#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: EXE代码:

#include <iostream>
#include "SampleDLL.h"

using namespace std;

void main()
{
    MyClass class1;

    cout << class1.getData() << endl;

}

It looks like you are seeing the issue described on connect.microsoft.com . 看来您看到的是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 ) 不要导出std :: string,而是在DLL接口中使用const char *(请参阅https://stackoverflow.com/a/5340065/12663
  2. Ensure the _ITERATOR_DEBUG_LEVEL matches for all your projects 确保_ITERATOR_DEBUG_LEVEL与您所有项目匹配

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. ". 链接到您提出的MS文章时说,某些STL类“ ...已经由C运行时DLL导出。因此,您不能从DLL中导出它们。”。 Including basic_string. 包括basic_string。 And your link error says that basic_string symbol "...already defined in OtherClass.obj". 并且您的链接错误表明basic_string符号“ ...已在OtherClass.obj中定义”。 Because linker sees two equal symbols in two different places. 因为链接器在两个不同的位置看到两个相等的符号。

When exporting STL std::basic_string template from DLL, I get a LNK2005 error 从DLL导出STL std :: basic_string模板时,出现LNK2005错误

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 . 另请参见Microsoft的KB 168958文章“ 如何导出标准模板库(STL)类和包含作为STL对象的数据成员的类的实例” From the article: 从文章:

To Export an STL Class 导出STL类

  1. In both the DLL and the .exe file, link with the same DLL version of the C run time. 在DLL和.exe文件中,均使用C运行时的相同DLL版本进行链接。 Either link both with Msvcrt.lib (release build) or link both with Msvcrtd.lib (debug build). 要么都与Msvcrt.lib链接(发行版),要么都与Msvcrtd.lib链接(调试版)。
  2. In the DLL, provide the __declspec specifier in the template instantiation declaration to export the STL class instantiation from the DLL. 在DLL中,在模板实例化声明中提供__declspec说明符,以从DLL中导出STL类实例。
  3. In the .exe file, provide the extern and __declspec specifiers in the template instantiation declaration to import the class from the DLL. 在.exe文件中,在模板实例化声明中提供extern和__declspec说明符,以从DLL导入类。 This results in a warning C4231 "nonstandard extension used : 'extern' before template explicit instantiation." 这将导致警告C4231“在模板显式实例化之前使用了非标准扩展名:'extern'”。 You can ignore this warning. 您可以忽略此警告。

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

To me the whole topic boiled down to 对我来说,整个话题归结为

  • Don't export STL stuff. 不要导出STL内容。 Ignore the warning. 忽略警告。 (At least up to MSVC2013.) (至少要达到MSVC2013。)
  • Of course make sure, that every party links to the C runtime in the same manner regarding debug/release, static/dynamic. 当然,请确保各方以相同的方式在调试/发布,静态/动态方面链接到C运行时。

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. 不幸的是,如果您无法控制要链接的源代码,那就没有答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM