Search code examples
c++inheritancestaticunresolved-external

Classes with same file name in different libs inheritance issue


When inheriting from a class with the same filename that resides in a different lib the linker yields an unresolved external symbol error. Think of this inheritance: LIB2::MyClass : public LIB1::MyClass.

static lib "lib1":

MyClass.h:

namespace LIB1
{

    class MyClass
    {
    public:
        MyClass();

        ~MyClass();
    };
}

static lib "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();
        };
    }

Let's assume both .cpp files exist.

lib2 links in lib1

Some executable then tries to link in lib2 and use the derived MyClass, say

#include "\lib2\MyClass.h"

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

Linking fails with

error LNK2001: unresolved external symbol "public: __thiscall LIB1::MyClass::~MyClass(void)

(same for ctor)

When I simply change the file name of one of the MyClass.cpp to MyClass1.cpp everything is fine.

Instead of searching the definitions for LIB1:MyClass in lib1.lib the linker tries to find them in MyClass.obj (from lib2) I suspect.

This behaviour just feels way too strange to be intentionally. What am I missing?

Furthermore when setting up a solution in VS2005/2010 including both the libs and the executable and having VS set up all lib dependencies through Project Properties->Common Properties->Framework and References (instead of supplying paths to the libs in the linker settings) linking succeeds.


Solution

  • I just made a solution in Microsoft Visual C++ 2010 Express containing two static library projects (lib1 and lib2) and an application project (main) with the contents that you describe and was able to reproduce your problem. Here is the complete build output I get:

    1>------ Build started: Project: lib1, Configuration: Debug Win32 ------
    1>  MyClass.cpp
    1>  lib1.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib1.lib
    2>------ Build started: Project: lib2, Configuration: Debug Win32 ------
    2>  MyClass.cpp
    2>  Replacing Debug\MyClass.obj
    2>  lib2.vcxproj -> c:\users\samuel windwer\documents\visual studio 2010\Projects\linker_test\Debug\lib2.lib
    3>------ Build started: Project: main, Configuration: Debug Win32 ------
    3>  main.cpp
    3>lib2.lib(MyClass.obj) : error LNK2019: unresolved external symbol "public: __thiscall LIB1::MyClass::MyClass(void)" (??0MyClass@LIB1@@QAE@XZ) referenced in function "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) referenced in function "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 : fatal error LNK1120: 2 unresolved externals
    ========== Build: 2 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    

    The message "Replacing Debug\MyClass.obj" sheds some light on the issue. This message was emitted by Microsoft's Library Manager (LIB.EXE) while building lib2.lib. In order to understand this message, it is important to understand exactly what a static library file (.lib) is, and by extension, exactly what LIB.EXE does.

    First thing's first: no code is actually linked when building a static library. A .lib file is just an archive that contains one or more .obj files inside of it. In other words, the purpose of a .lib file is to provide a convenient way to distribute a collection of .obj files as one file. All that LIB.EXE does is package up the project's .obj files into a .lib file. LIB.EXE also has options for doing other stuff with .lib files, such as listing all of the contained .obj files and extracting them; see MSDN for more info.

    Your question states that "lib2 links in lib1." I'm assuming this means that you put lib1.lib as an "Additional Dependency" in lib2's project settings, as shown in this screenshot:

    enter image description here

    In order to understand exactly what adding a .lib file as an "Additional Dependency" of a static library project like this does, after changing this setting, I followed the procedure in this answer to see the command-line that is used when running LIB.EXE to build lib2.lib. Here is is:

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

    This command produces a new static library file named lib2.lib that contains all of the .obj files in lib1.lib, as well as MyClass.obj. The fact that lib1.lib also contains an object named MyClass.obj is the source of your problem. As is stated in LIB.EXE's documentation on MSDN:

    To replace a library member with a new object, specify the library containing the member object to be replaced and the file name for the new object (or the library that contains it). When an object that has the same name exists in more than one input file, LIB puts the last object specified in the LIB command into the output library.

    The message "Replacing Debug\MyClass.obj" is printed to the console when LIB.EXE sees the second instance of MyClass.obj because it thinks that the second MyClass.obj is supposed to replace the first one. Renaming one of the MyClass.cpp files to MyClass1.cpp fixes this problem because there are no longer two object files named MyClass.obj, so both of them can live happily together in the same .lib file.

    It seems that you've already come up with some workarounds for this, but hopefully you now understand the behavior that you're seeing.