GCC C ++ & # 8220; Hello World & # 8221; programma - > .exe è grande 500kb quando compilato su Windows. Come posso ridurne le dimensioni?

StackOverflow https://stackoverflow.com/questions/1042773

Domanda

Di recente ho iniziato a studiare C ++ - Sto usando la versione di Nuwen di MingW su Windows, usando NetBeans come un IDE (ho anche MSDN AA versione di MSVC 2008, anche se non lo uso molto spesso).

Durante la compilazione di questo semplice programma:

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

il mio eseguibile era grande circa 1 MB. Quando ho cambiato la configurazione del progetto da Debug a Rilascio , 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 per ridurre ulteriormente la dimensione .exe? Penso solo che 544 KB sia troppo per un'applicazione così semplice).

È stato utile?

Soluzione

Il

#include <iostream>

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

Altri suggerimenti

Il problema qui non è tanto con la libreria quanto con il modo in cui
la libreria è collegata. Concesso, iostream è una biblioteca moderatamente grande, ma io non
penso che possa essere così grande da indurre un programma a generare un eseguibile che è
900KB più grande di uno simile che utilizza le funzioni C . Quello da incolpare
non è iostream ma gcc . Più precisamente, si deve incolpare collegamento statico .

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 eseguibili vengono generate esattamente con la stessa
costruire opzioni.

La risposta sta nel modo in cui gcc collega i file oggetto.
Quando confronti gli output 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 in cui differiscono (a parte i percorsi per
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 arriva
esattamente dopo il file oggetto che potrebbe assomigliare a questo:

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

Se giochi con le opzioni e rimuovi le librerie "non necessarie",
puoi ridurre la dimensione dell'eseguibile da 934KB a 4.5KB max
nel mio caso. Ho ottenuto quel 4.5KB usando -Bdynamic , la bandiera -O
e le librerie più importanti senza le quali l'applicazione non può vivere, ovvero
-lmingw32 , -lmsvcrt , -lkernel32 . Otterrai un 25 KB eseguibile in quel
punto. Spogliatelo su 10KB e UPX su 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 (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)

Un possibile motivo per l'inclusione di -Bstatic nelle opzioni di build predefinite
è per prestazioni migliori. Ho provato a costruire astyle con -Bdynamic e ho ottenuto
una riduzione della velocità di 1 secondo in media, anche se l'applicazione è stata molto efficace
più piccolo dell'originale (400 KB contro 93 KB quando UPXed).

Non sono sicuro di quanto ti servirà, ma qualcuno ha lavorato parecchio per ridurre le dimensioni di un semplice Windows .exe .

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.

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

La stessa applicazione hello world su cygwin usando g ++ 4.3.2 ha prodotto un eseguibile di 16495 byte, usando strip ha ridotto 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 del file eseguibile è importante, prenderei in considerazione l'idea di usarlo. Come indica -s probabilmente aiuterà a rimuovere gran parte delle informazioni di debug per te, che è raccomandato solo se è per uso di produzione.

Ottieni la libreria standard C ++ e altre cose, immagino, collegate staticamente in quanto mingw ha la sua implementazione di queste librerie.

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

Fondamentalmente, non c'è davvero nulla che tu possa fare per ridurre quella dimensione .exe con una distribuzione base di mingw. 550kb è il più piccolo possibile, perché mingw e gcc / g ++ in generale sono cattivi nel rimuovere le funzioni inutilizzate. Circa 530kb di ciò provengono dalla libreria msvcrt.a.

Se volessi davvero entrarci, potresti essere in grado di ricostruire la libreria msvcrt.a con le opzioni del compilatore -ffunction-sezioni -fdata-sezioni e quindi utilizzare le opzioni del linker -Wl, - gc-sezioni quando collegando la tua app e questo dovrebbe essere in grado di eliminare un sacco di roba del genere. Ma se stai solo imparando il C ++, ricostruire 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 grande molto velocemente. Se dopo aver rimosso il simbolo di debug, desideri comunque ridurre le dimensioni del tuo software, puoi utilizzare un packer come UPX . Ma attenzione, alcuni antivirus soffocano su exe pieno di UPX poiché alcuni virus lo hanno usato molto tempo fa.

Puoi sempre eseguire UPX sul tuo exe dopo averlo creato.

Se usi " nm " utilità o qualche altro programma che mostra ciò che è nel tuo .exe, vedrai che contiene tonnellate di classi che qualcuno potrebbe voler usare, ma che non lo fai.

Ho replicato il tuo test usando Cygwin e g ++. Il tuo codice è stato compilato a 480k con -O2. L'esecuzione di strip sull'eseguibile lo ha ridotto a 280k.

In generale, però, sospetto che il tuo problema sia l'uso di & iteam iostream > intestazione. Ciò provoca il collegamento di una libreria abbastanza grande. Inoltre, tieni presente che cout < < x fa molto di più della semplice stampa. Ci sono locali e flussi e ogni sorta di roba nascosta.

Se, tuttavia, avere una piccola dimensione eseguibile è un obiettivo reale e critico, evitalo e usa printf o put. In caso contrario, direi di pagare il costo una tantum di iostream e di farcela.

Se hai bisogno di piccoli eseguibili, Tiny C compilerà un eseguibile di 1536 byte per un printf (" Ciao mondo! ") TinyC è solo C, non C ++ ed è noto per compilare più velocemente e dare eseguibili più lenti di gcc.

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

Come mai altri compilatori come msvc8 o persino un compilatore di ordini come borland c ++ 5.5.1 sono in grado di produrre eseguibili di dimensioni molto ridotte, ma mingw gcc non è in grado di farlo?

Ho fatto una rapida compilazione di un 'ciao mondo' per ciascuno dei seguenti set di strumenti e osservato la dimensione eseguibile compilata. Si prega di notare che in in tutti questi casi la libreria di runtime è collegata staticamente e tutto il debug i simboli 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 modo di rimuovere il codice morto durante la fase di collegamento per mingw?

La maggior parte delle dimensioni deriva dall'uso di librerie di runtime abbastanza estese. Quindi, nella vita reale, in realtà stai 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 inutilizzate di una libreria collegata.

Ci sono due modi che conosco per simulare un'applicazione più piccola:

  1. Utilizza il collegamento dinamico. Quindi l'applicazione fa riferimento alla libreria caricata dinamicamente. Hai ancora bisogno delle dimensioni complete (in realtà di più) ma hai un eseguibile molto più piccolo.
  2. Utilizza un compressione eseguibile .
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top