web-dev-qa-db-fra.com

quelle est la différence entre ranlib, ar et ld pour créer des bibliothèques

Pour créer des bibliothèques en c ++/unix à partir de fichiers * .o, j'ai remarqué deux façons différentes dans mon projet (code hérité):

ar qc libgraphics.a *.o
ranlib libgraphics.a

et

ld -r -o libgraphics.a *.o

Quelle est la différence entre les deux approches et laquelle doit être utilisée dans quel but?

16
R71

ar

Sous Linux, ar est l'archiveur polyvalent GNU. (Il existe des variantes non GNU de ar dans d'autres Unix- comme les OS). Avec l'option c

ar c... archive-name file...

Il crée une archive contenant des copies de file.... Le archive-name a classiquement mais pas nécessairement l'extension .a (pour archive). Chaque file... peut être n'importe quel type de fichier, pas nécessairement un fichier objet.

Lorsque les fichiers archivés sont tous des fichiers objets, il est généralement prévu d'utiliser l'archive pour fournir cette sélection de fichiers objets dans la liaison de programmes ou DSO (Dynamic Shared Objects). Dans ce cas archive-name sera également conventionnellement donné le préfixe lib, par exemple libfoo.a, afin qu'il puisse être découvert en tant que fichier d'entrée de l'éditeur de liens candidat via l'option de l'éditeur de liens -lfoo.

Utilisé comme fichier d'entrée de l'éditeur de liens, libfoo.a est normalement appelé une bibliothèque statique. Cette utilisation est une source perpétuelle de confusion pour les programmeurs inexpérimentés, car elle les amène à penser qu'une archive libfoo.a est à peu près la même chose qu'un DSO, libfoo.so, normalement appelée une bibliothèque dynamique/partagée, et pour construire de fausses attentes sur cette base. En fait, une "bibliothèque statique" et une "bibliothèque dynamique" ne sont pas du tout des choses similaires et sont utilisées dans la liaison de manières totalement différentes.

Une différence notable est qu'une bibliothèque statique n'est pas produite par le linker, mais par ar. Donc, aucun lien ne se produit, aucune résolution de symbole ne se produit. Les fichiers objets archivés sont inchangés: ils sont juste mis dans un sac.

Lorsqu'une archive est entrée dans le lien de quelque chose qui est produit par l'éditeur de liens - tel qu'un programme ou DSO - l'éditeur de liens regarde dans le sac pour voir s'il y a des fichiers objets dedans qui fournir des définitions pour les références de symboles non résolues qui se sont accumulées plus tôt dans la liaison. S'il en trouve, il extrait ces fichiers objets du sac et lie - dans le fichier de sortie, exactement comme s'ils étaient nommés individuellement dans la ligne de commande de l'éditeur de liens et l'archive non mentionnée du tout. Ainsi, le rôle entier d'une archive dans la liaison est comme un sac de fichiers objets à partir duquel l'éditeur de liens peut sélectionner ceux dont il a besoin pour poursuivre la liaison.

Par défaut, GNU ar rend ses archives de sortie prêtes à être utilisées comme entrées de l'éditeur de liens. Il ajoute un "fichier" bidon à l'archive, avec un nom de fichier bidon magique, et dans ce fichier bidon, il écrit du contenu que l'éditeur de liens est capable de lire comme une table de recherche à partir des symboles globaux qui sont définis par n'importe quel fichier objet dans l'archive jusqu'aux noms et positions de ces fichiers objet dans l'archive. Cette table de recherche est ce qui permet au l'éditeur de liens pour rechercher dans l'archive et identifier les fichiers d'objets qui définissent les références de symboles non résolues qu'il a en main.

Vous pouvez supprimer la création ou la mise à jour de cette table de recherche avec l'option q (= rapide) - que vous avez en fait utilisée dans votre propre ar exemple - et aussi avec l'option (majuscule) S (= pas de table de symboles). Et si vous appelez ar pour créer ou mettre à jour une archive qui n'a pas de table de symboles (à jour) pour une raison quelconque, vous pouvez lui en donner une avec l'option s.

ranlib

ranlib ne crée pas du tout de bibliothèques. Sous Linux, ranlib est un programme hérité qui ajoute une table de symboles (à jour) à une archive ar si elle n'en a pas. Son effet est exactement le même que ar s, avec GNU ar. Historiquement, avant que ar soit équipé pour générer lui-même une table des symboles, ranlib était le kludge qui injectait le fichier bidon magique dans une archive pour permettre à l'éditeur de liens d'en extraire les fichiers objet. Dans les systèmes d'exploitation non GNU Unix, ranlib peut encore être nécessaire à cet effet. Votre exemple:

