【问题标题】:Unresolved Externals Nightmare未解决的外部噩梦
【发布时间】:2012-07-13 21:56:34
【问题描述】:

各位行业资深人士,

我是一名大三学生,开始了我的第一次暑期编程实习,但我的想法有点过头了。我工作的公司从另一家公司购买了一个巨大的应用程序,该公司自 90 年代初以来一直在缓慢地扩展和修改它。该解决方案包含超过 200,000 行代码,分布在 300 多个文件中。据称整个解决方案是按照 ANSI-C++ 标准编写的。代码几乎完全没有文档记录,其中大部分在我看来就像象形文字。最终,我的工作是将此代码移植到嵌入式 Linux。目前,我的工作只是在 Windows XP 上使用 Visual Studio 2008 进行编译。

今天,我遇到了像这样的链接器错误:

libcmtd.lib(sprintf.obj) : error LNK2005: _sprintf already defined in msvcrtd.lib(MSVCR90D.dll)

我的理解是,当解决方案中的不同项目使用不同的runtime libraries 编译时,通常会发生这种情况。我的解决方案中有 6 个项目。其中 4 个设置为使用多线程调试 DLL 运行时库 (/MDd) 进行编译,其中一个设置为使用多线程调试库 (/MTd) 进行编译,其中一个设置为使用多线程 dll 运行时库 (/MD)。收到此错误消息后,我尝试的第一件事是将 /MTd 和 /MD 开关更改为 /MDd,以便使用相同的运行时库编译所有内容。不幸的是,这导致了 afx.h 中的以下错误:

fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]

经过一番挖掘,我发现它已经告诉了我需要做什么。我继续将项目属性->配置属性->常规下的“使用 MFC”选项更改为“在共享 DLL 中使用 MFC”。此时我开始收到几十个未解决的外部错误,例如:

dataPropertySheet.obj : error LNK2019: unresolved external symbol "public: __thiscall CResizableSheet::CResizableSheet(unsigned short const *,class CWnd *,unsigned int)" (??0CResizableSheet@@QAE@PBGPAVCWnd@@I@Z) referenced in function "public: __thiscall CdataPropertySheet::CdataPropertySheet(unsigned short const *,class CWnd *,unsigned int)" (??0CdataPropertySheet@@QAE@PBGPAVCWnd@@I@Z)

ResizableLib.lib(ResizablePage.obj) : error LNK2001: unresolved external symbol "public: virtual int __thiscall CWnd::Create(char const *,char const *,unsigned long,struct tagRECT const &,class CWnd *,unsigned int,struct CCreateContext *)" (?Create@CWnd@@UAEHPBD0KABUtagRECT@@PAV1@IPAUCCreateContext@@@Z)

在阅读了 LNK2001LNK2019 上的 MSDN 页面后,我意识到我不知道发生了什么。这些不是他们在学校教我们如何处理的问题。我知道我的数据结构,仅此而已。我是如何走到现在的我已经超出了我的想象!

根据我有限的知识,这些模块的各种调试和发布版本似乎都纠缠在预处理器指令和#includes 的网络中。在整个解决方案的环境变量、文件名、宏等方面,几乎每个头文件和源文件中都有许多嵌套的#ifdef 检查和#define 语句。通过对我的编译器设置进行微小的更改,我似乎将程序的大部分重定向到具有非常不同函数定义的不同库。这是我对正在发生的事情的模糊概念理解。

我觉得在我有机会解决这些编译器错误之前,我需要更好地了解这段代码的工作原理。为此,我一直在尝试逐行浏览许多文件,以查看它们的引导位置、范围内的对象和变量等等。不幸的是,这并没有让我走得太远,因为对外部函数的每次调用都是模棱两可的,而且我无法通过预处理器了解应该调用哪个版本的任何给定函数。

我一直在寻找神奇的解决方案来规划程序并尝试理解它。我试过一个叫Doxygen,但要么我不知道如何正确使用它,要么它和我一样被预处理器的东西弄糊涂了。

