Le programme «Hello World» de GCC C ++ -> .exe a une taille de 500 Ko lorsqu’il est compilé sous Windows. Comment puis-je réduire sa taille?

J’ai récemment commencé à apprendre le C ++ – J’utilise la version de Nuwen de MingW sous Windows, en utilisant NetBeans comme IDE (j’ai également la version MSDN AA de MSVC 2008, bien que je ne l’utilise pas très souvent).

Lors de la compilation de ce programme simple:

#include  using namespace std; int dog, cat, bird, fish; void f(int pet) { cout << "pet id number: " << pet << endl; } int main() { int i, j, k; cout << "f(): " << (long)&f << endl; cout << "dog: " << (long)&dog << endl; cout << "cat: " << (long)&cat << endl; cout << "bird: " << (long)&bird << endl; cout << "fish: " << (long)&fish << endl; cout << "i: " << (long)&i << endl; cout << "j: " << (long)&j << endl; cout << "k: " << (long)&k << endl; } ///:~ 

mon exécutable faisait environ 1Mo. Lorsque j’ai modifié la configuration du projet de Debug à Release , en utilisant les indicateurs -O1-Os (en supprimant les symboles de débogage en cours de route), la taille binary a été réduite de 1 Mo à 544 Ko.

Je ne suis pas un “maniaque de la taille”, mais je me demandais simplement – y at-il un moyen de réduire encore plus la taille du fichier .exe? Je pense juste que 544 Ko est tout simplement trop pour une application aussi simple).

le

 #include  

permet de lier une grande partie de la bibliothèque standard, au moins avec g ++. Si vous êtes vraiment préoccupé par la taille des exécutables, essayez de remplacer toutes les utilisations de iostream par printf ou similaire. Cela vous donnera généralement un exécutable plus petit et plus rapide (le vôtre est d’environ 6K) au désortingment de la commodité et de la sécurité des types.

Le problème ici n’est pas tant avec la bibliothèque que avec la façon dont le
la bibliothèque est liée. Certes, iostream est une bibliothèque plutôt volumineuse mais je ne le fais pas
pense qu’il peut être si énorme pour amener un programme à générer un exécutable qui est
900KB plus qu’un 900KB similaire utilisant les fonctions C Celui à blâmer
n’est pas iostream mais gcc . Plus précisément, static linking sont à blâmer.

Comment expliqueriez-vous ces résultats (avec votre programme):

 g++ test.cpp -o test.exe SIZE: 935KB gcc test.cpp -o test.exe -lstdc++ SIZE: 64.3KB 

Différentes tailles d’exécutables sont générées avec exactement la même
construire des options.

La réponse réside dans la manière dont gcc relie les fichiers objects.
Lorsque vous comparez les résultats de ces deux commandes:

 g++ -v test.cpp -o test.exe // c++ program using stream functions gcc -v test.c -o test.exe // c program that using printf 

vous découvrirez que les seuls endroits où ils diffèrent (mis à part les chemins menant au
fichiers d’objects temporaires) est dans les options utilisées:

  C++(iostream) | C(stdio) ------------------------------- -Bstatic | (Not There) -lstdc++ | (Not There) -Bdynamic | (Not There) -lmingw32 | -lmingw32 -lgcc | -lgcc -lmoldname | -lmoldname -lmingwex | -lmingwex -lmsvcrt | -lmsvcrt -ladvapi32 | -ladvapi32 -lshell32 | -lshell32 -luser32 | -luser32 -lkernel32 | -lkernel32 -lmingw32 | -lmingw32 -lgcc | -lgcc -lmoldname | -lmoldname -lmingwex | -lmingwex -lmsvcrt | -lmsvcrt 

Vous avez votre coupable juste en haut. -Bstatic est l’option qui vient
exactement après le fichier object qui peut ressembler à ceci:

 "AppData\\Local\\Temp\\ccMUlPac.o" -Bstatic -lstdc++ -Bdynamic .... 

Si vous jouez avec les options et supprimez les bibliothèques “inutiles”,
vous pouvez réduire la taille de l’exécutable de 934KB à 4.5KB maximum
dans mon cas. J’ai obtenu ce 4.5KB en utilisant -Bdynamic , le drapeau -O
et les bibliothèques les plus cruciales que votre application ne peut pas vivre, à savoir
-lmingw32 , -lmsvcrt , -lkernel32 . Vous obtiendrez un exécutable de 25 Ko à cette
point. Bande-le à 10 Ko et UPX à environ 4.5KB-5.5KB .

