This would probably interest you, but here is a short version:
When you assemble the .cpp
, .c
or whatever files, each translation unit (that is, each file) generates an object file. When creating the final executable, you combine all the object files into a single binary. For static libraries, you compile the static archive (.a
or .lib
) along with all the object files into the binary itself. For linking to dynamic shared objects (.so
or .dll
), the binary is created with calls to the global offset table and you inform the linker that you wish to link with the shared object and the operating system loader builds the proper image when you run the program.
A general explanation of terms used to link libraries in C++
Starting with...
translation - This is where the high-level code (in C, Fortran or whatever) is translated into assembly code by translation unit. So, every .cpp
file is internally translated to assembly for a specific architecture.
assemble - Generates object files from the generated assembly. Object files are almost machine code, but they have a lot of "unresolved externals," which you can kind of think of as pointers to actual function definitions.
linking - This takes all your object files and puts them into a coherent binary, be it a dynamic shared object or an executable. You need to tell the linker where it should find all those unresolved externals from the previous stage or they will show up as errors here.
Now the binary sits on disk, which is waits until...
loader - The operating system loads a binary off of the disk, which contains all the information needed to build the program image. While the details are extremely platform specific, the loader is generally tasked with finding all the shared library references generated by the linker, loading those (recursively, since each DSO can have its own dependencies) and putting them into the memory space of the program.