我的问题是:
我还有哪些选择?

在这一点上,这是一个折腾:
a.) 转专业
b.) 跳桥

这些选择都不会帮助我更好地理解这个代码库并让它编译。有没有人有更好的想法?类似的经历?圣人智慧分享?

非常感谢,
-亚历克斯

【问题讨论】:

  • 处理此类配置混乱的一种方法是创建一个具有所需配置的空项目,然后比较设置。因此,使用 /MD 和共​​享 MFC dll 创建一个新项目,确保它可以编译,并将其与您的非编译项目进行比较。
  • 我不熟悉 Microsoft 运行时库,但我认为在这种情况下最好的做法是向您的老板解释问题的严重性。把这个问题变成一个 15 分钟的幻灯片演示。要非常酷和专业。不要使用诸如“巨大”或“噩梦”之类的词,否则他们会认为您在夸大其词,并且不要提及您自己的经验不足(“...我不知道发生了什么...”)否则他们会认为这就是问题所在。请记住,您不是抱怨辛勤工作的孩子,您是告知患者危及生命状况的专家。
  • Beta 提出了一个很好的观点,尽管我认为 15 分钟的演示文稿从 =) 开始会有点多。相反,你应该问问你的老板你应该在公司找谁来帮助你了解你面临的错误。
  • 他们现在知道了,他们和我一样困惑。至少知道在这个行业工作了 30 多年的人仍然可以像这样撞墙,这让人松了一口气。我现在有权联系原始软件供应商,请求帮助编译他们的代码。我想我会一直用头撞墙,直到我听到源头的回复。 :-/

标签: c++ mfc doxygen lnk2019 lnk2001


【解决方案1】:

看来您正在使用 CodeProject 中的 CResizableSheet 和 CResizeablePage。如果您使用的是从该页面编译的静态库,您可以尝试下载源代码并使用匹配的 /MDd 设置编译它,并使用它在项目的链接器输入部分中输出的 .lib。我还建议进行全部清理(转到构建->批量构建->全选然后单击清理),然后再次尝试构建以确保一切都是最新的。

【讨论】:

  • 不错的收获!看起来我们确实使用了这里的 ResizableLib 代码:link 不幸的是,它看起来已经过大量修改,添加了几十个文件,生成的静态库比那个大很多倍来自代码项目。幸运的是,我们拥有原始代码和修改代码的所有源文件。不幸的是,这些源文件似乎导致了我在使用 /MTd /MDd 时遇到的链接器问题。 叹息
【解决方案2】:

我听说护理是一个很棒的项目......

冒着迂腐的风险,您要解决的是链接器错误,而不是编译器错误。我的基本方法是创建一个新的解决方案,然后开始一次添加一个项目,让每个项目依次构建。

我也会认真考虑尽可能地标准化每个项目的设置。最简单的方法是在新解决方案中创建空项目,并将现有代码复制到其中。

首先,您应该假设以下设置(与 MFC 相关):

调试:在共享 DLL 中使用 MFC,/MDd
发布:在共享 DLL 中使用 MFC,/MD

MDd 和 MD 是相同的模式,但其中一个链接指向带有额外调试信息的调试库。

那么你所能做的就是一次只做一个项目。请注意,如果您按照建议创建新解决方案,则需要重建项目之间的依赖关系树。 (右键单击一个项目并选择“依赖项”,您会明白我的意思。)

当您在执行此操作时遇到问题时,您应该与工作场所的高级开发人员交朋友 =)。

【讨论】:

  • 那一点也不迂腐。我仍然在两者之间感到困惑。事实上,看起来所有 6 个项目都是单独编译的,但是当我尝试将它们链接在一起时,它们的表现并不好。还不知道该怎么做,但是谢谢!
【解决方案3】:

使用相同的运行时库编译所有内容。故事结束。

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 2020-03-14
    • 2010-11-13
    • 2010-12-22
    相关资源
    最近更新 更多