El progtwig “Hello World” de GCC C ++ -> .exe tiene una capacidad de 500kb cuando se comstack en Windows. ¿Cómo puedo reducir su tamaño?

Recientemente comencé a aprender C ++: estoy usando la versión de Nuwen de MingW en Windows, usando NetBeans como IDE (también tengo MSDN AA Version de MSVC 2008, aunque no la uso muy a menudo).

Al comstackr este sencillo progtwig:

#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; } ///:~ 

mi ejecutable era aproximadamente 1 MB grande. Cuando cambié la configuración del proyecto de Depurar a Versión , utilicé banderas -O1 -Os (eliminando los símbolos de depuración a lo largo del camino), el tamaño del binario se redujo de 1MB a 544KB.

No soy un “fanático del tamaño”, pero me pregunto: ¿hay alguna manera de reducir el tamaño .exe aún más? Solo pienso que 544 KB es demasiado para una aplicación tan simple).

los

 #include  

hace que se vincule una gran cantidad de la biblioteca estándar, al menos con g ++. Si realmente le preocupa el tamaño del archivo ejecutable, intente reemplazar todos los usos de iostreams con printf o similar. Normalmente, esto le dará un ejecutable más pequeño y más rápido (obtuve el suyo hasta aproximadamente 6K) a costa de la conveniencia y la seguridad del tipo.

El problema aquí no es tanto con la biblioteca como con la forma en que
la biblioteca está vinculada. De acuerdo, iostream es una biblioteca moderadamente grande, pero yo no
Creo que puede ser tan grande como para hacer que un progtwig genere un ejecutable que es
900KB más grande que uno similar que usa funciones C El culpable
no es iostream sino gcc Más exactamente, se debe culpar a los static linking .

¿Cómo explicarías estos resultados (con tu progtwig)?

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

Se están generando diferentes tamaños de ejecutables con exactamente el mismo
construir opciones

La respuesta radica en la forma en que gcc vincula los archivos objeto.
Cuando compara las salidas de estos dos comandos:

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

descubrirá que los únicos lugares donde difieren (aparte de los caminos hacia el
archivos temporales de objeto) está en las opciones utilizadas:

  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 

Tienes a tu culpable allí mismo en la parte superior. -Bstatic es la opción que viene
exactamente después del archivo objeto que puede verse más o menos así:

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

Si juegas con las opciones y eliminas bibliotecas ‘innecesarias’,
puede reducir el tamaño del ejecutable de 934KB a 4.5KB máximo
en mi caso. 4.5KB esos 4.5KB usando -Bdynamic , la bandera -O
y las bibliotecas más cruciales que su aplicación no puede vivir, es decir,
-lmingw32 , -lmsvcrt , -lkernel32 . Obtendrás un ejecutable de 25 KB en ese
punto. Tírelo a 10KB y UPX a alrededor de 4.5KB-5.5KB .

Aquí hay un Makefile para jugar, para patadas:

 ## This makefile contains all the options GCC passes to the linker ## when you compile 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 strip test.exe upx test.exe CLEAN: del *.exe *.o 

Resultados (YMMV):

 // Not stripped 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 // Stripped 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) 

Una posible razón para la inclusión de -Bstatic en las opciones de comstackción predeterminadas
es para un mejor rendimiento. Intenté construir astyle con -Bdynamic y obtuve
una disminución de la velocidad de 1 segundo en promedio, a pesar de que la aplicación fue muy
más pequeño que el original (400 KB frente a 93 KB cuando está UPXed).

No estoy seguro de cuánto usará para usted, pero alguien ha trabajado mucho para reducir el tamaño de un simple .exe de Windows .

Pudieron crear un .exe simple que se ejecutará en una versión moderna de Windows en 133 bytes, utilizando algunos métodos muy extremos.

Obtendrá la biblioteca estándar de C ++, y otras cosas, supongo, vinculadas estáticamente, ya que mingw tiene su propia implementación de estas bibliotecas.

No se preocupe tanto por eso, cuando haga un progtwig más complejo, el tamaño no crecerá en consecuencia.

Podría usar -s, que creo que está integrado en mingw también. Una aplicación hello world simple comstackda usando g ++ 3.4.4 en cygwin produjo un ejecutable de 476872 bytes, comstackndo nuevamente con -s (elimina datos innecesarios), redujo el mismo ejecutable a 276480 bytes.

La misma aplicación hello world en cygwin usando g ++ 4.3.2 produjo un ejecutable de 16495 bytes, usando strip redujo el tamaño a 4608 bytes. Por lo que puedo ver, probablemente sea mejor usar una versión más reciente de g ++.

