Troubleshooting LNK2001 or L2029 Unresolved External Errors

This article was previously published under Q138400
This article has been archived. It is offered "as is" and will no longer be updated.
The linker issues an Unresolved External message if it cannot resolve theaddress of a function while building a project.

With the 16-bit version of Visual C++, this message is:
L2029: '__symbol': unresolved external
With the 32-bit version of Visual C++ version 1.0, this message is:
LNK4016: unresolved external symbol '__symbol'
With the 32-bit version of Visual C++ version 2.0 and later, this messageis:
LNK2001: unresolved external symbol '__symbol'
The '__symbol' might be a label, a variable, or a function name.

This article discusses some of the most common causes of this error to helpyou troubleshoot it.
The following explanation of linker behavior explains why this erroroccurs. This is a simplified model, and the internal implementation mayvary slightly between compiler versions; however, the information issufficient for trying to find the cause of this error message.

During the compilation of a source file, name tables are built for eachobject module to allow the referencing of symbols between object modules. Apublic symbols table (PST) is created, which contains all of the publicsymbols for a given object module. Public symbols are symbols that otherobject modules can refer to -- such as global functions and variables. Eachobject module also has an unresolved symbol table (UST), which contains alist of symbols that need to be resolved for that module.

If no link errors occur, the linker can create a .map file that lists allthe public symbols (a combined PST table) contained in the object modulesthat were linked together.

To generate a .map file with 16-bit Visual C++, use the /MAP:FULL linkeroption. In the Visual Workbench, on the Options menu, click Project, andthen click Linker. Set the category to Miscellaneous, and place /MAP:FULLin the Other Options edit box. For 32-bit Visual C++, use the/MAP:<filename> option. With version 4.0, on the Build menu, clickSettings, and then switch to the Linker tab. Change the Category toGeneral, and select the Generate Map File check box.

Figure 1

                              Public Symbols for OBJ 1Module 1                      _____________________ _____________________________|    _var1----------|------------------|                             |    _func1         |                 || var1                        |___________________|                 || .                              |  PST for OBJ 1                   || .                              |                                  || .                              |                                  || func1 {                        |Required Symbols for OBJ 1        ||            func2( );         __|__________________                ||            var1 = 2;        |    _func2           |<<________     ||            var2 = 4;        |    _var2            |<<______ |     ||            }                |_____________________|       | |     ||                                |  UST for OBJ 1           | |     ||________________________________|                          | |     |                                                            | |     |                                                            | |     |                                                            | |     |                              Public Symbols for OBJ 2      | |     |Module 2                      _____________________         | |     | _____________________________|    _var2----------|---------| |     ||                             |    _func2---------|-----------|     || var2                        |___________________|                 || .                              |  PST for OBJ 2                   || .                              |                                  || .                              |                                  || func2 {                        |Required Symbols for OBJ 2        ||            func3( );         __|__________________                ||            var1 = 3;        |    _var1            |_______________||            var2 = 5;        |    _func3           |_______________|            }                |_____________________|               ||                                |  UST for OBJ 2                   ||________________________________|                                  |                                                                    |                                                                    |                                    Unresolved External Error is issued                                    for _func3() because there is no                                    definition found for func3() in                                    the PST for either OBJ module.				
The linker uses the PST and UST of a project's object and library files tomatch symbol names. If the linker finds a symbol in a UST table and cannotfind a matching entry in one of the many PST tables, it issues an"Unresolved External" error message. For example, in Figure 1, the linkercannot resolve the address for the function func3() and therefore issues an"Unresolved External" error.

Frequent Causes of the "Unresolved External" Error Message

The remainder of this article discusses in detail each of the followingpossible causes of "Unresolved External" errors:

  • Missing Object Files or Libraries
  • Missing Function Body or Variable
  • Symbol Can't be Found in the Libraries or Object Modules
  • Case Sensitivity
  • Name Decoration
  • A Symbol Is Not Public
  • Scoping Problems and Pure Virtual Functions
  • Function Inlining
  • Wrong Compiler Options or Mixing Incompatible Libraries

