Compilation et Création de Bibliothèques en C

Ce document présente les principes fondamentaux de la compilation, de l'édition de liens, et de la création et utilisation de bibliothèques en langage C sous Linux. Il s'adresse aux étudiants et développeurs souhaitant comprendre comment créer des fichiers objets, des bibliothèques statiques et dynamiques, et comment les utiliser dans un programme principal.

D'après le document Compilation et Création de Bibliothèques en C

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source

Compilation et Création de Bibliothèques en C

Programming, C Language, Libraries · PDF · 10 pages

Afficher l'aperçu du document

Consulter le document original →

Ce document présente les principes fondamentaux de la compilation, de l'édition de liens, et de la création et utilisation de bibliothèques en langage C sous Linux. Il s'adresse aux étudiants et développeurs souhaitant comprendre comment créer des fichiers objets, des bibliothèques statiques et dynamiques, et comment les utiliser dans un programme principal.

Création des fichiers sources et fichiers d'en-tête

Une bibliothèque en C est constituée d'un fichier source contenant plusieurs fonctions, mais sans fonction main. Ce fichier source peut être compilé en :

  • un fichier objet (.o)
  • une bibliothèque statique (.a)
  • une bibliothèque dynamique (.so)

Le programme principal, qui contient la fonction main, peut ensuite utiliser les fonctions et variables globales de cette bibliothèque.

Exemple de fichier source de bibliothèque : toto.c

#include <stdio.h>

int ma_variable=5;

void ma_fonction()
{
    printf("Bienvenue dans Ma Fonction !\n");
}

int mon_addition(int i,int j)
{
    printf("Bienvenue dans Mon Addition !\n");
    return (i+j);
}

Fichier d'en-tête associé : toto.h

int ma_variable;
void ma_fonction();
int mon_addition(int i,int j);

Remarques importantes :

  • Le fichier d'en-tête n'est pas généré automatiquement, il doit être écrit manuellement.
  • Dans la déclaration des paramètres des fonctions, chaque paramètre doit avoir son type explicitement indiqué, même si plusieurs paramètres sont du même type. Par exemple, int i, int j est correct, mais int i,j ne l'est pas.

Programme principal utilisant la bibliothèque : titi.c

#include <stdio.h>
#include "toto.h"

int main(void)
{
    printf("---- Début du programme principal ----\n");
    ma_fonction();
    printf("Ma_variable vaut : %i\n", ma_variable);
    printf("6+7=%i\n", mon_addition(6,7));
    printf("---- Fin du programme principal ----\n");
    return 0;
}

Note : #include "toto.h" indique que le fichier d'en-tête se trouve dans le répertoire courant. Si on écrit #include <toto.h>, gcc cherchera dans le répertoire système /usr/include.

Compilation des fichiers sources

1. Création et utilisation d'un fichier objet

Pour compiler le fichier source toto.c en fichier objet toto.o, on utilise l'option -c de gcc :

gcc -c toto.c

Cette commande produit le fichier objet toto.o sans effectuer l'édition de liens.

La commande objdump -t toto.o affiche la table des symboles du fichier objet, montrant les fonctions et variables définies.

Compilation du programme principal titi.c

Une compilation simple :

gcc titi.c

génère une erreur de lien :

undefined reference to `ma_fonction`
undefined reference to `mon_addition`

Car le corps des fonctions est dans toto.o, non indiqué à l'éditeur de liens.

Pour corriger cela, il faut indiquer le fichier objet lors de la compilation :

gcc titi.c toto.o

Le programme s'exécute alors correctement :

---- Début du programme principal ----
Bienvenue dans Ma Fonction !
Ma_variable vaut : 5
Bienvenue dans Mon Addition !
6+7=13
---- Fin du programme principal ----

2. Création et utilisation d'une bibliothèque statique

Une bibliothèque statique sous Linux a l'extension .a. Pour créer une bibliothèque statique libtoto.a à partir de toto.o :

ar cr libtoto.a toto.o
ranlib libtoto.a

La table des symboles peut être affichée avec :

objdump -t libtoto.a

Pour compiler titi.c en utilisant cette bibliothèque statique :

gcc titi.c libtoto.a

Le programme s'exécute alors de la même manière qu'avec le fichier objet.

Avantages : Le code de la bibliothèque est intégré dans l'exécutable, qui n'est plus dépendant des bibliothèques externes.

Inconvénient : Toute modification de la bibliothèque nécessite de recompiler le programme principal.

3. Création et utilisation d'une bibliothèque dynamique

Une bibliothèque dynamique sous Linux a l'extension .so. Pour créer une bibliothèque dynamique libtoto.so :

gcc -o libtoto.so -shared toto.o

La table des symboles est visible avec :

objdump -t libtoto.so

Pour compiler titi.c en utilisant la bibliothèque dynamique :

gcc -ltoto -L. titi.c
  • -ltoto indique à l'éditeur de liens d'utiliser libtoto.so
  • -L. indique que la bibliothèque se trouve dans le répertoire courant

Sans l'option -L., gcc cherche les bibliothèques dans /usr/lib par défaut.

4. Récapitulatif des commandes gcc

  • gcc toto.c : compilation + édition de liens → exécutable a.out
  • gcc -c toto.c : compilation seule → fichier objet toto.o
  • gcc toto.o : édition de liens seule → exécutable a.out

Pour un exécutable, une seule fonction main doit être présente. Si des fonctions externes sont utilisées, il faut indiquer leurs fichiers objets ou bibliothèques à gcc.

Exemple de compilation de titi.c avec la bibliothèque toto :

  • gcc titi.c toto.c
  • gcc titi.c toto.o
  • gcc titi.c libtoto.a
  • gcc titi.c -ltoto

