Ce document s’applique à la version 3.15p du compilateur Gnat. 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 très long document. Un bon nombres de commentaires personels ont été ajouté.
Dans cette page ...
Source des informations de ce document
Section 6 : le programme gnatmake
Section 8 : les pragmas et les pragmas de configuration
Section 10 : le gestionnaire de projet de Gnat
Section 20 : création de corps de package par défaut avec gnatstub
Section 21 : réduire la taille des exécutables Ada avec gnatelim
Section 25 : au sujet de Microsoft Windows
Section 26 : considérations sur la performance
Source des informations de ce document
La version originale, in english, peut être entre autres (il
en existe plusieurs versions) consultée ici
Gnat User Guide
et là
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 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 - memotechnique - 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, les librairies systèmes de GNAT, les fichiers verrouillés par protection en écriture du fichier ALI, etc. Ceci est utile pour recompiler une application tout entière, en recompilant 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 recompilation 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 recompilation 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 -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 repertoire 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 (mode silencieux, avec cette option gnatmake fait glouglou sans un bruit).
- option -z de gnatmake
- z - (pas de memotechnique) - 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 - Ada files 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 recompilation. 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 recompilation 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 memotechnique) - 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 u 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 démesurément énormes). 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 pragma sont présentées avec une pseudo signature, et son suivies de leurs descriptions.
- pragma Ada_83;
- Force la compilation en mode Ada83 stricte.
- pragma Ada_95;
- Force la compilation en mode Ada95 stricte (interdit les extensions de Ada2005 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 Ada83. 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 recompilation 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 Ada83. 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 Ada83. 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 detectée à la compilation). En on conclus que concrêtement, cette pragma interdit la laison avec la run-time, 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 run-time. 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-Time Ada Workshop 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). 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 à chaques routines de l’API pour lesquelles cela est souhaité, et de le faire dans une portion non interruptible du code.
Les options de ligne de commande spécifiques à Windows sont les suivantes …
- -mwindow : 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/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 assez énorme 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 locale) 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- TurboPascal et Borland-TurboC++).
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 bugées).
