Enroulant les différentes versions de bibliothèque statique dans les bibliothèques dynamiques

StackOverflow https://stackoverflow.com/questions/2801666

  •  25-09-2019
  •  | 
  •  

Question

Dans mon projet, il y a une dépendance à une bibliothèque statique (juste appelé libsomething à partir de maintenant) d'une 3ème partie. Récemment, libsomething est devenu disponible dans une autre version. Ma tâche est de fournir mon logiciel avec le soutien de l'ancien et la nouvelle version. Une seule version de libsomething est utilisé lors de l'exécution à un moment donné, mais la version est ce devrait être configurable entre les cycles de programme.

J'utilise MSVC2005 sur Windows XP, un objectif secondaire est de devenir prêt à passer à Linux et GCC.

Comme les deux versions de libsomething utilisent les mêmes symboles, en les reliant à la fois dans mon exécutable est hors de question que les symboles des deux versions vont entrer en conflit partout au lien en temps.

Alors que je pourrais créer deux executables (une liaison contre l'ancienne version, l'autre en utilisant la nouvelle version), je ne peux pas mettre en œuvre une décision sur l'exécutable pour appeler dans l'environnement de déploiement final (raisons historiques).

Je suis venu avec l'idée de créer une enveloppe de bibliothèque dynamique pour chaque version de libsomething et de les relier à l'exécution en fonction de certains fichiers de configuration. Avec MSCV, cela signifierait aller sur la route de l'utilisation LoadLibrary(), GetProcAddress(), etc., tandis que sur Linux, je dois utiliser dlopen() et dlsym().

Je crois que l'utilisation de libtool (à savoir, libtldl) tire à cette plate-forme de dépendance à l'aide de bibliothèques partagées. Est-ce un chemin approprié? Y at-il une meilleure (ou, au moins, différentes) façons? Est-ce que des solutions de rechange pour libtldl existent open source?

Était-ce utile?

La solution

Il a été quelques années maintenant, mais je voudrais mentionner une autre solution pour l'exhaustivité. Au lieu de dlopen et dlsym manuel, vous pouvez générer des talons simples pour toutes les fonctions nécessaires et au premier appel (ou au démarrage du programme) décider quelle version de la bibliothèque est nécessaire, le charger et de résoudre les adresses.

Vous pouvez écrire un script spécialement adapté pour votre projet ou utiliser l'outil Implib.so :

# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so

Implib.so est Linux uniquement atm, mais devrait être facilement adaptable à Windows.

Autres conseils

Je sais que vous avez dit que vous ne pouviez pas utiliser deux executables en raison de la décision dont l'exécution, mais ne pourrais pas vous exec et-vient entre executables selon la version est sélectionnée lors de la configuration?

Sur Linux, il serait plus facile pour vous de créer un lien vers la bibliothèque partagée et utiliser des liens symboliques pour corriger la version -. OMI, il est beaucoup plus facile que d'utiliser dlopen() + dlsym()

Ainsi, vous devez créer des bibliothèques partagées pour les anciennes et les nouvelles versions de votre bibliothèque:

g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive

et

g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive

Créer des liens symboliques:

ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so

Générez votre application, reliant à l'ancienne version de la bibliothèque. Je suppose que les deux versions sont binaires compatibles (ABI pas cassé), mais la nouvelle pourrait avoir des nouveaux symboles.

g++ -o myapp myapp.cpp -L. -lshared

Depuis la SONAME de bibliothèque partagée est libshared.so.1 votre application dépendra et cherchera libshared.so.1 dans les chemins de /etc/ld.so.conf ou LD_LIBRARY_PATH

Avant d'exécuter votre application, vous pouvez définir le lien symbolique libshared.so.1 pour pointer vers libshared.so.1.2 ou libshared.so.1.1.


Peu d'informations sur les options de l'éditeur de liens utilisés ici:

  

- l'archive complète
             Pour chaque archive mentionnée sur la ligne de commande après l'option --whole-archive, inclure tous les fichiers d'objets dans l'archive dans le              lien, plutôt que de chercher l'archive pour les fichiers objets nécessaires. Ceci est normalement utilisé pour transformer un fichier d'archive en commun              bibliothèque, ce qui oblige tous les objets à inclure dans la résultante bibliothèque partagée. Cette option peut être utilisée plus d'une fois.   
             Deux notes lors de l'utilisation de cette option de gcc: Tout d'abord, gcc ne connaît pas cette option, vous devez utiliser -Wl, -whole-archives.              Deuxièmement, ne pas oublier d'utiliser -Wl, -no-entier archives après votre liste d'archives, car gcc ajoutera sa propre liste d'archives à votre              lien et vous ne voulez pas ce drapeau pour affecter ceux aussi bien.

     

-soname = nom
             Lors de la création d'un objet ELF partagé, définir le champ DT_SONAME interne au nom spécifié. Quand un exécutable est lié à un              objet partagé qui a un champ de DT_SONAME, puis lorsque l'exécutable est exécuté l'éditeur de liens dynamique va tenter de charger l'objet partagé              spécifié par le champ DT_SONAME plutôt que l'utilisation du nom de fichier donné à l'éditeur de liens.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top