I. Introduction

Vous venez de développer une petite application sous Kylix et vous voulez maintenant la distribuer, par exemple sur Internet. Nous allons voir dans la suite de cet article une méthode pour distribuer une application en minimisant les manipulations pour l'utilisateur final.

II. Problèmes

Vous disposez du fichier exécutable de votre programme appelé MonProg. Et vous essayez de l'exécuter depuis la ligne de commande :

 
Sélectionnez
./MonProg
./MonProg: error while loading shared libraries: libqtintf-6.5-qt2.3.so: cannot open shared object file: No such file or directory

Et vous voyez apparaître le message d'erreur ci-dessus. Il manque donc une librairie partagée, l'équivalent d'une DLL sous Windows. Sauf que la gestion de ces librairies est bien différente sous Linux, comparée à Windows. Sous Windows, on met tout dans Windows/System, le programme va automatiquement y rechercher les librairies dont il a besoin et on prie très fort pour qu'il n'y ait pas de problème entre les différentes versions (prière hélas bien inutile). Sous Linux, l'approche est beaucoup plus explicite dans le sens où il faut tout indiquer, notamment quel fichier prendre quand on a besoin d'une librairie donnée et à quel endroit trouvé ce fichier. On peut ainsi avoir plusieurs versions d'une librairie qui cohabitent sans perturbation. Tout le contraire de ComCtl32.dll sous Windows :-)))

Revenons à MonProg. MonProg a donc besoin d'un certain nombre de librairies. Des détails peuvent d'ailleurs être trouvés dans le fichier DEPLOY qui se trouve dans le dossier de Kylix. Mais en pratique, une commande de Linux permet de connaître rapidement les besoins. Il s'agit de ldd :

 
Sélectionnez
ldd ./MonProg

/lib/libNoVersion.so.1 => /lib/libNoVersion.so.1 (0x40018000)
libqtintf-6.5-qt2.3.so => not found
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x40024000)
libpthread.so.0 => /lib/libpthread.so.0 (0x40107000)
libdl.so.2 => /lib/libdl.so.2 (0x4011d000)
libc.so.6 => /lib/libc.so.6 (0x40120000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Nous avons une petite collection de librairies. La plupart sont déjà disponibles dans la majorité des distributions Linux. Seule une librairie manque : libqtintf-6.5-qt2.3.so. Pour cause, c'est une librairie spécifique de Borland pour assurer la liaison entre la CLX et QT. Vous devez donc impérativement distribuer cette librairie.

À titre d'entraînement, commençons par mettre en œuvre cette librairie localement. Dans le dossier HOME de l'utilisateur courant, créez un dossier /MonProg. Copiez l'exécutable MonProg dedans. Puis allez dans /Kylix2/bin et copiez libqtintf-6.5.0-qt2.3.so dans /MonProg. C'est ce fichier qui sera utilisé pour la librairie manquante. Vous observerez qu'il y a une différence entre le nom demandé et le nom réel. Vous devez donc indiquer qu'il faut prendre le fichier libqtintf-6.5.0-qt2.3.so lorsqu'on a besoin de libqtintf-6.5-qt2.3.so. Ce renvoi se fait à l'aide d'un lien symbolique. Pour créer un lien symbolique, en ligne de commande, placez-vous dans le dossier /MonProg et tapez :

 
Sélectionnez
ln -s libqtintf-6.5.0-qt2.3.so libqtintf-6.5-qt2.3.so

Nous avons indiqué quel fichier prendre pour la librairie. Il nous reste à indiquer où prendre ce fichier. Pour trouver une librairie, le chargeur de librairie commence par explorer les dossiers stockés dans la variable LD_LIBRARY_PATH. La commande $LD_LIBRARY_PATH vous donne la liste des dossiers utilisés. Par défaut, le dossier courant n'est pas inclus. L'ajout en ligne de commande se fait comme suit :

 
Sélectionnez
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH

export n'est normalement pas utile. La modification de LD_LIBRARY_PATH s'applique normalement à toutes les instructions suivantes du shell. J'ai toutefois vu un cas où la modification n'était prise en compte par mon application que si export était ajouté avant.

./ pour le répertoire courant

$LD_LIBRARY_PATH l'ancien contenu de LD_LIBRARY_PATH auquel on ajoute donc le répertoire courant.

On remarque au passage que le répertoire courant est ajouté au début. Les librairies seront donc recherchées d'abord dans le répertoire courant, évitant les risques de confusion si plusieurs versions cohabitent.

Cette fois, tout doit être prêt. Un nouveau test avec ldd :

 
Sélectionnez
ldd ./MonProg
/lib/libNoVersion.so.1 => /lib/libNoVersion.so.1 (0x40018000)
libqtintf-6.5-qt2.3.so => ./libqtintf-6.5-qt2.3.so (0x4001a000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x401c6000)
libpthread.so.0 => /lib/libpthread.so.0 (0x402a9000)
libdl.so.2 => /lib/libdl.so.2 (0x402bf000)
libc.so.6 => /lib/libc.so.6 (0x402c2000)
libqt.so.2 => /usr/lib/libqt.so.2 (0x403d5000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x40893000)
libm.so.6 => /lib/libm.so.6 (0x408a1000)
libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x408bf000)
libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x408c9000)
libpng.so.2 => /usr/lib/libpng.so.2 (0x408e1000)
libz.so.1 => /lib/libz.so.1 (0x4090c000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x4091b000)
libmng.so.0 => /usr/lib/libmng.so.0 (0x4093a000)
libstdc++-libc6.2-2.so.3 => /usr/lib/libstdc++-libc6.2-2.so.3 (0x4097a000)
liblcms.so.1 => /usr/lib/liblcms.so.1 (0x409c3000)

