Bug of the week #3


Welcome to the next pikoTutorial!

The error we’re handling today is a C++ linker error:

undefined reference to `X`
collect2: error: ld returned 1 exit status

What does it mean?

In C++, an “undefined reference” error occurs during the linking stage. This error indicates that the linker cannot find the definition for a function, variable or object that has been declared but not defined. It typically happens when the code is separated into multiple files, and the linker cannot locate the necessary object files or libraries where the symbol is defined.

How to fix it?

Missing definition

Look at this code:

void function();

int main()
{
    function();
}

The function has been declared, but there’s no definition, so the linker will complaining throwing the following error:

main.cpp:(.text+0x9): undefined reference to `function()'
collect2: error: ld returned 1 exit status

To fix this, we need to add the implementation of the function:

void function()
{
    // implementation
}

int main()
{
    function();
}

Now everything works as expected.

Declaration/definition mismatch

Look at these 3 files:

function.h

void function(int);

function.cpp

#include "function.h"

void function()
{
    // implementation
}

main.cpp

#include "function.h"

int main()
{
    function(2);
}

In this case we get an error:

main.cpp:(.text+0xe): undefined reference to `function(int)'
collect2: error: ld returned 1 exit status

Linker tells us that it can’t find definition of function(int) and indeed, when we look closer at the function definition in .cpp file we see that although it has the same return type and the same name, it has no input argument, so the linker treats it as a completely different function than the one which has been declared in .h file. After adding the int input argument in the function’s definition, everything works fine:

void function(int)
{
    // implementation
}

File not added to the compilation

Look at these 4 files:

function.h

void function(int);

function.cpp

#include "function.h"

void function(int)
{
    // implementation
}

main.cpp

#include "function.h"

int main()
{
    function(2);
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(MyProject)
add_executable(MyExec main.cpp)

Here, although the function definition is present and there is no declaration/definition mismatch, we still get the same linker error. The reason is visible in the last line of CMakeLists.txt file. We’ve included in the compilation only source file (main.cpp) out of 2 that we have (main.cpp and function.cpp). So despite the function definition being present in the source code, it is not included in the compilation process. To fix this, we need to add function.cpp file in the CMakeLists.txt file:

cmake_minimum_required(VERSION 3.15)
project(MyProject)
add_executable(MyExec main.cpp function.cpp)

Library with the function definition not linked

Now let’s assume that we have the same set of files as in the previous example, but with one change – this time function() is defined and declared in a separate library:

cmake_minimum_required(VERSION 3.15)
project(MyProject)
add_library(FunctionLib function.cpp)
add_executable(MyExec main.cpp)

Despite the fact that the function definition exists, is correct and even function.cpp file is successfully compiled into a library, the whole process fails because the linker still complains about the undefined reference to function(int). The reason is that although FunctionLib has been successfully compiled, it has not been linked to our executable MyExec. After linking everything works as expected:

cmake_minimum_required(VERSION 3.15)
project(MyProject)
add_library(FunctionLib function.cpp)
add_executable(MyExec main.cpp)
target_link_libraries(MyExec PRIVATE FunctionLib)