1833

What are undefined reference/unresolved external symbol errors? What are common causes, and how do I fix and prevent these errors?

9
  • 1
    @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. Commented Apr 27, 2015 at 22:06
  • 2
    @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. Commented Oct 20, 2016 at 6:42
  • 2
    @Snaptastic see stackoverflow.com/a/12574407/673730 - A common mistake is forgetting to qualify the name :) Commented Oct 20, 2016 at 19:59
  • 9
    They may be useful, just as are many answers to questions that are flagged as too general. Commented Aug 16, 2019 at 19:07
  • 3
    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. Commented Sep 8, 2019 at 18:54

40 Answers 40

1
2
7

Functions or class-methods are defined in source files with the inline specifier.

An example:-

main.cpp

#include "gum.h"
#include "foo.h"

int main()
{
    gum();
    foo f;
    f.bar();
    return 0;
}

foo.h (1)

#pragma once

struct foo {
    void bar() const;
};

gum.h (1)

#pragma once

extern void gum();

foo.cpp (1)

#include "foo.h"
#include <iostream>

inline /* <- wrong! */ void foo::bar() const {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

gum.cpp (1)

#include "gum.h"
#include <iostream>

inline /* <- wrong! */ void gum()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

If you specify that gum (similarly, foo::bar) is inline at its definition then the compiler will inline gum (if it chooses to), by:-

  • not emitting any unique definition of gum, and therefore
  • not emitting any symbol by which the linker can refer to the definition of gum, and instead
  • replacing all calls to gum with inline copies of the compiled body of gum.

As a result, if you define gum inline in a source file gum.cpp, it is compiled to an object file gum.o in which all calls to gum are inlined and no symbol is defined by which the linker can refer to gum. When you link gum.o into a program together with another object file, e.g. main.o that make references to an external symbol gum, the linker cannot resolve those references. So the linkage fails:

Compile:

g++ -c  main.cpp foo.cpp gum.cpp

Link:

$ g++ -o prog main.o foo.o gum.o
main.o: In function `main':
main.cpp:(.text+0x18): undefined reference to `gum()'
main.cpp:(.text+0x24): undefined reference to `foo::bar() const'
collect2: error: ld returned 1 exit status

You can only define gum as inline if the compiler can see its definition in every source file in which gum may be called. That means its inline definition needs to exist in a header file that you include in every source file you compile in which gum may be called. Do one of two things:

Either don't inline the definitions

Remove the inline specifier from the source file definition:

foo.cpp (2)

#include "foo.h"
#include <iostream>

void foo::bar() const {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

gum.cpp (2)

#include "gum.h"
#include <iostream>

void gum()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Rebuild with that:

$ g++ -c  main.cpp foo.cpp gum.cpp
imk@imk-Inspiron-7559:~/develop/so/scrap1$ g++ -o prog main.o foo.o gum.o
imk@imk-Inspiron-7559:~/develop/so/scrap1$ ./prog
void gum()
void foo::bar() const

Success.

Or inline correctly

Inline definitions in header files:

foo.h (2)

#pragma once
#include <iostream>

struct foo {
    void bar() const  { // In-class definition is implicitly inline
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};
// Alternatively...
#if 0
struct foo {
    void bar() const;
};
inline void foo::bar() const  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#endif

gum.h (2)

#pragma once
#include <iostream>

inline void gum() {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

Now we don't need foo.cpp or gum.cpp:

$ g++ -c main.cpp
$ g++ -o prog main.o
$ ./prog
void gum()
void foo::bar() const
Sign up to request clarification or add additional context in comments.

Worth noting that if you put the definition in the header but omit the inline specifier you get the opposite error: Duplicate symbols ;-). Interestingly, the only guaranteed effect of inline is that it makes a definition file static. (In particular, inline makes no guarantee to actually inline anything ;-).)
6

Some typo errors to consider: (happened to me as a beginner a lot)

  • If you are using a class: check if you have not forgetton "classname::" before the function name inside your cpp file where you define the the function.
  • If you use forward declaration: be sure to declare the right type. E.g.: if you want to forward declare a "struct" use "struct" and not "class".

Actually the only difference between struct and class is whether the members default to public or private. I can't imagine an example where confusing the two would lead to the error in the question.
About the struct / class forward declaration: only MSVC will generate link errors when mixing the keywords. In that aspect, MSVC does not follow C++ Standard, but Microsoft has no plan to fix this bug as this would break ABI compatibility.
I would suggest you to add some explanations about the struct / class. @MarkRansom: This is because MSVC mangles both keywords differently, unlike GCC or Clang. You are the only answer that mentions that link error, but I faced it already a few times with our cross-platform company code base. As Windows is not our primary development platform, we typically discover it after commit is pushed, in CD/CI...
@prapin I did not know about MSVC's differing treatment of struct vs. class, thanks for the education. Being consistent about which keyword you use should be common sense no matter which compiler you use.
4

When you are using a wrong compiler to build your program

If you are using gcc or clang compiler suites, you should use the right compiler driver according to the language you are using. Compile and link C++ program using g++ or clang++. Using gcc or clang instead will cause references to the C++ standard library symbols to be undefined. Example:

$ gcc -o test test.cpp    
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: warning: relocation against `_ZSt4cout' in read-only section `.text' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `main': test.cpp:(.text+0xe): undefined reference to `std::cout' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x13): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccPv7MvI.o: in function `__static_initialization_and_destruction_0(int, int)': 
test.cpp:(.text+0x43): undefined reference to `std::ios_base::Init::Init()' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: test.cpp:(.text+0x58): undefined reference to `std::ios_base::Init::~Init()' 
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: warning: creating DT_TEXTREL in a PIE 
collect2: error: ld returned 1 exit status

Comments

3

Different architectures

You may see a message like:

library machine type 'x64' conflicts with target machine type 'X86'

In that case, it means that the available symbols are for a different architecture than the one you are compiling for.

On Visual Studio, this is due to the wrong "Platform", and you need to either select the proper one or install the proper version of the library.

On Linux, it may be due to the wrong library folder (using lib instead of lib64 for instance).

On MacOS, there is the option of shipping both architectures in the same file. It may be that the link expects both versions to be there, but only one is. It can also be an issue with the wrong lib/lib64 folder where the library is picked up.

Comments

3

Your linkage contains C++ object files and C++ libraries originating from different C++ compilers.

Typically, this type of undefined reference linkage error affects those attempting, on Windows, to make a linkage including C++ object files originating from the Windows GCC C++ compiler and libraries originating from Microsoft Visual C++, or vice versa.

The compilers are ABI incompatible. Part of that incompatibility is that they use different C++ name-mangling schemes. This means, e.g, that the function signature:

std::string greet()

is output to the linker by GCC C++ as the symbol:

_Z5greetB5cxx11v

but as:

?greet@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ

by MS Visual C++. So a reference to one does not match a definition of the other.

The different name mangling schemes are positively valuable because they guarantee a commonplace type of linktime failure in the absence of which subtler ABI incompatibility errors would ensue.

Such undefined reference errors might puzzle a first-time victim, because the linker's diagnostic helpfully de-mangles the name of the undefined symbol back to C++, and the victim is (correctly) sure that precisely that C++ identifier is defined in a linked library. But when the object file containing the undefined reference is examined without demangling with an appropriate binary utility - dumpbin (MS), nm or objdump (GNU) - and likewise the library in which the symbol is defined, the incongruity of nomenclature will be obvious.

Comments

2

Using Visual Studio Code with the Code Runner extension and multiple .c or .cpp files

Code Runner as shipped only works with compiled programs that have a single source file. It is not designed for use with multiple source files. You should use a different extension, such as the C/C++ Makefile Project extension or the CMake Tools extension, or perhaps fix the Code Runner extenion to work with multiple files, or just edit your .json configuration files by hand.

Comments

1

My example:

header file

class GameCharacter : public GamePart
{
    private:
        static vector<GameCharacter*> characterList;
...
}

.cpp file:

vector<GameCharacter*> characterList;

This produced an "undefined" loader error because "characterList" was declared as a static member variable, but was defined as a global variable.

I added this because -- while someone else listed this case in a long list of things to look out for -- that listing did not give examples. This is an example of something more to look for, especially in C++.

The fix is to add qualification to the global variable to define the static data member:

vector<GameCharacter*> GameCharacter::characterList;

While keeping the header the same.

This answer doesn't add suitable info for this question. You use not-standard macros(?) defines like TRUE. Thus users searching for an answer here may be overwhelmed by your use of vectors and inheritance.
0

This issue occurred for me by declaring the prototype of a function in a header file:

int createBackground(VertexArray rVA, IntRect arena);

But then defining the function elsewhere using a reference with the first parameter:

int createBackground(VertexArray& rVA, IntRect arena) {}

The fact that the prototype was not using a reference in the first parameter, while the definition was, was causing this issue. When I changed both to properly match either containing a reference or not containing a reference, the issue was fixed.

Cheers.

Comments

0

In my case, The syntax was correct, yet I had that error when a class calls a second class within the same DLL. the CPP file of the second class had the wrong Properties->Item Type inside visual studio, in my case it was set to C/C++ Header instead of the correct one C/C++ compiler so the compiler didn't compile the CPP file while building it and cause the Error LNK2019

here's an example, Assuming the syntax is correct you should get the error by changing the item type in properties

//class A header file 
class ClassB; // FORWARD DECLERATION
class ClassA
{
public:
ClassB* bObj;
ClassA(HINSTANCE hDLL) ;
//  member functions
}
--------------------------------
//class A cpp file   
ClassA::ClassA(HINSTANCE hDLL) 
{
    bObj = new ClassB();// LNK2019 occures here 
    bObj ->somefunction();// LNK2019 occures here
}
/*************************/

//classB Header file
struct mystruct{}
class ClassB{
public:
ClassB();
mystruct somefunction();
}

------------------------------
//classB cpp file  
/* This is the file with the wrong property item type in visual studio --C/C++ Header-*/
ClassB::somefunction(){}
ClassB::ClassB(){}

Comments

0

I am building a shared/dynamic library. It works on Linux and *BSD, but on Mac OS X the exact same compile and link commands produce unresolved reference errors. What gives?

Mac OS X is very different from Linux and *BSD internally. The object/executable format is

On Linux and *BSD, when building shared libraries, unresolved references are allowed by default. The expectation is that they will be satisfied at load time against the (yet unknown) main executable and/or other shared libraries. If these symbols cannot be resolved at load time, the shared library will fail to load.

On Mac OS X, when building dynamic libraries, unresolved references are not allowed by default. If you expect that a reference should be resolved at load time, you need to enable unresolved references explicitly. This is done with -undefined dynamic_lookup linker flag.

Allowing unresolved references is useful when building loadable plugins.

Comments

1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.