GNU/Linux >> Tutoriels Linux >  >> Linux

Lier libstdc++ de manière statique :des pièges ?

Vous devrez peut-être également vous assurer que vous ne dépendez pas de la glibc dynamique. Exécutez ldd sur votre exécutable résultant et notez toutes les dépendances dynamiques (libc/libm/libpthread sont des suspects habituels).

Un exercice supplémentaire serait de construire un tas d'exemples C++11 impliqués en utilisant cette méthodologie et d'essayer les binaires résultants sur un vrai système 10.04. Dans la plupart des cas, à moins que vous ne fassiez quelque chose de bizarre avec le chargement dynamique, vous saurez tout de suite si le programme fonctionne ou s'il plante.


Ce billet de blog est assez inexact.

Autant que je sache, des modifications de l'ABI C++ ont été introduites avec chaque version majeure de GCC (c'est-à-dire celles avec des composants de premier ou de deuxième numéro de version différents).

Pas vrai. Les seules modifications de l'ABI C++ introduites depuis GCC 3.4 ont été rétrocompatibles, ce qui signifie que l'ABI C++ est stable depuis près de neuf ans.

Pour aggraver les choses, la plupart des principales distributions Linux utilisent des instantanés de GCC et/ou corrigent leurs versions de GCC, ce qui rend pratiquement impossible de savoir exactement à quelles versions de GCC vous pourriez avoir affaire lorsque vous distribuez des binaires.

Les différences entre les versions corrigées des distributions de GCC sont mineures et ne changent pas l'ABI, par ex. Fedora 4.6.3 20120306 (Red Hat 4.6.3-2) est compatible ABI avec les versions amont FSF 4.6.x et presque certainement avec n'importe quelle version 4.6.x de n'importe quelle autre distribution.

Sur les bibliothèques d'exécution de GNU/Linux GCC, utilisez la gestion des versions de symboles ELF, il est donc facile de vérifier les versions de symboles nécessaires aux objets et aux bibliothèques, et si vous avez un libstdc++.so qui fournit ces symboles, cela fonctionnera, peu importe s'il s'agit d'une version corrigée légèrement différente d'une autre version de votre distribution.

mais aucun code C++ (ou tout code utilisant le support d'exécution C++) ne peut être lié dynamiquement si cela doit fonctionner.

Ce n'est pas vrai non plus.

Cela dit, un lien statique vers libstdc++.a est une option pour vous.

La raison pour laquelle cela pourrait ne pas fonctionner si vous chargez dynamiquement une bibliothèque (en utilisant dlopen ) est que les symboles libstdc++ dont il dépend n'ont peut-être pas été nécessaires à votre application lorsque vous l'avez (statiquement) liée, de sorte que ces symboles ne seront pas présents dans votre exécutable. Cela peut être résolu en liant dynamiquement la bibliothèque partagée à libstdc++.so (ce qui est la bonne chose à faire de toute façon si cela en dépend.) L'interposition de symboles ELF signifie que les symboles présents dans votre exécutable seront utilisés par la bibliothèque partagée, mais que d'autres non présents dans votre exécutable seront trouvés dans n'importe quel libstdc++.so il est lié à. Si votre application n'utilise pas dlopen vous n'avez pas besoin de vous en soucier.

Une autre option (et celle que je préfère) consiste à déployer le nouveau libstdc++.so à côté de votre application et assurez-vous qu'elle se trouve avant le système par défaut libstdc++.so , ce qui peut être fait en forçant l'éditeur de liens dynamique à chercher au bon endroit, soit en utilisant $LD_LIBRARY_PATH variable d'environnement au moment de l'exécution, ou en définissant un RPATH dans l'exécutable au moment de la liaison. Je préfère utiliser RPATH car il ne dépend pas de la configuration correcte de l'environnement pour que l'application fonctionne. Si vous liez votre application avec '-Wl,-rpath,$ORIGIN' (notez les guillemets simples pour empêcher le shell d'essayer d'étendre $ORIGIN ) alors l'exécutable aura un RPATH de $ORIGIN qui indique à l'éditeur de liens dynamique de rechercher les bibliothèques partagées dans le même répertoire que l'exécutable lui-même. Si vous mettez le nouveau libstdc++.so dans le même répertoire que l'exécutable, il sera trouvé au moment de l'exécution, problème résolu. (Une autre option est de mettre l'exécutable en /some/path/bin/ et le plus récent libstdc++.so dans /some/path/lib/ et lien avec '-Wl,-rpath,$ORIGIN/../lib' ou tout autre emplacement fixe par rapport à l'exécutable, et définissez le RPATH par rapport à $ORIGIN )


Un ajout à l'excellente réponse de Jonathan Wakely, pourquoi dlopen() est problématique :

En raison du nouveau pool de gestion des exceptions dans GCC 5 (voir PR 64535 et PR 65434), si vous ouvrez et fermez une bibliothèque liée statiquement à libstdc++, vous obtiendrez une fuite de mémoire (de l'objet pool) à chaque fois. Donc, s'il y a une chance que vous utilisiez dlopen, cela semble être une très mauvaise idée de lier statiquement libstdc++. Notez qu'il s'agit d'une véritable fuite par opposition à la bénigne mentionnée dans le PR 65434.


Linux
  1. Appnativefy - Transformez n'importe quel site Web en une seule image d'application exécutable

  2. La liaison statique Linux est morte?

  3. C/C++ avec GCC :ajouter statiquement des fichiers de ressources à l'exécutable/à la bibliothèque

  4. Pourquoi un dossier doit-il être exécutable ?

  5. Comment définir un fichier comme NON exécutable ?

Comment rendre un fichier exécutable sous Linux

Nativefier - Transformez facilement n'importe quel site Web en application de bureau

Existe-t-il une différence entre les fichiers binaires exécutables entre les distributions ?

Intégrer une icône dans un exécutable Linux

iconv tout encodage en UTF-8

Une expérience Java sur Raspberry PI ?