ar qc libgraphics.a *.o
ranlib libgraphics.a

dit:

  • Créer libgraphics.a en ajoutant à une archive tous les *.o fichiers dans le répertoire courant, sans table de symboles.
  • Ajoutez ensuite une table de symboles à libgraphics.a

Sous Linux, cela a le même effet net que:

ar cr libgraphics.a *.o

Par lui-même, ar qc libgraphics.a *.o, crée une archive que l'éditeur de liens ne peut pas utiliser, car elle n'a pas de table de symboles.

ld

Votre exemple:

ld -r -o libgraphics.a *.o

est en fait assez peu orthodoxe. Ceci illustre l'utilisation assez rare du linker, ld, pour produire un fichier objet fusionné en liant plusieurs fichiers d'entrée en une seule sortie fichier objet, dans lequel la résolution des symboles a été effectuée autant que possible, compte tenu des fichiers d'entrée. Le -r (= relocatable) option oblige l'éditeur de liens à produire une cible de fichier objet (plutôt qu'un programme ou DSO) en reliant les entrées autant que possible et à ne pas échouer linkaqe si des références de symboles non définies restent dans le fichier de sortie. Cette utilisation est appelée liaison partielle.

Le fichier de sortie de ld -r ... est un fichier objet, pas unar archive, et en spécifiant un nom de fichier de sortie qui regarde = comme celui d'une archive ar n'en fait pas un. Votre exemple illustre donc une tromperie. Cette:

ld -r -o graphics.o *.o

serait véridique. Je ne sais pas quel pourrait être le but d'une telle tromperie, car même si un fichier objet ELF est appelé libgraphics.a, et est entré dans une liaison soit par ce nom, soit par -lgraphics, l'éditeur de liens l'identifiera correctement en tant que fichier objet ELF, et non en tant qu'archive ar, et le consommera comme il consomme n'importe quel fichier objet de la ligne de commande: il le relie inconditionnellement au fichier de sortie, tandis que le point d'entrée d'une véritable archive est de lier les membres de l'archive uniquement à condition qu'ils soient référencés. Peut-être avez-vous juste un exemple de lien mal informé ici.

Conclusion ...

Nous avons en fait seulement vu un moyen de produire quelque chose qui est conventionnellement appelé une bibliothèque, et c'est la production d'une soi-disant statique bibliothèque, en archivant certains fichiers objets et en mettant une table de symboles dans l'archive.

Et nous n'avons pas du tout vu comment produire l'autre type de chose le plus important qui est conventionnellement appelé une bibliothèque, à savoir un objet partagé dynamique/bibliothèque partagée/bibliothèque dynamique.

Comme un programme, un DSO est produit par l'éditeur de liens. Un programme et un DSO sont des variantes du binaire ELF que le chargeur du système d'exploitation comprend et peut utiliser pour assembler un processus en cours d'exécution. Habituellement, nous appelons l'éditeur de liens via l'une des interfaces GCC (gcc, g++, gfortran, etc.):

Lier un programme:

gcc -o prog file.o ... -Ldir ... -lfoo ...

Lier un DSO:

gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...

Les bibliothèques partagées et les bibliothèques statiques peuvent être proposées à l'éditeur de liens par l'uniforme -lfoo protocole, lorsque vous liez un autre programme ou DSO. Cette option demande à l'éditeur de liens d'analyser ses répertoires de recherche spécifiés ou par défaut pour trouver soit libfoo.so ou libfoo.a. Par défaut, une fois qu'il a trouvé l'un d'eux, il entrera ce fichier dans la liaison, et s'il trouve les deux dans le même répertoire de recherche, il préférera libfoo.so. Si libfoo.so, est sélectionné, puis l'éditeur de liens ajoute ce DSO à la liste des dépendances d'exécution de n'importe quel programme ou DSO que vous créez. Si libfoo.a est sélectionné, puis l'éditeur de liens utilise l'archive comme sélection de fichiers objets à lier au fichier de sortie, si nécessaire, juste là et ensuite. Aucune dépendance d'exécution sur libfoo.a lui-même est possible; il ne peut pas être mappé dans un processus; cela ne signifie rien pour le chargeur du système d'exploitation.

29
Mike Kinghan