Il ne manque plus rien. Vous pouvez d'ailleurs tester MonProg en ligne de commande et ça doit fonctionner.

Nous venons de voir la mise en œuvre manuelle de l'ensemble des étapes nécessaires au fonctionnement d'une application Kylix élémentaire.

III. Solution pratique

Nous allons maintenant voir comment appliquer ces étapes chez l'utilisateur. Pour ceci, nous aurons recours à un script qui va automatiser ces étapes. Le script doit :

  • créer le lien symbolique ;
  • ajouter le dossier de la libraire dans LD_LIBRARY_PATH ;
  • démarrer le programme.

Pour simplifier le script, nous imposerons à l'utilisateur que tous les fichiers soient dans le même dossier, $HOME/MonProg par exemple. Le script, que vous appellerez startMonProg.sh, aura alors l'allure suivante :

 
Sélectionnez
#!/bin/sh
ln -s $HOME/MonProg/libqtintf-6.5.0-qt2.3.so $HOME/MonProg/libqtintf-6.5-qt2.3.so
export LD_LIBRARY_PATH=$HOME/MonProg/:$LD_LIBRARY_PATH
$HOME/MonProg//MonProg

Vous n'avez plus qu'à envoyer ce script, libqtintf et votre programme à l'utilisateur, en faisant un petit paquet avec une archive tar.gz. Un nouveau script pour automatiser cette tâche est le bienvenu :

 
Sélectionnez
#!/bin/sh
cd $HOME
tar -czf  MonProg/MonProg.tar.gz MonProg/libqtintf-6.5.0-qt2.3.so MonProg/startMonProg.sh MonProg/MonProg

Vous n'avez plus qu'à envoyer MonProg.tar.gz à vos utilisateurs en leur indiquant de le décompresser dans le répertoire HOME de l'utilisateur avec la commande effectuée dans le répertoire HOME

 
Sélectionnez
tar -xzf MonProg.tar.gz

Les fichiers vont automatiquement se mettre dans $HOME/MonProg. Puis un clic sur startMonProg.sh et ça roule. J'ai fait des essais sur la Debian d'un collègue de boulot et ça marche.

IV. Problèmes avec Libqt

En fait, ça ne roule pas toujours aussi bien que ça. Certaines distributions (Mandrake 8.0 à 8.2 et RedHat 7.0 à 7.3 à ma connaissance) ont été compilées avec une version non-officielle de gcc. Cette version de gcc ne respecte pas complètement les normes sur les formats des librairies. Ceci peut conduire à des incompatibilités. Et vous rencontrez une de ces incompatibilités avec libqt.so.2, librairie nécessaire aux applications de Kylix. Pour contourner ce problème, vous devez fournir votre propre version de libqt, en allant la chercher dans $HOME/Kylix2/bin. Et c'est lourd, car votre fichier tar.gz va passer de 800 ko à 3,6 Mo. Plusieurs solutions s'offrent à vous :

  • Vous mettez libqt en téléchargement séparé et vous dites aux utilisateurs des distributions précédentes de se débrouiller ;
  • Vous incluez d'office libqt (pour une diffusion par CD par exemple) ;
  • Vous faites deux versions de votre archive, une avec, l'autre sans libqt.

Nous allons voir en détail la dernière solution. Vous avez donc deux scripts de démarrage :

