Abrégé du guide d’utilisation de GNAT

Utilisation du compilateur Ada GNAT

Présentation…

Ce document s’applique autant à l’ancien GNAT « 3.15p » qu’au nouveau GNAT GPL. Il est un abrégé du guide d’utilisation pour la plus grande part, et du manuel de référence, pour les « pragmas ». Ce document n’est pas une traduction du document original, mais un abrégé ne retenant que le plus pertinent pour la plupart des usages. Cette reprise se veut plus concise et plus aisée à lire que l’original qui est un bien long document. Un bon nombres de commentaires personnels ont été ajouté.

Source des informations de ce document

La version originale, in English, peut être entre autres ( il en existe plusieurs versions ) consultée dans GNAT User Guide  et dans GNAT Reference Manual .

Section 6 : le programme gnatmake

Syntaxe d’invocation : « gnatmake [options] fichier1 [fichier-n] [options-de-mode] »

Compile toutes les dépendances ( d’où le nom de gnatmake ) et exécute la liaison des fichiers objet produit. Si l’option « -c » est employée, alors gnatmake n’effectue pas l’étape de liaison, mais seulement la compilation. Ceci ne signifie pourtant pas qu’il produit de fichier objets. Au lieu de fichiers objets, GNAT produit des fichiers ALI. Les fichiers ADB et ADS produisent donc des fichiers ALI, qui eux même produisent des fichiers objets par l’intermédiaire de gnatbind, qui est automatiquement invoqué par gnatmake si la liaison est requise.

Note inclassable : GNAT interprète l’attribut de protection en écriture des fichiers ALI. Il considère alors que le package ( « paquet » ) correspondant est verrouillé, et ne tiens alors pas compte de la date du fichier source, qui peut même ne pas être présent.

Les options sont présentés sous le format suivant

  • option « xxx » de gnatmake
  • option — mnémotechnique — titre résumant l’option
  • Commentaires détaillés de l’option

