Use libraries and see the light

Libraries in C

This post is an expansion of this one

What are Libraries ?

A library is a collection of functions and definitions people can use to make other programs.

If we made an analogy with woodwork: we may not want to make a hammer and a nail each time we want to hold two things together. We may prefer to get hammers and nails, understand how it works, use them and focus on something else (style, dimensions…).

It works the same here. Anytime we write a script and want to print something in the terminal we don’t want to write such a print function, or if we want to use macros, we don’t want to redefine them. Enter libraries. A library is a module, separate from our scripts we can invoke so that we can use all the things it contains. Want to print something ? #include <stdio.h> to invoke the standard c library and use either puts, putchar, or printf…Of course, we should know these functions prototypes to make them work, but we would not need to know the internal details. This stresses that libraries need to be well documented.

Static and Shared Libraries

There are two kinds of libraries in C, the graphics below illustrate their creation in linux.

  1. Static libraries
Static library creation and use in linux

When using a static library, during the linking phase of the compilation of my program, the object code from the library is included in my executable. The resulting code is completely standalone, but the file can get large as I include more and more functions. Then, if a library is updated, my program does not, I need to recompile it if I want to use an updated version of the library. On top of it, if multiple programs use the same library, the same code is copied several time, wasting space.

2. Shared Libraries

When using a shared library, during the linking phase of the compilation of my program, a tag is added to say to look for and load in memory the library at runtime. The time it takes to do so means the program may be slightly slower if the library is not loaded in memory. But then, the advantages are that the size of my program executable is not increased by embedding some more code, and different processes can use the same library loaded in memory at the same time. I can also use a new version of the library without recompiling.

Creating a shared library is more complex than creating a static library. But it has more options. To evoke those possibilities briefly: it can use dynamic linking by modifying the LD_LIBRARY_PATH to include the directory where the library is. We could also move the library to /libor /usr/liban then we run ldconfig to create the necessary links and cache and update the ld.so config file. We could use a soname to make different versions of the same library co-exist.

Finally, running ldd on my program prints all the dependencies I have. And running nm on my shared library lists all the functions it contains.

Conclusion

This is a short introduction to the two different libraries in C. While static libraries were a great invention when they were invented, as they avoided to repeat and copy code, now shared libraries are favored. Actually, when compiling a program the default behavior is to link with a shared library, and revert to a static library if the shared library does not exist. They are more complex objects but require more work from the developer but in return allow for more possibilities and flexibility.