startcourt.sh (le même qu'avant)
Sélectionnez
#!/bin/sh
ln -s $HOME/MonProg/libqtintf-6.5.0-qt2.3.so $HOME/MonProg/libqtintf-6.5-qt2.3.so
export LD_LIBRARY_PATH=$HOME/MonProg/:$LD_LIBRARY_PATH
$HOME/MonProg//MonProg

Et

startlong.sh
Sélectionnez
#!/bin/sh
ln -s $HOME/MonProg/libqtintf-6.5.0-qt2.3.so $HOME/MonProg/libqtintf-6.5-qt2.3.so
ln -s $HOME/MonProg/libqt.so.2.3.0 $HOME/MonProg/libqt.so.2
export LD_LIBRARY_PATH=$HOME/MonProg/:$LD_LIBRARY_PATH
$HOME/MonProg//MonProg

À quoi on ajoute deux scripts pour la compression, en sélectionnant la bonne version des scripts précédente :

tarcourt.sh
Sélectionnez
#!/bin/sh
cp $HOME/MonProg/startcourt.sh $HOME/MonProg/startMonProg.sh
cd $HOME
tar -czf  MonProg/MonProgCourt.tar.gz MonProg/libqtintf-6.5.0-qt2.3.so MonProg/startMonProg.sh MonProg/MonProg

Et

tarlong.sh
Sélectionnez
#!/bin/sh
cp $HOME/MonProg/startlong.sh $HOME/MonProg/startMonProg.sh
cd $HOME
tar -czf  MonProg/MonProgLong.tar.gz MonProg/libqtintf-6.5.0-qt2.3.so MonProg/startMonProg.sh MonProg/MonProg MonProg/libqt.so.2.3.0

L'exécution de ces deux scripts génère deux fichiers tar.gz que vous n'avez plus qu'à distribuer. Ainsi, les incompatibilités de certaines distributions n'empêchent pas la distribution des applications développées avec Kylix mais alourdissent un peu le travail.

Depuis, j'ai changé de méthode car j'en avais marre de passer des heures à télécharger les mises à jour de mes logiciels sur mon site web avec mon modem à 56K. Je ne fais plus qu'une seule version, la version légère. Mais dans le script de démarrage de la version légère, je mets en commentaire la création du lien symbolique vers libqt :

 
Sélectionnez
#!/bin/sh
ln -s $HOME/MonProg/libqtintf-6.5.0-qt2.3.so $HOME/MonProg/libqtintf-6.5-qt2.3.so
# ln -s $HOME/MonProg/libqt.so.2.3.0 $HOME/MonProg/libqt.so.2
export LD_LIBRARY_PATH=$HOME/MonProg/:$LD_LIBRARY_PATH
$HOME/MonProg//MonProg

Et je mets dans la documentation du logiciel qu'en cas de besoin, il faut aller chercher libqt sur la page correspondante de mon site web et retirer le # du script de démarrage.

V. Problème de langue

J'ai constaté des problèmes avec les caractères accentués. Dans certains cas, l'affichage des textes s'arrêtait au niveau des accents. Après investigation, il s'est avéré que la langue sélectionnée n'était pas le Français. Alors, par sécurité, forcez l'utilisation du Français dans le script de démarrage avec export LANG=fr_FR :

 
Sélectionnez
#!/bin/sh
ln -s $HOME/MonProg/libqtintf-6.5.0-qt2.3.so $HOME/MonProg/libqtintf-6.5-qt2.3.so
export LD_LIBRARY_PATH=$HOME/MonProg/:$LD_LIBRARY_PATH
export LANG=fr_FR
$HOME/MonProg//MonProg

VI. Remarques

Pour la désinstallation, les utilisateurs doivent simplement supprimer le dossier MonProg.

Pour les applications faites avec Kylix 1 et Kylix 3, je n'ai pas fait d'essais. Les librairies libqt et libqtintf n'ont pas tout à fait les mêmes noms ou numéros de version. Il faut adapter les scripts à ces différences.

Je n'ai pas parlé des paquets d'installation (rpm ou deb). Ceux-ci permettent d'automatiser les étapes d'installation/désinstallation. Mais comme ils ne sont pas unifiés, une solution à base de paquets sera moins universelle qu'avec des archives tar.gz.

Ma méthode d'installation tend à multiplier les librairies lorsqu'un utilisateur installe plusieurs applications Kylix. Si ce n'est pas très gênant avec libqtintf, c'est plus lourd avec libqt. Il peut être alors plus judicieux de réunir ces librairies dans un seul dossier commun à toutes les applications (du côté de /usr/local/lib) mais le déploiement s'en trouve compliqué.