N.B. les titres résumés sont donnés parce que les noms d’options sont le plus souvent cabalistiques.

  • option « -a » de gnatmake
  • a — all — compile même les fichiers de librairie
  • Lors de la compilation, tiens compte de tous les fichiers, y compris et surtout les fichiers de la runtime ( « librairie d’exécution » ), les librairies systèmes de GNAT, les fichiers verrouillés par protection en écriture du fichier ALI, etc. Ceci est utile pour re-compiler une application tout entière, en re-compilant même la runtime, ce qui est nécessaire si on désire appliquer par exemple des pragmas ou des clauses de représentation spécifiques. Attention : cette option ne force pas la re-compilation de tous les fichiers ( pour compilation malgré la date des fichiers, voir l’option « -f » ), mais indique seulement de tenir compte de tous les fichiers, et concrètement, la date de tous les fichiers dont GNAT tiendra compte, restera vérifiée.
  • option « -c » de gnatmake
  • c — compile — compilation seulement sans liaison
  • Compile sans lier. C’est utile en phase de codage, dans un cycle d’écriture de code et de teste visant à s’assurer que le code se compile sans erreur. On s’épargne alors de perdre du temps avec l’étape de la liaison. Le test de compilation sans liaison est souvent utile sur les fichiers de spécifications ( les fichiers ADS ). Voir aussi l’option « -l ».
  • option « -f » de gnatmake
  • f — force — force la compilation même des fichiers à-jours
  • Compile inconditionnellement, sans tenir compte de la date des fichiers. Attention : ceci n’implique pas une re-compilation de tous les fichiers, cette option ne traite en effet qu’avec la date, et les fichiers habituellement exclus du processus de compilation en reste toujours exclus ( pour inclure tous les fichiers, y compris les fichiers verrouillés et les fichiers systèmes de GNAT, voir l’option « -a » ).
  • option « -a » et « -f » de gnatmake
  • a + f — all + force — compilation forcée de tout les fichiers même de librairie
  • La combinaison intelligente de ces deux options est parfois utile ( voir les options individuelles )
  • option « -i » de gnatmake
  • i — in source directory — place les produits de la compilation dans le répertoire des sources
  • Place les fichiers ALI et les fichiers objets dans le répertoire de leurs sources, plutôt que dans le répertoire courant de la compilation. Très intéressant pour les gros projets ou même les petits projets dépendants d’autres petits projets ( comme des librairies personnelles par exemple ). Avec cette option, les fichiers ALI et objet sont en fait partagés par tous les projets qui les références ( plutôt que d’êtres produits dans le répertoire de chaque projet, ils sont ainsi centralisés ). Cette option devrait en fait être toujours dans le cas de projets utilisant des librairies partagées. On peut aussi avoir une organisation encore plus fine, en indiquant toujours que les fichiers ALI et les fichiers objets là encore partagés, mais en forçant cette fois un autre emplacement que celui du répertoire de leurs sources. Il suffit, de créer le répertoire pour les fichiers ALI et les fichiers objets, de créer ensuite des fichiers ALI ou objets factices, puis de placer ces répertoires dans les chemins de recherche. A la compilation, GNAT trouvera ces fichiers ALI et objets, et les mettra à jour à l’endroit même où il les a trouvés. Cela ressemble un peu à une astuce, s’en est une, mais cela fonctionne parfaitement. Avant de mettre ceci en place, il convient évidement de supprimer au préalable les fichiers ALI et objets correspondant aux sources concernées, et qui ne se trouveraient pas là où les prévoit l’organisation du projet.
  • option « -l » de gnatmake
  • l — link — liaison seulement sans compilation
  • Indique de n’effectuer que la liaison, sans compiler les sources. C’est utile pour gagner un tout petit peu de temps ( intéressant sur les vieux ordinateurs qui sont lents ) si on a seulement par exemple changé ou modifié que des fichiers objets non dépendant de sources Ada, comme des fichiers de ressources Windows. Dans ce cas, on évite de perdre du temps avec une phase de compilation inutile ( qui ne compilera rien, mais ne fera que constater que les dépendances sont à jour ). A utiliser seulement occasionnellement pour gagner un peu de temps, car même sans cette option, le plus souvent GNAT n’est pas très long et passe vite à l’étape de liaison. Toujours laisser GNAT tester les nécessités de mise à jour, évitera tout de même de passer à coté de dépendances qui ne serait plus à jour ( ce qui se produit facilement, car on a toujours vite fais de perdre la trace des petites bricoles ).
  • option « -M » de gnatmake
  • M — ( pas de memotechnique ) — teste les mises à jour et dépendances des fichiers ALI
  • Teste si tous les fichiers ALI et objets sont à jour, et s’ils le sont, alors envoie une liste des dépendances sur stdout. Voir aussi l’option « -a », car là aussi les fichiers propres à GNAT seront ignorés par ce processus, à moins que l’option « -a » ne soit donnée, si nécessaire.
  • option « -q » de gnatmake
  • q — quite — silencieux
  • « Mode carpe » : avec cette option gnatmake fait « glouglou » sans un bruit.
  • option « -z » de gnatmake
  • z — ( pas de mnémotechnique ) — pas de point d’entré main
  • Indique de ne pas passer par un point d’entrée main pour le binaire, c’est-à-dire encore, compile même si le fichier est un fichier de package au lieu d’être un fichier de programme principal ; le fichier de package produit alors un programme final, sans l’entrée main habituelle. Ceci peut être utile si par exemple on souhaite compiler pour un sous système particulier ou un framework ou même pour un binaire qui ne serait pas un fichier de programme ordinaire ( par exemple pour une image de section de boot d’une disquette bootable ou d’un CD ).
  • option « -aI{dir} » de gnatmake
  • aI — Adafiles include directory — chemin de recherche des sources Ada
  • Indique un chemin de recherche pour les fichiers sources Ada. Voir aussi « -aL{dir} », qui diffère dans son fonctionnement, et dont la documentation en dit plus, par contrario.
  • option « -aL{dir} » de gnatmake
  • aL — libraries path — chemin de recherche des librairies
  • Indique un chemin de recherche pour les librairies ( voir aussi l’option « -aI{dir} », qui diffère dans son fonctionnement ). A la différence « -aI{dir} », cette option à pour effet que si un fichier ALI est trouvé, alors il est utilisé, sans re-compilation. Ceci permet d’utilisé des fichiers ALI dont on ne posséderait pas les sources ( d’où le « L », qui signifie que c’est un chemin pour les librairies, et non pas un chemin pour les sources ). Malgré cela, si le code source est trouvé dans le chemin, et pas le fichier ALI, alors le code source est bien sûre tout de même compilé. Avec cette option, le fichier n’est pas nécessaire, mais il est tout de même utilisé s’il est trouvé. Voir aussi l’option « -aO{dir} », dans la même catégorie, mais qui fonctionne différemment. Notez qu’il est recommandé, si on ne souhaite pas de re-compilation automatique des fichiers ALI, de leur donner un attribut de protection en écriture. Cette option ne devrait donc normalement pas être utilisé. Mais elle peut être considérée comme plus pratique que la protection en écriture pour certaines personnes ou pour certains projets, et elle est de toute manière entièrement disponible pour raison de compatibilité, et peu donc être utilisé normalement.
  • option « -aO{dir} » de gnatmake
  • oO — objects path — chemin de recherche des fichiers objets
  • Indique le chemin de recherche pour les fichiers objets. Bien que cette option donne ( comme son nom l’indique ) le chemin pour les fichiers objets, elle permet tout autant de donner le chemin vers des fichiers ALI. Mais alors dans ce dernier cas, si le ALI n’est pas trouvé, aucune compilation n’est effectuée à partir du code source, même s’il est trouvé, et une erreur est alors renvoyée. En résumé, cette option indique le chemin des fichiers ALI et objets à utiliser tel quel. Voir aussi l’option « -aL{dir} », dans la même catégorie, mais qui fonctionne différemment.
  • option « -gnatp » de gnatmake
  • gnatp — ( pas de mnémotechnique ) — ne produit pas les testes d’exécution
  • Supprime tous les testes d’exécution de la runtime ( ce qui inclus les tests de validité à l’exécution ).
  • option « -I{dir} » de gnatmake
  • I — include directory — chemin de recherche des sources Ada et fichiers objets
  • Équivalent à « -aI{dir} » et « -aO{dir} ». Fourni donc en fait un chemin de recherche tant pour les sources Ada que pour les fichiers objets.
  • option « -L{dir} » de gnatmake
  • L — external libraries path — chemin de recherche des librairies ne dépendant pas de sources Ada
  • Indique le chemin pour la recherche des autres librairies nécessaires à la liaison, mais qui ne dépendent pas de source Ada ( comme les fichiers de ressources Windows par exemple ou les importations de DLL ).
  • option « -nostdlib » de gnatmake
  • nostdlib — no standard librarie — ne pas utiliser les librairies standards
  • Commande de ne pas utiliser les librairies du répertoire des librairies standards.
  • option « -cargs {option} » de gnatmake
  • cargs — compiler argument — option à passer au compilateur de code intermédiaire
  • Fourni une option à passer au compilateur ( normalement GCC ). Il faudra un « -cargs » pour chaque option, et il ne devra pas y avoir d’espaces dans le texte de l’option. Si un ou des espaces sont requis par l’option, alors il est possible d’obtenir cet effet en utilisant deux ou plusieurs « -cargs » qui se suivront. Notez bien l’espace entre « -cargs » et l’option à passer.
  • option « -largs {option} » de gnatmake
  • largs — linker arguments — options à passer à l’éditeur de liens
  • Fourni une option à passer au lieur ( normalement LD ). Il faudra un « -cargs » pour chaque option, et il ne devra pas y avoir d’espaces dans le texte de l’option. Si un ou des espaces sont requis par l’option, alors il est possible d’obtenir cet effet en utilisant deux ou plusieurs « -cargs » qui se suivront. Notez bien l’espace entre « -largs » et l’option à passer.

