Une bibliothèque statique (.a) est une bibliothèque qui peut être directement liée à l'exécutable final produit par l'éditeur de liens, elle y est contenue et il n'est pas nécessaire d'avoir la bibliothèque dans le système où l'exécutable sera déployé.
Une bibliothèque partagée (.so) est une bibliothèque qui est liée mais non intégrée dans l'exécutable final, elle sera donc chargée lorsque l'exécutable est lancé et doit être présente dans le système où l'exécutable est déployé.
Une bibliothèque de liens dynamiques sur windows (.dll) est comme une bibliothèque partagée (.so) sous linux mais il y a quelques différences entre les deux implémentations qui sont liées au système d'exploitation (Windows vs Linux) :
Une DLL peut définir deux types de fonctions :exportées et internes. Les fonctions exportées sont destinées à être appelées par d'autres modules, ainsi que depuis la DLL où elles sont définies. Les fonctions internes sont généralement destinées à être appelées uniquement à partir de la DLL où elles sont définies.
Un SO la bibliothèque sous Linux n'a pas besoin d'instruction d'exportation spéciale pour indiquer les symboles exportables, puisque tous les symboles sont disponibles pour un processus d'interrogation.
J'ai toujours pensé que les DLL et les objets partagés sont simplement des termes différents pour la même chose - Windows les appelle des DLL, alors que sur les systèmes UNIX, ce sont des objets partagés, avec le terme général - bibliothèque liée dynamiquement - couvrant les deux (même la fonction de ouvrir un .so sous UNIX s'appelle dlopen()
après 'bibliothèque dynamique').
Ils ne sont en effet liés qu'au démarrage de l'application, cependant votre notion de vérification par rapport au fichier d'en-tête est incorrecte. Le fichier d'en-tête définit les prototypes nécessaires pour compiler le code qui utilise la bibliothèque, mais au moment de la liaison, l'éditeur de liens regarde à l'intérieur de la bibliothèque elle-même pour s'assurer que les fonctions dont il a besoin sont bien là. L'éditeur de liens doit trouver les corps de fonction quelque part au moment de la liaison, sinon il générera une erreur. Il le fait AUSSI au moment de l'exécution, car comme vous le soulignez à juste titre, la bibliothèque elle-même peut avoir changé depuis la compilation du programme. C'est pourquoi la stabilité de l'ABI est si importante dans les bibliothèques de plate-forme, car le changement d'ABI est ce qui casse les programmes existants compilés avec des versions plus anciennes.
Les bibliothèques statiques ne sont que des ensembles de fichiers objets directement sortis du compilateur, tout comme ceux que vous construisez vous-même dans le cadre de la compilation de votre projet, ils sont donc extraits et transmis à l'éditeur de liens exactement de la même manière, et les bits inutilisés sont chuté exactement de la même manière.
Je peux élaborer sur les détails des DLL dans Windows pour aider à clarifier ces mystères à mes amis ici au *NIX-land...
Une DLL est comme un fichier d'objet partagé. Les deux sont des images, prêtes à être chargées en mémoire par le chargeur de programme du système d'exploitation respectif. Les images sont accompagnées de diverses métadonnées pour aider les éditeurs de liens et les chargeurs à faire les associations nécessaires et à utiliser la bibliothèque de code.
Les DLL Windows ont une table d'exportation. Les exportations peuvent être par nom ou par position dans la table (numérique). Cette dernière méthode est considérée comme "à l'ancienne" et est beaucoup plus fragile - reconstruire la DLL et changer la position d'une fonction dans la table se terminera par un désastre, alors qu'il n'y a pas vraiment de problème si la liaison des points d'entrée se fait par leur nom. Donc, oubliez cela comme un problème, mais sachez qu'il existe si vous travaillez avec du code "dinosaure" tel que des bibliothèques de fournisseurs tiers.
Les DLL Windows sont construites par compilation et liaison, comme vous le feriez pour un EXE (application exécutable), mais la DLL n'est pas censée être autonome, tout comme un SO est destiné à être utilisé par une application, soit via un chargement dynamique, soit par liaison au moment de la liaison (la référence au SO est intégrée dans les métadonnées du binaire de l'application et le chargeur de programme du système d'exploitation chargera automatiquement les SO référencés). Les DLL peuvent référencer d'autres DLL, tout comme les SO peuvent référencer d'autres SO.
Sous Windows, les DLL ne mettront à disposition que des points d'entrée spécifiques. Celles-ci sont appelées "exportations". Le développeur peut soit utiliser un mot-clé spécial du compilateur pour rendre un symbole visible de l'extérieur (pour d'autres éditeurs de liens et le chargeur dynamique), soit les exportations peuvent être répertoriées dans un fichier de définition de module qui est utilisé au moment de la liaison lorsque la DLL elle-même est Étant créé. La pratique moderne consiste à décorer la définition de la fonction avec le mot-clé pour exporter le nom du symbole. Il est également possible de créer des fichiers d'en-tête avec des mots clés qui déclareront ce symbole comme étant à importer depuis une DLL en dehors de l'unité de compilation courante. Recherchez les mots-clés __declspec(dllexport) et __declspec(dllimport) pour plus d'informations.
L'une des caractéristiques intéressantes des DLL est qu'elles peuvent déclarer une fonction de gestionnaire standard "lors du chargement/déchargement". Chaque fois que la DLL est chargée ou déchargée, la DLL peut effectuer une initialisation ou un nettoyage, selon le cas. Cela correspond bien à une DLL en tant que gestionnaire de ressources orienté objet, tel qu'un pilote de périphérique ou une interface d'objet partagé.
Lorsqu'un développeur souhaite utiliser une DLL déjà construite, il doit soit référencer une "bibliothèque d'exportation" (*.LIB) créée par le développeur de la DLL lors de la création de la DLL, soit charger explicitement la DLL au moment de l'exécution et demander la adresse du point d'entrée par nom via les mécanismes LoadLibrary() et GetProcAddress(). La plupart du temps, la liaison avec un fichier LIB (qui contient simplement les métadonnées de l'éditeur de liens pour les points d'entrée exportés de la DLL) est la façon dont les DLL sont utilisées. Le chargement dynamique est généralement réservé à l'implémentation du "polymorphisme" ou de la "configurabilité d'exécution" dans les comportements du programme (accès aux modules complémentaires ou à des fonctionnalités définies ultérieurement, alias "plugins").
La façon de faire de Windows peut parfois prêter à confusion; le système utilise l'extension .LIB pour faire référence à la fois aux bibliothèques statiques normales (archives, comme les fichiers POSIX *.a) et aux bibliothèques "stub d'exportation" nécessaires pour lier une application à une DLL au moment de la liaison. Ainsi, il faut toujours regarder pour voir si un fichier *.LIB a un fichier *.DLL du même nom; sinon, il y a de fortes chances que le fichier *.LIB soit une archive de bibliothèque statique et qu'il n'exporte pas les métadonnées de liaison pour une DLL.