Je lie avec deux bibliothèques partagées différentes. Les deux bibliothèques définissent des symboles qui partagent un nom mais ont des implémentations différentes. Je ne peux pas faire en sorte que chaque bibliothèque utilise sa propre implémentation par rapport à l'autre.
Par exemple, les deux bibliothèques définissent une fonction globale bar()
que chacune appelle en interne. Library one l’appelle depuis foo1()
et la deuxième bibliothèque l’appelle depuis foo2()
.
Lib1.so:
T bar
T foo1() // calls bar()
Lib2.so:
T bar
T foo2() // calls bar()
Si je lie ma demande à Lib1.so puis à Lib2.so, la barre d'implémentation de Lib1.so est appelée même si vous appelez foo2()
. Par contre, si je lie ma demande à Lib2.so puis à Lib1.so, alors bar est toujours appelé depuis Lib2.so.
Existe-t-il un moyen de faire en sorte qu'une bibliothèque préfère toujours sa propre implémentation à toute autre bibliothèque?
Il y a plusieurs façons de résoudre ce problème:
Passez -Bsymbolic
ou -Bsymbolic-functions
à l'éditeur de liens. Cela a un effet global: chaque référence à un symbole global (de type de fonction pour -Bsymbolic-functions
) pouvant être résolue en un symbole de la bibliothèque est résolue en ce symbole. Avec cela, vous perdez la possibilité d'interposer des appels de bibliothèque internes à ces symboles à l'aide de LD_PRELOAD. Les symboles sont toujours exportés, ils peuvent donc être référencés de l'extérieur de la bibliothèque.
Utilisez un script version pour marquer les symboles en tant que local dans la bibliothèque, par exemple. utilisez quelque chose comme: {local: bar;};
et passez --version-script=versionfile
à l'éditeur de liens. Les symboles sont non exportés.
Marquez les symboles avec une visibilité appropriée ( page d’information GCC pour visibilité ), qui sera soit masqué, interne ou protégé . protégés symboles de visibilité sont exportés en tant que .protected
, masqué symboles ne sont pas exportés, et interne symboles sont non exporté et vous vous engagez à ne pas les appeler de l’extérieur de la bibliothèque, même indirectement par le biais de pointeurs de fonction.
Vous pouvez vérifier quels symboles sont exportés avec objdump -T
.
Vous devrez créer deux bibliothèques partagées 'wrapper', une pour chacune de vos bibliothèques existantes. Chacun devrait être construit avec une liste --dynamic-list qui ne répertorie que quelques symboles non conflictuels qui définissent une API. Vous aurez également besoin de -Bsymbolic pour éviter toute combinaison globale.
Il pourrait être moins stressant d’avoir accès aux bibliothèques résultantes via dlopen avec des options appropriées.
Une autre façon de résoudre ce problème consiste à utiliser une macro pour changer d'espace de nom.
Conditions préalables
Solution
-DLibNS=LibNSv1
pour un cas et -DLibNS=LibNSv2
pour l'autre.Lorsque vous utilisez des bibliothèques dans le code, définissez une macro en fonction de votre situation actuelle.
#define LibNS LibNSv1
#include "my_lib.h"
#undef LibNS
Raisons pour lesquelles utiliser ceci à la place d'autres solutions
Problèmes potentiels
#include "my_lib.h"
utilise probablement des macros pour se protéger contre l'inclusion multiple et les indéfinir pour éviter cela pourrait causer beaucoup de problèmes différents (l'auteur de la bibliothèque pourrait changer le nom de la macro à l'avenir, l'en-tête définit d'autres macros, etc.).Remarques