Section 8 : les « pragmas » et les « pragmas » de configuration

Initialement, la section 8 ne traite que des pragmas de configuration, les autres ont été ajoutées. Les descriptions des pragmas sont issues du manuel de référence, et non pas du guide d’utilisation.

Les pragmas de configuration sont écrites par le programmeur dans un fichier « gnat.adc », qui au moment de la compilation, doit se trouver systématiquement dans le répertoire depuis lequel est invoqué gnatmake. Ce fichier est automatiquement utilisé s’il est présent à l’invocation de gnatmake, mais il n’est pas obligatoire. On peut spécifier à gnatmake d’ignorer ce fichier, même s’il est présent, en lui donnant l’option « -gnatA ». Ce fichier est d’abord utile pour faire du code finalisé, pour réduire la taille finale de l’exécutable ( en dehors de toute configuration spécifique dans ce sens, les exécutables produits par gnatmake sont malheureusement plus gros que l’on ne pourrait l’espérer, de 20% à 50% plus gros qu’un programme Pascal environ équivalent par exemple ). Il est possible d’utiliser un autre fichier que « gnat.adc » ou même en complément de « gnat.adc » ( dans ce cas, « gnat.adc » reste lut en premier ). Pour cela, on passe à gnatmake l’option « -gnatec{path} ». Path désigne le fichier de configuration à employer, en supplément de « gnat.adc » qui est toujours utilisé, sauf si on utilise l’option « -gnatA », qui elle- même d’ailleurs n’empêche pas l’utilisation du fichier spécifié par « -gnatec{path} ». Attention : si gnatmake reçoit plusieurs options « -gnatec{path} » à sa ligne de commande, alors il n’utilise que la dernière option, en ignorant totalement les autres. Donc bien qu’il ne soit syntaxiquement valide d’en spécifié plusieurs, dans les faits on ne peut en donner qu’une seule.

