Programma GCC C ++ “Hello World” -> .exe è grande 500kb quando compilato su Windows. Come posso ridurne le dimensioni?

Recentemente ho iniziato ad imparare C ++ – Sto usando la versione nuwen di MingW su Windows, usando NetBeans come IDE (ho anche MSDN AA Version di MSVC 2008, anche se non lo uso molto spesso).

Quando compili questo semplice programma:

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

il mio eseguibile era di circa 1 MB. Quando ho modificato la configurazione del progetto da Debug in Release , ho usato i flag -O1 -Os (eliminando i simboli di debug lungo il percorso), la dimensione binaria è stata ridotta da 1 MB a 544 KB.

Non sono un “maniaco della dimensione”, ma mi sto solo chiedendo – esiste un modo, che potrei ridurre la dimensione .exe ancora di più? Penso solo che 544 KB siano troppo per un’applicazione così semplice).

Il

 #include  

fa sì che gran parte della libreria standard sia collegata, almeno con g ++. Se sei davvero preoccupato delle dimensioni dell’eseguibile, prova a sostituire tutti gli usi di iostreams con printf o simili. Questo in genere ti darà un eseguibile più piccolo, più veloce (ho ottenuto il tuo fino a circa 6K) al costo della convenienza e della sicurezza del tipo.

Il problema qui non è tanto con la biblioteca quanto con il modo in cui
la biblioteca è collegata. Certo, iostream è una biblioteca abbastanza grande, ma io no
penso che possa essere così grande da far sì che un programma generi un eseguibile che è
900KB più grande di uno simile che utilizza le funzioni C Quello da incolpare
non è iostream ma gcc . Più precisamente, il static linking è da biasimare.

Come spiegheresti questi risultati (con il tuo programma):

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

Diverse dimensioni di file eseguibili vengono generati esattamente con lo stesso
build opzioni.

La risposta sta nel modo in cui gcc collega i file object.
Quando confronti le uscite di questi due comandi:

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

scoprirai che gli unici posti che differiscono (a parte i percorsi verso il
file di oggetti temporanei) è nelle opzioni utilizzate:

  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 

Hai il tuo colpevole proprio lì in alto. -Bstatic è l’opzione che viene
esattamente dopo il file object che potrebbe essere simile a questo:

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

Se giochi con le opzioni e rimuovi le librerie “inutili”,
è ansible ridurre la dimensione dell’eseguibile da 934KB a 4.5KB max
nel mio caso. Ho ottenuto quel 4.5KB usando -Bdynamic , il flag -O
e le librerie più importanti che la tua applicazione non può vivere senza, cioè
-lmingw32 , -lmsvcrt , -lkernel32 . Avrai un eseguibile di 25KB a questo
punto. Striscia a 10KB e UPX a circa 4.5KB-5.5KB .

Ecco un Makefile con cui giocare, per i calci:

 ## 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 

Risultati (misura con le pinze):

 // 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 ansible ragione per l’inclusione di -Bstatic nelle opzioni di generazione predefinite
è per prestazioni migliori. Ho provato a build uno astyle con -Bdynamic e ottenuto
una diminuzione della velocità di 1 secondo in media, anche se l’applicazione era di moda
più piccolo dell’originale (400KB contro 93KB quando UPXed).

Non sei sicuro di quanto sarà utile per te, ma qualcuno ha fatto un bel po ‘di lavoro per ridurre le dimensioni di un semplice .exe di Windows .

Sono stati in grado di creare un semplice .exe che verrà eseguito su una versione moderna di Windows in 133 byte, utilizzando alcuni metodi molto estremi.

Si ottiene la libreria standard C ++, e altre cose credo, collegate staticamente in quanto mingw ha la propria implementazione di queste librerie.

Non preoccuparti così tanto, quando fai un programma più complesso, le dimensioni non cresceranno di conseguenza.

Potresti usare -s, che credo sia integrato anche in mingw. Una semplice applicazione mondiale Hello compilata utilizzando g ++ 3.4.4 su eseguibile prodotto da cygwin che era 476872 byte, la compilazione di nuovo con -s (elimina i dati non necessari), ha ridotto lo stesso eseguibile a 276480 byte.

La stessa ciao applicazione mondiale su cygwin che utilizza g ++ 4.3.2 ha prodotto un eseguibile di 16495 byte, usando la striscia ridotta la dimensione a 4608 byte. Per quanto posso vedere, probabilmente è meglio usare la versione più recente di g ++.

MingW ha appena rilasciato gcc 4.4.0, quindi se la dimensione dell’eseguibile è importante allora prenderei in considerazione l’utilizzo di questo. Come indica -s probabilmente aiuterà a rimuovere gran parte delle informazioni di debug per te, che è consigliato solo se è destinato alla produzione.

Fondamentalmente, non c’è davvero nulla che tu possa fare per ridurre quella dimensione .exe con una distribuzione base di mingw. 550kb è tanto piccolo quanto è ansible ottenerlo, perché mingw e gcc / g ++ in generale sono dannosi per la rimozione delle funzioni inutilizzate. Circa 530kb di questo sono dalla libreria msvcrt.a.

Se volessi davvero approfondire la questione, potresti essere in grado di ribuild la libreria msvcrt.a con le opzioni del compilatore -ffunction-section -fdata-section e quindi utilizzare le opzioni del link -Wl, – gc-section quando colleghi la tua app e questo dovrebbe essere in grado di eliminare molte cose da lì. Ma se stai solo imparando C ++, ribuild quella libreria potrebbe essere un po ‘avanzato.

O potresti semplicemente usare MSVC, che è ottimo per rimuovere le funzioni inutilizzate. Lo stesso bit di codice compilato con MSVC produce un exe da 10kb.

Bene, quando usi la libreria standard C ++, exe può diventare molto veloce. Se dopo aver rimosso il simbolo di debug, vuoi comunque ridurre la dimensione del tuo software, puoi usare un packer come UPX . Ma, attenzione, alcuni antivirus soffocano su exe pieno di UPX come alcuni virus l’hanno usato molto tempo fa.

Puoi sempre eseguire UPX sul tuo exe dopo averlo creato.

Se usi l’utility “nm” o qualche altro programma che mostra cosa c’è nel tuo .exe, vedrai che contiene tonnellate di classi che qualcuno potrebbe voler usare, ma che tu non lo fai.

Ho replicato il tuo test usando Cygwin e g ++. Il tuo codice è stato compilato a 480k con -O2. La striscia in esecuzione sull’eseguibile l’ha ridotta a 280k.

In generale, però, sospetto che il tuo problema sia l’uso dell’intestazione . Ciò causa il collegamento di una libreria abbastanza grande. Inoltre, nota che cout << x fa molto più della semplice stampa. Ci sono locali e corsi d'acqua e ogni genere di roba sotto il cofano.

Se tuttavia, avere una piccola dimensione eseguibile è un objective reale, mission-critical, evitarlo e usare printf o puts. Se non lo è, allora direi pagare il costo una tantum di iostream e farla finita.

Se hai bisogno di piccoli eseguibili, Tiny C compilerà un eseguibile di 1536 byte per un printf (“Hello world!”) TinyC è solo C, non C ++ ed è noto per la compilazione più veloce e per fornire eseguibili più lenti di gcc.

EDITED: Ho appena provato un cout <"Hello World!" in DevC ++ (bundle Mingw 4.8 e Ide) e ho ottenuto un eseguibile di 4,5 MB !!

Com’è ansible che altri compilatori come msvc8 o persino un compilatore di ordini come borland c ++ 5.5.1 siano in grado di produrre eseguibili molto piccoli, ma mingw gcc non è in grado di farlo?

Ho fatto una rapida compilazione di un “mondo ciao” per ciascuno dei seguenti strumenti e ho osservato la dimensione eseguibile compilata. Si noti che in tutti questi casi la libreria di runtime è collegata staticamente e tutti i simboli di debug sono stati rimossi:

 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 

La cosa interessante è che la versione successiva di gcc 4.4.1 produce un eseguibile ancora più grande di gcc3.4.5, probabilmente a causa della diversa versione di libstdc ++.

Quindi non c'è davvero alcun modo per rimuovere il codice morto durante la fase di collegamento per mingw?

La maggior parte della dimensione deriva dall’uso di librerie di runtime abbastanza estese. Quindi nella vita reale stai effettivamente collegando un pezzo molto grande di “codice morto” se hai un’applicazione così semplice.

Per quanto ne so, non ci sono flag linker per saltare le parti non utilizzate di una libreria collegata.

Ci sono due modi in cui so per simulare un’applicazione più piccola:

  1. Usa il collegamento dinamico. Quindi la tua applicazione si riferisce alla libreria caricata dynamicmente. Hai ancora bisogno della dimensione completa (in realtà più) ma hai un eseguibile molto più piccolo.
  2. Utilizzare un sistema di compressione eseguibile .