Categories
c++ c++-faq linker-errors undefined-reference unresolved-external

What is an undefined reference/unresolved external symbol error and how do I fix it?

1716

What are undefined reference/unresolved external symbol errors? What are common causes and how to fix/prevent them?

7

  • @LuchianGrigore ‘feel free to add an answer’ I preferred to add the relevant link (IMHO) your primary answer, if you’d like to permit.

    Mar 3, 2014 at 22:36

  • @jave.web: While that does happen, the programmer usually notices that he has no this pointer and no access to class members. It’s quite rare to complete compilation and only fail during linking, when a non-static member function is missing its qualified-name.

    – Ben Voigt

    Apr 27, 2015 at 22:06

  • @jave.web: This was exactly my problem. Thank you! I am new to cpp, but as far as I can tell, I was having the exact problem that Ben Voigt says was quite rare. I think your solution would make a great answer.

    – RoG

    Oct 20, 2016 at 6:42


  • 7

    They may be useful, just as are many answers to questions that are flagged as too general.

    Aug 16, 2019 at 19:07

  • 1

    I would like to see minimal reproducible example as something we ask of most new users , honestly. I don’t mean anything by it, it is just – we can’t expect people to follow the rules we don’t inforce onto ourselves.

    – Danilo

    Sep 8, 2019 at 18:54


955

Compiling a C++ program takes place in several steps, as specified by 2.2 (credits to Keith Thompson for the reference):

The precedence among the syntax rules of translation is specified by the following phases [see footnote].

  1. Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set
    (introducing new-line characters for end-of-line indicators) if
    necessary. [SNIP]
  2. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to
    form logical source lines. [SNIP]
  3. The source file is decomposed into preprocessing tokens (2.5) and sequences of white-space characters (including comments). [SNIP]
  4. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. [SNIP]
  5. Each source character set member in a character literal or a string literal, as well as each escape sequence and universal-character-name
    in a character literal or a non-raw string literal, is converted to
    the corresponding member of the execution character set; [SNIP]
  6. Adjacent string literal tokens are concatenated.
  7. White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. (2.7). The
    resulting tokens are syntactically and semantically analyzed and
    translated as a translation unit. [SNIP]
  8. Translated translation units and instantiation units are combined as follows: [SNIP]
  9. All external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the
    current translation. All such translator output is collected into a
    program image which contains information needed for execution in its
    execution environment.
    (emphasis mine)

[footnote] Implementations must behave as if these separate phases occur, although in practice different phases might be folded together.

The specified errors occur during this last stage of compilation, most commonly referred to as linking. It basically means that you compiled a bunch of implementation files into object files or libraries and now you want to get them to work together.

Say you defined symbol a in a.cpp. Now, b.cpp declared that symbol and used it. Before linking, it simply assumes that that symbol was defined somewhere, but it doesn’t yet care where. The linking phase is responsible for finding the symbol and correctly linking it to b.cpp (well, actually to the object or library that uses it).

If you’re using Microsoft Visual Studio, you’ll see that projects generate .lib files. These contain a table of exported symbols, and a table of imported symbols. The imported symbols are resolved against the libraries you link against, and the exported symbols are provided for the libraries that use that .lib (if any).

Similar mechanisms exist for other compilers/ platforms.

Common error messages are error LNK2001, error LNK1120, error LNK2019 for Microsoft Visual Studio and undefined reference to symbolName for GCC.

The code:

struct X
{
   virtual void foo();
};
struct Y : X
{
   void foo() {}
};
struct A
{
   virtual ~A() = 0;
};
struct B: A
{
   virtual ~B(){}
};
extern int x;
void foo();
int main()
{
   x = 0;
   foo();
   Y y;
   B b;
}

will generate the following errors with GCC:

