C++ Linker
C++ is a compiled language, which means a compiler has to take your written C++ code and convert it to binary code that the computer can actually understand. There are two stages to compilation of code in C++:
- Compiling from source code to object files
- Linking the object files to executable binaries
I wrote an article about compiling in C++. I’ll link to it at the end of this article.
What is Linking?
Linking is what happens when you build your project in C++.
Linking is a process going from source C++ files to executable binary. The first stage to compilation is compiling the source files. After compilation. Linking is the process that follows.
Okay, let’s talk about C++ linking.
The primary focus of linking is to find where each symbol and function is and link them together. Why do we need to link them?
Why Linking?
In C++, each file is compiled into a separate object file called translation units. These translation units are independent of each other and cannot interact, so how then do you have your multiple C++ files talk to each other? That is what the C++ Linker does.
Linking in C++ is best explained with an example. Say we have this code called math.cpp with two functions.
#include <iostream>
void Log(const char* message) {
std::cout << message << std::endl;
}
int Multiply(int a, int b) {
Log("A multiply function is being called");
return a * b;
}
int main() {
std::cout << Multiply(2, 5) << std::endl;
std::cin.get();
}
This is a perfectly valid code in C++. This code will start at the entry point i.e., the main
function and print A multiply function is being called
and 10
to the console. Perfectly valid.
Now let’s demonstrate the process of Linking here.
If I move the Log function to a separate file called log.cpp
, the math.cpp file will no longer compile because there is a Log()
function which is not declared anywhere in the math.cpp
file.
Let’s fix that by referencing the Log function from the log.cpp file.
#include <iostream>
void Log(const char* message) {
std::cout << message << std::endl;
}
and in my main.cpp file, I will have a declaration of Log function.
#include <iostream>
void Log(const char* message); // declaration of Log function
int Multiply(int a, int b) {
Log("A multiply function is being called");
return a * b;
}
int main() {
std::cout << Multiply(2, 5) << std::endl;
std::cin.get();
}
If I build this main.cpp file now, it builds successfully, why?
The first thing to note is that there is a declaration of Log function without the curly braces i.e., no body for this function. This declaration of Log function is what tells the compiler that this function exists somewhere else and that during the linking stage, the linker should look for a function called Log and link it to this main.cpp file. That’s it. That’s what the linker does.
So that’s the C++ linker. That’s how it works in C++. Linking of multiple symbols in a project that exists in different translation units.
I believe that you have learnt something from this article.
Thanks for reading. 🙂
If you notice, I boldened some terms in this article. That is because these terms are necessary for understanding important concepts in C++ and other low-level languages. If you would like to learn more about these terms. I have an article that talks about them here. You can check them out below.