tools - El programa "Hello World" de GCC C++->.exe tiene una capacidad de 500kb cuando se compila en Windows. ¿Cómo puedo reducir su tamaño?
netbeans c++ tutorial (13)
¿Cómo es que otros compiladores como msvc8 o incluso un compilador de órdenes como Borland C ++ 5.5.1 son capaces de producir ejecutables muy pequeños pero mingw gcc no puede?
Hice una compilació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 compilado. 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?
Recientemente comencé a aprender C ++: estoy usando nuwen''s 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 compilar este sencillo programa:
#include <iostream>
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).
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 compilador -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 compilado 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.
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 programa 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 programa)?
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 compilació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).
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:
- Usa enlaces dinámicos. 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.
- Usa un sistema de compresión ejecutable .
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 programa 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 compilada usando g ++ 3.4.4 en cygwin produjo un ejecutable de 476872 bytes, compilando 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.
Repetí tu prueba usando Cygwin y g ++. Su código compilado 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 <iostream>. 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 corrientes y todo tipo de cosas bajo el capó.
Sin embargo, si tener un pequeño tamaño ejecutable es un objetivo 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 compilará un ejecutable de 1536 bytes para una impresión ("¡Hola mundo!") TinyC solo es C, no C ++ y se sabe que compila 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 !!
Si usas la utilidad "nm" o algún otro programa 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í.
Siempre puede ejecutar UPX en su exe después de haberlo creado.
los
#include <iostream>
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.