Voici un Makefile avec lequel vous pouvez jouer:

 ## This makefile contains all the options GCC passes to the linker ## when you comstack like this: gcc test.cpp -o test.exe CC=gcc ## NOTE: You can only use OPTIMAL_FLAGS with the -Bdynamic option. You'll get a ## screenfull of errors if you try something like this: make smallest type=static OPTIMAL_FLAGS=-lmingw32 -lmsvcrt -lkernel32 DEFAULT_FLAGS=$(OPTIMAL_FLAGS) \ -lmingw32 \ -lgcc \ -lmoldname \ -lmingwex \ -lmsvcrt \ -ladvapi32 \ -lshell32 \ -luser32 \ -lkernel32 \ -lmingw32 \ -lgcc \ -lmoldname \ -lmingwex \ -lmsvcrt LIBRARY_PATH=\ -LC:\MinGW32\lib\gcc\mingw32\4.7.1 \ -LC:\mingw32\lib\gcc \ -LC:\mingw32\lib\mingw32\lib \ -LC:\mingw32\lib\ OBJECT_FILES=\ C:\MinGW32\lib\crt2.o \ C:\MinGW32\lib\gcc\mingw32\4.7.1\crtbegin.o COLLECT2=C:\MinGW32\libexec\gcc\mingw32\4.7.1\collect2.exe normal: $(CC) -c test.cpp $(COLLECT2) -Bdynamic $(OBJECT_FILES) test.o -B$(type) -lstdc++ -Bdynamic $(DEFAULT_FLAGS) $(LIBRARY_PATH) -o test.exe optimized: $(CC) -c -O test.cpp $(COLLECT2) -Bdynamic $(OBJECT_FILES) test.o -B$(type) -lstdc++ -Bdynamic $(DEFAULT_FLAGS) $(LIBRARY_PATH) -o test.exe smallest: $(CC) -c -O test.cpp $(COLLECT2) -Bdynamic $(OBJECT_FILES) test.o -B$(type) -lstdc++ -Bdynamic $(OPTIMAL_FLAGS) $(LIBRARY_PATH) -o test.exe ultimate: $(CC) -c -O test.cpp $(COLLECT2) -Bdynamic $(OBJECT_FILES) test.o -B$(type) -lstdc++ -Bdynamic $(OPTIMAL_FLAGS) $(LIBRARY_PATH) -o test.exe ssortingp test.exe upx test.exe CLEAN: del *.exe *.o 

Résultats (YMMV):

 // Not ssortingpped or compressed in any way make normal type=static SIZE: 934KB make normal type=dynamic SIZE: 64.0KB make optimized type=dynamic SIZE: 30.5KB make optimized type=static SIZE: 934KB make smallest type=static (Linker Errors due to left out libraries) make smallest type=dynamic SIZE: 25.6KB // Ssortingpped and UPXed make ultimate type=dynamic (UPXed from 9728 bytes to 5120 bytes - 52.63%) make ultimate type=static (Linker Errors due to left out libraries) 

Une raison possible pour l’inclusion de -Bstatic dans les options de construction par défaut
est pour une meilleure performance. J’ai essayé de construire astyle avec -Bdynamic et j’ai
une diminution de la vitesse de 1 seconde en moyenne, même si l’application était beaucoup
plus petit que l’original (400 Ko contre 93 Ko lorsque UPXed).

Vous ne savez pas exactement à quoi vous en aurez besoin, mais quelqu’un a beaucoup travaillé à la réduction de la taille d’un simple fichier .exe .

Ils ont réussi à créer un simple fichier .exe qui s’exécutera sur une version moderne de Windows de 133 octets, en utilisant des méthodes très extrêmes.

Vous obtenez la bibliothèque standard C ++, et d’autres éléments liés, statiquement, car mingw a sa propre implémentation de ces bibliothèques.

Ne vous inquiétez pas trop à ce sujet, lorsque vous créez un programme plus complexe, la taille ne croît pas en conséquence.

Vous pouvez utiliser -s, qui, je crois, est également intégré à mingw. Une simple application hello world, compilée à l’aide de g ++ 3.4.4 sur un exécutable produit par cygwin de 476872 octets, recompilant avec -s (supprime les données inutiles), a réduit le même exécutable à 276480 octets.

La même application hello world sur cygwin utilisant g ++ 4.3.2 a généré un exécutable de 16495 octets, l’utilisation de ssortingp ayant été réduite à 4608 octets. Autant que je sache, il vaut probablement mieux utiliser une version plus récente de g ++.

MingW vient de publier la version 4.4.0 de gcc. Par conséquent, si la taille de l’exécutable est importante, nous envisagerons de l’utiliser. Comme il est indiqué, -s aidera probablement à supprimer une grande partie des informations de débogage, ce qui n’est recommandé que pour une utilisation en production.

En gros, vous ne pouvez rien faire pour réduire cette taille .exe avec une dissortingbution de base de mingw. 550 Ko est à peu près aussi petit que vous pouvez l’obtenir, parce que mingw et gcc / g ++ sont en général mauvais pour supprimer des fonctions inutilisées. Environ 530 Ko de cela proviennent de la bibliothèque msvcrt.a.

Si vous voulez vraiment y entrer, vous pourrez peut-être reconstruire la bibliothèque msvcrt.a avec les options du compilateur -ffunction-sections -fdata-sections, puis utiliser les options de l’éditeur de liens -Wl, – gc-sections pour lier votre application. , et cela devrait pouvoir enlever beaucoup de ces choses là. Mais si vous venez d’apprendre le C ++, la reconstruction de cette bibliothèque risque d’être un peu avancée.

Ou vous pouvez simplement utiliser MSVC, ce qui est excellent pour supprimer les fonctions inutilisées. Le même bit de code compilé avec MSVC produit un fichier exe de 10 ko.

Eh bien, lorsque vous utilisez la bibliothèque standard C ++, exe peut devenir grand très rapidement. Si, après avoir supprimé le symbole de débogage, vous souhaitez toujours réduire la taille de votre logiciel, vous pouvez utiliser un programme de compression tel que UPX . Mais, soyez averti, certains antivirus s’étouffent sur des fichiers exe bourrés d’UPX car certains virus les utilisaient depuis longtemps.

Vous pouvez toujours exécuter UPX sur votre exe après l’avoir créé.

Si vous utilisez l’utilitaire “nm” ou un autre programme affichant ce qui se trouve dans votre fichier .exe, vous verrez qu’il contient des tonnes de classes que quelqu’un pourrait vouloir utiliser, mais que vous ne pouvez pas utiliser.

J’ai répliqué votre test en utilisant Cygwin et g ++. Votre code compilé à 480k avec -O2. L’exécution de la bande sur l’exécutable l’a réduite à 280k.

En général, cependant, je suppose que votre problème est l’utilisation de l’en-tête . Cela a pour effet de lier une bibliothèque assez volumineuse. De plus, notez que cout << x fait beaucoup plus que simplement imprimer. Il y a des lieux, des ruisseaux et toutes sortes de choses sous le capot.

Si toutefois, avoir une petite taille d’exécutable est un objective réel et crucial, alors évitez-le et utilisez printf ou put. Si ce n'est pas le cas, alors je dirais qu'il faut payer le coût ponctuel de iostream et en finir avec ce coût.

Si vous avez besoin de petits exécutables, Tiny C comstackra un exécutable de 1536 octets pour un printf (“Hello world!”). TinyC n’est que C, pas C ++, et il est connu pour comstackr plus rapidement et donner des exécutables plus lents que gcc.

EDITED: Je viens d’essayer un cout <"Hello World!" dans DevC ++ (bundles Mingw 4.8 et un Ide) et j'ai obtenu un exécutable de 4,5 Mo !!

Comment se fait-il que d’autres compilateurs tels que msvc8 ou même un compilateur d’ordre tel que borland c ++ 5.5.1 soient capables de produire de très petits exécutables mais que Mingw gcc n’en soit pas capable?

J’ai compilé rapidement un «monde de salut» pour chacun des outils suivants et observé la taille de l’exécutable compilé. Veuillez noter que dans tous ces cas, la bibliothèque d’exécution est liée statiquement et que tous les symboles de débogage ont été supprimés:

 comstackr toolchain exe size exe size (w/iostream header) (w/cstdio printf) ------------------------------------------------------------------------- Borland C++ 5.5.1 110kbyte 52kbyte MSVC 2008 express 102kbyte 55kbyte MinGW- GCC 3.4.5 277kbyte <10kbyte MinGW- GCC 4.4.1 468kbyte <10kbyte 

Ce qui est intéressant, c’est que la dernière version de gcc 4.4.1 produit un exécutable encore plus volumineux que gcc3.4.5, probablement du fait d’une version différente de libstdc ++.

Donc, n'y a-t-il vraiment aucun moyen de supprimer le code mort pendant la phase de liaison pour mingw?

La majeure partie de la taille découle de l’utilisation de bibliothèques d’exécution assez étendues. Donc, dans la vie réelle, vous liez un très gros “code mort” si vous avez une application aussi simple.

Autant que je sache, il n’existe aucun indicateur d’éditeur de liens pour ignorer les parties inutilisées d’une bibliothèque liée.

Je connais deux façons de simuler une application plus petite:

  1. Utilisez des liens dynamics. Ensuite, votre application fait référence à la bibliothèque chargée dynamicment. Vous avez toujours besoin de la taille complète (en réalité plus) mais vous avez un exécutable beaucoup plus petit.
  2. Utilisez un système de compression exécutable .