/home/AbiSfw/ccvvuHoX.o: In function `main':
prog.cpp:(.text+0x10): undefined reference to `x'
prog.cpp:(.text+0x19): undefined reference to `foo()'
prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
/home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
collect2: ld returned 1 exit status

and similar errors with Microsoft Visual Studio:

1>test2.obj : error LNK2001: unresolved external symbol "void __cdecl foo(void)" ([email protected]@YAXXZ)
1>test2.obj : error LNK2001: unresolved external symbol "int x" ([email protected]@3HA)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" ([email protected]@[email protected])
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" ([email protected]@@UAEXXZ)
1>...\test2.exe : fatal error LNK1120: 4 unresolved externals

Common causes include:

9

  • 22

    Personally, I think the MS linker error messages are just as readable as the GCC errors. They also have the advantage of including both the mangled and unmangled names for the unresolved external. Having the mangled name can be helpful when you need to look at the libraries or object files directly to see what the problem might be (for example, a calling convention mismatch). Also, I’m not sure what version of MSVC produced the errors here, but newer versions include the name (both mangled and unmangled) of the function referring to the unresolved external symbol.

    Dec 30, 2013 at 20:29

  • 9

    David Drysdale wrote a great article about how linkers work: Beginner’s Guide to Linkers. Given the topic of this question, I thought it might prove useful.

    – Pressacco

    May 22, 2015 at 14:48


  • @TankorSmash Use gcc? MinGW to be more precise.

    – doug65536

    Oct 15, 2016 at 1:17


  • 5

    @luchian it would be nice if you add the correct, fixing the above errors

    – Phalgun

    Feb 21, 2018 at 23:35

  • 1

    I just came across another possible reason for the unresolved symbol compiler error. A function was originally defined as inline inside a header, but I changed it to a declaration and defined it separately inside a source file. This failed with an unresolved symbol compiler error until I removed the inline keyword from both the declaration and definition.

    – Jake Levi

    Jan 25 at 17:42

192

Class members:

A pure virtual destructor needs an implementation.

Declaring a destructor pure still requires you to define it (unlike a regular function):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

This happens because base class destructors are called when the object is destroyed implicitly, so a definition is required.

virtual methods must either be implemented or defined as pure.

This is similar to non-virtual methods with no definition, with the added reasoning that
the pure declaration generates a dummy vtable and you might get the linker error without using the function:

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

For this to work, declare X::foo() as pure:

struct X
{
    virtual void foo() = 0;
};

Non-virtual class members

Some members need to be defined even if not used explicitly:

struct A
{ 
    ~A();
};

The following would yield the error:

A a;      //destructor undefined

The implementation can be inline, in the class definition itself:

struct A
{ 
    ~A() {}
};

or outside:

A::~A() {}

If the implementation is outside the class definition, but in a header, the methods have to be marked as inline to prevent a multiple definition.

All used member methods need to be defined if used.

A common mistake is forgetting to qualify the name:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

The definition should be

void A::foo() {}

static data members must be defined outside the class in a single translation unit:

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

An initializer can be provided for a static const data member of integral or enumeration type within the class definition; however, odr-use of this member will still require a namespace scope definition as described above. C++11 allows initialization inside the class for all static const data members.

1

  • Just thought you might want to stress that doing both is possible, and the dtor is not actually an exception. (it’s not obvious from your wording at first glance.)

    Sep 20, 2014 at 19:26

131

Failure to link against appropriate libraries/object files or compile implementation files

Commonly, each translation unit will generate an object file that contains the definitions of the symbols defined in that translation unit.
To use those symbols, you have to link against those object files.

Under gcc you would specify all object files that are to be linked together in the command line, or compile the implementation files together.

g++ -o test objectFile1.o objectFile2.o -lLibraryName

-l... must be to the right of any .o/.c/.cpp files.

The libraryName here is just the bare name of the library, without platform-specific additions. So e.g. on Linux library files are usually called libfoo.so but you’d only write -lfoo. On Windows that same file might be called foo.lib, but you’d use the same argument. You might have to add the directory where those files can be found using -L‹directory›. Make sure to not write a space after -l or -L.

For XCode: Add the User Header Search Paths -> add the Library Search Path -> drag and drop the actual library reference into the project folder.

Under MSVS, files added to a project automatically have their object files linked together and a lib file would be generated (in common usage). To use the symbols in a separate project, you’d
need to include the lib files in the project settings. This is done in the Linker section of the project properties, in Input -> Additional Dependencies. (the path to the lib file should be
added in Linker -> General -> Additional Library Directories) When using a third-party library that is provided with a lib file, failure to do so usually results in the error.

It can also happen that you forget to add the file to the compilation, in which case the object file won’t be generated. In gcc you’d add the files to the command line. In MSVS adding the file to the project will make it compile it automatically (albeit files can, manually, be individually excluded from the build).

In Windows programming, the tell-tale sign that you did not link a necessary library is that the name of the unresolved symbol begins with __imp_. Look up the name of the function in the documentation, and it should say which library you need to use. For example, MSDN puts the information in a box at the bottom of each function in a section called “Library”.

1

  • 4

    It’d be good if you could explicitly cover the common mistake of gcc main.c instead of gcc main.c other.c (which beginners often do before their projects get so large as to build .o files) .

    – M.M

    Nov 4, 2019 at 20:43