When and why would we use libraries?
Imagine you are writing a paper on the evolution and history of tortoises in Madagascar. You just want to dive right into writing about tortoises and don’t want to be bothered rehashing Darwin’s entire theory of evolution. Naturally, you just simply invoke his theory by name: “Darwin’s theory of evolution.” Additionally, you cite Darwin’s seminal book, “On the Origin of Species”, so those who don’t know what the “theory of evolution” is can go to the library and see what exactly those three words, when combined, really stand for.
C libraries are more or less built upon the same premise: one can save a lot of time and effort by reusing the work someone (including your past self) already did. We also benefit from the fact that Darwin probably articulated his theory better than we can, and similarly, the collective consciousness of developers who worked on something like the C standard library most likely wrote a more robust function for printing a string than we could given time constraints (at least that’s true in my case).
A library is a lot like an executable, but instead of being directly executed, they are invoked by name from your program with the parameters you specify.
How to create a static library on Linux?
To create static libraries, we use the command
ar which stands for the program “archiver”. This program can create, list, and modify static libraries, or “archive files,” from our command line.
To create the static library for the function we used in our above example, use the command:
ar -r -c libalphabet.a print_alphabet.o
This command creates a static library called
libalphabet.a and puts a copy of the file
print_alphabet.o in it.
-rflag tells the archiver to replace any older object files with the newer object files.
-uflag tells the archiver to create the file
libalphabet.aif it doesn’t exist.
But, that’s not all. We can, and should, index our library, so the compiler will find our linked programs faster and more efficiently. The command to create an index of our library (or update an existing index) is
ranlib which takes our library as the argument:
This step isn’t always necessary since it is sometimes done automatically.
To see the contents of our library we can use the
ar -t combo. But if we want even more info, then we can use the
nm command. This command lists each symbol’s value, type, and name.
How to create a dynamic library on Linux?
To create a dynamic library, we first need to compile all of the files containing the desired functions for the linking stage using the flag
-fPIC which generates Position Independent Code.
gcc -c -fPIC *.c
Next, we need to convert this object code code into a shared library. Instead of using the archiver tool, as we did with static library generation, we use the flag
-shared in another run with
gcc. Make sure you include the
-o flag to give your library a custom name. The library needs the extension
.so for shared object and, by convention, the prefix
lib to indicate it’s a library. To include all of our object code, we use the wildcard
* followed by the
.o (object file) extension.
gcc -shared -o libalphabet.so *.o
Finally, if you want to check and see which exact function are contained within your newly created library, you can use the command
nm with the
-D flag which references the symbols in the initialized data section.
nm -D libalphabet.so
What are the key differences between static and dynamic libraries?
Static libraries differ from dynamic (sometimes called: shared) libraries in that static library code is linked directly into your final executable.
Dynamic linking points to the address of your function in memory rather than pasting the object code directly in. The actual object code comes in only when the program is run (during run-time).
Static linking has a couple of drawbacks when compared with dynamic linking.
- Size: each function in your program will have the object code linked directly in. This is the equivalent of copying and pasting “On the Origin of Species” every time you want to say “theory of evolution”. Which, as you can imagine, would make your essay on tortoises much more bulky and inefficient than it needs to be.
- Updates: if the library you static linked is updated (for a bug-fix or something), then you have to recompile your entire program.
Consider the function
print_alphabet(). It resides within a file called
print_alphabet.c and it looks something like this:
#include <stdio.h>void print_alphabet(void)
#include <stdio.h>includes the C standard I/O library which has the
printf()function in it.
printf()is a standard library function which simply prints a string.
print_alphabet() function doesn’t do anything flashy; it does one thing and it does it well: printing the alphabet.
We can convert this program to object code using the following command:
gcc -c print_alphabet.c
Our file is now
print_alphabet.o and contains object code instead of source code. This object code is directly pasted into any program that uses the static library containing the
print_alphabet() function: static linking in a nutshell.
What are the pros and cons of static and dynamic libraries?
║ Pros ║ Cons ║
║ 1. No runtime dependencies ║ 1. Uses lots of memory ║
║ ║ 2. Needs to be recompiled if ║
║ ║ updated ║
╚════════════════════════════╩══════════════════════════════╝ vs.Dynamic libraries:╔════════════════════════════╦════════════════════════════╗
║ Pros ║ Cons ║
║ 1. Takes up less memory ║ 1. Library must be present ║
║ ║ in order for program ║
║ ║ to run ║
║ 2. Don't need to recompile ║ 2. Less portable ║
║ main program following ║ ║
║ an update ║ ║
Thanks for reading.