Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : DICE - compilation séparée, bibliothèque reliable
(Article écrit par Laurent Faillie et extrait d'Amiga News - mars 1994)
|
|
Comme promis la dernière fois, nous allons parler
de la compilation séparée et des bibliothèques reliables qui n'en sont qu'une application.
Pour être plus parlant
Citons la version 2.0 de DiceConfig qui, à l'heure où vous lirez ces lignes, devrait être
disponible dans le DP. Cette version est bien plus évoluée que les précédentes et dispose
d'une interface graphique créée grâce à GadToolsBox 2.0b de Jaba Development. Une fois
toutes les fonctions programmées, les sources pèsent 70 ko et mettent près de trois
minutes à compiler...
Lorsque l'on commence à programmer Intuition, nos programmes prennent vite des tailles
très importantes. Si tout se trouvait dans le même fichier, il faudrait à chaque modification de
nouveau trois minutes pour recompiler, ce qui est idiot car certaines parties, la majorité,
sont restées inchangées. La solution est de découper le source en plusieurs fichiers :
- Gui.c contient toute la gestion de l'interface graphique (20 ko).
- fonc_Gui.c contient les fonctions appelées par l'activation d'un gadget (26 ko).
- DiceConfig.c contient le reste : gestion des paramètres contenues dans l'icône,
du fichier de configuration, (environs un 10 ko).
- DCLocale.c gère la locale.library (6 ko).
Le reste des 70 ko est constitué des includes (voir plus loin).
Compilation
Pour compiler, il suffit de faire :
Dcc Gui.c fonc_Gui.c DiceConfig.c -oDiceConfig -new
|
Notez l'option "-new". Elle permet de ne recompiler que les blocs modifiés, ce
qui accélère largement le temps de développement. J'en reparlerai... Il est évident
que je ne vais pas reprendre ici un source de cette taille. Nous prendrons donc
le programme suivant :
Il n'a pour fonction que d'afficher la date et l'heure de la compilation du programme.
Si on le compile tel quel, il affichera :
Bonjour, Je suis fonction1
Fonc2 a été compilé le Oct 10 1993 a 17:09:09
|
Le module principal a été compilé le 10 octobre 1993 à 17:09:09.
Remarquez que la fonction main() et fonc2() ont été compilés au même moment,
car ils sont dans le même fichier !
Suivant ce que j'ai dit précédemment, nous
allons le séparer en plusieurs blocs logiques : fonc1.c contiendra... la première fonction,
fonc2.c la seconde et main.c, la procédure principale.
Prototyper les fonctions
Votre source étant coupé en petits morceaux, il nous reste du travail à faire. Il faut
prototyper toutes les fonctions qui sont utilisées dans plusieurs blocs car,
pour le compilateur, jusqu'à l'éditeur de lien, les blocs sont indépendants les
uns des autres. Il faut donc dire quels sont les paramètres à passer, le type de
valeur retourné... Il en va de même pour les #define, les variables, les typedefs,
en bref, toutes les définitions partagées. Tout ceci sera placé dans un fichier
"header" nommé ici "Partage.h" mais il peut prendre n'importe quel nom.
Comme il ne se trouve pas dans DInclude: mais dans le répertoire courant, il
faudra ajouter #include "Partage.h" à chacun de nos fichiers sources.
main.c deviendra donc :
Notez au passage que la variable globale "comp" a été définie dans ce module.
Occupons-nous maintenant du fichier header :
Notez les "externe" que précèdent toutes les définitions : ils indiquent au compilateur
que l'objet en question peux ne pas se trouver dans le fichier actuellement en compilation.
Compilons :
Dcc fonc1.c fonc2.c main.c -o tst -new
|
A l'exécution, il affichera :
Bonjour, Je suis fonction1
Fonc2 a été compilé le Oct 10 1993 a 17:32:47
|
Le module principal a été compilé le 10 octobre 1993 à 17:32:49.
Notez que, les deux fonctions n'ont plus les mêmes heures de compilation !
Modifions le bloc principal en ajoutant simplement un commentaire :
Nouvelle compilation. Si vous mesurez le temps pris par le compilateur, vous verrez que
cette fois, c'est plus rapide. A l'exécution, une heure a changé :
Bonjour, Je suis fonction1
Fonc2 a été compilé le Oct 10 1993 a 17:32:47
|
Le module principal a été compilé le 10 octobre 1993 à 17:35:27.
Explication : grâce à l'option "-new", Dcc ne va recompiler que les fichiers qui ont
été modifiés. Pour ce faire, il regarde si le fichier objet (par exemple Dtmp:main.o)
est plus vieux que le source (main.c). Si ce n'est pas le cas, le source a été modifié
et il le recompile.
Ça ne marche pas
Si vous avez la version 2.07.54R de DICE, il est probable que tout a été
recompilé. Comme je l'avais dit en présentant cette version, Dcc a un bogue
qui fait que les fichiers objets sont effacés si la compilation a réussi.
Heureusement Matt Dillon a fourni les sources (dans la quatrième
disquette, le répertoire Dcc) et il est donc facile de remédier à ce problème.
Éditer le fichier main.c, aller à la ligne 1125. Modifier le source comme suit :
Le tour est joué
Autre solution, pour ceux qui n'ont pas de courage (ou pas assez de mémoire pour recompiler Dcc).
Il s'agit d'un script CSH qui fait la même chose :
Son utilisation est simple : mettre dans un fichier le nom de tous les sources
(fichier par exemple) puis tapez dans CSH :
Multi_Dcc_F fichier resultat
|
...où "resultat" est le nom de l'exécutable produit.
Bibliothèques reliables
Pour finir sur ce chapitre, je vais parler des bibliothèques reliables.
Ces bibliothèques sont stockées dans Dlib: et ont le suffixe ".lib".
Souvenez-vous, dans cet article,
nous avons déjà abordé ces lorsque nous avons parlé des glues-code.
Nous en avons même -presque- créé une avec les fonctions LFPrintf()
et LFSPrintf() de mes_fonctions.o. Elles aussi sont faites de code objet,
mais à la différence des .o, elles sont composées de "blocs"
que l'éditeur de liens n'inclut dans l'exécutable que s'il est utilisé...
Bon, nouvel exemple pour être plus clair. Reprenons les deux fonctions précédemment citées,
sauvegardons-les dans deux fichiers séparés et compilons en ne créant que du code
objet :
Dcc LFPrintf.a -c -o LFPrintf.o
Dcc LFSPrintf.a -c -o LFSPrintf.o
|
Pour les réassembler :
Join LFPrintf.o LFSPrintf.o TO malibrairiexxx.lib
|
"xxx" étant remplacé par le modèle du code ("s" pour Small, "1" pour Large),
puis par "r" s'il y a utilisation des registres pour le passage des arguments et
enfin "p" s'il y a profilage. Sans options particulières, se sera donc ma_librairies.lib
(car Small-code par défaut). Évidemment, le code objet peut être produit par un source
C. Le source suivant crée une fonction qui affiche un message dans une alerte (dans le style du... Guru !).
Au lieu de compiler à la main, nous allons utiliser un programme nommé LibMake fourni
avec DICE. La première chose que nous ayons à faire c'est de créer un fichier
(ici liste_fch) contenant le nom de tous les fichiers sources :
#Sources de ma_librairie.lib
LFPrintf.a
LFSPrintf.a
LFatal.c
|
Les lignes qui commencent par "#" sont considérées comme des commentaires.
La compilation se fait par :
LibMake Liste_fch -lma_librairie.lib
|
Piège : il faut effacer les fichiers objets lorsque l'on change les options de
compilation (Delete DTMP:#?.o) sinon la même bibliothèque est créée.
Voir l'option "-new".
Dernière opération : il faut créer les prototypes des fonctions utilisées, mais là,
je vous laisse faire...
|