Créer et utiliser une bibliothèque statique en C

Il est tout simple de créer une bibliothèque statique en C pour ensuite s’en servir dans un autre programme. Dans la suite, j’expliquerai comment faire en ligne de commande puis avec Code::Blocks. Je reprend largement les explications données en anglais ici pour la création.

En ligne de commande

Commençons par faire tout ceci en ligne de commande, dans notre terminal. J’utilise dans la suite gcc sous Ubuntu. Je commence par créer le fichier source util.c de la bibliothèque:

#include <stdio.h>

void UTIL_says_hello(void)
{
	puts("UTIL says hello !");
}

Je crée aussi le fichier d’en-tête util.h qui me permettra de faire connaitre à un autre programme la fonction proposée par ma bibliothèque.

void UTIL_says_hello(void);

Je compile mon fichier avec l’option -c pour simplement générer un fichier objet et non un exécutable :

gcc -Wall -c util.c

J’utilise ensuite ar pour générer l’archive (voir ici pour les options) :

ar crs libutil.a util.o

Je me retrouve avec mon splendide fichier .a accompagné de son fichier .h. On peut utiliser readelf -sW dessus pour voir les symboles qu’il contient, on voit qu’il y a notre fonction et puts. Je vous laisse faire la manipulation si vous voulez voir le résultat.

Vient le moment d’utiliser cette bibliothèque. Je crée pour cela un second fichier source où j’utilise la fonction de ma bibliothèque :

#include "util.h"

int main(void)
{
	UTIL_says_hello();
	return 0;
}

Je génère mon exécutable avec gcc :

gcc -Wall main.c -L. -lutil

L’option -L. permet d’ajouter le dossier courant (le dossier .) à la liste des dossiers où le linker ira chercher les bibliothèques puisque c’est là que se trouve ma bibliothèque. L’option -lutil ajoute la bibliothèque util (on remarquera que le lib est sous-entendu) à la liste des bibliothèques à trouver et à utiliser. L’option -Wall… Vous prenez mon pied aux fesses et vous vous dirigez vers Google si elle vous est inconnue. J’obtiens un fichier que je peux exécuter :

$ ./a.out 
UTIL says hello !

Avec Code::Blocks

Si vous utilisez CodeBlocks, il est encore plus simple de créer une bibliothèque statique. Il suffit de faire File / New / Project… et de choisir Static Library. Vous écrivez vos fichiers sources et vous cliquez sur Build. On peut voir dans la console qu’il fait la même chose que ce qu’on a fait précédemment avec gcc dans le terminal. Voici ce que ça donne sous Windows 7 avec MinGW :

------------- Build: Debug in util (compiler: GNU GCC Compiler)---------------

mingw32-gcc.exe  -Wall -g   
-c D:\Users\pgradot\Documents\util\main.c -o out\Debug\main.o
ar.exe -r -s libutil.a out\Debug\main.o 
ar.exe: creating libutil.a
Output size is 2.31 KB
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 0 warnings (0 minutes, 0 seconds)

Il ne reste plus qu’à écrire le fichier d’en-tête.

Si vous souhaitez utiliser une bibliothèque dans Code::Blocks, il faut aller dans les options du projet dans le menu Project / Build options…, sélectionner la cible qui va bien et de modifier les options du linker. Pour une bibliothèque, je conseille de sélectionner la configuration parente pour que toutes les configurations connaissent la bibliothèque. Dans la capture d’écran suivante, vous pouvez voir que je sélectionne bien util qui est la configuration parente. Les configurations debug et release héritent des propriétés de leur parente :
add_static_lib_codeblocks
Il y a deux solutions. La première est renseigner les options en mode texte dans le champ de texte à droite, comme dans le terminal. La seconde est de cliquer sur le bouton Add dans la zone de gauche, ce qui ouvre une fenêtre d’exploration pour aller chercher le fichier souhaité.

2 Réponses

  1. Attention aux pièges:
    – Il manque une garde au fichier .h (#ifdef #define #endif, ou alors un « #pragma once » si on aime les extensions gcc)
    – Il est utile de préciser que seuls les fichiers .o de la lib dont au moins un symbole est référencé sont embarqués dans l’exécutable final. Sinon, il faut utiliser –whole-archive
    – L’ordre des librairies statiques est important: seul les symboles référencés par ce qui est *avant* la lib dans la ligne de commande sont embarqués. Pour faire de la résolution cyclique (par exemple si deux libs statiques sont interdépendantes), il faut utiliser « –start-group fichier1.o lib1.a lib2.a fichier2.o –end-group » (ou -l1 -l2, mais on risque de linker dynamiquement contre un .so s’il y en a un dans le même dossier!)

    On n’oubliera pas d’utiliser –function-sections –data-sections à la compilation et –gc-sections au link pour n’embarquer que ce qui est nécessaire de la lib. Au liue d’avoir un grain d’une unité de compilation (un fichier .o), on aura un grain de une fonction ou une variable à la fois. Ce qui évite d’embarquer 2Mo de lib pour rien dans un exécutable.

    J’aime

    16 novembre 2013 à 10:47

  2. Je me demandais qui allait me faire remarquer que je n’ai pas mis de garde d’inclusion (pas très utiles ici….) ^^

    Merci pour ce complément à mon article en tout cas, tu recommences quand tu veux !

    J’aime

    18 novembre 2013 à 7:56

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.