Commons reasons for linker errors

After having worked several years in C++ development with Visual Studio, here’s a quite comprehensive compilation of the linker error’s I’ve encountered

Possible reasons for linker errors

Compiler errors most often point to the exact location of the problem. Linker errors in (Visual Studio) C++ are not that programmer-friendly – it’s more of a guesswork, as various reasons lead to the same error message “LNK2019: unresolved external symbol”. Here are some hints (vaguely ordered by occurence in every-day work):

  • The importing project is missing the reference to the exporting project (or the library is not specified in the imports, respectively)
  • Missing dllimport/dllexport statement (usually a macro) before class/function declaration
  • Build problems – the file from which the class/function is imported does not match with the header (e.g. the lib file is out of date for some reason)
  • Function/member variable declared but not implemented
  • Function is implemented with a diffent signature than it was declared with (different name (e.g. typo), different parameters, different return type)
  • Mismatching Character Encoding settings (unicode/non-unicode) in the dlls (which will cause that the signature is different)
  • Mismatching setting for “treat wchar_t as builtin type” (dumpbin/undname is really useful in this case, as it will show the varying types)
  • Problems with the macro that defines the dllimport/dllexport modifier
  • Functions only – the header declaring the function is not included in the file where it is defined
  • The header declaring the class/function is not included in any file in the exporting dll (or that file is excluded from compilation)
  • The calling convention (such as __cdecl) is different in the declaration and the implementation
  • If the linker error involves the main/WinMain function, consider that in UNICODE it is wmain/wWinMain (preferably use _tmain/_tWinMain), or the subsystem linker setting might be wrong – if /SUBSYSTEM:WINDOWS is specified, the main function has to be WinMain (rather use _tWinMain), if /SUBSYSTEM:CONSOLE is specified, the main function has to be main (rather use _tmain).

Additional information is available on the LNK2019 MSDN page

Tools for resolving linker errors

The best tool is your sharp mind, the following two however will be useful in some cases:

  • “undname” undecorates mangled names (i.e. converts something like “?TestFunction@@YAHPBD@Z” to “int __cdecl TestFunction(char const *)”)
  • “dumpbin” shows all exported symbols of a lib/dll file (you can also use your favourite text editor to find the function export in the dll/lib as these are stored in readable text within the binary)

These are mostly useful when there’s a problem with the function signature or the exporting file does not match the exporting headers.

Both need to be started from the Visual Studio Command Prompt.

Example code producing a linker error due to a missing function implementation

(TestDeclaration.h)

THISPROJECT_EXPORT int TestFunction(const char* pChar);
int TestFunction(const int* pChar)
{
	return 0;
}

(TestUsage.cpp)

int i = TestFunction("hi");

As the function is not implemented anywhere, the following linker error will result:

TestUsage.obj : error LNK2019: 
unresolved external symbol "__declspec(dllimport) int __cdecl TestFunction(char const *)" (__imp_?TestFunction@@YAHPBD@Z) 
referenced in function "public: __thiscall TestUsage::TestUsage(void)" (??0TestUsage@@QAE@XZ)

undname

The usage of undname (undecorates names) then looks like this:

c:\Program Files\Microsoft Visual Studio 9.0\VC>undname ?TestFunction@@YAHPBD@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?TestFunction@@YAHPBD@Z"
is :- "int __cdecl TestFunction(char const *)"

dumpbin

The usage of dumpbin looks like this (may produce tons of output, so it’s streamed to a file):

c:\Program Files\Microsoft Visual Studio 9.0\VC>dumpbin -exports C:\dev\linkertest\LinkerTest.lib > C:\dev\linkertest\dump.txt

Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


The dump.txt file then looks like this:

File Type: LIBRARY
[snip...]
                  ?TestFunction@@YAHPBD@Z (int __cdecl TestFunction(char const *))
This entry was posted in Software. Bookmark the permalink.

2 Responses to Commons reasons for linker errors

  1. Narendra says:

    The problem is like this:
    I have a project with many different modules.
    I build .lib for each module (and also some dlls) and then link all of them to create an exe.
    This is working fine.
    But, we had some bug and while root causing this bug, I noticed an issue.
    We have one class (say, class A) in one module and this calls has a static member variable.
    This is used in other modules also and also in the test code, that gets compiled into exe.
    Since the member variable is a static variable, it is supposed to have a single instance in the whole project.
    But, since we are compiling .lib files, .dlls and .exe separately, each of them have different instance of this static variable.
    So, to solve this I used __declspec(dllexport) for compiling .lib and .dlls
    and used __declspec(dllimport) while compiling .exe.
    The .lib and .dlls get built without any issues.
    But, while building exe, I am getting the error:

    Error 90 error LNK2005: "public: class com_sony_csx_loader::ICacheManager * __thiscall my_space::ClassA::getManager(void)const " (?getManager@ClassA@my_space@@QBEPAVICaManager@2@XZ) already defined in LibB.lib(LibB.dll) D:\Proj-ABC\workspace_win7\develop\dir1\dir2\dir3\tests\LibA.lib(fileX.obj)

    The “class A” that I mentioned is part of LibA.lib.
    And LibB.lib needs LibA.lib. So, LibA.lib is linked while building LibB.lib.

    And the exe depends on both LibA.lib and LibB.lib. So, it is linked to both the libraries.

    When I don’t use dllexport/dllimport, I am not getting any error.
    But, when I use dllexport/import, I get one error for each of the methods of “class A”.

    Can you please suggest me, what could be wrong and any ways to solve this?

  2. Sti says:

    I haven’t worked with C++ for years, but I think the solution is that you need to use the appropriate dllexport/dllimport statements (using macros) for your modules.

    When building LibA, you need to use dllexport, when builing LibB and the exe, you need to use dllimport.
    From what you’re describing, you also need to have LibB use dllimport. You must already be using some macros to switch the dllexport/dllimport for building LibA and the exe, you just need to set the macro switch variable for LibA while building LibB

    Or, if the only reason why you need to do this is the static variable you mentioned, you could move from the class to a c-type static variable only declared in the implementation file, and only provide getters and setters in the class, thus it would be limited to only this one module. But the better solution (and more robust for the future, e.g. if you introduce additional static variables) is of course to use the correct dllexport/dllimport linkage.

    Hope that helps

Comments are closed.