Pour la finalisation du code, voir aussi l’abrégé de la section 26 ( considération sur la performance ).

Dans un fichier de configuration par pragmas ( que ce soit « gnat.adc » ou un autre fichier ), chaque ligne est constituée du mot clé pragma, suivit du nom de la pragma, puis des éventuels paramètres entre parenthèses, et d’un point virgule final ( par exemple : « pragma Ada_95; » ).

Les pragmas sont présentées avec une pseudo signature, et son suivies de leurs descriptions.

  • « pragma Ada_83; »
  • Force la compilation en mode Ada 83 stricte.
  • « pragma Ada_95; »
  • Force la compilation en mode Ada 95 stricte ; interdit les extensions de Ada 2005 supporté par GNAT, qui ne les supporte d’ailleurs pas toutes.
  • « pragma Ada_2005; »
  • Cette pragma n’existe pas, mais l’effet est obtenu en ne spécifiant ni « Ada_83 » ni « Ada_95 » ; par défaut GNAT accepte certaines extensions de Ada 2005, mais ni ne les implémente ni ne les reconnaît toutes.
  • « pragma Comment (string); »
  • Ajoute un commentaire dans le fichier objet et dans l’exécutable final.
  • « pragma Eliminate (*); »
  • Élimine certaines éléments pour la finalisation du code, permettant ainsi une économie dans le code binaire, ce qui offre de réduire parfois très sensiblement la taille du dit binaire. Notez que les éléments locaux sont automatiquement supprimés, sans qu’il ne soit nécessaire pour cela d’employer une telle pragma ( celle pragma ne traite d’ailleurs qu’avec les entités globales ). Les « pragmas Eliminate » sont de préférence produite automatiquement par gnatelim ( il est possible de les écrire manuellement, mais c’est totalement inefficace, car nombreux oublis nécessairement probables et important risques d’erreur ). Le paramètre, de format assez complexe, n’est pas décrit ici, car pour la génération des « pragmas Eliminate », il est préférable de passer par gnatelim.
  • « pragma External (*); »
  • Cette pragma correspond à la « pragma Export » de la spécification de Ada. Elle est présente pour la compatibilité avec certains anciens compilateurs Ada 83. Pour plus d’information, referez-vous au manuel de référence Ada.
  • « pragma Finalize_Storage_Only (Nom); »
  • Indique que la routine de finalisation ne doit pas être appelée pour les éléments déclarés au niveau package. De cette manière la finalisation habituellement effectuée juste avant la fin du programme pour ces objets, n’est alors pas invoquée. Quand le programme se termine, il n’est par exemple pas nécessaire de libérer la mémoire utilisée par certains objets, même on doit évidemment toujours finaliser ceux qui sont associé à d’autres types de ressources comme des sockets par exemple. Malgré que cette pragma soit intéressante, son paramètre n’est malheureusement pas correctement documenté par le manuel de référence de GNAT ( ce qui est étrange ).
  • « pragma Initialize_Scalars; »
  • Comparable à « Normalize_Scalars » ( voir le manuel de référence Ada ), mais diffère de celle-ci en deux points. La première différence est que contrairement à « Normalize_Scalars » qui est globale est s’applique à toutes les unités package et programme principal ), « Initialize_Scalars » s’applique localement à chaque unité. En conséquence, il n’y a pas nécessairement de re-compilation de la runtime. La deuxième différence est qu’il est possible de choisir n’importe quelle valeur pour l’initialisation des scalaires. La valeur est introduite dans le binaire par bind ( référez-vous donc à la documentation de bind si avez à employer cette pragma ). Cette pragma est utile à fin de teste. Vous pouvez ainsi tester le comportement de votre application avec différentes valeurs initiales pour les scalaires. Si l’application se comporte de la même manière quelles que soient les valeurs d’initialisation des scalaires, c’est que votre application est fiable. Dans le cas contraire, il vous faudra déterminer soigneusement la cause de ces différences de comportement, et le corriger. Il y aura également sûrement beaucoup à gagner à effectuer les mêmes testes en variants l’initialisation des structures plus complexes, mais ceci devra obligatoirement passer par une modification du code source de l’application à tester.
  • « pragma Interface (*); »
  • Cette pragma correspond à la « pragma Import » de la spécification de Ada. Elle est reconnue pour raison de compatibilité avec certains anciens compilateurs Ada 83. Pour plus d’information, vous pouvez vous référer au manuel de référence Ada.
  • « pragma License (Type_de_Licence); »
  • C’est une pragma intelligente qui vous permet de vous assurer en permanence que vous respecter la cohérence des différentes licences en vigueurs dans votre projet de développement. Cette pragma n’est donc utile que dans les projets concernés pas des licences multiples, et pour lesquelles les package ne sont pas tous sous une licence identique. Placez cette pragma dans chaque unité pour laquelle il existe une licence à indiqué ; et à la compilation, GNAT vous signalera par un message d’erreur, toutes occurrences d’incompatibilité de licence. Le paramètre peut prendre l’une des valeurs suivantes : « Restricted », « Unrestricted », « GPL » et « Modified_GPL ». Cette pragma peut vous aider à éviter de mauvaise surprise.
  • « pragma Link_With; »
  • Cette pragma correspond à la « pragma Linker_Options » de la spécification de Ada. Elle est reconnue pour raison de compatibilité avec certains anciens compilateurs Ada 83. Pour en savoir plus, referez vous à « Linker_Options » dans le manuel de référence Ada.
  • « pragma Linker_Alias (Nom_Entité, Alias); »
  • Crée un alias pour le lieur. Référez-vous à la documentation de GCC pour apprendre ce que sont, et comment fonctionnent les alias destiné au lieur.
  • « pragma Linker_Section (Nom_Entité, Nom_Section); »
  • Spécifie la section du binaire dans laquelle l’entité doit être placée. C’est utile si vous créer des binaires qui ne sont pas standards ( comme des images bootable depuis une disquette, un disque dur ou un CD par exemple ). Referez-vous à la documentation de GCC pour en savoir plus.
  • « pragma No_Run_Time; »
  • Cette pragma permet de s’assurer que le binaire produit n’utilise pas la runtime Ada. Si la runtime est référencée par quelque partie du programme que ce soit, même implicitement, alors une erreur de liaison se produira ( tandis qu’aucune erreur ne sera détectée à la compilation ). En on conclus que concrètement, cette pragma interdit la liaison avec la runtime, ce qui indirectement ( même si ce n’est pas très proprement ), abouti à l’effet recherché, qui est d’interdire l’utilisation de la runtime. Voyez aussi la « pragma Restricted_Run_Time ».
  • « pragma Pure_Function (Nom_Fonction); »
  • Indique que la fonction n’a conceptuellement aucun effet de bord dont dépendrait le résultat de la fonction nommée ou même d’une autre fonction. Ceci autorise certaines optimisations du code binaire par le compilateur, et permet l’usage de la fonction dans les expressions d’adresse. Attention : cette pragma étant spécifique à GNAT, elle n’est pas portable ( elle sera sans effet avec les compilateurs qui ne la reconnaisse pas, ce qui en soit ne représente malgré tout aucun risque ).
  • « pragma Ravenscar; »
  • Cette pragma assure que le code est conforme aux restrictions du Ravenscar Profile, tel que défini par le International Real-TimeAdaWorkshop 1997. Les personnes concernées seront sûrement déjà renseignées sur la signification de cet ensemble de restrictions.
  • « pragma Restricted_Run_Time; »
  • Cette pragma commande d’utiliser une version réduite de la runtime. Si le code ne s’y prête pas, un message d’erreur sera généré à la liaison. Voyez aussi la « pragma No_Run_Time ».
  • « pragma Unreferenced (Nom_Entité); »
  • Précise explicitement que l’entité nommée n’est pas référencée. Il arrive parfois que l’on doive introduire dans un code, par exemple une variable qui n’est pas référencée ( même cette obligation est rare ). L’indication explicite que l’entité est volontairement non référencée, épargne d’être inondé(e) de messages d’avertissement tout aussi inutiles qu’ennuyeux. Si l’entité nommée est pourtant référencée par le code, alors un message d’erreur est émis par le compilateur.
  • « pragma Validity_Checks (string | All_Checks | On | Off); »
  • Contrôle la génération du code des différents tests de validité d’instruction à l’exécution. Cette pragma complète les paramètres fournis à la ligne de commande ou dans le fichier projet paramétrant le même aspect, qui sont lus d’abord, et éventuellement écrasés ensuite en conformité avec cette pragma. Cette pragma peut être employée dans le fichier de configuration de pragma « gnat.adc » ou dans tout autre fichier de configuration de pragma désigné avec l’option de ligne de commande appropriée ( en l’occurrence, l’option « -gnatec{path} » ). La pragma peut également être employée en tous points du code. Si l’argument chaîne est employé pour cette pragma, alors son format est le même que celui de l’option de ligne de commande « -gnatV » ( pour plus de détail sur cette option, référez-vous au guide d’utilisation de GNAT ).

