One of the tools that compilers supply us with are libraries. A library is a file containing several object files, that can be used as a single entity in a linking phase of a program. Normally the library is indexed, so it is easy to find symbols (functions, variables and so on) in them. For this reason, linking a program whose object files are ordered in libraries is faster than linking a program whose object files are separate on the disk. Also, when using a library, we have fewer files to look for and open, which even further speeds up linking. Unix systems (as well as most other modern systems) allow us to create and use two kinds of libraries — static libraries and shared (or dynamic) libraries. Static libraries are just collections of object files that are linked into the program during the linking phase of compilation, and are not relevant during runtime. This last comment seems obvious, as we already know that object files are also used only during the linking phase, and are not required during runtime — only the program’s executable file is needed in order to run the program.

Why use libraries?

  • Code reuse. Avoid code duplication.
  • Agility and speed in development. Thanks to the reuse of code we achieve faster development, since we will not waste time developing new functionalities.
  • Lower cost in development. Finishing a project earlier means that dedication is less and the cost of a project decreases.
  • Good development practices with the use of patterns. They are based on design patterns, which indicate guidelines on how to solve a specific problem that has already occurred before.
  • Minimizing errors and making it easier to solve possible errors that you may have will always be better than developing it from scratch.
  • Ease of finding code that already covers functionalities of a particular development.
  • Facilitates collaboration with other developers.
  • It facilitates maintenance when the application needs to be updated or an evolutionary one needs to be carried out, taking less time and reducing the total cost.

How to create them

ar rc libutil.a util_file.o util_net.o util_math.o

After an archive is created, or modified, there is a need to index it. This index is later used by the compiler to speed up symbol-lookup inside the library, and to make sure that the order of the symbols in the library won’t matter during compilation (this will be better understood when we take a deeper look at the link process at the end of this tutorial). The command used to create or update the index is called ‘ranlib’, and is invoked as follows:

ranlib libutil.a

How they work and How to use them

This will create a program using object file “main.o”, and any symbols it requires from the “util” static library. Note that we omitted the “lib” prefix and the “.a” suffix when mentioning the library on the link command. The linker attaches these parts back to the name of the library to create a name of a file to look for. Note also the usage of the ‘-L’ flag — this flag tells the linker that libraries might be found in the given directory (‘.’, refering to the current directory), in addition to the standard locations where the compiler looks for system libraries.

Example of creating a simple library in C

sum.c

/*
* FILE: suma.c
*/

int suma(int n1, int n2){
return n1+n2;
}

resta.c

/*
* FILE: resta.c
*/

int resta(int n1, int n2){
return n1-n2;
}

Now, we will compile the files sum.c and subtraction.c to obtain the objects sum.o and subtraction.o

gcc -c suma.c
gcc -c resta.c

Once we have the objects of the addition and subtraction functions, we proceed to create the library that contains them, our own “.a” file.

ar -cvr libcalculadora.a suma.o resta.o

This command will create a static library called “libcalculator.a” that will contain the implementations of the functions addition () and subtraction (). If we list the content of the functions stored in the library, we can see it:

/tmp/libcalculadora$ ar -t libcalculadora.a
suma.o
resta.o

calculadora.h

/*
* FILE: calculadora.h
*/

#ifndef CALCULADORA_H
#define CALCULADORA_H

#include<stdio.h>
#include<stdlib.h>

int suma(int,int);
int resta(int,int);

#endif

And finally, the calculator.c file, with the code of the main () function, for the implementation of the functions addition () and subtraction () only the prototypes are needed and they are taken from the previously created static library.

/*
* FILE: calculadora.c
*/
#include "calculadora.h"

int main(int argc, const char *argv[]){
int (*ptr_fc)(int,int);
int n1 = atoi(*(argv+1));
int n2 = atoi(*(argv+3));
char op = *(*(argv+2));

switch(op){
case '+':
ptr_fc = suma;
break;
case '-':
ptr_fc = resta;
break;
default:
printf("Opción incorrecta!!\n");}

printf(">>> %d %c %d = %d\n", n1, op, n2, (*ptr_fc)(n1,n2));
return 0;}

It is compiled indicating to gcc where to look for the libraries, and which library to use:

gcc calculadora.c -L/tmp/libcalculadora -lcalculadora

Developing in Holberton School