Missing Object Files or Libraries

If a needed object module or library is not included on the link commandline, the linker may not be able to find addresses for one or more symbols,so it issues an unresolved external error message. You need to place thenecessary library or object file in the project.

The names of the C Run-Time libraries needed at link time are included inthe object module by the compiler. For 32-bit versions of Visual C++, theMFC libraries are also included. If you use the /NOD (/NODEFAULTLIB) linkerswitch, these libraries will not be linked into the project unless you haveexplicitly included them. The same problem occurs if you use the/NOD:<libraryname> switch to prevent specific libraries from being linkedin.

If the unresolved external is a C Run-Time library function, then you needto specify the Run-Time library to the linker. Starting with Visual C++version 4.0, the libraries containing the C Run-Time function are listed inthe online help for the function.

With Visual C++ version 4.0, the library containing each Windows APIfunction is listed under the QuickInfo link in the online help for eachfunction. For 32-bit versions of Visual C++, a list of the librariescontaining each Windows API function is in the Win32api.csv file located inthe \Lib subdirectory. This is a comma-separated variable file that can beloaded into a spreadsheet for easy viewing. It can also be viewed with atext editor. Note that there is no similar file for the 16-bit Windows APIfunctions.

A DLL should provide a .lib or .def file that allows the linker to resolvereferences to the DLL functions unless you are using explicitLoadLibrary()and GetProcAddress() calls in your code.

With the 16-bit linker, using over 32 libraries will cause problems as the33rd library will be ignored. For more information, please see thefollowing article in the Microsoft Knowledge Base:
31986Maximum Number of Libraries LINK Supports

Missing Function Body or Variable

If just a function prototype is provided, the linker will not be able toresolve any function calls because there is no function definition. As aresult, the function is not listed in the combined PST table. Similarly, ifan external variable is declared but not defined, the same problem occurs.

