Compilazione e Linking
Come funziona la compilazione?
Sezione intitolata “Come funziona la compilazione?”Quando premi “compila” nel tuo editor, sembra che il programma parta magicamente. In realtà, dietro le quinte succedono tre cose distinte.
Capire questo processo ti aiuta a:
- interpretare gli errori — ci sono errori di compilazione ed errori di linking, e si risolvono in modi diversi
- lavorare con progetti grandi — con più file
.cpp, devi sapere come metterli insieme - usare il terminale — spesso si compila da riga di comando, specialmente in ambito professionale
Le tre fasi: dalla ricetta al piatto
Sezione intitolata “Le tre fasi: dalla ricetta al piatto”Pensa al tuo codice come a una ricetta scritta in italiano. Per “eseguirla” su un computer, bisogna:
- Preprocessing — il preprocessore prepara gli ingredienti (espande
#include, sostituisce le macro#define, ecc.) - Compilazione — il compilatore traduce la ricetta in lingua macchina
- Linking — il linker unisce tutti i pezzi in un unico programma eseguibile
Fase 1: Preprocessing
Sezione intitolata “Fase 1: Preprocessing”Il preprocessore elabora il tuo codice prima della compilazione. Sostituisce ogni #include con il contenuto del file incluso, espande le macro e gestisce i blocchi #ifdef.
#include <iostream> // viene sostituito con tutto il contenuto di iostream#define PI 3.14159 // ogni occorrenza di PI viene sostituita con 3.14159
int main() { // dopo il preprocessing questa riga diventa: // double area = 3.14159 * 5 * 5; double area = PI * 5 * 5; return 0;}Puoi vedere il risultato del preprocessing con il flag -E:
g++ -E main.cpp -o main.iIl file main.i contiene il codice dopo il preprocessing — di solito è molto lungo perché include tutto il contenuto degli header.
Fase 2: Compilazione
Sezione intitolata “Fase 2: Compilazione”Il compilatore prende il codice preprocessato e lo trasforma in codice oggetto — un file in linguaggio macchina con estensione .o (su Linux e macOS) o .obj (su Windows).
Il codice oggetto contiene istruzioni che il processore capisce, ma non è ancora un programma completo: mancano i collegamenti alle funzioni scritte in altri file.
# Compila senza collegare (-c = solo compilazione)g++ -c main.cpp -o main.og++ -c matematica.cpp -o matematica.oFase 3: Linking (collegamento)
Sezione intitolata “Fase 3: Linking (collegamento)”Il linker prende tutti i file oggetto e li unisce in un unico programma eseguibile. Risolve i “ponti” tra i file: se main.cpp chiama la funzione somma() definita in matematica.cpp, il linker collega le due parti.
# Collega i file oggetto in un unico eseguibileg++ main.o matematica.o -o programmaIl comando completo con g++
Sezione intitolata “Il comando completo con g++”Di solito fai tutto in un unico comando, senza pensare alle fasi:
g++ main.cpp matematica.cpp -o programmaQuesto comando esegue automaticamente tutte e tre le fasi per ogni file .cpp e poi collega tutto insieme.
I flag di g++ più utili
Sezione intitolata “I flag di g++ più utili”I flag sono opzioni che puoi aggiungere al comando per modificarne il comportamento. Iniziano sempre con -.
Il nome dell’output
Sezione intitolata “Il nome dell’output”g++ file.cpp -o mio_programma # l'eseguibile si chiamerà "mio_programma"g++ file.cpp # senza -o, l'eseguibile si chiama "a.out"Warning — gli avvisi del compilatore
Sezione intitolata “Warning — gli avvisi del compilatore”I warning non sono errori: il programma compila lo stesso, ma il compilatore ti avvisa di cose sospette.
g++ -Wall file.cpp -o output # abilita la maggior parte dei warningg++ -Wextra file.cpp -o output # warning aggiuntivig++ -Wall -Wextra file.cpp -o output # entrambi — consigliato!Esempi di warning utili:
int x; // warning: x usata senza essere inizializzataif (x = 5) // warning: probabilmente volevi == invece di =Leggi sempre i warning e correggili — anche se il programma funziona.
Debug — per trovare gli errori
Sezione intitolata “Debug — per trovare gli errori”g++ -g file.cpp -o output # include informazioni di debug nel programmaCon -g puoi usare strumenti come gdb per eseguire il programma passo passo e vedere cosa succede.
Ottimizzazione — per rendere il programma più veloce
Sezione intitolata “Ottimizzazione — per rendere il programma più veloce”g++ -O0 file.cpp -o output # nessuna ottimizzazione (utile durante lo sviluppo)g++ -O1 file.cpp -o output # ottimizzazione leggerag++ -O2 file.cpp -o output # ottimizzazione moderata (consigliata per la versione finale)g++ -O3 file.cpp -o output # ottimizzazione aggressivaUsa -O0 durante lo sviluppo e il debug. Usa -O2 quando vuoi distribuire il programma.
Standard C++ — scegliere la versione del linguaggio
Sezione intitolata “Standard C++ — scegliere la versione del linguaggio”g++ -std=c++11 file.cpp -o output # C++11g++ -std=c++14 file.cpp -o output # C++14g++ -std=c++17 file.cpp -o output # C++17 (buona scelta moderna)g++ -std=c++20 file.cpp -o output # C++20Specifica sempre lo standard se usi funzionalità moderne. C++17 è una buona scelta oggi:
g++ -std=c++17 -Wall -Wextra main.cpp -o programmaAggiungere cartelle per gli header
Sezione intitolata “Aggiungere cartelle per gli header”g++ -I./include file.cpp -o output # cerca gli header anche nella cartella "include"g++ -I /percorso/assoluto file.cpp -o outputErrori di compilazione vs errori di linking
Sezione intitolata “Errori di compilazione vs errori di linking”Saper distinguere i due tipi di errore ti fa trovare il problema molto più in fretta.
Errori di compilazione
Sezione intitolata “Errori di compilazione”Riguardano la sintassi o la logica del tuo codice. Il compilatore non capisce cosa hai scritto:
main.cpp:5:10: error: 'somma' was not declared in this scopeHai usato somma senza dichiararla. Manca il prototipo della funzione o l’#include dell’header giusto.
main.cpp:8:5: error: expected ';' before '}' tokenHai dimenticato un punto e virgola.
Errori di linking
Sezione intitolata “Errori di linking”Riguardano riferimenti non risolti tra file diversi. Il compilatore conosce la funzione, ma il linker non trova la sua definizione:
undefined reference to `somma(int, int)'Significa: hai dichiarato somma (il compilatore è felice), ma non hai dato al linker il file .cpp che la definisce.
Soluzione: aggiungi il file mancante al comando:
# SBAGLIATO: manca matematica.cppg++ main.cpp -o programma
# CORRETTOg++ main.cpp matematica.cpp -o programmaEsempio pratico con più file
Sezione intitolata “Esempio pratico con più file”Struttura del progetto:
progetto/├── main.cpp├── studente.h└── studente.cppCompilazione in un unico comando:
g++ -std=c++17 -Wall main.cpp studente.cpp -o programmaOppure in due fasi (utile nei progetti grandi — ricompili solo i file modificati):
# Compila i singoli fileg++ -std=c++17 -c main.cpp -o main.og++ -std=c++17 -c studente.cpp -o studente.o
# Collega tuttog++ main.o studente.o -o programmaMakefile — automatizzare la compilazione
Sezione intitolata “Makefile — automatizzare la compilazione”Nei progetti con molti file, riscrivere il comando g++ ogni volta è noioso e rischioso. Il Makefile è un file che descrive come compilare il progetto automaticamente.
# MakefileCXX = g++CXXFLAGS = -std=c++17 -Wall -Wextra
programma: main.o studente.o $(CXX) main.o studente.o -o programma
main.o: main.cpp studente.h $(CXX) $(CXXFLAGS) -c main.cpp
studente.o: studente.cpp studente.h $(CXX) $(CXXFLAGS) -c studente.cpp
clean: rm -f *.o programmaPer compilare, scrivi solo:
makePer cancellare i file compilati:
make cleanNon devi padroneggiare il Makefile subito — ma è utile sapere che esiste.
Riepilogo dei flag principali
Sezione intitolata “Riepilogo dei flag principali”| Flag | Cosa fa |
|---|---|
-o nome | Specifica il nome del file di output |
-Wall | Abilita i warning principali |
-Wextra | Warning aggiuntivi |
-g | Aggiunge informazioni per il debug |
-O2 | Ottimizzazione (consigliata per la versione finale) |
-std=c++17 | Usa lo standard C++17 |
-c | Solo compilazione, senza collegamento |
-I percorso | Aggiunge una cartella dove cercare gli header |
-E | Solo preprocessing |
Comando consigliato durante lo studio
Sezione intitolata “Comando consigliato durante lo studio”Usa sempre questo comando quando studi e sviluppi:
g++ -std=c++17 -Wall -Wextra file.cpp -o programmaI warning sono tuoi alleati: leggili con attenzione e correggili sempre, anche quando il programma compila senza errori.