I have been working on a problem mately, and I'm stuck with an error that I did not find how to resolve. Please, can you help me ?
All the details of it has been posted here : https://stackoverflow.com/questions/68841669/undefined-symbols-for-architecture-x86-64-linker-issue?noredirect=1#comment121663792_68841669
The error is not related to UNIX/Windows/any other OS, but rather to the languages themselves. It is actually rather simple to diagnose with the information that compilers provide. Usually they will tell you what symbol is missing and sometimes where it is being used. The main reasons for a symbol to be missing are:
- You have declared but never defined it
- You have defined it, but did not add the compiled symbol (object file/library) to the linker
- It is external and you forgot to link the library, or you are linking an invalid version, or in the wrong order.
The first one is a little trickier if you intended to define the symbol but did not match the declaration (declared void foo( int, double );, but defined void foo( double, int ). As with all other cases, the compiler will tell you the exact signature that it is looking for, make sure that you have defined that symbol, and not something close or similar, a particular corner case can be if you are using different calling conventions in the declaration and the definition, as they will look very similar in code.
In the case of libraries external code the complexity is in identifying what library needs to be linked for that symbol to be added, and that comes from the documentation of the lib. Beware that with static libraries the order of the libs in the linker command line affects the result.
To help you in finding what symbols are actually defined you can use nm (gcc, which is common among unix systems). So basically you can run nm against the object files/libs that you are linking and search for the symbol that the linker is complaining about. This will help in cases where the order is what makes the difference (i.e. the symbol is there, but the linker skipped it).
At runtime (thanks to Matthieu M. for pointing it out) you might have similar issues with dynamic libraries, if the wrong version of a library is found in the LD_LIBRARY_PATH you might end up with a library that does not have a required symbol.
Although they can be platform dependent, I have some "more complex" instances of some of the points from Andreas and David:
- When dealing with shared libraries (.so or.dll) and linking against symbols which are not exported (dllimport/dllexport on Windows and visibility("default") with GCC on *nix)
- Or similar: Linking against the static lib, while expecting a shared lib or vice versa. This one is bit similar to Mathieu's comment about linking against another, unexpected version of the library.
- Creating a pure virtual classs and not providing an implementation for at least one method (causing no vtable to be available).
- Actually a more complex case of declaring but not defining: The linking errors you can get when dealing with large, nested templates. Finding out what was not defined can be difficult with large error messages.
dynamic linking - finding undefined symbol - Unix & Linux Stack Exchange
how to debug undefined symbol
c++ - What is an undefined reference/unresolved external symbol error and how do I fix it? - Stack Overflow
error: undefined symbol ... during make
Videos
Say you have the following code:
// a.cpp
int get() { return 0; }
// b.cpp
int get(); // usually, one doesn't write this directly, but gets these
// declarations from included header files
int x = get();
When compiling b.cpp, the compiler simply assumes that get() symbol was defined somewhere, but it doesn't yet care where. The linking phase is responsible for finding the symbol and correctly linking the object files produced from a.cpp and b.cpp.
If a.cpp didn't define get, you would get a linker error saying "undefined reference" or "unresolved external symbol".
C++ Standard Wording
Compiling a C++ program takes place in several phases specified in [lex.phases], the last of which is relevant:
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.
See Keith Thompson's answer for a summary of these phases.
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 source files into object files or libraries, and now you want to get them to work together.
Linker Errors in Practice
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)" (?foo@@YAXXZ)
1>test2.obj : error LNK2001: unresolved external symbol "int x" (?x@@3HA)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?foo@X@@UAEXXZ)
1>...\test2.exe : fatal error LNK1120: 4 unresolved externals
Common Causes
- Failure to link against appropriate libraries/object files or compile implementation files
- Declared and undefined variable or function.
- Common issues with class-type members
- Template implementations not visible.
- Symbols were defined in a C program and used in C++ code.
- Incorrectly importing/exporting methods/classes across modules/dll. (MSVS specific)
- Circular library dependency
- undefined reference to `WinMain@16'
- Interdependent library order
- Multiple source files of the same name
- Mistyping or not including the .lib extension when using the
#pragma(Microsoft Visual Studio) - Problems with template friends
- Inconsistent
UNICODEdefinitions - Missing "extern" in const variable declarations/definitions (C++ only)
- Visual Studio Code not configured for a multiple file project
- Errors on Mac OS X when building a dylib, but a .so on other Unix-y systems is OK
- Your linkage consumes libraries before the object files that refer to them
- Your linkage contains C++ object files and C++ libraries originating from different C++ compilers
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.
According to a Wikipedia article on the subject, in Herbert B. Enderton's book Computability: An Introduction to Recursion Theory (2011), even if nowhere else (no other reference is given, and I've never seen the usage):
If
is a partial function on
and
is an element of
, then this is written as
and is read as "
is defined."
If
is not in the domain of
, then this is written as
and is read as "
is undefined".
I have never seen such a symbol. I don't think it would be very useful, and it might make unexperienced people less aware that they are dealing with an undefined entity, and start doing calculations with it getting meaningless results.