Portons-nous bien

Problématique

Dans le cadre de certains portages Ada, on peut souhaiter continuer à faire vivre un temps le code legacy tout en commençant à utiliser le code porté.

Si, à l’issue du portage, on découvre un problème ou une évolution dans le code legacy, on devra alors reporter les modifications induites dans le code porté. On peut aussi avoir la situation inverse. En d’autres termes, les codes devront coexister.

Pour faciliter cette coexistence, il faut s’assurer d’avoir une certaine homogénéité par exemple en terme d’arborescence et de nommage des fichiers ainsi que de formatage. Idéalement, il faudrait avoir le même code.

Pour cela, avant d’entreprendre un portage, il peut être pertinent de réagencer l’arborescence et le nommage des fichiers legacy ainsi que leur formatage pour qu’ils soient plus faciles à prendre en compte par la chaîne de compilation ciblée par le portage. Dans le cadre d’un portage vers le GNAT, il est judicieux d’utiliser les outils gnatchop et gnatpp pour adresser efficacement et sûrement le nommage et le formatage des fichiers.

Cela étant, il est fort probable qu’il y aura des divergences entre le code legacy et le code porté. Ces divergences étant souvent liées :

  • Aux implémentations des compilateurs.
  • Au contexte cible du portage.

Comment adresser simplement ces divergences ?

Il y a un certain nombre de solutions. On peut créer des hiérarchies dédiées par exemple : Sys.XXX et Sys.GNAT ou aussi avoir deux implémentations du même paquetage Sys et de son éventuelle filiation. Dans les deux cas, les systèmes de build pour GNAT et XXX devront prendre en compte leurs fichiers respectifs.

Une autre solution intéressante est d’utiliser un préprocesseur (ici gnatprep) afin d’avoir les mêmes fichiers pour GNAT et XXX au travers par exemple d’un porting_kit.

Le « Porting_Kit » Ada

Le Porting_Kit est une hiérarchie de paquetages permettant :

  • De faciliter le portage en modifiant à minima le code legacy.
  • De permettre la coexistence entre le code legacy et le code porté si cette dernière est requise.

Concernant ce dernier point, une solution simple est d’utiliser l’outil gnatprep pour préprocesser le code à sa convenance.

Par exemple, si nous avons le fichier porting_kit-sys.ads.prep suivant :

#if GNAT then

with System.Storage_Elements,
   GNAT.Debug_Utilities;
use System;
#else
  -- xxx Ada compiler
#end if;

package Porting_Kit.Sys is
#if GNAT then
   function Image (Item : in Address) return String 

   subtype Offset is Storage_Elements.Storage_Offset;

   function "+" (Left : in Address; Right : in Offset) return Address renames 


#else
   -- xxx Ada compiler
   function Image (Item : in Address) return String 

   subtype Offset is 

   function "+" (Left : in Address; Right : in Offset)
   return Address renames 


#end if;
end Porting_Kit.Sys;

Alors la commande gnatprep -c -DGNAT=true porting_kit-sys.ads.prep porting_kit-sys.ads produira le fichier porting_kit-sys.ads suivant :

--! #if GNAT then
with System.Storage_Elements,
GNAT.Debug_Utilities;
use System;
--! #else
--! -- xxx Ada compiler
--! #end if;

package Porting_Kit.Sys is
--! #if GNAT then
   function Image (Item : in Address) return String ...

   subtype Offset is Storage_Elements.Storage_Offset;

   function "+" (Left : in Address; Right : in Offset) return Address renames ...
...
--! #else
--! -- xxx Ada compiler
--! function Image (Item : in Address) return String ...
--!
--! subtype Offset is ...
--!
--! function "+" (Left : in Address; Right : in Offset) return Address renames ...
--! ...
--! #end if;
end Porting_Kit.Sys;

Le fichier Ada ainsi produit est compréhensible par le compilateur GNAT. Si nous voulons notre même fichier pour le compilateur xxx utilisé pour le legacy, il suffira simplement de faire gnatprep -c -DGNAT=false porting_kit-sys.ads.prep porting_kit-sys.ads. Ainsi donc, nous pouvons basculer simplement d’un source pour un compilateur et son contexte à un autre.

Même si cette approche est intéressante, il faut bien garder à l’esprit que les sources Ada (*.ad[sb]*) concernés sont maintenant devenus des fichiers .prep. Cette indirection nécessitera donc un minimum de prétraitements qui devront rester raisonnables et ne pas venir trop entraver au quotidien le développement.

Il est à noter qu’au même titre que cpp, gnatprep peut s’utiliser à la volée lors de la compilation d’un fichier Ada. Dans ce cas, la présente problématique ne pourrait être adressée.

Référence

[1] : The gnat compilation model — conditional compilation

Commentaires