If you have been coding long enough, then the linker errors are probably the ones you ended up hating the most! Once you’ve finally designed the program logic, cleaned up all those frustrating syntax errors, and prepared yourself to see the output, you may still need to deal with linker errors. The linker errors are particularly frustrating because they are not necessarily related to anything you have written in your program. What exactly are these linker errors anyway? How do we fix them?
First of all, what is a linker?
When you write a piece of code, it is not ready to produce the output just yet. There are a few steps involved. First step is the preprocessing stage. You may have used some predefined functions and macros in your code. So your machine first preprocesses them and includes all the necessary functions. These functions are useful because you don’t have to rewrite them, but your machine still needs to put these functions together with your code. The next step is the compiler stage. The compiler is the thing which checks for all the syntax errors in your code. It will not let you proceed further until you fix all these syntax errors.
Once you fix all the syntax errors, your compiler successfully generates the object files. What are these object files? For now, think of object files as intermediate files which will be used by your machine to get the overall build of your project. In our code, we use something called “libraries”. These libraries are inbuilt functions provided by the programming language or extensions provided by other people. We include them and directly use them in our code. These are very useful because they are highly optimized and we don’t have to rewrite anything. You also have something called startup code. This provides the program with necessary initialization instructions.
Alright, so now we have the object files, the libraries and the startup code. We take these things and go to the next step, which is the linker stage. Linker takes these things and generates the executable file. It links everything together. This is what we want! The “executable” is the final program which takes the inputs and provides outputs. In order to debug out code, we look at error messages. Syntax errors are pretty obvious because we know exactly where they are. But linker errors are cryptic and it takes time to fix them if you don’t know what they mean. Let’s look at a few cases.
You may have issues with how you set up your compiler. For instance, even if you include the correct header files for all of your functions, you still need to provide your linker with the correct path to the library that has the actual implementation. It’s like sending your ID card to work! You actually need to be physically present in the office. Not including the correct path to the library is something very similar. This is the actual body that the code needs.
This will lead to getting “undefined function” error messages. To get around this error, some people just include their own declaration of a function to get around a compile-time error. This is like sending your mannequin to the office. Still doesn’t count! If your compiler supports the function, then fixing this problem usually requires compiler-specific settings. You’ll generally want to look for how to tell the compiler where to look for libraries and make sure that the libraries were actually installed correctly.
Not including the object files
Linker errors can also come about in functions that you have declared and defined if you fail to include all of the necessary object files in the linking process. Now why can’t the machine do this automatically? For simple cases, it can. But in real life projects, there are a huge number of files. To keep things optimal, people like more control over these things. For example, if you write your class definition in one file, and your main function is in another file, your compiler will create two object files and the linker will need both of them to finish the creation of the new program.
When you define something more than once, the linker throws this type of error. That something can be a class, variable or a function. Why would you do that? Well, you may define two global variables, both declared as external variables to be accessible outside of the source code file. This is a legitimate concern for both functions and variables, and it definitely can happen. On the other hand, sometimes the problem is with the directives to the linker. People also include multiple copies of the same object file in the linking process. The linker doesn’t like it!
The last bizarre type of linker error is a complain about an “undefined reference to main”. This particular linker error differs from the other errors in that it may have nothing to do with including object files or having the correct paths to your libraries. Instead, it means that the linker tried to create an executable and couldn’t figure out where the main() function was located. This can happen if you forget to include the main function at all, or if you attempt to compile code that was never meant to be a stand-alone executable. For instance, if you compile a library, there will be no main function. It is not meant to be a stand-alone either.