Les pragmas qui suivent sont issues de la spécification du langage Ada, et sont reconnues par GNAT. Pour en savoir plus, referez-vous au manuel de référence de Ada.

  • « C_Pass_By_Copy »
  • « Component_Alignment »
  • « Discard_Names »
  • « Elaboration_Checks »
  • « Eliminate »
  • « Extend_System »
  • « Extensions_Allowed »
  • « External_Name_Casing »
  • « Float_Representation »
  • « Initialize_Scalars »
  • « License »
  • « Locking_Policy »
  • « Long_Float »
  • « No_Run_Time »
  • « Normalize_Scalars »
  • « Polling »
  • « Propagate_Exceptions »
  • « Queuing_Policy »
  • « Ravenscar »
  • « Restricted_Run_Time »
  • « Restrictions »
  • « Reviewable »
  • « Source_File_Name »
  • « Style_Checks »
  • « Suppress »
  • « Task_Dispatching_Policy »
  • « Unsuppress »
  • « Use_VADS_Size »
  • « Volatile »
  • « Warnings »
  • « Validity_Checks »

Section 10 : le gestionnaire de projet de GNAT

Cette section fera d’une page à elle seule ( à venir pour une date indéterminée ). C’est une toute autre manière d’utiliser GNAT, en s’épargnant le passage options sur la ligne de commande. Plus pratique, c’est vrai, mais l’utilisation directe de la ligne de commande est bien pratique elle aussi pour les petites compilations de petits programme… ou encore si on préfère utiliser une autre méthode de gestion avec un programme fait maison, qui se charge d’appeler gnatmake en générant automatiquement les options… ce qui peut éventuellement permettre de répondre à des exigences spécifiques. Sachez tout de même que ce service est fourni par GNAT.

