Qt a des principes assez stricts en ce qui concerne la compatibilité entre versions : par exemple, si une application fonctionne parfaitement avec Qt 5.0.0, elle continuera à fonctionner avec Qt 5.0.1 sans recompilation (aux défauts corrigés près) et vice-versa : c’est une compatibilité tant ascendante que descendante.
Au contraire, les versions mineures (Qt 5.1, 5.2, etc.) ne garantissent qu’une compatibilité ascendante : si une application est compilée avec Qt 5.0, elle fonctionnera avec Qt 5.1 sans nécessiter de recompilation de l’application — une compatibilité descendante serait ici impossible, car de nouvelles fonctionnalités font leur apparition d’une version à l’autre. Par contre, une version majeure peut casser cette compatibilité : pour passer de Qt 4 à 5, il a été nécessaire de recompiler toutes les applications et d’en retoucher légèrement les sources. Toutefois, les modules d’extension de Qt ne sont pas sujets aux mêmes garanties.
Ces garanties facilitent la vie des distributeurs de logiciels, particulièrement pour les distributions Linux : une version partagée de Qt suffit pour tout le système, elle peut être mise à jour indépendamment des applications — ce qui limite fortement l’utilisation de bande passante pour les mises à jour, économise de l’espace disque et permet la correction de défauts rapidement.
Un casse-tête pour les développeurs…
Pour atteindre ces objectifs, les développeurs de Qt doivent faire attention à deux points : les compatibilités au niveau des sources et des binaires. La première est relativement simple : l’interface de programmation doit rester identique d’une version à l’autre, les ajouts étant autorisés ; par conséquent, une fonction ne peut pas changer de prototype (un nouveau paramètre ne peut pas devenir obligatoire d’une version à l’autre). Par le principe d’encapsulation, une classe peut être réimplémentée complètement sans casser cette compatibilité des sources.
Par contre, la compatibilité binaire est plus épineuse : elle est atteinte quand un programme qui lie dynamiquement une version plus ancienne de Qt peut être utilisée avec de nouvelles versions de Qt sans recompilation de l’application. Alors qu’il est souvent bénin d’ajouter des fonctions sans casser la compatibilité binaire, il est impossible de changer la taille d’un objet en mémoire, car cela casserait les mécanismes d’allocation dynamique. Ces modifications doivent alors être planifiées pour la prochaine version majeure, où la recompilation sera nécessaire. De même, rendre une fonction constante change le nom du symbole associé, c’est-à -dire que le système d’exploitation ne la trouvera plus dans la bibliothèque partagée.
… et pour les distributions Linux
La compatibilité binaire facilite fortement la maintenance d’une distribution Linux, mais il faut s’assurer qu’elle est bien respectée. Pour ce faire, Fedora s’est dotée d’un nouvel outil : ABI Tracker. Il remplace le Linux Upstream Tracker, qui n’est plus mis à jour.
Ainsi, les mainteneurs de la distribution peuvent réagir pour chaque non-respect de la compatibilité binaire et décider de mettre à jour telle ou telle bibliothèque : ils peuvent prédire la quantité de dysfonctionnements à attendre de cette opération. Il peut s’agir d’un comportement erratique du programme (par exemple, un symbole de plus dans une énumération : les tests sur la valeur peuvent alors échouer), voire d’un plantage pur et simple lorsque l’exécution passe à un point donné du programme (un symbole n’existe plus). Par exemple, le module Qt Core a eu tous ces problèmes en passant de la version 5.1.1 à 5.2.0, selon l’outil de Fedora.
Qt respecte-t-il ses principes de compatibilité ?
En regardant la page montrant l’évolution de Qt, une chose saute à l’Å“il : la garantie de compatibilité binaire est loin d’être respectée depuis Qt 4.7 (sorti fin 2010), sauf pour les dernières versions correctives de Qt 4.8.
Ce constat mérite néanmoins d’être nuancé. Pour Qt 5.0, le score de zéro pour cent est totalement justifié, étant donné que c’était l’objectif du changement de version majeure. Pour Qt 5.6, la prochaine version avec support à long terme, le score est catastrophique, avec moins de nonante pour cent au lieu des cent promis ; en regardant le détail, on se rend compte qu’une bonne partie est due à une erreur d’empaquetage, Qt 3D étant inclus dans le rapport précédent, alors que ce module est loin d’être finalisé ; d’autres modules ont été supprimés et n’aident pas le score.
Plus en détail, pour le module Qt Quick, qui n’atteint qu’un score de 92,3 %, une bonne partie des symboles supprimés correspond à une classe qui n’a jamais fait partie de l’API publique (DesignerSupport). Le tiers restant correspond néanmoins aux destructeurs de classes publiques. A contrario, les dernières versions correctives de Qt 4.8 ne posent strictement aucun souci.
Bien évidemment, cette vision est partielle, parce qu’elle est obtenue avec un outil générique, qui ne prend pas en compte certaines spécificités de Qt (les API privées). Il n’empêche que certaines modifications semblent casser cette compatibilité, sans qu’elles ne posent de problème spécifique aux mainteneurs.
Sources : Qt Version Compatibility, Future of the Linux upstream tracker.
Voir aussi : Pensées sur la compatibilité binaire et sur les conventions d’appel.