CS107 Compilazione di programmi C con GCC

Scritto da Chris Gregg, con modifiche di Nick Troccoli

Clicca qui per un video esplicativo.

Il compilatore che useremo per CS107 è chiamato “GNU Compiler Collection” (gcc). È uno dei compilatori più usati, ed è sia software libero che disponibile su molte piattaforme di calcolo diverse.

gcc esegue il passo di compilazione per costruire un programma, e poi chiama altri programmi per assemblare il programma e per collegare le parti componenti del programma in un programma eseguibile che si può eseguire. Impareremo un po’ su ognuno di questi passi durante CS107, ma la cosa bella è che gcc può produrre l’intero programma eseguibile (eseguibile) per voi con un solo comando.

In CS107, useremo prevalentemente Makefile per compilare, assemblare e collegare il nostro codice, ma il Makefile esegue gcc per fare il lavoro. This is just a quick overview on how to compile and run your own programs should you decide to do so without a Makefile.

The simplest way to run gcc is to provide gcc a list of .c files:

$ gcc hello.c$

Note that you do not put header files (.h) into the gcc command: it reads in the header files as it compiles, based on the #include statements inside .c files.

If the program compiled without errors or warnings, you don’t get any output from gcc, and you will have a new file in your directory, called a.out. To run this file, you need to tell the shell to run the file in the current directory, by using ./ before the name:

$ ./a.outHello, World!$

In genere non vogliamo che i nostri programmi si chiamino a.out, quindi potete dare a gcc un’opzione, -o programName, per dirgli come chiamare il file eseguibile:

$ gcc hello.c -o hello$ ./helloHello, World!$

Nota: state attenti a non inserire accidentalmente un nome di file eseguibile che sia lo stesso del vostro file di input – qualcosa come:

$ gcc hello.c -o hello.c

Su myth, il vostro profilo è stato impostato per catturare l’errore e non compilarlo, lasciando il vostro file sorgente intatto. Questo non è il caso di molti altri sistemi Linux, quindi fate attenzione! Su altri sistemi, GCC sovrascriverebbe il vostro file sorgente con il nuovo eseguibile.

gcc accetta molte diverse opzioni della linea di comando (flags) che cambiano il suo comportamento. Uno dei flag più comuni è il flag “livello di ottimizzazione”, -O (la ‘o’ maiuscola). gcc ha la capacità di ottimizzare il vostro codice per varie situazioni.

  1. -O o -O1: Ottimizzare. L’ottimizzazione della compilazione richiede un po’ più di tempo e molta più memoria per una funzione grande. Con -O, il compilatore cerca di ridurre la dimensione del codice e il tempo di esecuzione, senza eseguire alcuna ottimizzazione che richiede molto tempo di compilazione.
  2. -O2: Ottimizza ancora di più. GCC esegue quasi tutte le ottimizzazioni supportate che non comportano un compromesso spazio-velocità. Rispetto a -O, questa opzione aumenta sia il tempo di compilazione che le prestazioni del codice generato.
  3. -O3: Ottimizza ancora di più. -O3 attiva tutte le ottimizzazioni specificate da -O2 e attiva anche altre ottimizzazioni. Questa è spesso l’opzione migliore da usare.
  4. -O0: riduce il tempo di compilazione e fa sì che il debug produca i risultati attesi. Questo è il default.
  5. -Os: Ottimizza per le dimensioni. -Os abilita tutte le -O2 ottimizzazioni che non aumentano tipicamente la dimensione del codice. Esegue anche ulteriori ottimizzazioni progettate per ridurre le dimensioni del codice.
  6. -Veloce: Trascura la stretta osservanza degli standard. -Ofast abilita tutte le -O3 ottimizzazioni. Abilita anche le ottimizzazioni che non sono valide per tutti i programmi conformi agli standard.
  7. -Og: Ottimizza l’esperienza di debug. -Og abilita le ottimizzazioni che non interferiscono con il debug. Dovrebbe essere il livello di ottimizzazione scelto per il ciclo standard edit-compile-debug, offrendo un livello ragionevole di ottimizzazione pur mantenendo una compilazione veloce e una buona esperienza di debug. Useremo -Og in CS107 quando facciamo il debug.

Vedi la pagina man per gcc per maggiori dettagli sull’ottimizzazione (o vedi qui per maggiori informazioni sulle ottimizzazioni).

Un altro flag comune è l’opzione -std=gnu99, che dice a gcc di usare la “versione gnu c dello standard c del 1999”. Lo standard fornisce sintassi come la possibilità di definire una variabile all’interno di una dichiarazione di ciclo for (ad esempio, for (int i = ...). Useremo questo standard in CS107.

Utilizzeremo anche il flag -g, che ci permette di usare il debugger, gdb, per darci i numeri di linea esatti nel nostro codice quando lo eseguiamo.

Esempio:

$ gcc -std=gnu99 -g -Og loop.c -o loop 

Se siete interessati a maggiori informazioni su gcc, consultate la Sezione 1 di questo documento sugli strumenti di programmazione Stanford Unix, così come il manuale completo di gcc (GNU).