Everything there is to know about C static libraries (or at least most of it)

Laura Roudge
6 min readMar 2, 2019

--

When we code in C, it’s good practice to separate our functions in different source files and put their prototypes in a custom header file. This is because in C we need to have our function declaration (or prototype), placed before the call to it, and placing it in a header file allows us to respect that. When we do this, we need to include the header files with the preprocessor direction #include, at the very top of the source file. Then we need to compile all your source files together, because C is a compiled and not interpreted programming language.

But at one point, we may have a lot of different functions dispatched into many files that we need to include in one program, and adding all of them together at compilation might be a lot of work (yes, us programmers are lazy). This is what libraries are for. They contain object files, which are source code files compiled and assembled, but not linked (see Compiling C files with gcc, step by step). These files are not human readable and have the extension “.o”. There are two types of them: static and dynamic. Today, we are going to discuss static libraries only.

What are static libraries?

A static library is just an archive containing object files that will only be needed during the linking stage, not at runtime. This is because at runtime we only need the executable program that we compiled and linked with the library.

Conventionally, they end with the “.a” extension on Unix-like systems, or “.lib” on Windows.

Why use static libraries?

As we introduced earlier, static libraries allow us to save time and type less when compiling a program. This is because we will not need to compile all the source files again once we put their object code inside the library. We will just need to link the library once at compilation time. There are other reasons why we might privilege a static library: we might want other programmers to link to our library without having access to the source code. Also, when we recompile a dynamic library, and try to run the new version of the program with the new library, the compiler will find the old version of the library in memory and add it to our program, ignoring the modified dynamic library.

How they work

Static libraries function this way: the linker makes a copy of all the functions it finds inside the library to the executable program. This can have one drawback, which is the use of memory. Since the linker links all the functions, even the one not called in the program, it takes more memory. But that’s a story for another time…

How to create static libraries

Back to our static libraries. How do we create one? It requires a terminal window where we can have access to the shell (that is the program that interacts directly with the kernel). There, on the command line, we will use the “ar” command. According to the ar manual page provided by the GNU development tools on Unix-like systems, “The GNU ar program creates, modifies, and extracts from archives. An archive is a single file holding a collection of other files in a structure that makes it possible
to retrieve the original individual files (called members of the archive).”
Like many commands, we can specify options with the ar command. For example, the “c” option creates the library if it doesn’t already exist, and the “r” option replaces older object files with the new ones we add to the library. So, if we want to create a static library called “mylib” containing “file1.o” and “file2.o”, we’ll enter this command and press enter:

Note the presence of the “lib” prefix and the “.a” extension

But wait, how do we create a “.o” object file? This can be done with a compiler, like gcc, and the option “-c” that will stop the compilation before the linking stage, as mentioned before:

compiling “file1.c” into “file1.o”

One more thing! We need to index the static library once it’s created. There are two ways to do that. First, we can use the “ranlib” command. According to its man page, “ranlib generates an index to the contents of an archive and stores it in the archive. The index lists each symbol defined by a member of an archive that is a relocatable object file.” To use it on our “mylib.a” library, we just need to type:

The other option we have is actually adding the option “s” to our “ar” command, which is probably faster since we can just add “s” to “rc” and do everything in one command. Another cool option we can use with “ar” is “t”, which displays a list of the files contained in the library.

Another command that might come in handy when dealing with static libraries is “nm”. When you type “nm libmylib.a”, a list of symbols (metadata about the addresses of variables and functions used in the program) from object files in the libmylib.a library will be displayed.

How to use static libraries

Now that the library is created, we can use it for a program. Let’s say I want to create a program called “myprog”, that has an entry point, aka the main() function in which the calls to all the other functions are done and the core of the code is. The main() function is often written in the main.c file.

The first step is to make main.c into an object file, like we saw earlier, using the gcc compiler for example:

This gives us the main.o object file

Now, we can finally link our program into an executable. This will also be done with gcc here, using the “-L” option with a “.” that tells the linker to look for the static library in the current directory. We will also use the “-o” option followed by the name we want to give the program. If we don’t do this step the program will by default be called “a.out” by the compiler. Here’s the full command:

We didn’t need to put the “lib” prefix and the “.a” suffix when linking the library on the command because the linker will reattach them for us, when we put the “-l” option and the name of the library right after it (here “mylib”).

Now we can finally run our executable program, typing “./myprog” and pressing enter.

--

--

Laura Roudge

Software Engineer at Deezer in Paris, former student at Holberton School in San Francisco, always striving to build a better world.