Utilitaires pour la gestion des bibliothèques partagées

  • ldd <programme> : affiche les bibliothèques partagées utilisées par un programme.
  • ldconfig : régénère les liens symboliques dans les répertoires de bibliothèques partagées (listés dans /etc/ld.so.conf), permettant de gérer plusieurs versions d'une bibliothèque sans arrêter le système. L'option -v affiche les bibliothèques installées.
  • export LD_LIBRARY_PATH=`pwd` : ajoute le répertoire courant au chemin de recherche des bibliothèques partagées.
  • ltrace : suit les appels aux fonctions des bibliothèques dynamiques effectués par un programme, utile pour le débogage.

Exemple d'utilisation de ltrace

Pour un programme a.out compilé avec libtoto.so, la commande :

ltrace a.out

affiche les appels aux fonctions de la bibliothèque, comme :

ma_fonction()
printf("Bienvenue dans Ma Fonction !\n")
mon_addition(6,7)
printf("Bienvenue dans Mon Addition !\n")

La commande :

ldd a.out

montre les bibliothèques partagées utilisées, par exemple :

libtoto.so => /usr/lib/libtoto.so
libc.so.6 => /lib/tls/libc.so.6

Utilisation des bibliothèques existantes dans le système

Les fonctions courantes sont souvent déjà disponibles dans des bibliothèques installées, par exemple pour afficher une image JPEG ou lire un fichier MP3.

1. Connaître les bibliothèques installées

La commande :

ldconfig -v

affiche toutes les bibliothèques installées. Pour rechercher une bibliothèque liée au traitement JPEG :

ldconfig -v | grep jpeg

On trouve par exemple libjpeg.so dans /usr/lib.

2. Connaître les fonctions disponibles dans une bibliothèque

Pour afficher la table des symboles d'une bibliothèque :

objdump -T /usr/lib/libjpeg.so

On peut filtrer les fonctions avec :

objdump -T /usr/lib/libjpeg.so | grep Base

Ce qui affiche une liste des fonctions exportées, par exemple :

  • jpeg_read_header
  • jpeg_start_decompress
  • jpeg_finish_decompress
  • etc.

3. Trouver le fichier d'en-tête associé

Les fichiers d'en-tête sont généralement dans /usr/include. Pour trouver celui lié à JPEG :

ls /usr/include/*jpeg*.h

On obtient par exemple /usr/include/jpeglib.h.

Note : le fichier d'en-tête ne porte pas toujours le même nom que la bibliothèque partagée (ex. libjpeg.so vs jpeglib.h).

4. Exemple d'utilisation de la bibliothèque libjpeg.so

Le programme suivant affiche la résolution d'une image JPEG :

/* Ce programme test.c affiche la résolution d'une image toto.jpg en utilisant libjpeg.so */
#include <stdio.h>
#include <jpeglib.h>

int main(void)
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE *file;
    char *fichier = "toto.jpg";

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    if ((file = fopen(fichier, "rb")) == NULL)
    {
        fprintf(stderr, "Erreur : impossible d'ouvrir le fichier texture.jpg\n");
        exit(1);
    }

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, TRUE);
    printf("La largeur de l'image est %i pixels\n", cinfo.image_width);
    printf("La hauteur de l'image est %i pixels\n", cinfo.image_height);
    return 0;
}

Pour compiler ce programme :

gcc -ljpeg test.c

À l'exécution, on obtient par exemple :

La largeur de l'image est 400 pixels
La hauteur de l'image est 342 pixels

Glossaire des termes clés

  • Fichier objet (.o) : fichier produit par la compilation d'un fichier source, contenant du code machine non lié.
  • Bibliothèque statique (.a) : archive de fichiers objets intégrée dans l'exécutable lors de l'édition de liens.
  • Bibliothèque dynamique (.so) : bibliothèque partagée chargée au moment de l'exécution, permettant la mutualisation du code.
  • Éditeur de liens (linker) : outil qui combine plusieurs fichiers objets et bibliothèques pour produire un exécutable.
  • Table des symboles : liste des fonctions et variables définies ou utilisées dans un fichier objet ou une bibliothèque.
  • gcc : compilateur GNU pour le langage C, qui effectue compilation et édition de liens.
  • ar : utilitaire pour créer des archives, utilisé pour fabriquer des bibliothèques statiques.
  • ranlib : utilitaire qui génère un index pour une archive, facilitant l'accès aux symboles.
  • ldd : commande affichant les bibliothèques partagées utilisées par un exécutable.
  • ldconfig : commande qui met à jour les liens symboliques des bibliothèques partagées du système.
  • ltrace : outil pour tracer les appels aux fonctions des bibliothèques dynamiques d'un programme.
  • Fichier d'en-tête (.h) : fichier contenant les déclarations de fonctions et variables, utilisé pour l'interface entre sources.

Points clés à retenir

  • Un fichier source de bibliothèque ne contient pas de fonction main et peut être compilé en fichier objet, bibliothèque statique ou dynamique.
  • Le fichier d'en-tête doit être écrit manuellement et déclare les prototypes des fonctions et variables globales.
  • Pour utiliser une bibliothèque dans un programme, il faut indiquer à l'éditeur de liens le fichier objet ou la bibliothèque correspondante.
  • Les bibliothèques statiques sont intégrées à l'exécutable, tandis que les bibliothèques dynamiques sont chargées à l'exécution.
  • Les outils objdump, ldd, ldconfig et ltrace sont essentiels pour gérer et déboguer les bibliothèques.
  • Les bibliothèques système sont souvent déjà installées et documentées, avec leurs fichiers d'en-tête dans /usr/include.
  • Pour compiler un programme utilisant une bibliothèque système, il faut inclure le fichier d'en-tête et lier la bibliothèque avec -l.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions