1
votes

Passer `-l ` vs passer `lib .a` directement à l'éditeur de liens?

Supposons que j'ai deux fichiers

// a.c
int a() {return 1;}

// b.c
int a();
int b() {return a();}

et que je les compile en ao et bo , respectivement.

Pour tenter de créer un exécutable ou une bibliothèque partagée, on peut appeler gcc ao bo -o libab.so -shared . Mais j'ai aussi remarqué que l'on peut aussi appeler gcc b.o -L. -l: a.o -o libab.so -shared pour générer (apparemment) la même sortie. À ma grande surprise, même en exécutant gcc a.o -L. -l: b.o -shared donne une bibliothèque qui a à la fois a () et b () . (L'éditeur de liens ne devrait-il pas supprimer la bibliothèque inutilisée bo puisque ao n'en dépend pas?)

Les deux derniers passent probablement un comme si ao était une bibliothèque. Maintenant, si j'exécute ar rcs liba.a a.o , gcc b.o -L. -l: liba.a -shared et gcc bo liba.a -shared fonctionnent tous deux sans aucun problème et donnent le même résultat.

Cependant, j'ai aussi vu le cas où cette astuce ne fonctionne pas et entraîne des références non définies. Ma question est donc comme le disent les titres: quelles sont les différences entre le passage d'un objet en tant que bibliothèque et en tant que fichier objet normal, et y a-t-il des différences en C ++?

Le problème est né dans un projet beaucoup plus vaste. Désolé de manquer de mcve car je n'arrive pas à isoler le problème.


13 commentaires

Je pense qu'il y a là un malentendu. les bibliothèques statiques sont simplement une archive de fichiers .o, il n'est donc pas surprenant que l'éditeur de liens puisse traiter un seul fichier .o comme une bibliothèque. En soi, cela ne devrait pas conduire à un comportement indéfini. J'ai peur que vous deviez travailler davantage pour isoler le cas de test.


@SergeyA, je comprends que .a est une archive de fichiers .o . Pour simplifier, disons simplement que .a est .o , la question est alors en quoi gcc ao bo est-il différent de gcc ao -L . -l: b.o .


C'est exactement ce que je dis, il n'y a pas de réelle différence. De plus, -l: est la syntaxe que je ne connais pas, et je ne la trouve référencée nulle part. Je suppose que cela fonctionne, mais je suis presque sûr que ce n'est pas conventionnel.


renvoie des références non définies - qu'est-ce que cela signifie exactement?


@KamilCuk, cela signifie littéralement référence non définie à par l'éditeur de liens.


"quelles sont les différences entre le passage d'un objet en tant que bibliothèque et en tant que fichier objet normal" exécutez gcc en mode verbeux et vérifiez ce qu'il transmet à l'éditeur de liens sous le capot dans les deux cas et voyez s'il y a des différences


@Slava, j'ai exécuté ld directement et je n'ai vu aucune différence dans certains cas et des échecs dans d'autres cas. Je crois que ce n'est pas une chose gcc , mais je vais essayer.


Si tel est le cas, vous devriez poser des questions sur ld et non sur gcc ou g ++


Vous savez que l'ordre des bibliothèques est important dans l'invocation de l'éditeur de liens? Peut-être que cela pourrait être une réponse? L'ordre des symboles n'a pas d'importance lors de l'utilisation de fichiers .o, alors que pour les fichiers .so, c'est important?


@KamilCuk, je le fais, alors vous dites que seul l'ordre importe, pas comment il est transmis?


C'est comme connecté? L'ordre est important car les fichiers .so sont transmis à l'aide du commutateur -l .


@KamilCuk, je suppose que c'est pourquoi, du moins très probablement. Lors du passage de .o directement, les objets étaient avant les bibliothèques externes, tandis que lors de l'utilisation de -l , ils ont été ajoutés à la fin, et mes expériences brutes peuvent le confirmer. Pouvez-vous préciser la différence d'ordre entre .o et .so ?


Mais si vous spécifiez les fichiers .a avec le commutateur -l , ce sera la même chose, il n'y a pas de différence.


3 Réponses :


1
votes

[Comment] Passer -l vs [diffère de] transmettre lib .a directement à l'éditeur de liens?

Passer -llibname.so fera que l'éditeur de liens GNU traversera la bibliothèque une seule fois lors de la recherche d'un symbole (si ce n'est pas après l'option --whole-archive ). Spécifier le fichier .a directement dans l'éditeur de liens le fait rechercher chaque symbole dans tous les fichiers objets du fichier .a pour chaque symbole, pas seulement une fois.

À partir des options GCC Linker (c'est moi qui souligne): < / p>

-llibrary

...

Cela fait une différence où dans la commande vous écrivez cette option; l'éditeur de liens recherche et traite les bibliothèques et les fichiers objets dans l'ordre dans lequel ils sont spécifiés. Ainsi, «foo.o -lz bar.o» recherche dans la bibliothèque «z» après le fichier foo.o mais avant bar.o. Si bar.o fait référence à des fonctions dans «z», ces fonctions peuvent ne pas être chargées.

À partir des options binutils ld :

-l namespec

...

L'éditeur de liens ne recherchera une archive qu'une seule fois, à l'emplacement où il est spécifié sur la ligne de commande. Si l'archive définit un symbole qui n'a pas été défini dans un objet apparaissant avant l'archive sur la ligne de commande, l'éditeur de liens inclura le (s) fichier (s) approprié (s) de l'archive. Cependant, un symbole non défini dans un objet apparaissant plus tard sur la ligne de commande ne fera pas que l'éditeur de liens recherchera à nouveau l'archive.


1 commentaires

Passer -llibname.so fera que l'éditeur de liens GNU traversera la bibliothèque une seule fois ... Spécifier un fichier .a directement à l'éditeur de liens le fera rechercher tous les symboles dans tous les fichiers objets dans le fichier .a . Je ne vois pas la distinction, et en fait je ne pense pas qu'il y ait une distinction - j'ai toujours cru que spécifier -lx par rapport à (disons) < code> /lib/libx.a s'est comporté de la même manière.



1
votes

Quelles sont les différences entre le passage d'un objet en tant que bibliothèque et en tant que fichier objet normal, et y a-t-il des différences en matière de C ++?

Cela dépend de l'implémentation. Au sens le plus général, les éditeurs de liens de style Unix tels que vous demandez recherchent des objets nommés via les options -l dans un chemin de recherche de bibliothèque, alors que si vous nommez un fichier directement, vous devez spécifier le fichier exact.

De plus, si vous utilisez une option -l pour spécifier un fichier à lier, alors, dans le cas général, l'éditeur de liens construit un nom de fichier à partir de l'argument en ajoutant «lib» au début et en ajoutant «.a ", ou d'une autre manière, comme en recherchant également ou à la place des fichiers" .so ". (L'éditeur de liens GNU que vous semblez utiliser fournit une exception à ce comportement lorsque le premier caractère de l'argument est : . Dans ce cas, il prend le reste de l'argument comme nom de fichier exact, et recherche cela.)

De nombreux éditeurs de liens acceptent également les noms de bibliothèques explicites spécifiés sur la ligne de commande (par exemple libfoo.a au lieu de -lfoo ), ils doivent donc être en mesure de déterminer quel type de fichier chacun est. Normalement, c'est en examinant le fichier, pas en se fiant à son nom. Et GNU ld , au moins, étend cette détection de type de fichier aux fichiers spécifiés via les options -l .

L'ordre dans lequel les objets et les bibliothèques sont spécifiés sur la ligne de commande, quelle que soit la forme spécifique, est important pour les implémentations typiques de l'éditeur de liens. Par exemple, la documentation pour GNU ld spécifie que

les options qui font référence à des fichiers, telles que «-l» ou «-T», font que le fichier être lu au point où l'option apparaît dans la ligne de commande, par rapport aux fichiers objets et autres options de fichiers

ce qui est important car

L'éditeur de liens ne recherchera une archive qu'une seule fois, à l'emplacement où est spécifié sur la ligne de commande. Si l'archive définit un symbole qui n'était pas défini dans un objet apparaissant avant l'archive sur la ligne de commande, l'éditeur de liens inclura le (s) fichier (s) approprié (s) à partir des archives. Cependant, un symbole non défini dans un objet apparaissant plus tard sur la ligne de commande, l'éditeur de liens ne recherchera pas archiver à nouveau.

Mais bien sûr

Vous pouvez lister la même archive plusieurs fois sur la ligne de commande.

La documentation n'est pas tout à fait claire à ce sujet, mais empiriquement, l'utilisation du terme "archive" dans ce qui précède est significative. Il ne s'agit en fait que de fichiers archives - bibliothèques statiques - auxquels s'applique la disposition "recherché une seule fois". En première approximation, l'ordre relatif des différents fichiers d'objets ordinaires et des bibliothèques partagées sur la ligne de commande de l'éditeur de liens GNU, quelle que soit leur désignation, n'a pas d'impact sur la résolution des symboles.

Alors oui, peu importe que vous spécifiiez des fichiers objets normaux ou des archives statiques ou des bibliothèques partagées dans l'éditeur de liens (GNU), et leur ordre compte dans une certaine mesure, mais la manière dans laquelle vous spécifiez peu importe.

J'ai également vu des cas où cette astuce ne fonctionne pas et entraîne des références non définies.

Avec l'éditeur de liens GNU, ce sera à cause de bibliothèques ou d'objets réellement manquants, ou à cause d'un ordre inadapté des archives statiques par rapport à d'autres fichiers objets ou archives. Certains autres linkers sont plus sensibles.


0 commentaires

0
votes

Réponses courtes:

  1. Les options -L et -l fournissent un raccourci pour localiser les archives de la bibliothèque (et les bibliothèques partagées). Mais une fois que vous avez utilisé -l pour localiser une bibliothèque (dans les emplacements standard, ou dans un emplacement spécifié par -L ), la lecture de cette bibliothèque est identique à la façon dont il serait lu si vous spécifiiez son nom de fichier (par exemple /lib/libx.a ) au même endroit sur la ligne de commande de manière explicite.

  2. Lorsque vous spécifiez un seul fichier objet ( .o ), tout le contenu de ce fichier est chargé sans condition. Lorsque vous spécifiez un fichier d'archive de bibliothèque ( .a ), seuls les objets qu'il contient qui sont nécessaires (pour satisfaire les références non définies exceptionnelles) sont chargés.


0 commentaires