Création de bibliothèques partagées
Les sections suivantes énumèrent certains éléments à prendre en compte lors de la création de bibliothèques partagées.
Utilisation de symboles provenant de bibliothèques partagées
Les symboles - fonctions, variables ou classes - contenus dans les bibliothèques partagées destinées à être utilisées par des clients, tels que des applications ou d'autres bibliothèques, doivent être marqués d'une manière spéciale. Ces symboles sont appelés symboles publics et sont exportés ou rendus publiquement visibles.
Les autres symboles ne doivent pas être visibles de l'extérieur. Sur la plupart des plateformes, les compilateurs les masquent par défaut. Sur certaines plateformes, une option spéciale du compilateur est nécessaire pour masquer ces symboles.
Lors de la compilation d'une bibliothèque partagée, celle-ci doit être marquée pour l'exportation. Pour utiliser la bibliothèque partagée à partir d'un client, certaines plates-formes peuvent exiger une déclaration d'importation spéciale.
En fonction de votre plateforme cible, Qt fournit des macros spéciales qui contiennent les définitions nécessaires :
- Q_DECL_EXPORT doit être ajoutée aux déclarations des symboles utilisés lors de la compilation d'une bibliothèque partagée.
- Q_DECL_IMPORT doit être ajoutée aux déclarations de symboles utilisées lors de la compilation d'un client qui utilise la bibliothèque partagée.
Maintenant, nous devons nous assurer que la bonne macro est invoquée - que nous compilions une bibliothèque partagée elle-même, ou seulement le client qui utilise la bibliothèque partagée. Généralement, cela peut être résolu en ajoutant un en-tête spécial.
Supposons que nous voulions créer une bibliothèque partagée appelée mysharedlib. Un en-tête spécial pour cette bibliothèque, mysharedlib_global.h, ressemble à ceci :
#include <QtCore/QtGlobal> #if defined(MYSHAREDLIB_LIBRARY) # define MYSHAREDLIB_EXPORT Q_DECL_EXPORT #else # define MYSHAREDLIB_EXPORT Q_DECL_IMPORT #endif
Dans chaque en-tête de la bibliothèque, nous spécifions ce qui suit :
#include "mysharedlib_global.h" MYSHAREDLIB_EXPORT void foo(); class MYSHAREDLIB_EXPORT MyClass...
Nous devons ensuite nous assurer que MYSHAREDLIB_LIBRARY est défini pour le compilateur lors de la construction de la bibliothèque elle-même. Cela se fait dans le système de construction de la bibliothèque. Si nous utilisons CMake, nous augmentons la cible de la bibliothèque partagée :
target_compile_definitions(mysharedlib PRIVATE MYSHAREDLIB_LIBRARY)
Si nous utilisons qmake, nous ajoutons
DEFINES += MYSHAREDLIB_LIBRARY
au fichier .pro de la bibliothèque partagée.
Note : Les assistants de bibliothèque dans Qt Creator et Qt VS Tools vous fournissent un squelette qui met en place ces éléments pour vous.
Considérations sur le fichier d'en-tête
En règle générale, les clients n'incluent que les fichiers d'en-tête publics des bibliothèques partagées. Ces bibliothèques peuvent être installées à un autre endroit lors du déploiement. Il est donc important d'exclure les autres fichiers d'en-tête internes qui ont été utilisés lors de la construction de la bibliothèque partagée.
Par exemple, la bibliothèque peut fournir une classe qui englobe un périphérique matériel et contient une poignée vers ce périphérique, fournie par une bibliothèque tierce :
#include <footronics/device.h> class MyDevice { private: FOOTRONICS_DEVICE_HANDLE handle; };
Une situation similaire se produit avec les formulaires créés par Qt Widgets Designer lors de l'utilisation de l'agrégation ou de l'héritage multiple :
#include "ui_widget.h" class MyWidget : public QWidget { private: Ui::MyWidget m_ui; };
Lors du déploiement de la bibliothèque, il ne doit pas y avoir de dépendance vis-à-vis des en-têtes internes footronics/device.h ou ui_widget.h.
Ce problème peut être évité en utilisant l'idiome " Pointer to implementation" décrit dans plusieurs livres de programmation C++. Pour les classes ayant une sémantique de valeur, envisagez d'utiliser QSharedDataPointer.
Compatibilité binaire
Pour que les clients qui chargent une bibliothèque partagée fonctionnent correctement, l'agencement de la mémoire des classes utilisées doit correspondre exactement à l'agencement de la mémoire de la version de la bibliothèque utilisée pour compiler le client. En d'autres termes, la bibliothèque trouvée par le client au moment de l'exécution doit être binairement compatible avec la version utilisée au moment de la compilation.
Cela ne pose généralement pas de problème si le client est un logiciel autonome qui fournit toutes les bibliothèques dont il a besoin.
Toutefois, si l'application cliente s'appuie sur une bibliothèque partagée qui appartient à un autre paquetage d'installation ou au système d'exploitation, nous devons alors réfléchir à un système de versions pour les bibliothèques partagées et décider à quel niveau la compatibilité binaire doit être maintenue. Par exemple, les bibliothèques Qt ayant le même numéro de version majeure sont garanties comme étant binairement compatibles.
Le maintien de la compatibilité binaire impose certaines restrictions sur les modifications que vous pouvez apporter aux classes. Une bonne explication peut être trouvée à KDE - Policies/Binary Compatibility Issues With C++. Ces questions doivent être prises en compte dès le début de la conception de la bibliothèque. Nous recommandons d'utiliser le principe de la dissimulation d'informations et la technique du pointeur vers l'implémentation dans la mesure du possible.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.