La compilation séparée
Thèmes abordés
• La compilation séparée
Déco page de projets en fichiers séparés – Découpage de projets en fichiers séparés – Compilation séparée
– Conception de bibliothèques
Introduction
• Constat
Logiciel : intégration de nombre ses fonctionnalités – Logiciel : intégration de nombreuses fonctionnalités.
– Les logiciels ont tendance à croître fortement en taille.
• Difficile de comprendre un très long fichier de code source.
• Modification d’une ligne -> recompilation de tout le fichier.
– Temps de compilation de plus en plus élevés.
• Objectif
– Décomposer un logiciel volumineux en modules
Analyse et programmation 2 - La compilation séparée 2
p g
La compilation séparée
Principes généraux
module module module
1 immense fichier contenant tout le programme
module
module module
module module
d l module
module module
Analyse
• Avantages
Ecrit re de mod les pl s petits pl s faciles à comprendre – Ecriture de modules plus petits, plus faciles à comprendre.
– Recompilation d’un module -> plus rapide.
– Donne une structure plus lisible au programme.
– Possibilité de réutilisation de certains modules.
• Mais cela requiert :
– Un petit travail d’analyse supplémentaire.
Un petit effort de mise en place des modules
Analyse et programmation 2 - La compilation séparée 4
– Un petit effort de mise en place des modules.
– Effort rapidement compensé par les bénéfices.
La compilation séparée
La chaîne de compilation du langage C - rappel
main.c stdlib.h stdio.h
fichier1.c
2. Compilateur Code source complet 1. Préprocesseur de texte
Exécutable complet main.o
3. Editeur de liens
crt.lib fichier1.o
Constitution d’un module
• Que peut apporter un module ?
– Des inclusions – Des inclusions.
– Des définitions de symboles.
– Des types de données.
– Des constantes, des variables.
– Des fonctions.
• Structure d’un module en langage C
– Fichier en-tête : .h l dé l
Analyse et programmation 2 - La compilation séparée 6
• Comporte toutes les déclarations.
• Décrit les services offerts par le module.
• C’est l’interface du module.
– Fichier source : .c
• Comporte l’implémentation.
La compilation séparée
Première solution – Répétition des prototypes
voidrotation(vecteur_plan* u, double angle) {
fichier vecteur_plan.c
voidrotation(vecteur_plan* u, double angle);
traitement_image.c {
vecteur_plan copie;
copie = *u;
u->x = copie.x * cos(angle) – copie.y * sin(angle);
u->y = copie.x * sin(angle) + copie.y * cos(angle);
}
. . . . recalage_image() {
rotation(. . . .);
}
voidrotation(vecteur_plan* u, double angle);
main.c
. . . . main()
Que se passe-t-il si on
Première solution – Répétition des prototypes - Conséquences
• Propagation des modifications
Une modification de protot pe doit être propagée dans to s les – Une modification de prototype doit être propagée dans tous les
fichiers utilisateurs.
– Travail fastidieux.
– Coûteux en temps.
– Risque d’oubli
• Avec des conséquences fatales pour le logiciel.
Analyse et programmation 2 - La compilation séparée 8
La compilation séparée
Constitution d’un module – utilisation de fichiers en-tête
#
fichier vecteur_plan.h
#
fichier vecteur_plan.c
#define _USE_MATH_DEFINES
#include <math.h>
#define TAILLE_LISTE 1000 typedef struct
{
double x, y;
} vecteur_plan;
const vecteur_plan I = { 1.0, 0.0 };
const vecteur_plan J = { 0.0, 1.0 };
#include "vecteur_plan.h"
double produit_scalaire(vecteur_plan u, vecteur_plan v)
{
return u.x * v.x + u.y * v.y;
}
voidrotation(vecteur_plan* u, double angle) {
vecteur_plan copie;
copie = *u;
u->x = copie.x * cos(angle) – double produit_scalaire(vecteur_plan u,
vecteur_plan v);
void rotation(vecteur_plan* u, double angle);
u >x copie.x cos(angle) copie.y * sin(angle);
u->y = copie.x * sin(angle) + copie.y * cos(angle);
}
Exemple d’utilisation
vecteur_plan.h Inclusion multiple de vecteur_plan.h !
graphique.h
graphique.c
trajectoire.h
trajectoire.c
vecteur_plan.c
Analyse et programmation 2 - La compilation séparée 10
main.c
Problème à la compilation
Error 1:'vecteur_plan' : redefinition; different basic types vecteur_plan.h 9
La compilation séparée
Conséquences de la double inclusion
#include "trajectoire.h"
main.c
#include "vecteur plan.h"
trajectoire.h
typedef struct vecteur_plan.h j
#include "graphique.h" _p yp
{
double x, y;
} vecteur_plan;
#include "vecteur_plan.h"
graphique.h
typedef struct {
vecteur_plan.h {
double x, y;
} vecteur_plan;
Définition multiple de vecteur_plan !
Protection contre la duplication des définitions
#ifndef __VECTEUR_PLAN_H_
#define __VECTEUR_PLAN_H_
#define _USE_MATH_DEFINES
#include <math.h>
#define TAILLE_LISTE 1000 typedef struct
{
double x, y;
} vecteur_plan;
Analyse et programmation 2 - La compilation séparée 12
constvecteur_plan I = { 1.0, 0.0 };
constvecteur_plan J = { 0.0, 1.0 };
double produit_scalaire(vecteur_plan u, vecteur_plan v);
void rotation(vecteur_plan* u, double angle);
#endif
La compilation séparée
Problème de définition multiple des constantes et variables
Problème à la liaison
Error 1 error LNK2005: I already defined in main.obj vecteur plan.obj_ y j _p j Error 2 error LNK2005: _J already defined in main.obj vecteur_plan.obj Error 3 error LNK2005: _I already defined in main.obj trajectoire.obj Error 4 error LNK2005: _J already defined in main.obj trajectoire.obj Error 5 fatal error LNK1169: one or more multiply defined symbols found
#include "trajectoire.h"
main.c
vecteur plan h trajectoire.h
#include "vecteur_plan.h"
c
constvecteur_plan I = { 1.0, 0.0 };
constvecteur_plan J = { 0.0, 1.0 };
vecteur_plan.h
#include "trajectoire.h"
trajectoire.c
_I _J main.obj
_I _J trajectoire.obj
compilation
Comment éviter les définitions multiples - extern
#
fichier vecteur_plan.h
#
fichier vecteur_plan.c
#ifndef __VECTEUR_PLAN_H_
#define __VECTEUR_PLAN_H_
#define _USE_MATH_DEFINES
#include <math.h>
#define TAILLE_LISTE 1000 typedef struct
{
double x, y;
} vecteur_plan;
#include "vecteur_plan.h"
constvecteur_plan I = { 1.0, 0.0 };
constvecteur_plan J = { 0.0, 1.0 };
double produit_scalaire(vecteur_plan u, vecteur_plan v) {
return u.x * v.x + u.y * v.y;
}
voidrotation(vecteur_plan* u, double angle)
Analyse et programmation 2 - La compilation séparée 14
extern const vecteur_plan I;
extern const vecteur_plan J;
double produit_scalaire(vecteur_plan u, vecteur_plan v);
void rotation(vecteur_plan* u, double angle);
#endif
double angle) {
vecteur_plan copie;
copie = *u;
u->x = copie.x * cos(angle) - copie.y * sin(angle);
u->y = copie.x * sin(angle) + copie.y * cos(angle);
La compilation séparée
Partage de constantes et de variables
• Dans le fichier en-tête (.h)
extern type variable;
extern type variable;
extern const type constante;
• Dans le fichier source (.c)
type variable;
const type constante = valeur;
Structure du projet
Analyse et programmation 2 - La compilation séparée 16
Tous les fichiers .c doivent être inclus dans le projet.
Chaque .c produit un .obj
La compilation séparée
Recette de cuisine – le fichier .h
#ifndef __VECTEUR_PLAN_H_
#define VECTEUR PLAN H
Protection contre l’inclusion multiple
#ifndef
#define . . .
#endif // Tout à la fin du fichier Vecteur_plan.h
#define __VECTEUR_PLAN_H_
#define _USE_MATH_DEFINES
#include <math.h>
#define TAILLE_LISTE 1000 typedef struct
{
double x, y;
} vecteur_plan;
extern const vecteur_plan I;
#endif // Tout à la fin du fichier
Inclusion des fichiers contenant des symboles utilisés dans ce .h
Définition de symboles.
Définition de types.
extern const vecteur_plan J;
double produit_scalaire(vecteur_plan u, vecteur_plan v);
voidrotation(vecteur_plan* u, double angle);
#endif
Déclarations de constantes et variables globales partagées précédées par « extern »
Déclaration de prototypes de fonctions.
Recette de cuisine – le fichier .c
#include "vecteur_plan.h"
Inclusion du .h
Définition des constantes et variables Vecteur_plan.c
constvecteur_plan I = { 1.0, 0.0 };
constvecteur_plan J = { 0.0, 1.0 };
double produit_scalaire(vecteur_plan u, vecteur_plan v) {
return u.x * v.x + u.y * v.y;
}
voidrotation(vecteur_plan* u, double angle) {
vecteur plan copie;
Définition des fonctions dont le prototype est dans le .h, ou de nouvelles fonctions.
globales partagées précédées par « extern »
Analyse et programmation 2 - La compilation séparée 18
vecteur_plan copie;
copie = *u;
u->x = copie.x * cos(angle) - copie.y * sin(angle);
u->y = copie.x * sin(angle) + copie.y * cos(angle);
La compilation séparée
Recompilation efficace d’un projet
• Compilation incrémentale
To s les fichiers c n’ont pas besoin d’être recompilés à chaq e – Tous les fichiers .c n’ont pas besoin d’être recompilés à chaque
changement d’un fichier source.
– En exploitant le graphe de dépendances, le compilateur détermine quels fichiers doivent être recompilés.
– Temps de compilation divisés par 10 ou plus !
Recompilation – quel module doit être recompilé après un changement ?
vecteur plan h
graphique.h trajectoire.h
vecteur_plan.h
vecteur_plan.c
Analyse et programmation 2 - La compilation séparée 20
main.c
graphique.c trajectoire.c
modifié
modifié
recompilé
La compilation séparée
Recompilation – quel module doit être recompilé après un changement ?
vecteur plan h
graphique.h trajectoire.h
vecteur_plan.h
vecteur_plan.c
main.c
graphique.c modifié trajectoire.c
modifié
recompilé
Recompilation – quel module doit être recompilé après un changement ?
vecteur plan h
graphique.h trajectoire.h
vecteur_plan.h
vecteur_plan.c
modifié
Analyse et programmation 2 - La compilation séparée 22
main.c
graphique.c trajectoire.c
modifié
recompilé
La compilation séparée
Recompilation – quel module doit être recompilé après un changement ?
vecteur plan h modifié
graphique.h trajectoire.h
vecteur_plan.h
vecteur_plan.c modifié
graphique.c trajectoire.c
La compilation séparée
Types de compilation avec Visual Studio
tous les projets de la solution
Compilation complète de tous les projets de la solution
Effacement de tous les .obj de tous les projets de la solution
Compilation incrémentale du projet en cours
Compilation complète du projet en cours
Analyse et programmation 2 - La compilation séparée 24
projet en cours
Effacement de tous les .obj de tous les projets de la solution.
La compilation séparée
Problèmes potentiels – incohérence des prototypes
#
fichier main.c
#
fichier vecteur_plan.c
#include <stdio.h>
#include <stdlib.h>
#include "vecteur_plan.h"
int main() {
vecteur_plan v1 = { 3.0, 4.0 };
double norme1;
norme1 = norme(v1);
printf("Norme du vecteur v1"
"(%lf, %lf) : %lf\n", v1.x, v1.y, norme1);
#include "vecteur_plan.h"
double produit_scalaire(vecteur_plan u, vecteur_plan v) {
return u.x * v.x + u.y * v.y;
}
double norme(vecteur_plan u) {
return sqrt(produit_scalaire(u, u));
} v1.x, v1.y, norme1);
system("PAUSE");
return 0;
}
Problèmes potentiels – incohérence des prototypes
• Absence de prototype dans le .h
Par défa t la fonction norme est considérée comme étant – Par défaut, la fonction norme est considérée comme étant
int norme(vecteur_plan u);
– Or, elle retourne un double.
– Aucune détection du problème par le compilateur.
• Résolution
– Ajouter simplement le prototype de norme dans vecteur_plan.h double norme(vecteur plan u);
Analyse et programmation 2 - La compilation séparée 26
double norme(vecteur_plan u);
La compilation séparée
Problèmes potentiels – recompilation incohérente
• Manque de fiabilité de la gestion des graphes de dépendance
dépendance
– Rencontrée lors du remplacement d’un fichier source par un fichier plus ancien.
• En cas de doute:
– Toujours forcer la recompilation complète.
– Surtout avant un test en vraie grandeur.
Graphe de dépendance – références circulaires
#
fichier a.h
#
fichier b.h
#include "fichier_b.h" #include"fichier_a.h"
NON COMPILABLE
Analyse et programmation 2 - La compilation séparée 28
Problème à la compilation
Error 1 fatal error C1014: too many include files : depth = 1024 fichier_b.h 1 main.c
La compilation séparée
Graphe de dépendance – résolution des références circulaires
fichier a.h fichier b.h
#include "fichier_a.h"
#include "fichier_b.h"
fichier a.c
#include"fichier_a.h"
#include"fichier_b.h"
fichier b.c
main.c
Solution :
-Eliminer la dépendance entre interfaces (.h)
-Conserver la dépendance entre implémentations (.c)
Bibliothèques distribuables
• La compilation séparée
Permet de créer des fichiers h et c indépendants – Permet de créer des fichiers .h et .c indépendants.
– Pouvant contenir des fonctions d’usage général.
– Pouvant être réutilisées sur plusieurs projets.
• On ne souhaite pas toujours livrer le code source (.c)
– Il contient une propriété intellectuelle à protéger.
– L’intégration de fichiers .c entraine des temps de compilation.
C t di t ib l f ti li l ?
Analyse et programmation 2 - La compilation séparée 30
• Comment distribuer les fonctions sans livrer les sources ?
La compilation séparée
Bibliothèques distribuables - Exemple
• Livraison de
To s les fichiers h
vecteur_plan.h
– Tous les fichiers .h
– Tous les fichiers compilés .obj
trajectoire.obj Vecteur_plan.obj
graphique.obj graphique.h
• Malcommode
trajectoire.h
Bibliothèques distribuables – Exemple – Livraison empaquetée
• Livraison de
To s les fichiers h pl s n fichier q i incl t to s les a tres
Robotique.lib
vecteur_plan.h
– Tous les fichiers .h, plus un fichier qui inclut tous les autres.
– Tous les fichiers compilés rassemblés dans un seul fichier .lib.
Vecteur_plan.obj
graphique.obj graphique.h
robotique.h
Analyse et programmation 2 - La compilation séparée 32
• Plus commode
– Il faut inclure seulement robotique.h dans les programmes – Il faut lister seulement robotique.lib dans les options du lieur.
trajectoire.obj trajectoire.h
La compilation séparée
Bibliothèques distribuables - création
• La plupart des outils de développement C
Permettent de créer n lib à partir de obj – Permettent de créer un .lib à partir de .obj
• Avec Visual Studio
– Il existe un modèle de projet appelé « static library » – Lister simplement les
fichier de code source .c – La compilation produit
un fichier .lib
Bibliothèques distribuables - utilisation
• Les fichiers .h doivent se trouver
A n emplacement conn d compilate r : #incl de – A un emplacement connu du compilateur : #include <>
– Ou dans le répertoire du projet : #include " "
• Le fichier .lib
– Doit être fourni explicitement au lieur
– Une option de liaison existe avec tous les outils.
• Avec Visual studio, paramétrage dans les options de projet.
Analyse et programmation 2 - La compilation séparée 34
La compilation séparée
Bibliothèques distribuables - utilisation
Qu’avons-nous appris ?
• Comment utiliser la compilation séparée pour modulariser
modulariser.
• Comment gérer les problèmes liés à l’inclusion multiple.
• Comment partager des fonctions, des variables, des constantes entre modules.
• L’importance des prototypes avec la compilation séparée.
Analyse et programmation 2 - La compilation séparée 36