La compilation séparée en C
Un article de Games Creators Network.
Dans ce tutorial, je vais vous apprendre à faire une compilation par objet, c'est-à-dire que vous allez pouvoir développer et compiler de manière autonome différente partie du projet.
Sommaire |
[modifier] Définition
Un header signifie en français une entête. En C ils sont identifiables par une extension ".h". Et en C++ par une extension ".h" ou ".hpp". Ces fichiers peuvent être assimilés à des interfaces.
[modifier] Ce qu'un header contient
Un header peut être constitué de plusieurs choses :
- De déclaration de constantes
- De déclaration de structures
- De prototype de fonctions ou de classes
Il est conseillé de garder cet ordre car en général les constantes sont utilisées dans la déclaration des structures. Et enfin les prototypes de fonctions utilisent ces structures.
Le header ne contient surtout pas de code sauf pour les fonctions inline et les macros
[modifier] Application
Fichier tuto1.c :
#include "tuto1.h" int main(void) { struct printtxt txt1 = { "Hello world" }; print(&txt1); return 0; } void print(struct printtxt *txt) { printf("%s %i\n", txt->data, CONSTANT); }
Fichier tuto1.h :
#ifndef H_TUTO1On vérifie que le fichier n'a pas été déjà inclus, pour cela on utilise la fonction #ifdef et #ifndef du pré-processeur
#define H_TUTO1Si H_TUTO1 n'a pas été défini, cela veut dire que le fichier n'a pas été inclus, on défini donc H_TUTO1 pour éviter de re-inclure le header par erreur plus tard.
#ifndef CONSTANTSi la constante a déjà été déclaré à l'extérieur de ce header on ne la re-déclare pas
#define CONSTANT 12 #endif // #ifndef CONSTANT struct printtxt { char *data; }; void print(struct printtxt *); // ou void print(struct printtxt *txt); #endif //la fin du #ifndef H_TUTO1
Voici un exemple simple de header.
[modifier] Quelques améliorations
- Les entêtes sont souvent utilisées pour contenir des commentaires qui en général explicitent ce que chaque fonction fait, à quoi sert chaque structure. Ainsi que la date de création et auteur. On peut trouver aussi la licence utilisation. Il est fortement recommandé de faire ces commentaires ce qui permettra à une autre équipe ou un autre développeur d'utiliser votre code.
- Un problème se pose quand votre code est du C et que le code du projet qui utilise votre bibliothèque est en C++. Dans ce cas il faut ajouter avant et après les prototypes de fonctions
#ifdef __cplusplus extern "C" { #endif //ici le corps du header normal #ifdef __cplusplus } #endif
Ceci indiquera au compilateur que ces fonctions ont été compilées en C.
[modifier] La compilation séparée
La compilation séparée permet de compiler tout les fichiers sources un par un les un après les autres. Puis de les lier tous ensemble. L'avantage est :
- La possibilité de ne compiler que la partie modifiée du projet
- De séparer les diverses fonctions du programme et permette ainsi un plus grand lisibilité
- D'avoir un code modulaire et donc testable unitairement
- La possibilité de développer chaque module dans un langage différent
Comment compiler ce genre de projet :
gcc fichier1.c -c gcc fichier2.c -c ... gcc fichiern.c -c
Ou pour les fainéants
gcc *.c -c
Après il faut lier tous les fichiers objet
gcc fichier1.o fichier2.o ... fichier_n.c -o exécutable
Ou
gcc *.o -o exécutable
Si vous utilisez une IDE comme VC++, DevC++ ou autre dans ce cas là, il faut créer un projet et inclure tous les codes sources dans ce projet.
Un dernier avantage de l'utilisation des headers et de la compilation séparée : imaginez vous une société qui propose une bibliothèque et qui ne veut pas dévoiler son code source. Dans ce cas il compile la bibliothèque et envoie le .o ou le .a ou le .lib ou le .dll ou enfin le .so + .h correspondant. Le client lui, de son côté, inclue le .h dans son projet et lors de l'édition des liens il inclue le fichier objet donné par la société en question.(Les différentes étapes d'une compilation d'un source sont les suivantes : source->pré processeur->création des fichiers objets->édition de lien entre les librairies et les codes objets->génération du code machine (0 et 1) au format du microprocesseur de la machine où à eu lieu la compilation ou d'une plateforme explicitement citée).
[modifier] Conclusion
Pour résumer la compilation séparée et l'utilisation des headers ont pour avantage de :
- Améliorer la lisibilité d'un gros code source
- Permettre un code plus modulable
- Réutilisation facile du code dans autre projet
- La possibilité d'utiliser des modules codés d'en d'autres languages
Pour rappel dans les headers il ne doit pas avoir une ligne de code (ce qui n'est évidemment jamais respecté, ce qui ne facilite pas la relecture du code...) exception faite des fonctions inline et des macros.