MingW acaba de lanzar gcc 4.4.0, por lo que si el tamaño del archivo ejecutable es importante, consideraría usarlo. Como indica, probablemente le ayudará a eliminar gran parte de la información de depuración, solo se recomienda si es para uso de producción.

Básicamente, realmente no hay nada que puedas hacer para reducir ese tamaño .exe con una distribución base de mingw. 550kb es lo más pequeño que se puede obtener, porque mingw y gcc / g ++ en general son malos para quitar las funciones no utilizadas. Aproximadamente 530kb de eso es de la biblioteca msvcrt.a.

Si realmente deseaba acceder, podría reconstruir la biblioteca msvcrt.a con las opciones del comstackdor -funciones-secciones -fdata-secciones, y luego usar las opciones del vinculador -Wl, – gc-sections al vincular su aplicación , y esto debería poder quitar muchas de esas cosas de allí. Pero si solo está aprendiendo C ++, la reconstrucción de esa biblioteca puede estar un poco avanzada.

O simplemente puede usar MSVC, que es excelente para eliminar funciones no utilizadas. Ese mismo código comstackdo con MSVC produce un exe de 10kb.

Bueno, cuando utilizas la biblioteca estándar de C ++, exe puede crecer realmente rápido. Si después de eliminar el símbolo de depuración, aún desea reducir el tamaño de su software, puede usar un empaquetador como UPX . Pero, se advirtió, algunos antivirus se ahogaban en el antivirus repleto de UPX ya que algunos virus lo usaban hace mucho tiempo.

Siempre puede ejecutar UPX en su exe después de haberlo creado.

Si usas la utilidad “nm” o algún otro progtwig que muestre lo que está en tu .exe, verás que contiene toneladas de clases que alguien podría querer usar, pero no es así.

Repetí tu prueba usando Cygwin y g ++. Su código comstackdo a 480k con -O2. Correr tira en el ejecutable lo redujo a 280k.

Sin embargo, en general, sospecho que su problema es el uso del encabezado . Esto hace que se vincule una biblioteca bastante grande. Además, tenga en cuenta que cout < < x hace mucho más que solo imprimir. Hay lugares y streams y todo tipo de cosas bajo el capó.

Sin embargo, si tener un pequeño tamaño ejecutable es un objective real de misión crítica, entonces evítelo y use printf o puts. Si no es así, entonces diría que pague el costo único de iostream y termine con esto.

Si necesita archivos ejecutables pequeños, Tiny C comstackrá un ejecutable de 1536 bytes para una impresión (“¡Hola mundo!”) TinyC solo es C, no C ++ y se sabe que comstack más rápido y le da ejecutables más lentos que gcc.

EDITADO: Acabo de probar un cout < "Hello World!" en DevC ++ (paquetes Mingw 4.8 y un Ide) y obtuve un ejecutable de 4,5 MB !!

¿Cómo es que otros comstackdores como msvc8 o incluso un comstackdor de órdenes como Borland C ++ 5.5.1 son capaces de producir ejecutables muy pequeños pero mingw gcc no puede?

Hice una comstackción rápida de un ‘mundo de saludo’ para cada uno de los siguientes conjuntos de herramientas y observé el tamaño del archivo ejecutable comstackdo. Tenga en cuenta que en todos estos casos, la biblioteca de tiempo de ejecución está vinculada de forma estática y todos los símbolos de depuración se han eliminado:

 compiler 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 

Lo interesante es que la última versión de gcc 4.4.1 produce un ejecutable aún mayor que gcc3.4.5, probablemente debido a una versión diferente de libstdc ++.

Entonces, ¿realmente no hay forma de eliminar el código muerto durante la fase de vinculación para mingw?

La mayor parte del tamaño se debe al uso de bibliotecas de tiempo de ejecución bastante extensas. En la vida real, en realidad estás vinculando una gran pieza de ‘código muerto’ si tienes una aplicación tan simple.

Hasta donde sé, no hay indicadores de enlazador para omitir las partes no utilizadas de una biblioteca vinculada.

Hay dos formas que conozco de falsificar una aplicación más pequeña:

  1. Usa enlaces dynamics. Entonces su aplicación se refiere a la biblioteca cargada dinámicamente. Todavía necesita el tamaño completo (en realidad más) pero tiene un ejecutable mucho más pequeño.
  2. Usa un sistema de compresión ejecutable .