9
votes

Bibliothèques chargées dynamiques et symboles globaux partagés

Étant donné que j'ai observé un comportement étrange de variables globales dans mes bibliothèques chargées de manière dynamique, j'ai écrit le test suivant.

Au début, nous avons besoin d'une bibliothèque liée statique: l'en-tête test.hpp code> p> xxx pré>

et la source test.cpp code> p> xxx pré>

puis j'ai écrit une bibliothèque chargée de manière dynamique: bibliothèque.cpp code> p> xxx pré>

et un programme client chargement de cette bibliothèque: client.cpp code> p> xxx pré>

maintenant je compile la bibliothèque chargée statique avec p> xxx

la bibliothèque chargée dynamiquement p> xxx pré>

et le client p> xxx pré>

maintenant j'observe: le client et La bibliothèque chargée dynamiquement possède une version différente de la variable global_test code>. Mais dans mon projet, j'utilise CMAKE. Le script de construction ressemble à ceci: p> xxx pré>

analyser le fabricant Makefile code> S J'ai trouvé que CMAKE construit le client avec P>

g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client


3 commentaires

Ma première réaction serait de remettre en question la nécessité de cette variable globale.


OK, dans mon programme d'origine, cette variable globale est une constante fournie par une bibliothèque liée statique. Mais néanmoins, il sera désigné deux fois dans la version cmake


Même problème postulerait pour tout modèle singleton, donc je ne vois pas de problème avec le monde


6 Réponses :


1
votes

Ma première question est s'il y a une raison particulière pour laquelle vous êtes à la fois statique et dynamique (via dlopen), liez le même code?

Pour votre problème: -RDynamic exportera les symboles de votre programme et ce qui se passe probablement probablement Est-ce que cette liaison dynamique résout toutes les références à votre variable globale au premier symbole qu'il rencontre dans des tables de symboles. Lequel est que je ne sais pas.

Edit: Compte tenu de votre objectif, je lierais votre programme de cette façon: xxx

Vous devrez peut-être corriger la commande.


5 commentaires

Parmi certaines fonctions, j'ai défini des constantes volumineuses dans la bibliothèque liée statiquement liée. La bibliothèque chargée de manière dynamique est un plugin pour le client à l'aide de ces fonctionnalités fournies par la bibliothèque liée statique.


@phlipsy: La façon dont vous devriez probablement utiliser ces constantes consiste à relier la bibliothèque statique à l'exécutable principal, à lier l'exécutable principal avec -RDynamic (comme cmake le fait) et ne liez pas les plugins avec la bibliothèque statique. Je ne sais cependant pas comment lier votre plugin contre le programme. Vous pouvez essayer de prendre en compte le code commun (bibliothèque statique) à la bibliothèque dynamique et relierez à la fois le programme et le plugin.


Ensuite, au moment de l'exécution, le plugin utilisera les définitions des symboles d'occasion situés dans l'exécutable du client? Est-ce légal?


Désolé, mais le moyen suggéré de lier mon programme ne correspond pas à mes objectifs. La bibliothèque doit être chargée de manière dynamique comme plugin.


Rien ne vous empêche de le faire. Mais vous devez ensuite résoudre tous les symboles des plugins et du programme principal à l'aide de DLSym et vous passez simplement -llibrary à partir de la commande de lien.



2
votes

Si vous utilisez des bibliothèques partagées, vous devez définir les éléments que vous souhaitez exporter avec macro comme ici . Voir DLL_Public Macro Définition là-bas.


1 commentaires

C'est une macro générale. Je travaille à la fois sur GNU / Linux et Windows. Voir le #Ifdef en déclaration.



2
votes

Par défaut, le linker ne combine pas une variable globale (A 'D') dans la base exécutable avec une dans une bibliothèque partagée. L'exécutable de la base est spécial. Il pourrait y avoir un moyen obscur de le faire avec l'un de ces fichiers de contrôle obscur que LD se lit, mais je le doute en quelque sorte.

- Exporter-Dynamic va causer des symboles «D» à la disposition des libs partagés.

Cependant, considérez le processus. Étape 1: Vous créez un DSO d'un .o avec un 'U »et un .a avec un« D ». Donc, la liaison intègre le symbole de l'ODM. Étape 2, vous créez l'exécutable avec un «U» dans l'un des fichiers .O et «D» dans un fichier .A et le DSO. Il essaiera de résoudre en utilisant la règle de gauche à droite.

Variables, par opposition aux fonctions, pose certaines difficultés pour la liaison entre les modules dans tous les cas. Une meilleure pratique consiste à éviter les références globales variables sur les limites du module et utilisez les appels de fonction. Cependant, cela échouerait toujours pour vous si vous mettriez la même fonction à la fois à la fois exécutable de la base et à une lib.


3 commentaires

Vous voulez dire lier le client et la bibliothèque contre libbase.a est une mauvaise idée? OK, vous suggérez de ne pas relier la bibliothèque contre libbase.a car au moment de l'exécution Les symboles du client sont prennent pour les appels de la bibliothèque? Ça marche ... mais est-ce légal?


J'ai édité de simplifier depuis que je ne suis pas tout à fait sûr de votre question que les fichiers se retrouvent là où.


Il y a une bibliothèque communiquement liée statiquement utilisée (appelée libbase.a ), une bibliothèque chargée de manière dynamique (un plug-in) à l'aide de pièces de libbase.a et un client chargeant le plugin et en utilisant parties de libbase.a aussi.



3
votes
g++ -Wall -g -ldl -rdynamic client.cpp libbase.a -o client

0 commentaires

1
votes

Je conseillerais d'utiliser un dlopen (... rtld_lazy | rtld_global); pour fusionner les tables de symboles globales.


1 commentaires

J'ai eu un cas de Segfault lors de la prise d'une exception définie par l'utilisateur de chargé à l'aide de la bibliothèque Dlopen. Utilisation de rtld_global au lieu de RTLD_Local résolu. Merci



0
votes

Je proposerais de compiler n'importe quelle bibliothèque statique que vous envisagez de créer un lien vers une bibliothèque dinamique, avec -fvisibilité = paramètre caché, donc:

g ++ -wall -fvisibilité = caché -g -c base.cpp


2 commentaires

Pouvez-vous expliquer pourquoi?


Je suis désolé, cela faisait longtemps que j'étais impliqué dans ce problème et je ne vois plus le contexte. Cependant, j'apprécie ma suggestion était utile. N'était pas? ;-)