Libraries in C: static or dynamic?
What is a library in C?
When you write a program, chances are you may need to print something to the screen. How would you do it? Would you write a printf function from scratch or use the one available in the <stdio.h> library?
The answer is obvious.
When you compile and run the program with printf from the <stdio.h>, you’ve used a library.
In order to access to this library, you’ve added #include <stdio.h> at the beginning of the program.
It’s only at the linking stage, the last of the four stages of the compilation process, that you can specify how the source code for functions you have called, will be linked: dynamically or statically.
Why choose one over the other?
Remember one of the coding exercises for beginner, the one that requires to enter a name, then prints out “Hello name”? It’s certainly over simplifying but, to a certain extent, the idea is the same: when you hard-code a name, it’s static, and when you can modify the output message without having to re-compile the program, it’s dynamic.
With static library, at the linker stage of the compilation process, all object codes of the required functions are copied (hard-coded) into the application file. As you can imagine, the executable program size of a statically-linked will take more space than the one dynamically-linked. Even worse, if multiple programs use the same library, the same code is copied several time, wasting space.
The resulting code is completely standalone with no external dependencies.
The other obvious drawback is when the libraries evolve, to fix bugs for instance, the statically-linked program wouldn’t benefit from the up-to-date versions, unless it is re-compiled.
Dynamic (or shared) library
If an application uses a dynamic library, a dynamic loader checks out which shared libraries were linked with the program, loads them to memory, and attaches them to the copy of the program in memory.
The program may be slower than a statically-linked program. The advantages are 1) different processes can use the same library loaded in memory at the same time, thus saving memory footprint and space 2) and can benefit from any new version of the library seamlessly, without having to re-compile.
Pros & Cons in a nutshell
Static or dynamic library? It depends on whether you prioritize efficiency (static) over flexibility (dynamic).
How to create a Static library?
Please consult my post about for further information.
How to create a Dynamic / Shared library?
There are four main steps to build a dynamic library. The first step is the same as for the building process of a Static library.
- Put all source files into one directory.
The header (.h) file must contain all the files’s prototypes.
2. Compile the source code for Position Independent Code (PIC).
gcc -c -fPIC *.c
- -c: compile and assemble the source code, but do not link (create object files).
- -fPIC: since different programs may use the same library, and each load it into a different memory in address, we need that all calls will use relative addresses, and not absolute addresses.
3. Create a shared library from an object file.
gcc -shared -o liball.so *.o
- -shared: creates a Shared Object(.so) which can be linked with other objects to form an executable.
- -o: name the executable file
4. Add the working directory to the LD_LIBRARY_PATH environment variable.
Since Dynamic Library is linked during runtime, we need to make this file available during runtime. The dynamic linker searches standard paths available in the LD_LIBRARY_PATH environment variable.
This is what happens when we list the shared libraries of a program before adding the working directory to LD_LIBRARY_PATH:
linux-vdso.so.1 => (0x00007fff5d1d2000)
libholberton.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f74c6bb9000)
Therefore we’d need to add the working directory to the LD_LIBRARY_PATH environment variable so that the linker can find our library file.
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
You can then check if the system locates the library properly for a given program linked with this library:
linux-vdso.so.1 => (0x00007fff41ae9000)
libholberton.so => ./libholberton.so (0x00007fd4bf2d9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd4beef6000)
How to use a static or dynamic library?
We use the same method as for the static library to include the dynamic library in a program.
gcc -L. *.c -lname -o out
Let’s go over the structure of this command:
-L.flag specifies that our library is in the current working directory (hence the ‘.’).
-lnameflag has a unique structure; -l <libraryname without lib prefix and extension>.
That’s it! we now have a final executable file
out that combined our C files and our libraries.
Thanks for reading!