2

我提前为这篇长文道歉......

当我们在 VS 菜单 > 工具 > 选项 > VC++ 目录 > 包含和库文件的目录下列出 STLPort 包含和库目录时,我曾经能够构建我们的 VC++ 解决方案(我们在 VS 2008 上)。但是,我们希望过渡到完全依赖 .vcproj 和 .sln 文件的构建过程。与必须在每台开发 PC 上单独配置的 VS 选项不同,这些可以检查到源代码控制中。我们通过将包含目录添加到每个项目的属性页 > 配置属性 > C/C++ > 常规 > 附加包含目录和库目录到链接器 > 常规 > 附加库目录来处理大多数库的转换。

不幸的是,这种方法不适用于 STLPort。我们在链接期间收到 LNK2019 和 LNK2001 错误:

Error   1   error LNK2019: unresolved external symbol "public: virtual bool __thiscall MyClass::myFunction(class stlp_std::basic_istream<char,class stlp_std::char_traits<char> > &,class MyOtherClass &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > &)const " (?myFunction@MyClass@@UBE_NAAV?$basic_istream@DV?$char_traits@D@stlp_std@@@stlp_std@@AAVSbprobScenarioData@@AAV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@3@@Z) referenced in function _main MyLibrary.obj   

Error   5   error LNK2001: unresolved external symbol "public: static void __cdecl MyClass::myFunction(class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,long,enum MyClass::MessageType,int,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &)" (?myFunction@MyClass@@SAXABV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@stlp_std@@000JW4MessageType@1@H0@Z)  MyLibrary.lib   

这发生在将可执行项目链接到作为库项目的依赖项时。奇怪的是,在链接库项目本身时不会发生这种情况。有任何想法吗?

4

6 回答 6

5

正如其他答案中提到的,这是一个链接器错误,可能是库和应用程序使用不同选项编译的结果。已经有一些解决方案可以跟踪这个问题(目前其中一个作为选择的答案)。这些解决方案起作用。但是,有一些工具可以让您的搜索变得更加容易

对于初学者,了解修饰名称会有所帮助。在所有这些垃圾中,你会认出一些东西:你的函数名命名空间、你正在使用的一些类类型。它们周围的所有这些字符对编译器都意味着什么,但你不需要编译器告诉你它们是什么。

输入 undname.exe:


undname.exe <装饰名称>
  • 是一个简单的命令行程序,位于 VS bin 目录中。
  • 将装饰名称作为它的第一个参数。
  • 输出符号的人类可读格式。

有了这些知识,您现在可以继续为错误创建的符号找到合理的候选者。

首先,您可以按照其他地方的建议在十六进制编辑器中编辑您的库。但是,有一种更简单的方法可以找到符号。

输入dumpbin.exe:


dumpbin.exe <开关> <库名称>
  • 是一个简单的命令行程序,位于 VS bin 目录中。
  • 需要一组开关和一个库来应用它们。
  • 从图书馆输出信息

您对问题感兴趣的开关是/linkermember。还有许多其他开关可以为您提供非常有趣的信息,但这个会列出库中的所有符号。

在这一点上,一点命令行知识会很好地为您服务。grep之类的工具确实可以缩短您的工作周期,但您可以通过重定向到文件并使用记事本等来解决问题。

由于我没有您的代码或库,我将从 TinyXML 设计一个示例。

假设您的错误消息是这样的:

Error   1       error LNK2019: unresolved external symbol "public: unsigned char __cdecl TiXmlComment::Accept(bool,class TiXmlVisitor *) " (?Accept@TiXmlComment@@ZBE_NPAVTiXmlVisitor@@@Z) referenced in function _main     MyLibrary.obj 

确定这是 TinyXML 中的一个函数后,我可以开始寻找不匹配的符号。我将从转储库的链接器成员开始。(注意这个开关是单数的,当我从记忆中输入它时,这总是让我明白!)


>dumpbin /linkermember tinyxml.lib
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file tinyxml.lib

File Type: LIBRARY

Archive member name at 8: /
4992E7BC time/date Wed Feb 11 08:59:08 2009
         uid
         gid
       0 mode
    B402 size