For example:
   /* test.cpp  */      void DoSomething(void);   void main(void){   DoSomething( );   // This line causes an unresolved external error                     // because the prototype for DoSomething() allows the                     // compiler to think the function exists. However,                     // the linker finds that it doesn't.   }				
When using C++, make sure you provide a function definition for eachfunction in a class and not just a prototype in the class definition. Ifyou are defining the function outside of the class definition, be sure toinclude the class name before the function in the Classname::MemberFunctionstyle. See the "Scoping Problems and Pure Virtual Functions" section for anexample.

Symbol Can't Be Found in the Libraries or Object Modules

Use Dumpbin.exe or Lib.exe to find out if the symbol is in the objectmodule or library.

With 32-bit COFF object modules and libraries, you can verify whether asymbol is in the file with Dumpbin.exe. For object modules, use thiscommand:
   DUMPBIN /SYMBOLS <filename.obj>				
For libraries, use this command:
    DUMPBIN /LINKERMEMBER[:{1|2}] <libraryname.lib>				
For 16-bit libraries, use Lib.exe to view the symbols defined in thelibrary. To create a listing use this command:
   LIB <filename.lib>, <filename.lst>				
If you want to determine what symbols are contained in an object module,create a dummy library and listing file from the object module withLib.exe. For example:
   LIB <dummy.lib> +<filename.obj>, <filename.lst>				
On Windows 95, you can use the QuickViewer to see some of this sameinformation for .exe and .dll files.

Some functions can only be used in certain environments so they are not inevery library. To determine what environment a Run-Time function can beused in, check the compatibility in the online documentation.

Not every compiler vendor offers the same libraries of functions. Microsoftoffers all the ANSI standard functions for C plus many others. Microsoftmay offer functions other companies do not, and vice-versa. Similarly,mixing versions of Microsoft libraries and compiler products can beproblematic. Each released product is tested only with components includedin that release, unless otherwise stated in the documentation or releasenotes. A new compiler version's libraries may contain new symbols thatcannot be found in the libraries included with previous versions.

Case Sensitivity

Case is important when linking function references in each object module'sUST to the references in the PSTs. The only exception is if you are doingall three of the following:

  • Compiling C code only.

  • Using the 16-bit linker.

  • Not using the /NOI switch. Note that using this switch specifies that the 16-bit linker should take case into account when linking.
The best solution is to exactly match the case of the symbol in allreferences and in all instances. For example, if you name a variable "var1"in one source file and try to access it as "VAR1" in another, you wouldreceive an unresolved external error. Again, only in the one exceptionnamed above would the 16-bit linker link references to var1, VaR1, VAR1,vAR1 all to the same address.

Name Decoration

Usually "name decoration" refers to C++ naming conventions, but it appliesto a number of non-C++ cases as well. The compiler may use the name of afunction, its parameters, and its return type when calculating a name for afunction. For example, with Visual C++ 2.0, the function name for
   void CALLTYPE test(void)				
might come to anything in the following table depending on what theCALLTYPE is and whether it is a C or a C++ file.
   Calling convention         extern "C"     .CPP, .CXX, or .C file      C naming convention   (__cdecl)                  _test          ?test@@YAXXZ      Fastcall naming   convention (__fastcall)    @test@0        ?test@@YIXXZ      Standard Call naming   convention (__stdcall)     _test@0        ?test@@YGXXZ				
CALLTYPEs such as _cdecl, _fastcall, and _stdcall change the namingconventions for a function or variable. The 32-bit specific__declspec(<attribute>) modifier can also affect the name of the function.

If using C++, be sure to use extern "C" if you are calling a C functionfrom a C++ program or if you are calling a function in a C++ from a Cprogram. Extern "C" forces use of the C naming convention for global C++functions; this enables them to be called from a C program. Be aware ofcompiler switches like /Tp or /Tc that force a file to be compiled as a C(/Tc) or C++ (/Tp) file regardless of the filename extension, or you mayget different function names than you expected.

Function prototypes with mismatched parameters can also cause unresolvedexternal errors. Many name-decoration schemes incorporate the parameters ofa function into the final decorated function name. Calling a function withparameter types that do not match those in the function definition may alsocause this error. This can be a problem in other languages, like FORTRAN,which may also add name decoration to a function. In the following example,the header file with the function prototype does not match the functiondefinition; this causes the problem.

   // Test1.h   void _stdcall func( char, float );      // Test1.cpp   void _stdcall func( char a ){        a = 'a';   }      // Test.cpp   #include "test1.h"   void main(void) {       char var1;       float var2 = 5;       func ( var1, var2 ); // Unresolved external error occurs here   }				
There is no set standard for naming conventions between compiler vendors oreven between different versions of a compiler. Therefore cross-linkingobject files compiled with other compilers or compiler versions may causeunresolved externals.

A Symbol Is Not Public

Only global functions and variables are placed in the object file's PSTtable. Trying to access variables of the types below may cause UnresolvedExternals.

Static functions/variables:

"Static" functions and variables have file scope. Trying to access staticsymbols from outside of the file they are defined in will cause anunresolved external. For example:
   /* main.cpp */       extern void func1(void);      void main(void) {      func1();          // Unresolved external occurs because func1() is a                        // static function in the file test.cpp.    }      /* test.cpp */       static void func1(void) {      //Do something     }				
Automatic (function scope) variables:

A variable declared within a function can only be used within the scope ofthat function. For example:
   /* main.cpp */     void test(void);       static int lnktest3 = 3;    int lnktest4 = 4;       void main()  {       static int lnktest1 = 1;       int lnktest2 = 2;       test();    }      /*  test.cpp */     extern int lnktest1;    extern int lnktest2;    extern int lnktest3;    extern int lnktest4;       void test(void)    {      int i =0;       i = lnktest1;   //causes unresolved external, reason 6-2       i = lnktest2;   //causes unresolved external, reason 6-2       i = lnktest3;   //causes unresolved external, reason 6-1       i = lnktest4;   // OK    }				
Global Constants in C++:

C++ global constants have static linkage. This is different from C. If youtry to use a global constant in C++ in multiple files, you get anunresolved external error. The following code illustrates this error:
   /* main.cpp */     void test(void);    const int lnktest1 = 0;    void main(void) {    test( );    }      /* test.cpp */      extern int lnktest1;     void test(void)  {      int i = lnktest1;   // Causes unresolved external, reason 6-3    }				
One alternative is to include the const initializations in a header file,and include that header in your C++ files when necessary, just as if it wasa function prototype. Another possibility is to make the variable non-constant and use a const reference when accessing it.

Global Inline Functions in C++:

Global inline functions have static or internal linkage. They cannot becalled from functions in other modules. See the "Function Inlining" sectionfor further information on function inlining.

Scoping Problems and Pure Virtual Functions

A common cause of scoping problems is incorrectly included prototypes thatcause the compiler to expect a function body that is not provided.

A::F() or F():

Sometimes a call to a function F() may map to a class implementation, classA::F(), instead of a global implementation of F() because C++ implicitlylinks with class implementations when resolving function calls inside otherclass function bodies. Alternatively, if you defined the C++ implementationof a class member function A::F() outside of the class declaration itself,you must explicitly include the class name in the function definition. Bothof these cases can cause confusion if you have both a class and a globalimplementation of a function F(). For example:
   /* test.cpp */       class A {    public:      F(void);      // No implementation here.      void PublicStatMemFunc1(void) {          F( );     // This implicitly calls A::F because it's      }             // inside a class member function declaration.                    // May have forgotten to implement A::F() or meant                    // to call ::F( )      };      void F(void) {  //Maybe meant to be the implementation of A::F( ) ?   }      void main(void) {      A testclsObject;      testclsObject.PublicStatMemFunc1( ); //This code needed for compiler                                           // to add entry to UST and                                           // generate unresolved external.   }				
This case could be wrong in one of two ways. The function call inPublicStatMemFunc1() should have the scope resolution operator (::) addedto make a call to ::F(). The compiler will then know that the user meant tocall a global function. Alternatively, if the user meant F() to be theclass implementation of F(), the definition needs to be changed to A::F().

Abstract Base classes:

Attempting to call a pure virtual C++ function from the constructor ordestructor of an abstract base class also causes this problem. This isbecause by definition, a pure virtual function should have no base classimplementation. The following example illustrates this situation:
   /* test.cpp */       class testcls {   public:    virtual void DoSomething(void)=0;  // Makes this a virtual base class    testcls::testcls( )  {      DoSomething( );    }   };      class testcls2: public testcls {   public:     virtual void DoSomething(void) {} ;   };      void main(void) {     testcls2 testclsObject;  // Needs to be here for error to occur                              // since it forces the compiler to call                              // the constructor for testcls.   }				

Function Inlining

Mixing inline and non-inline compile options on different modules can causeproblems. Consider the following example that has:

  • A library Test.lib with inline functions.
  • A header file containing the function prototypes for the library (Test.h).
  • An application App.exe, which is linking with Test.lib using the Test.h header file.
If Test.lib is created with function inlining turned on (/Ob1 or /Ob2), youwill get an unresolved external error on any inline functions from Test.libthat are used in App.exe. The function's address is not in the PST forTest.lib because the functions were inlined inside the library. You need toeither disable inlining (/Ob0) when building the library or place theinline function code in the header file (Test.h).

Similarly, a project that uses function inlining yet defines the functionsin a source file rather than in the header file will also get this error.The header file is included everywhere deemed appropriate, but thefunctions are only inlined in the source file where they are defined.Therefore, the linker sees the functions as unresolved externals when usedin other modules. For example:
   /* Compile Options Needed: /Ob1 or /Ob2  */       /* testcls.h */    class testcls {    public:     void PublicFunc(void);   };      /* clasfunc.cpp */    #include "testcls.h"   inline void testcls::PublicFunc(void) {}   void DummyFunc(void) {     testcls TestClass;     TestClass.PublicFunc();   }      /* test2.cpp */    #include "testcls.h"   void main(void) {    testcls testclsObject;    testclsObject.PublicFunc( );                       // This adds the entry to UST and causes an                       // unresolved external because this module can not    }                  // see the implementation of PublicFunc( );				
For more information on inline functions and unresolved externals, pleasesee the following article in the Microsoft Knowledge Base:
123768Unresolved Externals for Inline Functions
When inlining, if you are using the #pragma inline_depth compilerdirective, make sure you have set a value of one or greater. A value ofzero will turn off inlining. Also use the /Ob1 or /Ob2 compiler switches.These switches allow the compiler to inline functions. To set these optionsin 32-bit Visual C++ version 4.0, on the Build menu, click Settings, andthen switch to the C/C++ tab, and choose Optimizations. For 16-bit VisualC++, on the Options menu, click Project, and then click Compiler, andchange the Category to Optimizations.

NOTE: You can't force the compiler to inline anything. You can only suggestfunctions that would be suitable for inlining with the options mentionedabove.

Wrong Compiler Options or Mixing Incompatible Libraries

Certain compiler options have implications with respect to the library thatshould be used at link time. The following table shows the relationship forVisual C++ version 2.x. The compiler will include the name of the libraryyou should link to in the object file. Using the /NODEFAULTLIB switch willcause the compiler to ignore these references, so you need to make surethat you link with the correct libraries.
Compile option   Run-time usage            Link with--------------------------------------------------------/ML (default)    Single threaded static                 run-time library          Libc.lib/MT              Multithread run-time                 library                   Libcmt.lib/MD              Multithread using DLL     Msvcrt.lib/LD              Changes the default run-time library support                 to /MT if you have not explicitly specified                 /MD, /ML, or /MT.				
Msvcrt.lib will link with a different version of the run time depending onthe version of Visual C++ that you are using. For version 2.x, the DLL isMsvcrt20.dll. Also, note that with Visual C++ version 2.x, there are twoversions of Msvcrt20.dll -- one that targets Windows NT and Windows 95 andone that targets Win32s. For more information on these DLLs, please see thefollowing article in the Microsoft Knowledge Base:
125476PRB Error "...MSVCRT20.DLL is not compatible with Win32s"
Libc.lib, Libcmt.lib, and Msvcrt.lib and their corresponding compileoptions are mutually exclusive for one project. Only one switch and itscorresponding library should be used for compiling and linking all of themodules in a project.

The following are some cases where these options can cause unresolvedexternals:

  • Linking code compiled with an explicit or implicit /ML to the Libcmt.lib or Msvcrt.lib library causes various unresolved externals. A fairly common unresolved symbol is _errno.
  • Linking code compiled with /MT with Libc.lib may cause unresolved externals on _beginthread, _beginthreadex, _endthread, and _endthreadex. LIBC is not multithreaded, so it does not contain these run-time functions. This case occurs with Visual C++ version 2.0. The version of MFC that shipped with 2.0 is multithread-aware.
  • Compiling with /MD and then linking with the LIBC or LIBCMT libraries may result in unresolved externals. When using /MD a call to a run-time function in your source code becomes a reference "__imp__function" in the object because the C Run-Time Library functions will be imported from Msvcrtxx.dll rather than be statically linked. For example:
       /* Test.c                                    */    /* Compile Options: /MD /c                   */    /* Link Options: /NOD:msvcrt.lib libcmt.lib  */    #include <stdio.h>   void main(void) {      printf("hello"); // Generates unresolved external on __imp__printf   }						
  • With Visual C++ version 4.0, if you compile with the /MLd, /MTd, or /MDd options or define _DEBUG and there are calls to any of the Debug Routines, then linking with the non-debug libraries will cause unresolved externals on the debug routines.
Search in the Microsoft Knowledge Base using L2029 for a list of articlesthat describe the problems you may encounter with the 16-bit version ofVisual C++. For the 32-bit versions, search using LNK2001 or LNK4016.

Article ID: 138400 - Last Review: 12/04/2015 12:12:21 - Revision: 2.1

Microsoft C/C++ Professional Development System 7.0, Microsoft Visual C++ 1.0 Professional Edition, Microsoft Visual C++ 1.5 Professional Edition, Microsoft Visual C++ 1.51, Microsoft Visual C++ 1.52 Professional Edition

  • kbnosurvey kbarchive kbprb KB138400