Learn Programming: C Static Libraries
What are libraries in C programming?
In a general sense libraries are collections of precompiled functions that have been written to be reused by other programmers. Libaries consist of a set of related functions to perform a common task; for example, the standard C library, ‘libc.a’, is automatically linked into your programs by the “gcc” compiler and can be found at /usr/lib/libc.a. Standard system libraries are usually found in /lib and /usr/lib/ directories. Check out those directories. By default the gcc compiler or more specifically its linker needs to be directed to which libraries to search other than the standard C library — which is included by default.
There are a number of conventions for naming libraries and telling the compiler where to find them. A library filename always starts with lib. The last part of the name determines what type of library it is:
.a: static, traditional libraries. Applications link to these libraries of object code.
.so: dynamically linked shared object libraries. These libraries can either be linked in at run-time but statically aware or loaded during execution by the dynamic link loader.
The way to view a static library is that it is linked by the linker and included in the execution code. So if 10 applications linked in a static library it would mean that each application’s resulting binary would include the referenced library in its program binary. This leads to large executable files. To address this people use shared libraries. These libraries contain the same references to those found in static ones but the code for those functions are not directly included in the resulting executable. Rather, shared libraries access a single copy of the library that is shared by all the 10 applications while all executing at the same time. There is some operating system magic to make this happen safely but it is a foundation on modern computing.
Why should you use libraries?
There are many library functions available in C programming that are standard to help you write a good and efficient program. But, why should you use it? Below are the 4 most important advantages of using library functions.
- They work
One of the most important reasons you should use library functions is simply because they work. These functions have gone through multiple rigorous testing and are easy to use.
2. The functions are optimized for performance
Since, the functions are “standard library” functions, a dedicated group of developers constantly make them better. In the process, they are able to create the most efficient code optimized for maximum performance.
3. It saves considerable development time
Since the general functions like printing to a screen, calculating the square root, and many more are already written. You shouldn’t worry about creating them once again. It saves valuable time and your code may not always be the most efficient.
4. The functions are portable
With ever changing real world needs, your application is expected to work every time, everywhere. And, these library functions help you in that they do the same thing on every computer.
There are static and dynamic libraries. Static will “merge” with your code (faster but use more memory) and dynamic (little slower but can reuse the library if it is already in the memory) will link with your application when you start your program. Dynamic library is probably the way to go in many cases!
What are static libraries in C?
Static libraries are simply a collection of ordinary object files; conventionally, static libraries end with the ``.a’’ suffix. This collection is created using the ar (archiver) program. Static libraries aren’t used as often as they once were, because of the advantages of shared libraries (described below). Still, they’re sometimes created, they existed first historically, and they’re simpler to explain.
Static libraries permit users to link to programs without having to recompile its code, saving recompilation time. Note that recompilation time is less important given today’s faster compilers, so this reason is not as strong as it once was. Static libraries are often useful for developers if they wish to permit programmers to link to their library, but don’t want to give the library source code (which is an advantage to the library vendor, but obviously not an advantage to the programmer trying to use the library). In theory, code in static ELF libraries that is linked into an executable should run slightly faster (by 1–5%) than a shared library or a dynamically loaded library, but in practice this rarely seems to be the case due to other confounding factors.
How do static libraries work?
A static library or statically-linked library is a set of routines, external functions and variables which are resolved in a caller at compile-time and copied into a target application by a compiler, linker, or binder, producing an object file and a stand-alone executable. This executable and the process of compiling it are both known as a static build of the program. Historically, libraries could only be static. Static libraries are either merged with other static libraries and object files during building/linking to form a single executable, or they may be loaded at run-time into the address space of the loaded executable at a static memory offset determined at compile-time/link-time.
How to create a static library?
To create a static library using GCC we need to compile our library code into an object file so we tell GCC to do this using -c
$ gcc -c *.c
Here in the above command , all the .c extension files( C files) in the current working directory have been converted in to their respective object files. Once we have object file(s), we use the GNU ar command to create our final library/archive
$ ar -rc libholberton.a *.o
This tells ar to create an archive (option c) and to insert the objects, replacing older files where needed (option r) .
Whenever files are added to a library, including the initial creation of the library , the library needs to be indexed, which is done with the command
ranlibmakes a header in the library with the symbols of the object file contents.This helps the compiler to quickly reference symbols. A large library may have thousands of symbols meaning an index can significantly speed up finding references.
$ ranlib libholberton.a
This step may or may not be necessary depending on your computer system or your archiver(not necessary with ar).
If we want to see the contents of our library, we can use the
ar -t libholberton.a
We can also see the symbols in our library, using the command
nm, which lists each symbol’s symbol value, symbol type, and symbol name from object files.
Using static libraries
We have now created a static library libholberton.a and now let us use the static library by invoking it as part of the compilation and linking process when creating a program executable. Incase of gcc we use following flags to create static library
- -l<libraryname without lib prefix and extension>
- -L : specifies the path to the library .We can use -L. inorder to point to the current directory and -L/home/tmp to point to the /home/tmp directory.
gcc main.c -L. -lholberton -o main
Now run the executable program ‘main’
Executables generated using static libraries are no different than executables generated from individual source or object files. Static libraries are not required at runtime, so you do not need to include them when you distribute your executable. At compile time, linking to a static library is generally faster than linking to individual source files.
here are the advantages of using Static Libraries.
- Static libraries are not required at runtime, so you do not need to include them when you distribute your executable.
- At compile time, linking to a static library is generally faster than linking to individual source files.
Static linking is very straight forward, but has a number of drawbacks.The two main disadvantages are..
- If the library code is updated (say, to fix a bug) you have to recompile your program into a new executable.
- Every program in the system that uses that library contains a copy in its executable. This is very inefficient (and a pain if you find a bug and have to recompile, as per point one).