correct header end

    859 public symbols

    16292 ??$_Allocate@D@std@@YAPADIPAD@Z
    16292 ??$_Char_traits_cat@U?$char_traits@D@std@@@std@@YA?AU_Secure_char_traits_tag@0@XZ
    16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
    16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
    16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
    16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
    16292 ??$use_facet@V?$ctype@D@std@@@std@@YAABV?$ctype@D@0@ABVlocale@0@@Z
    16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@IAE@V?$allocator@D@1@@Z
    16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@QAE@ABV01@@Z

这显然是太多的阅读,但我们不必,我们知道我们在寻找什么,所以我们只是寻找它。


>dumpbin /linkermember tinyxml.lib | grep Accept
    529AE ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z

这更容易阅读。查看我们的错误,我们正在寻找 TiXmlComment 的 Accept 函数。如果我们有很多匹配项(例如查看 stl 中的 size 函数!),我们可以为该名称另外 grep 输出,但在这种情况下,我们可以从列表中选择它。这是我们转向 undname 的地方:


>undname ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z"
is :- "public: virtual bool __thiscall TiXmlComment::Accept(class TiXmlVisitor *)const "

因此,在此示例中,我们的应用程序正在寻找一个返回unsigned char的函数,但库中有一个返回bool的函数。

这是一个人为的示例,但它说明了用于跟踪您的问题的技术。您可能正在寻找根据您的选项设置不同的 typedef 类型。

我遇到的问题是time_t。在我使用的一些库中,time_t使用 32 位类型作为其内部表示的一部分。这个库是用旧的编译器生成的,这是默认的。在 VS 2005 中,time_t默认使用 64 位类型。我必须添加预处理器定义_USE_32BIT_TIME_T才能编译。正如我所描述的那样,我准确地追踪了这个问题。

我希望这可以帮助某人解决这个问题!

于 2009-03-26T19:23:23.457 回答
3

Raymond Chen 最近在The Old New Thing上谈到了这一点——这些问题的一个原因是库是使用一组开关编译的,但您的应用程序使用的是不同的一组开关。你要做的是:

获取链接器正在寻找的确切符号。这将是一个可怕的错位名称。使用十六进制编辑器(IIRC,Visual Studio 将执行此操作)查看您链接到的 .lib 文件。找到几乎是链接器正在寻找的东西的符号,但不完全是。鉴于符号的差异,尝试找出哪些命令行开关会有所帮助。祝你好运——对于不习惯这类问题的人来说,解决方案可能需要几天时间才能弄清楚(!)

于 2008-12-30T01:35:59.387 回答
1

这些链接错误表明您的应用程序中的某些类没有使用 STLPort 编译或已从构建中省略。他们并不建议您不链接 STLport。

我的猜测是:

  • MyClass 的构建设置以某种方式覆盖了包含路径的项目范围设置,因此 MyClass 是使用默认的 C++ STL 实现而不是 STLport 构建的。这应该很容易检查 - 对目标文件运行 dumpbin 并检查其中的函数是否引用了 stlp_* 命名空间中的标准库。如果不是,则编译器可能没有选择正确的包含路径。我还想看看 IDE 调用编译器的命令行。这些也可以通过 C/C++ 配置属性查看。
  • 正如其他海报也提到的那样,MyClass 有可能没有被构建,但这应该很容易检查。
于 2008-11-15T21:00:21.900 回答
1

您必须配置 STL 端口才能使用本机 IOStreams 实现。

还有你使用 STLPort 的任何具体原因吗?除非您尝试制作跨平台应用程序,否则建议使用默认的 STL 实现 - 即使在大多数情况下,它也不是真正需要的。

于 2008-11-21T15:37:24.437 回答
0

这是一个链接错误。它与您的包含路径无关。

您要么忘记将 MyClass.cpp 添加到项目中,要么忘记定义这两个函数。

“链接”库项目时未发生错误的原因是库项目未链接。它们只是一堆 OBJ,由 LIB 程序组合成一个库文件。

于 2008-11-04T13:50:24.477 回答
0

将库名称添加到要链接的其他库列表中。抱歉,我没有在最新版本的 VS 面前确切知道它的去向。

于 2008-11-06T04:08:10.283 回答