Section 20 : création de corps de « package » par défaut avec gnatstub

Cette utilitaire fourni par la suite GNAT, vous facilite la tâche fastidieuse d’écrire un corps initial correspond à une spécification.

Gnatstub crée un corps body ) à partir d’un fichier de spécification spec. ). On peut en pratique, travailler de deux manières. La première manière et de créer un body, pour développement incrémental, et créer une spécification à partir du body lorsque celui-ci est bien avancé. On peut travailler à l’opposé, dans l’autre sens également, et créer une spécification et créer le body seulement ensuite.

Gnatstub permet justement de créer automatiquement un body initial à partir d’un fichier de spécification. Il ne reste alors plus qu’à éditer le body pour en écrire l’implémentation effective. Le body est néanmoins compilable, même sans avoir à l’éditer : les corps de fonctions et procédures sont initialisées avec une instruction « null », ce qui permet d’avoir un body valide, même sans l’éditer au préalable. Il sera bien sûre tout de même nécessaire d’éditer le fichier body si on souhaite avoir un body véritablement concret.

Syntaxe d’invocation : « gnatstub [options] fichier [répertoire] »

  • « fichier » : correspond au fichier de spécification.
  • « répertoire » : est le répertoire où le body devra être créé.
  • « -f » : remplace le body même s’il existe déjà et même s’il est à jour.
  • « -hs » : recopie le commentaire d’en-tête depuis le fichier de spécification vers le corps.
  • « -hd » : crée un commentaire d’en-tête vide.
  • « -q » : mode musaraigne ( cherchez le point commun entre une carpe et une musaraigne ).
  • « -v » : mode verbeux ( je ne vous parle même pas du caniche de la voisine du dessous ).

