Lezione 3 di 7 · 10 min di lettura

Un progetto vero

Un file solo va bene per un saluto. Per tutto il resto c'è c3c init, la struttura standard e i comandi build e run.

Dal file singolo al progetto

Finora abbiamo compilato un file alla volta con c3c compile. Funziona, ma appena il programma cresce (più file, librerie esterne, opzioni di compilazione) diventa scomodo ripetere ogni volta tutto a mano.

C3 ha una soluzione integrata: il progetto. Un progetto è una cartella con una struttura standard e un file project.json che descrive come compilare. Il compilatore fa il resto.

Creare un progetto

Dalla cartella degli esercizi:

terminale
c3c init first_project
cd first_project

c3c init crea una cartella con dentro tutto questo:

output
first_project/
├─ build/          ← qui finiscono gli eseguibili e i file temporanei
├─ docs/           ← documentazione
├─ lib/            ← librerie C3 esterne (cartelle .c3l)
├─ resources/      ← immagini, suoni, file di dati
├─ scripts/        ← script di supporto
├─ src/            ← IL TUO CODICE
│  └─ main.c3
├─ test/           ← test automatici
├─ LICENSE
├─ project.json    ← la configurazione del progetto
└─ README.md

Sembra tanto, ma quasi tutte le cartelle sono vuote. Le uniche due cose che contano oggi sono src/main.c3 (il codice) e project.json (la configurazione). Il resto lo useremo quando servirà.

Il file principale

Apri src/main.c3. Il compilatore ci ha già messo un Hello World, con una novità:

src/main.c3
module first_project;
import std::io;

fn int main(String[] args)
{
	io::printn("Hello, World!");
	return 0;
}

Due cose nuove:

  • module first_project; dichiara che questo file appartiene al modulo first_project. In un progetto ogni file dice a quale modulo appartiene; i moduli sono il modo in cui C3 organizza e separa il codice. Ne parleremo a fondo in un modulo dedicato del corso.
  • fn int main(String[] args) è la versione “completa” di main: restituisce un int (il codice di uscita, return 0; = tutto bene) e riceve args, la lista degli argomenti passati da riga di comando. Per ora non li useremo, ma non danno fastidio.

Compilare ed eseguire

Dentro la cartella del progetto:

terminale
c3c run
output
Program linked to executable 'build/first_project'.
Launching ./build/first_project
Hello, World!
Program completed with exit code 0.

c3c run compila tutti i file in src/ e lancia il risultato. L’eseguibile finisce in build/, così la cartella del codice resta pulita.

Se vuoi solo compilare, senza lanciare:

terminale
c3c build
./build/first_project

E per buttare via tutto ciò che è stato compilato e ripartire da zero:

terminale
c3c clean

Quiz

Sei nella cartella di un progetto e hai modificato src/main.c3. Qual è il comando più rapido per vedere il risultato?

Uno sguardo a project.json

Non serve capirlo tutto adesso, ma vale la pena sapere che esiste. Aprilo: è un file JSON, lo stesso formato usato da mezzo web.

project.json (estratto)
{
	"langrev": "1",
	"warnings": [ "no-unused" ],
	"dependency-search-paths": [ "lib" ],
	"dependencies": [ ],
	"version": "0.1.0",
	"sources": [ "src/**" ],
	"test-sources": [ "test/**" ],
	"output": "build",
	"targets": {
		"first_project": {
			"type": "executable"
		}
	},
	"opt": "O0"
}

(Il file vero è pieno di commenti che spiegano ogni voce: leggili, sono utili.)

Le voci interessanti:

  • sources: dove cercare i file .c3 (src/** = tutto ciò che sta dentro src, sottocartelle incluse).
  • dependencies: le librerie esterne da usare (vuoto per ora).
  • targets: cosa produrre. Qui un eseguibile chiamato first_project. Un progetto può avere più target, per esempio una libreria e un programma che la usa.
  • opt: il livello di ottimizzazione. O0 = nessuna ottimizzazione e tutti i controlli di sicurezza attivi, comodo mentre sviluppi; i livelli più alti (fino a O5) rendono il programma sempre più veloce, e da O2 in su spengono alcuni controlli di sicurezza in cambio di velocità.
Dettagli nerd Cosa fa l'ottimizzatore?

Con l’ottimizzazione attiva, il compilatore riscrive il tuo programma in una versione equivalente ma più veloce: calcola in anticipo le operazioni di cui conosce già il risultato (60 * 60 diventa direttamente 3600), elimina il codice che non viene mai eseguito, e tiene i valori usati spesso nei registri, le pochissime celle di memoria che stanno dentro il processore, molto più veloci della RAM.

Il prezzo: la compilazione è più lenta, e l’eseguibile assomiglia meno al codice che hai scritto, cosa che rende più difficile seguirlo passo passo con un debugger. Per questo si sviluppa con O0 e si ottimizza solo alla fine.

Esercizio · sul tuo computer

Il tuo primo progetto

  1. Crea un progetto chiamato exercises con c3c init exercises.
  2. Entra nella cartella e lancia c3c run. Deve stampare Hello, World!.
  3. Modifica src/main.c3 per stampare una frase a tua scelta, e rilancia c3c run.
  4. Lancia c3c build, poi trova l’eseguibile in build/ e lancialo a mano.

Se ogni passo ha funzionato, segna l’esercizio come fatto. Da ora in poi puoi decidere tu se fare gli esercizi in questo progetto o in file singoli.

Ricapitolando

  • c3c init name crea un progetto con la struttura standard.
  • Il codice va in src/, gli eseguibili finiscono in build/.
  • c3c run compila e lancia; c3c build compila soltanto; c3c clean pulisce.
  • module name; in cima a ogni file dice a quale modulo appartiene.
  • fn int main(String[] args) è la forma completa di main.

Bene: sai installare, scrivere, compilare, organizzare. È ora di far pensare il programma. Prossima lezione: variabili e tipi.