2

当从位于不同库中的具有相同文件名的类继承时,链接器会产生未解决的外部符号错误。想想这个继承:LIB2::MyClass : public LIB1::MyClass。

静态库“lib1”:

MyClass.h:

namespace LIB1
{

    class MyClass
    {
    public:
        MyClass();

        ~MyClass();
    };
}

静态库“lib2”:

MyClass.h:

    #include "..\MyClass.h"  // Header of MyClass from lib1 somewhere else than this header file
    namespace LIB2
    {

        class MyClass : public LIB1::MyClass
        {
        public:
            MyClass();

            ~MyClass();
        };
    }

假设两个 .cpp 文件都存在。

lib1 中的 lib2 链接

然后一些可执行文件尝试链接 lib2 并使用派生的 MyClass,例如

#include "\lib2\MyClass.h"

int main()
{
    LIB2::MyClass c;            
}

链接失败

错误 LNK2001:未解析的外部符号“公共:__thiscall LIB1::MyClass::~MyClass(void)

(与ctor相同)

当我只是将其中一个 MyClass.cpp 的文件名更改为 MyClass1.cpp 时,一切都很好。

我怀疑链接器不是在 lib1.lib 中搜索 LIB1:MyClass 的定义,而是尝试在 MyClass.obj(来自 lib2)中找到它们。

这种行为感觉太奇怪了,不可能是故意的。我错过了什么?

此外,在 VS2005/2010 中设置解决方案时,包括库和可执行文件,并让 VS 通过项目属性->通用属性->框架和引用设置所有库依赖项(而不是在链接器设置中提供库的路径)链接成功。

4

1 回答 1

0

我刚刚在 Microsoft Visual C++ 2010 Express 中制作了一个解决方案,其中包含两个静态库项目(lib1 和 lib2)和一个应用程序项目(main),其中包含您描述的内容并且能够重现您的问题。这是我得到的完整构建输出:

1>----- 构建开始:项目:lib1,配置:调试 Win32 ------
1> MyClass.cpp
1> lib1.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib1.lib
2>------构建开始:项目:lib2,配置:调试Win32 ------
2> MyClass.cpp
2> 替换 Debug\MyClass.obj
2> lib2.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib2.lib
3>------构建开始:项目:主,配置:调试Win32 ------
3> 主.cpp
3>lib2.lib(MyClass.obj) : error LNK2019: unresolved external symbol "public: __thiscall LIB1::MyClass::MyClass(void)" (??0MyClass@LIB1@@QAE@XZ) 在函数“public: __thiscall LIB2::MyClass::MyClass(void)" (??0MyClass@LIB2@@QAE@XZ)
3>lib2.lib(MyClass.obj) : error LNK2019: unresolved external symbol "public: __thiscall LIB1::MyClass::~MyClass(void)" (??1MyClass@LIB1@@QAE@XZ) 在函数“public”中引用: __thiscall LIB2::MyClass::~MyClass(void)" (??1MyClass@LIB2@@QAE@XZ)
3>c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\main.exe : 致命错误 LNK1120: 2 unresolved externals
========== 构建:2 成功,1 失败,0 最新,0 跳过 ==========

消息“Replaceing Debug\MyClass.obj”阐明了这个问题。此消息由 Microsoft 的库管理器 (LIB.EXE) 在构建 lib2.lib 时发出。为了理解此消息,重要的是要准确了解静态库文件 (.lib) 是什么,以及通过扩展了解 LIB.EXE 的作用。

第一件事是:在构建静态库时实际上没有链接任何代码。.lib 文件只是一个存档,其中包含一个或多个 .obj 文件。换句话说,.lib 文件的目的是提供一种方便的方式将 .obj 文件集合作为一个文件进行分发。LIB.EXE 所做的只是将项目的 .obj 文件打包成一个 .lib 文件。LIB.EXE 还具有对 .lib 文件执行其他操作的选项,例如列出所有包含的 .obj 文件并提取它们;有关详细信息,请参阅MSDN

您的问题指出“lib1 中的 lib2 链接”。我假设这意味着您将 lib1.lib 作为“附加依赖项”放在 lib2 的项目设置中,如下图所示:

在此处输入图像描述

为了准确了解将 .lib 文件添加为像这样的静态库项目的“附加依赖项”的作用,在更改此设置后,我按照此答案中的过程查看运行 LIB 时使用的命令行.EXE 构建 lib2.lib。这是:

lib.exe "/OUT:c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib2.lib" lib1.lib /LIBPATH:..\Debug Debug\MyClass.obj

此命令生成一个名为 lib2.lib 的新静态库文件,其中包含 lib1.lib 中的所有 .obj 文件以及 MyClass.obj。lib1.lib 还包含一个名为 MyClass.obj 的对象这一事实是您问题的根源。正如MSDN 上的 LIB.EXE 文档中所述:

要将库成员替换为新对象,请指定包含要替换的成员对象的库以及新对象(或包含它的库)的文件名。当多个输入文件中存在同名对象时,LIB 会将 LIB 命令中指定的最后一个对象放入输出库中。

当 LIB.EXE 看到 MyClass.obj 的第二个实例时,消息“Replaceing Debug\MyClass.obj”会打印到控制台,因为它认为第二个 MyClass.obj 应该替换第一个。将其中一个 MyClass.cpp 文件重命名为 MyClass1.cpp 可以解决此问题,因为不再有两个名为 MyClass.obj 的目标文件,因此它们可以在同一个 .lib 文件中愉快地生活在一起。

您似乎已经为此想出了一些解决方法,但希望您现在了解您所看到的行为。

于 2012-02-06T01:54:23.997 回答