Section 21 : réduire la taille des exécutables Ada avec gnatelim

Cette section fait l’objet d’une page à elle toute seule : Réduire la taille des exécutables produits par GNAT .

Section 25 : au sujet de Microsoft Windows

Il n’est pas possible d’utiliser « GetLastError » et « SetLastError » avec un programme qui emploie des tâches, des enregistrements protégés ( mécanisme de synchronisation ) ou des exceptions ( c’est-à-dire pratiquement 100% des programmes Ada ). GNAT utilise ces deux procédures de l’API Windows, et sa runtime peut donc modifier la valeur de l’indicateur de code d’erreur de l’API Windows dans le dos de votre application. On pourra utiliser « GetLastError » et « SetLastError » si on est dans aucun de ces cas de contre-indication, mais même alors, le résultat n’est pourtant même pas garanti. En bref, même si c’est ennuyeux, il faut apprendre à se débrouiller sans ou alors appelé « GetLastError » immédiatement après l’appel à chaque routines de l’API pour lesquelles cela est souhaité, et de le faire dans une portion non interruptible du programme.

Les options de ligne de commande spécifiques à Windows sont les suivantes…

  • « -mwindows » : crée un exécutable avec le sous système graphique de Windows.
  • « -mconsole » : cette option n’existe pas, mais on obtient ce résultat en ne spécifiant pas « -mwindows » ( le mode console est le mode par défaut, et à défaut d’indication du contraire ).

La question de la création de l’utilisation et création de DLL Windows fera l’objet d’une page à elle toute seule ( à venir ).

Section 26 : considérations sur la performance

Pour produire du bon code bien finalisé ( et surtout réduire la taille finale de l’exécutable, qui est par défaut un peu trop importante avec GNAT ).

Pour la finalisation du code, voir aussi la section 8 ( les pragmas de configuration ).

