【问题标题】:LNK2001 error when compiling apps referencing STLport-5.1.4 with VC++ 2008使用 VC++ 2008 编译引用 STLport-5.1.4 的应用程序时出现 LNK2001 错误
【发布时间】:2010-09-20 15:43:51
【问题描述】:

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

当我们在 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   

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

【问题讨论】:

    标签: c++ visual-studio-2008 visual-c++ linker stlport


    【解决方案1】:

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

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

    输入 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 才能编译。正如我所描述的那样,我准确地追踪了这个问题。

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

    【讨论】:

    • 谢谢!听起来很有希望,我明天先试试。
    【解决方案2】:

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

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

    【讨论】:

    • 另一个技巧是使用 /VERBOSE 链接,它将打印它找到的东西。这至少帮助我找到了这类问题。感谢这篇文章,它确实帮助我查明了我的问题。现在的问题是为什么一个 .lib 有一个函数的 _cdecl 声明而另一个有一个 _this_call。
    【解决方案3】:

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

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

    【讨论】:

    • 这是我无法更改的遗留代码,不会给自己和他人带来巨大的痛苦。我试过了,但我不确定我是否正确设置了所有设置。不知道我是否也必须重新编译它。
    【解决方案4】:

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

    我的猜测是:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 是的,我也试过了。但话又说回来,我可能需要更多时间来检查所有内容,以确保它们正确连接在一起。我相信你们都知道,维护几十年前的软件很困难。尤其是对于我们这些菜鸟。 XD
      【解决方案6】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-11
        • 2011-01-01
        • 2022-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多