OVH Cloud OVH Cloud

Liaison statique ou dynamique

21 réponses
Avatar
Lucas Levrel
Bonjour,

Je cross-poste sans FU2 car je ne sais pas quel est le groupe le plus
adapté, et la réponse peut même varier selon l'OS, alors je vous laisse
voir...

J'écris un programme en C++ avec une interface en GTK+ (mais mes questions
sont plus générales). Sous Windows, GTK+ est livré avec des .def, .lib,
.dll.a, et .dll (chaque bibli a un ou plusieurs fichiers avec ces
extensions). Sous Linux j'ai des .so et .la pour certaines biblis,
seulement des .so pour d'autres.

Je compile avec GCC (dans MinGW sous Windows). Je voudrais obtenir un
exécutable qui se suffise à lui-même, c'est-à-dire utilisable sans
installer GTK+ au préalable (donc distribuable sans redistribuer GTK+ à
côté). Je croyais l'obtenir en passant l'option -static à GCC, d'ailleurs
le fichier produit est beaucoup plus gros avec cette option que sans. Mais
patatras : sous Win, si je tente de lancer l'exécutable « statique » sur
une machine n'ayant pas GTK+, j'obtiens une erreur « ne trouve pas
libmachin.dll » ; sous Linux, n'ayant pas de machine sans GTK+ à dispo, je
n'ai pas pu tester (y a-t-il moyen de « cacher » les biblis installées le
temps d'un test ?).

Mes questions sont donc :
- peut-on produire un exécutable qui se suffise à lui-même, et avec
quelles options de compilation ?
- si oui, quels sont les ingrédients nécessaires en termes de
bibliothèques (quel format de fichier) ?
- à défaut, peut-on « dégraisser » des bibliothèques dynamiques pour n'en
garder que les fonctions réellement utilisées par l'application ? (L'idée
étant d'alléger au maximum le paquet exécutable+biblis à distribuer.)

Merci pour votre aide et vos explications.

--
LL

10 réponses

1 2 3
Avatar
Lucas Levrel
Le 8 mars 2012, Tonton Th a écrit :

exe_statique : main.o blabla.o
g++ -o $@ $^ $(shell pkg-config --libs gtk+-2.0) -mwin32 -static



Et en mettant le -static avant le pkg_config ?



Erreur de ma part. C'est bien ce que j'ai fait dans mon dernier essai :
g++ -o $@ $^ -static $(shell pkg-config --libs gtk+-2.0) -mwin32

--
LL
Avatar
Lucas Levrel
Le 8 mars 2012, JKB a écrit :

Le .la est un fichier texte qui est compris par libtool. Il contient
entre autre l'adresse de la bibliothèque .a et ses dépendances.



---
cat /usr/lib64/libgtk-x11-2.0.la


(...)
# Names of this library.
library_names='libgtk-x11-2.0.so.0.1800.6 libgtk-x11-2.0.so.0
libgtk-x11-2.0.so'

# The name of the static archive.
old_library=''
(...)
---

Mauvais signe, non ?

Comment appeler directement le linker (plutôt que g++) et lui demander
d'être bavard ?



Avec la commande ld, mais il ne faut pas se louper dans les modèles
de mémoire.



C'est tout l'objet de mon « Comment » ;-)

Normalement. Mais il ne faut pas oublier que la gestion des
bibliothèques est un truc particulièrement foireux sous Windows. Il
faudrait que tu regardes avec l'équivalent de nm si les symboles
soi-disant manquant sont dans l'exécutable ou non. Ce serait déjà un
bon début.



MinGW fournit nm. Qu'est-ce qu'un symbole ?

L'erreur que j'obtiens au lancement d'exe_statique est du style « Il est
impossible de trouver libtruc.dll. » sans plus de détails. Bien sûr
libtruc.dll est dans la ligne de compilation. Ah mais tiens, il faudrait
peut-être que je passe --static à pkg-config :-D J'essaierai ce soir.

--
LL
Avatar
Lucas Levrel
Le 8 mars 2012, Fred a écrit :

Les DLL de GTK+ doivent obligatoirement etre présentes si des fonctions de
ces DLL sont utilisées statiquement



Qu'appelles-tu « utiliser statiquement une fonction d'une DLL » ?

(sous Windows, on n'a pas besoin de lib pour les
interfaces, totu est dans l'api)



Je suppose que l'API est quand même implémentée dans des bibliothèques,
non ?

mais si les DLL ne sont pas trop grosses ou trop nombreuses, on peut à
la rigueur les mettre en resources et les extraire au premier lancement.



Ça permet de fusionner les DLL dans l'exécutable ? Comment faire en
pratique ?

Merci.
--
LL
Avatar
JKB
Le Thu, 8 Mar 2012 15:44:18 +0100,
Lucas Levrel écrivait :
Le 8 mars 2012, JKB a écrit :

Le .la est un fichier texte qui est compris par libtool. Il contient
entre autre l'adresse de la bibliothèque .a et ses dépendances.



---
cat /usr/lib64/libgtk-x11-2.0.la


(...)
# Names of this library.
library_names='libgtk-x11-2.0.so.0.1800.6 libgtk-x11-2.0.so.0
libgtk-x11-2.0.so'

# The name of the static archive.
old_library=''
(...)
---

Mauvais signe, non ?



Je n'avais encore jamais vu un truandage pareil ;-)

Comment appeler directement le linker (plutôt que g++) et lui demander
d'être bavard ?



Avec la commande ld, mais il ne faut pas se louper dans les modèles
de mémoire.



C'est tout l'objet de mon « Comment » ;-)

Normalement. Mais il ne faut pas oublier que la gestion des
bibliothèques est un truc particulièrement foireux sous Windows. Il
faudrait que tu regardes avec l'équivalent de nm si les symboles
soi-disant manquant sont dans l'exécutable ou non. Ce serait déjà un
bon début.



MinGW fournit nm. Qu'est-ce qu'un symbole ?



nm $exec renvoie la liste des symboles si l'exécutable n'est pas
'strippé' ainsi que l'état. Si cet état est t ou T, le symbole et sa
déclaration est dans l'exécutable. Si cet état est 'U', il est
'unresolved' et doit être trouvé par ld lors du chargement en
mémoire (la plupart du temps dans une bibliothèque dynamique).

L'erreur que j'obtiens au lancement d'exe_statique est du style « Il est
impossible de trouver libtruc.dll. » sans plus de détails. Bien sûr
libtruc.dll est dans la ligne de compilation. Ah mais tiens, il faudrait
peut-être que je passe --static à pkg-config :-D J'essaierai ce soir.



JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Olivier Miakinen
Le 08/03/2012 13:06, JKB répondait à Lucas Levrel :

Je cross-poste sans FU2 car je ne sais pas quel est le groupe le plus
adapté





Ce faisant, Lucas, tu te coupes de tous tes lecteurs potentiels passant
par des serveurs tels que ceux de Free, de GalacSys, de Neottia, et
sûrement un certain nombres d'autres. Sur ces serveurs, les articles
diapubliés sur au moins trois groupes n'apparaissent pas s'il n'y a
pas un suivi de positionné.

Cordialement,
--
Olivier Miakinen
Avatar
torri
On Thu, 08 Mar 2012 13:01:49 +0100, Lucas Levrel wrote:


- peut-on produire un exécutable qui se suffise à lui-même, et avec
quelles options de compilation ?



Il faut lier statiquement les bibliothèques à ton programme. Si tu
utilises libtool (et donc les autotools), passes -all-static au LDFLAGS
de ton prog dans le Makefile.am correspondant. Regarde :

http://sourceware.org/autobook/autobook/autobook_89.html

- si oui, quels sont les ingrédients nécessaires en termes de
bibliothèques (quel format de fichier) ?

il faut les bibliothèques statiques (les .lib)

- à défaut, peut-on « dégraisser » des bibliothèques dynamiques pour n'en
garder que les fonctions réellement utilisées par l'application ? (L'idée
étant d'alléger au maximum le paquet exécutable+biblis à distribuer.)

Tu peux compiler ton programme avec l'option -Os pour diminuer la taille
des exécutable, au détriment des performances

si tu ne veux pas de symboles de debug, link ton programme avec -s (ou -
Wl,-s)

si tu as gcc >= 4.7, tu peux passer -lto (regarde la doc de gcc) pour la
compilation de ton programme, ça aidera un chouia pour la taille et les
performances.

tu peux essayer d'utiliser l'utilitaire strip sur les dll et les .lib de
gtk et de ses dépendances.

Au passage, je te recommande fortement MinGW-w64 pour le compilateur.
C'est utilisable avec MSYS, ou bien en cross compilation sous linux (je
fais les 2), et c'est largement mieux maintenu que MinGW.
Et tu peux avoir accès au dernier compilateur (gcc 4.7 sortira fin mars,
et début avril, tu auras son archive sur le site de MinGW-w64, mais tu
peux déjà l'utiliser)
Avatar
Tonton Th
On 03/08/2012 09:37 PM, Olivier Miakinen wrote:

Je cross-poste sans FU2 car je ne sais pas quel est le groupe le plus
adapté





Ce faisant, Lucas, tu te coupes de tous tes lecteurs potentiels passant
par des serveurs tels que ceux de Free, de GalacSys, de Neottia, et
sûrement un certain nombres d'autres. Sur ces serveurs, les articles
diapubliés sur au moins trois groupes n'apparaissent pas s'il n'y a
pas un suivi de positionné.



(foutou distribution)

Cette valeur de 3 vient-elle d'une RFC, d'une estimation à
la louche, ou d'un consensus entre les serveurs dont tu
parles ?

--

Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Avatar
Antoine Leca
[ Ici fclc! fu2 positionné ]

Lucas Levrel écrivit :
Je compile avec GCC (dans MinGW sous Windows). Je voudrais obtenir un
exécutable qui se suffise à lui-même,



Liaison statique.

Mais patatras : sous Win, si je tente de lancer l'exécutable
« statique » sur une machine n'ayant pas GTK+, j'obtiens une erreur « ne
trouve pas libmachin.dll »



Cause la plus probable ÀMHA : tu as lié avec gtk.lib (ou libgtk.a sous
Unix), mais le contenu de cette bibliothèque n'a pas lui-même été généré
avec l'option -static, et donc il [le contenu] dépend de certaines
bibliothèques dynamiques.

Un indice de cet état de choses est que toutes les .a ne sont pas
livrées sous Linux.


Une des raisons de la confusion est une astuce de nommage de la liaison
dynamique (*nix ou Windows) qui a été introduite pour faciliter la vie
des programmeurs et rendre les choses « transparentes »...

Sous Windows, l'éditeur de liens utilise (exclusivement) des
machintruc.lib; mais si dans le cas (ancien) de la liaison statique ce
fichier contenait des modules contenant eux-même du code objet, dans le
cas de la liaison dynamique le fichier .lib ne contient que des
pointeurs vers les entrées (les __dllimport__) de la .DLL associée ; on
appelle ce .lib un « bibliothèque d'importation ».
Au passage, le fichier .def ne sert qu'à générer cette bibliothèque
d'importation. Résultat, tu ne peux pas savoir si un .lib est prévu pour
être lié statiquement ou dynamiquement.

Sous *nix c'est un poil plus complexe, car en voyant -lmachin l'éditeur
de liens est capable de chercher d'abord machin.so puis ensuite
machin.a, et il sait extrapoler à partir de la bibliothèque dynamique
elle-même (le .so) les informations qui sont nécessaires dans le fichier
produit (qui peut être un exécutable ou un autre .so)


Mais dans tous les cas, aucune des deux options de compilation, statique
ou dynamique, n'est automatiquement transitive, seul le choix par défaut
de l'une ou de l'autre l'est ; et aujourd'hui, c'est l'option dynamique
qui prévaut. L'option statique reste potentiellement disponible... mais
à chaque étage ! Donc, pour générer une application purement statique,
il faut utiliser des bibliothèques contenant uniquement du code prévu
pour fonctionner statiquement.
Au final, il faut disposer de toutes les bibliothèques statiques (.a
sour *nix), à tous les niveaux, y compris donc celles qui sont liées
indirectement
Et sous Windows, de telles bibliothèques auront le même nom que la
bibliothèque « normale », mais avec un contenu différent.
Sous *nix, les noms sont différents, mais il y a souvent beaucoup plus
de répertoires examinés pour y trouver les fichiers à lier, ce qui est
un autre problème.

En fait, le mouvement est récursif jusqu'à la bibliothèque standard
(libc.so/libc.a/libcXX.lib, dont la DLL associée s'appelle msvcrtXX.dll
sous Windows), voire même jusqu'à l'interface du système d'exploitation
qui sous Windows est constitué d'entrées dynamiques... mais là, pour
pouvoir lier avec le contenu statique il faudrait revenir 15 ans en
arrière, et travailler dans l'équipe de développement à Redmond !


Antoine
Avatar
LL
On 9 mar, 13:49, Antoine Leca wrote:
> Mais patatras : sous Win, si je tente de lancer l'exécutable
> « statique » sur une machine n'ayant pas GTK+, j'obtiens une erreur « ne
> trouve pas libmachin.dll »

Cause la plus probable ÀMHA : tu as lié avec gtk.lib (ou libgtk.a sou s
Unix), mais le contenu de cette bibliothèque n'a pas lui-même été généré
avec l'option -static, et donc il [le contenu] dépend de certaines
bibliothèques dynamiques.



J'ai manqué de précision (mea culpa). « machin » est une des bib de
GTK, explicite dans la ligne de commande, donc pas une dépendance. Ce
qui m'épate, c'est que la compilation lie une DLL alors que j'ai
précisé -static. Je me serais attendu à obtenir un message d'erreur
(ou au pire un warning).

Sous Windows, l'éditeur de liens utilise (exclusivement) des
machintruc.lib; mais si dans le cas (ancien) de la liaison statique ce
fichier contenait des modules contenant eux-même du code objet, dans le
cas de la liaison dynamique le fichier .lib ne contient que des
pointeurs vers les entrées (les __dllimport__) de la .DLL associée ; on
appelle ce .lib un « bibliothèque d'importation ».
Au passage, le fichier .def ne sert qu'à générer cette bibliothèq ue
d'importation. Résultat, tu ne peux pas savoir si un .lib est prévu p our
être lié statiquement ou dynamiquement.



Mais si j'ouvre ce .lib, je verrai la différence, non ? (Et aussi au
niveau de la taille, le .lib doit être beaucoup plus gros dans le
premier cas que dans le second.)

