What are undefined reference/unresolved external symbol errors? What are common causes, and how do I fix and prevent these errors?
40 Answers 40
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
gumwith inline copies of the compiled body ofgum.
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
inline is that it makes a definition file static. (In particular, inline makes no guarantee to actually inline anything ;-).)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".
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.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.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...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
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
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
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
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 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
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
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.
thispointer 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.