Les options de ligne de commande spécifiques à l’optimisation, sont les suivantes…

  • « -O0 » : aucune d’optimisation ( état par défaut ).
  • « -O1 » : optimisation moyenne.
  • « -O2 » : optimisation élevée.
  • « -O3 » : optimisation élevée avec inlining ( instanciation en lieu et place de l’invocation ) des petites fonctions de procédures.

L’inlining peut être produit également avec « -O1 » et « -O2 » pour les procédures ou fonctions explicitement déclarées inline dans le code. Notez bien à ce sujet, que même si une procédure est explicitement déclarée inline dans le code, elle ne sera pourtant pas compilé inline si le niveau d’optimisation n’est pas au moins égal à 1. Avec « -O0 », une procédure est toujours compilée et invoquée comme un sous programme ordinaire, même si elle est déclarée inline dans le code ( ceci correspond d’ailleurs au comportement qu’avais les compilateurs Borland Turbo Pascal et Borland Turbo C++ ).

Comprenez bien que « -O3 » ne donne pas nécessairement les meilleurs résultats, et que le meilleur résultat dépend de l’environnement global ( matériel et logiciel ), et de l’application elle-même. Le mieux est donc de tester les trois niveaux d’optimisation de 1 à 3, et de sélectionner le meilleur résultat parmi les trois.

Un moyen simple et assez fiable de déterminer le meilleur résultat, consiste en voir la taille du code produit. En effet, bien que l’on argue parfois qu’une augmentation de la taille du code binaire soit souvent le prix à payer pour un code plus rapide, ceci est loin d’être toujours le cas, et ne peut surtout être maîtriser que par les algorithmes de l’application, c’est-à-dire au niveau conception et développement, et non pas au niveau de l’optimisation automatique de code par un compilateur. On constate souvent avec GCC et G++ parce exemple, qu’avec les niveaux d’optimisation élevés, non seulement on augmente de beaucoup la taille du code pour un gain de vitesse d’exécution souvent dérisoire, qui plus est, il arrive même que bien au contraire, le code ainsi optimisé soit en fait plus lent qu’avec un niveau d’optimisation inférieur ( un code plus lent, et qui est encore plus volumineux est vraiment sans intérêt ).

Un autre fait concret qui justifie de s’intéresser d’abord à la taille de l’exécutable, est qu’un code de petite taille, contient des sections souvent de petites taille également, qui tiendront mieux dans le cache des processeurs. Un contre exemple pour vous faire comprendre : le développement en ligne d’une boucle à nombre d’itérations statiquement déterminé n’est pas toujours une bonne idée. En effet, sous forme de boucle, la totalité du code peut assez aisément se trouver entièrement dans le cache du processeur, ceci pendant toute la durée d’exécution de toutes les itérations de la boucle. Au contraire, quand la boucle est développée, le processeur doit faire de plus fréquentes requêtes mémoire pour récupérer la suite du code. Le résultat est un code nettement plus gros et aussi tristement nettement plus lent ( phénomène plusieurs fois constaté ).

Et c’est aussi en règle générale que l’on constate que les binaire les plus petits sont aussi souvent les plus rapides. Tout ceci pour vous dire que pour choisir le meilleur résultat parmi les 3 niveaux d’optimisation disponible, le critère à considérer en priorité est celui de la taille du binaire produit… seulement ensuite vienne les testes effectifs de la vitesse d’exécution sur le plus petit binaire ( pour s’assurer au moins de la conformité avec les attentes ).

Par ailleurs et pour finir avec l’optimisation : Il est bien connu que certains compilateurs introduisent des bugs dans les codes optimisés. GCC semble avoir été assez bien testé à ce niveau, et il faut savoir que même certains rare bugs, n’apparaissent que dans le code non- optimisé. En conséquence, vouloir ne pas optimiser au prétexte que cela permettrait d’obtenir un code plus fiable, serait une erreur. Attention : la fiabilité du code optimisé dépend malgré tout de la version de GCC employé ( certaines versions sont tout de même bien connues pour êtres très buggés ).