The static Library:

Martin Smith
6 min readOct 8, 2018

--

As continue my progression through Holberton, to become a software engineering and with “C” in general as the first leg. I’ve reached a point where all the functions I’ve been coded up to this point could use their library, which directs me to the topic of this article.

The main focus, I’ll explore Static libraries on how to make them and also why we would use them. However, I’ll also explore some reason you would use them over a shared library and other topic relating to the creation and uses of these libs.

So right place to start would be first to define what a library — lib for short — is in this context, be it static or shared. As its name implies a library, in this case, is a file that contains several object files that provides a single entity during the linking phase of a program — more on object files and linking stage later. As aforementioned there two lib types Static and Shared — also known as Dynamic — libraries in Unix and most modern operating systems. How they differ is on how the linked to an application.

To reiterate what a Static library is a collection of objects that are linked into the program during the linking phase of the compilations, and are not relevant during the runtime. A static library is just an archive of object files and an object file used only during the linking phase.

Why Use them?

While it’s possible to compile an application with just the main source with the header file and any other required source files. Notably, the additional sources associated with the header, It can get messy if you end you always have to remember to include them to add them. Avoiding the solution below would be favourable.

gcc main.c _putchar.o _strlen.o _puts.o _memcpy.o ... -o some_app

While the above example would work — minus the ellipsis — it’s not ideal. It’s evident the problems that would occurs as we start to scale up the complexity of our application or just the file management difficulties alone — much copying and moving of files would be required and clean up to avoid clutter.

If I were hypothetically creating a small program was using 25+ custom functions, first, off I probably wouldn’t want all 25+ inside one source. Possibly only 5–10 are for dealing with some data type and the rest for math — or w/e. Even then we might have the functions for that imaginary data type broken up into a subset of files for organisational purposes. However, you imagine the scenario It would make compiling prone to human error or have a command length comically long.

Where once was possibly 25 entries now become 1 or 2 libraries — base on the hypothetical scenario above.

How to Create one?

Let look at the creation phase to an example of a use case.

As mentioned a few time Static lib is an archive of object files. The creation of an object is relatively simple, using the gcc it just a matter of adding the -c flag and then the source files. Using this option outputs a file/s with the same name but with a .oextension in place of the .c .

$ ls
some_src.c header.h main.c
$ gcc -c some_src.c
$ ls
some_src.c some_src.o header.h main.c
$ gcc main.c some_src.o -o dose_something

A object file is some machine code that the assembler outputs of a source file, simply put it’s just some source already compiled awaiting to be linked to a program. However, it’s more likely we’ll deal with more than one object. You could add the object as needed to the command (cmd) line, but a more elegant way would be to pack all those objects into a library.

Below is how you would create a Static Lib from several files — assuming that the current directory has some source files present.

$ gcc -c *.c # create object
$ ar -rc libmimic.a *.o # add objects to lib

Going over the steps, first, we need to compile our source files using the gcc

$ gcc -c *.c
$ ls
0-isupper.c
0-isupper.o
0-memset.c
0-memset.o
0-strcat.c
0-strcat.o
100-atoi.c
100-atoi.o
.
.
.
$

Once compiling all the source to machine code we can then use the ar— archive — tool to pack them up. Well also accompany the ‘ar’ with some options -rc

  • c: creates the archive.
  • r: insert the file members into the create archive

libmimic.a being the name or the archive and *.ouse all the object we just compiled.

ar tool also comes with some helpful options to list all the objects currently inside a archive -t , there is also another tool nm print a list of the symbols of the object files inside the archive.

Using ar

$ ar -t libmimic.a # View objects within a lib using the '-t'
0-isupper.o
0-memset.o
0-strcat.o
100-atoi.o
.
.
.
$

Using nm

$ nm libmimic.a0-isupper.o:
0000000000000000 T _isupper
0-memset.o:
0000000000000000 T _memset
0-strcat.o:
0000000000000000 T _strcat
.
.
.
$

How To Use a Static Library?

Using the library we create is reasonably straightforward but does have a small gotchya so worth demonstrating. Below is the code for main.c we’ll use with the lib.

I agree a static library maybe overkill for this example, but humor me.

#include "mimic.h"int main(void)
{
_puts("\"At the end of the day, my goal was to be the best hacker\"\n\t- Kevin Mitnick");
return (0);
}

To create the program, usegcc as we would any other time but with few extra options. Also the file with a _ prefixes are meant to signify they’re a directory.

$ ls
_header _libs main.c README.md _src
$ gcc main.c -I ./_header -L ./_libs -l mimic -o quote
$ ./quote
"At the end of the day, my goal was to be the best hacker"
- Kevin Mitnick
$

In my example above I decided to do a little housekeeping, so I use extra options, even if it was just a simple program. First, was dealing with the header file, the -I option allows for the header to exist in a directory that the application’s code.

$ gcc ... -Iinclude_path ...

Next is the -L./_libs option point to where a director of libraries are in this case _libs and then -lmimic this tell gcc which library to use for linking with the program. Note that the prefix “lib” and suffix “.a” are not included.

$ gcc ... -L ./_libs -l mimic ...

In the case for the library options — L and l — it’s important to have the order right since -L points to a directory and -l searches for a library match that name within the destination given by -L. You are also able to provide several location and libraries but there is an order of operations taken into account.

Shared libs

While talking about Shared libraries is outside the scope of this article I should still mention how it differs. Has to do with how the linker used this library and also performed in two stages. The first step is the linker — at compile time — checks if all the symbols required by the program are linked or is in one of the shared libraries. Rather than embedding the object files from a shared library into the program, when an application executes the dynamic loader — which is a program part of the system — checks for which dynamic libraries linked to the program. The load then load them to memory and attached them to the copy of the program in memory.

Uses of a dynamic Lib adds complexity to a program, that can lead to slightly slower launching times. However, this slight drawback is out weight by the benefits. For which ill save the details for another post.

--

--