Mais dans tous les cas, aucune des deux options de compilation, statique
ou dynamique, n'est automatiquement transitive, seul le choix par défau t
de l'une ou de l'autre l'est



Très instructif !

En fait, le mouvement est récursif jusqu'à la bibliothèque standard
(libc.so/libc.a/libcXX.lib, dont la DLL associée s'appelle msvcrtXX.dll
sous Windows), voire même jusqu'à l'interface du système d'exploita tion
qui sous Windows est constitué d'entrées dynamiques... mais là, pou r
pouvoir lier avec le contenu statique il faudrait revenir 15 ans en
arrière, et travailler dans l'équipe de développement à Redmond !



Quand on arrive à ce niveau c'est plutôt une bonne chose, non ? J'ai
l'impression que sans ce comportement, un exécutable produit sous une
version de l'OS (disons XP) ne marcherait pas sous une autre (mettons
Win 2000).

Merci pour toutes ces infos. As-tu une idée de ce que peuvent être les
fichiers .dll.a ?

--
LL
Avatar
Antoine Leca
LL écrivit :
Ce qui m'épate, c'est que la compilation lie une DLL alors que j'ai
précisé -static. Je me serais attendu à obtenir un message d'erreur
(ou au pire un warning).



Tu peux essayer de soumettre un rapport de bogue contre binutils.

-static est une option de GCC/GNU ld, qui sont des outils conçus par et
pour le monde *nix (cf. http://www.gnu.org/gnu/manifesto.fr.html)
Dans ce contexte, son adaptation à la logique (qui est différente) des
DLLs Windows ne peut pas être absolue.

En l'occurrence, il faut se rappeler que -static n'est pas l'opposé de
-shared, mais plutôt un raccourci de -Bstatic c'est-à-dire l'opposé de
-Bdynamic : -Bdynamic *permettant* l'utilisation des bibliothèques
dynamiques, et -Bstatic ne le permettant pas (comportement par défaut
avant 1986) ; ce qui était très utile au moment de la conception de la
liaison dynamique ne se justifie peut-être plus en 2012, surtout avec
Windows où tu auras systématiquement un avertissement puisque
l'interface avec le système d'exploitation s'effectue uniquement au
moyen de liaison dynamique (depuis 1984) ; en fait, obtenir une erreur à
ce niveau empêcherait totalement d'utiliser cet outil...



On 9 mar, 13:49, Antoine Leca wrote:
En fait, le mouvement est récursif jusqu'à la bibliothèque standard
[...] voire même jusqu'à l'interface du système d'exploitation [...]


Quand on arrive à ce niveau c'est plutôt une bonne chose, non ? J'ai
l'impression que sans ce comportement, un exécutable produit sous une
version de l'OS (disons XP) ne marcherait pas sous une autre (mettons
Win 2000).



En fait, tu as toujours la possibilité que cela ne marche pas, même sans
aller aussi loin ; c'est parce que la compatibilité ascendante est
beaucoup plus courante que la compatibilité descendante. On conseille
d'ailleurs le plus souvent de faire le contraire, et de compiler pour la
plateforme la plus ancienne.

<HS>
Des élucubrations sur ce sujet (en anglais) ÀMHA intéressantes :
http://kobyk.wordpress.com/2007/07/20/dynamically-linking-with-msvcrtdll-using-visual-c-2005/
</HS>



Merci pour toutes ces infos. As-tu une idée de ce que peuvent être les
fichiers .dll.a ?



Si tu lis l'anglais :
http://cygwin.com/cygwin-ug-net/dll.html (2e résultat avec mon Google)


Antoine
1 2 3