Costruire software
Nella pagina dedicata al linguaggio C hai compiuto il primo atto vero del mestiere del costruttore di software, perché hai scritto un programma dentro un semplice file di testo, l'hai consegnato al compilatore con una riga di comando e hai raccolto in cambio un file eseguibile capace di correre sul ferro reale, senza macchine virtuali né interpreti di mezzo, e tutto questo accadeva in un mondo piccolo e comodo, dove il programma intero sta in un foglio solo, dove la mente tiene ogni riga sott'occhio come gli attrezzi al chiodo del muro e dove sbagliare costa poco, perché rileggersi un foglio da cima a fondo è questione di minuti. Questa pagina apre la porta di quel cortile e ti porta sul cantiere vero, quello dove i programmi smettono di essere fogli solitari e diventano palazzi, e promette una cosa sola, e cioè che a fine lettura saprai riconoscere ogni strumento del banco professionista, capire perché esiste e usarlo con le tue mani, un esperimento dopo l'altro.
Per capire che cosa cambia davvero quando un programma cresce conviene misurare la scala del problema con calma, e allora immaginiamo una capanna di legno, la quale si costruisce in un pomeriggio tenendo tutto in mente senza disegni né regole, e adesso immaginiamo che quella capanna, stagione dopo stagione, venga ingrandita fino a diventare un palazzo di cento piani, perché è esattamente questo il salto che compie un programma quando passa da una pagina di codice, circa cinquanta righe scritte in un'ora buona, alle centomila righe di una grande applicazione e poi ai cinque milioni di righe che il libro di Tanenbaum racconta come una cifra del tutto normale per un sistema operativo moderno. La capanna reggeva perché la tenevi in testa tutta intera, il palazzo regge soltanto se qualcuno porta disegni, divide i mestieri e monta le impalcature, e la buona notizia è che le impalcature del software esistono già, le ha inventate gente che ha costruito palazzi prima di noi, e adesso noi le esaminiamo una per una con la calma di chi smonta un banco per capirne il meccanismo.
Percorriamo il cantiere seguendo l'ordine in cui le cose accadono davvero sulla scrivania di chi sviluppa, e così cominceremo dall'editor, il banco dove si scrivono i sorgenti, passeremo al compilatore e al linker, cioè alla squadra che traduce i pezzi e li unisce in un unico eseguibile, apriremo il magazzino delle librerie per capire la differenza fra gli attrezzi che ti porti a casa e quelli che restano in comune, faremo conoscenza con make e il suo registro che ricorda cosa va ritradotto dopo ogni modifica, impareremo l'arte antica del debugging, cioè la caccia al guasto, proveremo la scuola più alta del mestiere, che è leggere il codice degli altri fino ai sorgenti di MINIX, apriremo l'archivio che conserva ogni versione del progetto, seguiremo il percorso dal sorgente scaricato al programma installato e infine parleremo della documentazione, il manuale che si scrive mentre si costruisce, prima degli esperimenti sul tuo computer, perché di questo mestiere ci si innamora sporcandosi le dita.
Quello che cambia per primo, quando il programma cresce, è la testa di chi lo scrive, perché la memoria di lavoro della mente umana resta sempre della stessa misura mentre il codice si moltiplica, e questa disuguaglianza fra una mente ferma e un palazzo che cresce è il motore di tutto quello che vedremo, dato che ogni strumento di questa pagina esiste per rispondere alla stessa domanda, e cioè come fa una persona sola, oppure un gruppo di persone che devono intendersi fra loro, a costruire e a curare nel tempo una cosa troppo grande per essere abbracciata con un solo sguardo. La risposta che il mestiere ha perfezionato nel corso di mezzo secolo è antica come l'artigianato, perché consiste nel dividere il palazzo in stanze, attribuire a ogni stanza un mestiere ben preciso, scrivere le misure su cartelli che tutti possono consultare e tenere un registro che dica in che punto del cantiere si trova ogni cosa, e noi vedremo che ognuna di queste quattro abitudini ha un corrispondente preciso fra gli strumenti del software.
Cominciamo dal banco di lavoro, l'editor, il programma con cui si scrivono e si
modificano i file di testo che chiamiamo sorgenti, ed esso è paragonabile al banco del falegname,
sul quale l'artigiano passa la giornata intera, dove ogni attrezzo ha il suo gancio e dove la
qualità del legno si sente sotto le dita, perché è dentro finestre piene di righe colorate che il
costruttore trascorre la maggior parte delle sue ore e per questo la scelta dell'editor è una di
quelle questioni che gli artigiani discutono con calore da decenni, con nomi che suonano come
vecchie marche di scalpelli, dal veterano vi nato negli anni settanta fino agli
editor moderni che compiono in un lampo rifornimenti come completare i nomi e cercare un pezzo in
mille file. Quello che conta sapere, per il momento, è soltanto che il sorgente resta un testo
semplice, leggibile anche dopo giorni, e che questa leggibilità è un tesoro, perché qualsiasi
strumento futuro, compreso quello che inventerai tu, può leggerlo e capirlo.
Il primo gesto che il palazzo impone è la divisione del lavoro in tanti file, e conviene capire subito perché, dato che un file unico di centomila righe somiglierebbe a una stanza grande quanto un campo, dentro la quale ogni passo per raggiungere un attrezzo costerebbe fatica, mentre tanti file di dimensioni modesti somigliano a stanze separate, ciascuna con la sua porta, il suo scopo e il suo custode. In C questa divisione veste i file in due modi diversi, perché i file che portano la sostanza hanno estensione .c mentre quelli che portano le misure condivise, chiamati file di intestazione o header, hanno estensione .h e vengono inclusi dentro i primi con un'istruzione che ordina al traduttore di andare a leggere le definizioni comuni, un po' come un cartello dell'officina dove sono scritte le misure che tutti i falegnami rispettano per far combaciare i pezzi alla prima. Il meccanismo ha un'anima, chiamata preprocessore, che legge il file riga per riga e, quando incontra un'istruzione di inclusione, va a prendere fisicamente l'header nominato, espande le macro, risolve le parti condizionali riservate a certe macchine e passa il risultato alla fase seguente come se i due file fossero stati incollati in un foglio solo, e questo stratagemma permette per esempio a MINIX di tenere separate le righe scritte per processori Intel da quelle scritte per altre architetture, attivando il blocco giusto a seconda del tavolo su cui si costruisce.
Quando il preprocessore ha finito di incollare, entra in scena il cuore del traduttore, il compilatore vero e proprio, che nella pagina precedente hai usato come una scatola unica e che adesso possiamo aprire e osservare all'opera, perché esso prende ogni file .c e lo trasforma in un file oggetto con estensione .o, il quale contiene già istruzioni binarie scritte per la macchina di destinazione, le stesse che la CPU eseguirà direttamente, e su questo punto il libro Modern Operating Systems di Andrew S. Tanenbaum invita a fermarsi un istante e a fissare bene la differenza, perché nel mondo del C l'oggetto è già carne del processore e non esiste nulla di simile al bytecode di Java o di Python, che invece è un dialetto intermedio affidato a interpreti oppure a compilatori just-in-time, cioè a traduttori dell'ultimo minuto che lavorano mentre il programma è già in corsa. Il file oggetto, però, resta soltanto un pezzo del mobile, con i bordi grezzi e i riferimenti agli altri pezzi ancora spiegati a parole, perché il compilatore che ha tradotto un file da solo ignora dove finiranno, nella memoria definitiva, le funzioni scritte negli altri file, ed è proprio questa incompletudine ordinata che consegna la parola all'attrezzista del cantiere.
L'attrezzista si chiama linker, dal verbo inglese che significa collegare, ed è il programma che raccoglie tutti i file oggetto e li monta in un unico eseguibile, compiendo tre gesti che vale la pena conoscere per nome. Il primo gesto è risolvere i riferimenti, cioè tradurre in indirizzi veri ogni chiamata che un pezzo rivolge a una funzione nata in un file diverso, il secondo è rilocare, vale a dire sistemare nella pianta definitiva del programma ogni pezzo che il suo traduttore aveva provvisoriamente misurato a partire da zero, e il terzo è attingere al magazzino delle librerie le funzioni richieste, così che quando il linker ha finito il risultato, tradizionalmente chiamato a.out nei sistemi della famiglia UNIX, è un file unico e autosufficiente che il sistema operativo sa caricare e far partire. Nota bene la divisione dei mestieri, perché essa è la lezione portante di tutto il capitolo, visto che ogni compilatore lavora al buio sul proprio pezzo senza sapere nulla degli altri, esattamente come il falegname che taglia una trave secondo le misure del cartello senza conoscere la facciata intera, e il linker, come il capocantiere, è l'unico che vede il palazzo completo e decide dove ogni trave va appoggiata.
Intorno al cantiere esiste un magazzino di attrezzi già fatti che si chiama libreria, e la parola va presa alla lettera, perché una libreria è una raccolta di funzioni scritte da altri, collaudate da milioni di mani e messe a disposizione di chiunque le chiami, così che il costruttore raramente parte dal legno grezzo, dato che perfino il piccolo programma della pagina precedente, quello che stampava un saluto, attingeva già alla libreria del C per parlare con lo schermo senza conoscere un solo segnale elettrico della scheda video. MINIX mostra l'anatomia completa di questo magazzino con chiarezza didattica, perché nei suoi sorgenti esiste una directory chiamata lib che raccoglie il codice di tutte le procedure di libreria, le quali altro non fanno che avvolgere le chiamate al sistema in vestiti comodi, e lo stesso sistema operativo, quando ha bisogno di leggere un file, si rivolge a quelle procedure come un falegname si rivolge alla cassetta comune del laboratorio quando gli serve una pialla già regolata.
Nel magazzino convivono due specie di librerie, e distinguerle è una delle cose più utili che questa pagina possa consegnarti. La prima specie è la libreria statica, con estensione .a, il cui destino è di essere copiata dentro l'eseguibile al momento del collegamento, funzione per funzione, così che il programma finito porta i suoi attrezzi in proprio, come il falegname che possiede una cassetta tutta sua e può lavorare ovunque, anche in casa di un cliente lontano dal laboratorio, con la comodità dell'autonomia e il prezzo di una cassetta ripetuta in ogni officina della città. La seconda specie è la libreria condivisa, con estensione .so, che resta invece un unico esemplare sul disco e in memoria al servizio di tutti i programmi della macchina, un po' come la cassetta degli attrezzi del condominio che ogni inquilino attinge senza doverne comprare una copia, con il vantaggio che cento programmi occupano la memoria di cento programmi più un sola libreria anziché cento copie di essa, e con la magia aggiuntiva che riparare l'esemplare unico sistema in un colpo solo tutti i programmi che vi attingono.
Fino a questo punto il cantiere sembra un luogo ragionevole, ma immaginiamo adesso di correggere una sola riga, una sola, dentro un cantiere di cinquanta mila file, e chiediamoci quanto dovrebbe durare la ritraduzione dell'intero palazzo per quella piccola parola cambiata, perché far ripassare il compilatore su cinque milioni di righe costerebbe ore e il libro di Tanenbaum racconta che i primi costruttori vissero esattamente questo supplizio, finché qualcuno capì che il problema stava nell'affidare il ricordo alla sola memoria umana, da cui nacque il magazziniere del cantiere, il programma make, il quale legge un registro chiamato Makefile e compie il miracolo modesto di riconoscere, dopo ogni modifica, soltanto i pezzi che devono passare di nuovo sotto il banco del compilatore e lasciare intatti tutti gli altri. Il trucco sta nel registro, che dichiara per ogni pezzo di quali ingredienti quel pezzo dipende, e nel paragone domestico esso somiglia a una lista della spesa intelligente, quella che ti permette di tornare dal negozio con la sola cipolla mancante anziché ricomprare l'intero frigorifero, così come make, accorgendosi che un file sorgente è stato toccato dopo la nascita del suo oggetto, fa ritradurre quello e lascia in pace il resto del quartiere.
Per apprezzare la disciplina che questo registro impone conviene osservare come ragiona sulle conseguenze, dato che una modifica a un header diffuso su migliaia di file si comporta come un sasso nello stagno, spingendo make a ritradurre tutti i file che lo includono, mentre una modifica a un angolo remoto dell'edificio tocca pochi vicini e lascia il resto del palazzo in silenzio, e in ogni caso la quantità di lavoro si riduce al minimo indispensabile, un risparmio che nei cantieri grandi misura la differenza fra produrre e impazzire. Tanenbaum fa notare che scrivere a mano un registro così capillare diventa esso stesso un lavoro delicato, tanto che in certi progetti esistono strumenti che lo redigono in automatico, e MINIX porta la stessa disciplina fino in fondo, perché ogni directory della sua alberatura custodisce un Makefile locale che governa la propria stanza, mentre un Makefile capo, sistemato nella directory degli strumenti, orchestra la ricostruzione dell'intero sistema copiando prima le intestazioni aggiornate nel posto dove il compilatore si aspetta di trovarle, così che ricompilare MINIX per intero, l'esercizio finale che la pagina sul kernel ti aveva promesso, è questione di pochi comandi ben ordinati.
Ogni costruttore onesto sa che le assi, per quanto bene tagliate, a volte scricchiolano sotto il peso, e nel mestiere del software il punto che scricchiola si chiama bug, parola inglese che significa insetto e che conserva la leggenda di una falena rimasta incastrata fra i relè di un calcolatore antico, e dare la caccia a questo insetto si chiama debugging, e nella nostra officina questa caccia somiglia molto al mestiere del meccanico che lascia il motore al minimo e si china ad ascoltare, perché il guasto raramente si presenta con un cartello luminoso e più spesso si lascia indovinare da un ticchettio storto, da un valore che non torna, da una riga che stampa una parola sbagliata al posto della giusta. L'arma più antica e più usata resta lo stampare messaggi intermedi, cioè far dire al programma, mentre lavora, che cosa sta facendo e quali numeri tiene in mano, un po' come infilare un dito in ogni giunto del motore per sentire dove arriva il calore, e la regola d'oro che i vecchi consegnano ai giovani è di spezzare il percorso a metà e chiedersi da che parte sta sbagliando il valore, restringendo la zona sospetta a ogni prova, finché l'insetto non resta rinchiuso in una scatola così piccola che non gli resta alcun angolo dove nascondersi.
Accanto a quest'arte artigiana cammina lo strumento industriale, il debugger, dal verbo che significa togliere gli insetti, ed è un programma che ti prende per mano e ti fa camminare dentro il tuo programma mentre questo accade, un passo alla volta, con le sue fermate a richiesta chiamate punti di interruzione, piazzate con un colpo di pennello sulla riga sospetta come quando si stacca un fusibile per capire fin dove arriva la corrente, e con la possibilità di ispezionare a ogni passo il valore di ogni variabile, il contenuto di ogni registro e il percorso esatto delle chiamate che ti hanno portato fin lì. Perché il debugger possa fare tutto questo, il compilatore deve essere invitato a conservare le informazioni di accompagnamento, un gesto che in C si compone aggiungendo un'opzione alla riga di comando e che i libri consigliano come abitudine quotidiana durante lo sviluppo, perché un eseguibile munito di queste etichette risponde alle domande del meccanico con una precisione che il motore al minimo, lasciato a se stesso, non potrebbe mai regalare.
Esiste infine una scuola superiore di questo mestiere, e la si trova in un luogo che pochi immaginano, perché essa abita dentro il codice scritto da altri, dato che un sorgente ben fatto è come la bottega di un maestro artigiano, dove l'apprendista impara più guardando le mani che lavorano che ascoltando le parole, e leggere come un costruttore esperto ha affrontato un problema è una crescita che nessun esercizio inventato da un insegnante riesce a eguagliare. Qui entra in scena MINIX con la sua offerta più generosa, dato che i suoi sorgenti, nella versione spiegata nel libro Operating Systems, Design and Implementation di Andrew S. Tanenbaum e Albert S. Woodhull, sono abbastanza piccoli, dell'ordine delle decine di migliaia di righe, da poter essere letti da una persona sola con la calma di chi affronta un romanzo corposo, e la pagina dedicata al kernel e a MINIX ti aveva già lanciato questo invito, promettendoti che il codice di un sistema operativo vero poteva essere percorso riga per riga, promessa che manteniamo adesso mostrando come quella lettura sia organizzata per stanze e per piani.
La chiave di lettura di MINIX è la sua alberatura, cioè il modo in cui i file sono disposti dentro directory annidate come gli armadi di una casa ben tenuta, con i sorgenti che vivono sotto una directory chiamata src e con le intestazioni raccolte in include, dove risiede la copia maestra che i Makefile copiano nel posto d'uso prima di ogni ricostruzione, un trucco che permette di tenere tutto il necessario dello sviluppo in un unico luogo e di sperimentare copie parallele dell'intero albero senza paura di confondersi. Sotto la radice si aprono poi i reparti del palazzo, e cioè kernel per il cuore che governa processi, messaggi e interruzioni, drivers per i servitori che parlano con dischi e schede, servers per i servizi come il gestore dei file e quello dei processi, lib per il codice delle librerie, tools per gli strumenti di ricostruzione del sistema e una folla di comandi d'uso quotidiano raccolti in commands, con la versione del libro che lascia da parte le parti opzionali per restare leggibile in un semestre di studio, e il consiglio dei suoi autori è di leggere seguendo le chiamate dal programma principale in avanti, tenendo due segnalibri, uno sul testo e uno sul codice, come si cammina nella pianta di un palazzo guardando due stanze alla volta.
Il palazzo che resta in piedi per anni, con tante mani che vi passano, esige una memoria collettiva, ed è questo il mestiere del controllo di versione, che è un archivio pignolo che ricorda ogni versione del progetto con la sua data, il suo autore e un appunto scritto a mano, e il paragone che ci aiuta a vederlo è il registro di classe della scuola, quel libro rigato dove ogni mattina si segna chi è presente, chi è assente e chi è uscito in anticipo con la giustificazione firmata, perché quando qualcosa va storto in classe, e qualcosa va sempre storto in classe, il registro permette di risalire a chi fece cosa e quando, senza accuse e senza misteri. Nel software questo registro prende nomi come git, e ogni suo ingresso, chiamato commit negli ambienti di lavoro anglosassoni, è una fotografia completa del cantiere in un istante preciso, con la possibilità di tornare a qualsiasi fotografia, di confrontarle e di capire perché una certa riga esiste proprio lì, grazie all'appunto che l'accompagna.
La potenza di questo archivio si misura nel momento del disastro, perché quando una modifica combina un guasto grosso, il costruttore che lavora sotto versione ha la fortuna di tornare con calma alla fotografia di ieri, ripartendo da lì come una classe che rientra in aula dopo la gita e ritrova i banchi esattamente come li aveva lasciati. Le versioni moderne dell'archivio aggiungono persino la possibilità di tenere sul tavolo due bozze parallele dello stesso progetto, una per la riparazione urgente e una per il lavoro lungo, e di fonderle quando sono pronte, un gioco di rami che i libri chiamano ramificazione e che assomiglia alla doppia matita del disegnatore tecnico, il quale tira linee di prova su un foglio trasparente, sicuro di poter sempre tornare alla linea buona. Il registro di classe del software, insomma, è scritto in modo che nessuna pagina possa mai essere strappata, e gli strumenti di cui parla questa pagina, dal compilatore al debugger, custodiscono ciascuno il proprio registro da decenni, segno che l'abitudine vale più di qualsiasi strumento nuovo.
Con gli strumenti del banco a posto, possiamo seguire il rito di passaggio che ogni
apprendista del software libero compie una volta nella vita, e cioè il percorso che porta dal
sorgente appena scaricato al programma installato e funzionante, percorso che quasi tutti i
progetti aperti documentano con tre gesti consacrati, il configurare, il compilare e
l'installare, e il paragone che ci illumina è il mobile da montare comprato in un grande
magazzino, quella scatola piatta con le assi avvolte nella carta, i vitini nel sacchetto e
il libretto di istruzioni che promette un tavolo in un pomeriggio di lavoro onesto. Il primo
gesto, lanciato con ./configure, è il montatore che entra in casa tua e prende le
misure, perché esso ispeziona la tua macchina per scoprire dove stanno il compilatore, quali
librerie ci sono già e quali mancano, e dispone sul tavolo un Makefile su misura per quella
stanza precisa. Il secondo gesto, lanciato con make, è il montaggio vero, con la
traduzione di tutti i pezzi e la loro unione nell'eseguibile finale, e il terzo, lanciato con
sudo make install, è il trasporto del mobile finito nella stanza giusta della casa,
dove il sistema operativo ripone i programmi che tutti possono chiamare.
Resta da parlare del libretto di istruzioni del mobile, e cioè della documentazione, che è il manuale d'uso e di manutenzione del software e che segue la regola d'oro di essere scritto mentre si costruisce, perché il costruttore che rimanda la spiegazione a cantiere chiuso scopre di aver dimenticato metà dei perché, esattamente come chi promette di ricordarsi la ricetta dopo aver sparecchiato scopre di ricordare soltanto che nel piatto c'era qualcosa di buono. La documentazione di un progetto vive in tre stanze, il file di benvenuto che spiega cosa sia il progetto e come si monti, le pagine di manuale che spiegano come si usi ogni comando con le sue opzioni e i suoi esempi, e i commenti dentro il codice, quelle righe che il compilatore salta ma che raccontano al lettore umano le ragioni di una scelta bizzarra, e i sorgenti di MINIX sono un modello anche da questo punto di vista, perché Tanenbaum e Woodhull li hanno curati come un libro da leggere, con la prosa del codice pulita, i nomi parlanti e le parti oscure spiegate nel testo che le affianca. Chi scrive la documentazione mentre costruisce, insomma, lascia accesa la luce per chi entrerà nella stanza dopo di lui, e quel chi potresti essere tu, oppure tu stesso fra sei mesi, che è il visitatore più frequente di ogni cantiere.
Tiriamo le fila di tutto il cantiere e fermiamoci un istante sul significato d'insieme, perché forse la cosa più importante che questa pagina possa dirti è che ogni strumento che hai visto, l'editor, il compilatore, il linker, il make, il debugger, l'archivio delle versioni e persino lo stesso MINIX, è esso stesso software libero, cioè un mobile il cui disegno è pubblico e che chiunque può studiare, modificare e ricostruire in casa con gli stessi gesti che hai imparato qui. Questo dettaglio cambia la prospettiva dell'apprendista in modo profondo, dato che gli attrezzi del mestiere smettono di essere oggetti magici acquistati dietro una vetrata e diventano mobili costruiti da altri falegnami che hanno lasciato i disegni sul tavolo, e studiare un attrezzo significa poterne leggere i sorgenti, compilarli con le proprie mani e persino correggerli, come racconta la storia intera del software libero, che è la storia di migliaia di persone che hanno migliorato gli strumenti condivisi proprio perché i disegni erano aperti. Per chi desidera costruire software in autonomia questo è il messaggio di fondo, e cioè che il banco su cui lavorano i professionisti è esattamente il tuo, che le impalcature del palazzo sono le stesse che puoi piantare in giardino, e che l'unica cosa che separa il lettore dal costruttore è la pratica costante, la quale adesso può cominciare sul tuo computer, un esperimento dopo l'altro.
La teoria, per quanto raccontata con calma, resta nebbia finché non la si tocca con le mani,
quindi adesso lascia la poltrona, accendi il tuo computer e vieni a fare otto esperimenti sul
tavolo vero, tutti dentro un terminale, quel finestrone scuro dove il computer accetta le tue
richieste scritte e le esegue alla lettera, e se qualche strumento mancasse dal tuo banco niente
paura, perché ogni sistema ha un gestore di pacchetti, cioè un magazziniere che installa
il necessario in pochi colpi, con apt sui sistemi della famiglia Debian, con
dnf su quelli Fedora e con brew sul Mac. Il primo esperimento è una semplice ispezione del banco, e consiste nello
scrivere gcc --version, make --version e git --version,
tre righe che chiedono a ciascun attrezzo di presentarsi dichiarando la propria età, e se tutti
e tre rispondono con un numero di versione il tuo cantiere è già completo e puoi procedere
sicuro verso gli esperimenti seguenti.
Per il secondo esperimento riprendi in mano il piccolo programma che avevi scritto nella
pagina precedente, quello che stampava il saluto, e questa volta scendi un gradino dentro il
meccanismo che prima usavi come scatola unica, compilando in due tempi distinti con
gcc -c ciao.c, che produce il file oggetto senza costruire l'eseguibile, e poi con
gcc ciao.o -o ciao, che collega quel pezzo unico e sforna il programma finito, e
fra un passo e l'altro guarda dentro la cartella con ls per vedere comparire il
file .o, il pezzo grezzo che prima ti sfuggiva. Prova poi a lanciare gcc ciao.c
lasciando stare il nome di uscita, e osserva il file chiamato a.out che appare come per magia,
il nome tradizionale che il linker dava ai propri figli, e capirai che la scatola unica che
usavi era soltanto i due gesti rapidi che hai appena separato con le tue mani, uno dopo l'altro.
Per il terzo esperimento spezza il programma in due file come fanno i palazzi veri, mettendo
per esempio il calcolo dentro un file chiamato aiuto.c e la stampa dentro un file chiamato
ciao.c, poi traducili separatamente con gcc -c ciao.c e gcc -c aiuto.c
e infine uniscili con gcc ciao.o aiuto.o -o ciao, così che il linker,
quell'attrezzista che adesso conosci per nome, risolva con le sue mani il riferimento fra i due
file. Per vederlo all'opera digita nm aiuto.o, un comando che svela l'elenco dei
nomi custoditi nel pezzo grezzo, e nota come il nome della funzione ci sia anche se il file da
solo ignora ancora dove dormirà, poi prova a togliere un punto e virgola da uno dei due file e
ricompila, e osserva con attenzione il messaggio che ricevi, perché capire la differenza fra
l'errore del compilatore, che parla di grammatica, e il lamento del linker, che parla di pezzi
mancanti, è una delle abilità che ti faranno sentire a casa dentro il cantiere.
Per il quarto esperimento scrivi con l'editor un Makefile accanto ai due file, dichiarando in
una riga che l'eseguibile dipende dai due oggetti e in una riga sottostante, fatta cominciare da
un carattere di tabulazione, che il compilatore deve unirli, poi aggiungi le due regole che
dicono come nascano i due oggetti dai due sorgenti, senza fretta e controllando che ogni riga
d'ordine cominci davvero con la tabulazione, perché il registro è pignolo su questo punto. Lancia
poi make per la prima volta e guarda il cantiere costruire tutto, tocca un sorgente
con touch aiuto.c, che finge di averlo appena modificato aggiornandone l'orario,
rilancia make e osserva il registro ritradurre il solo pezzo toccato, poi
rilancialo subito ancora una volta e gusta il silenzio solenne di un magazziniere che non ha
nulla da fare, perché il registro è già in ordine e la lista della spesa, stavolta, è vuota.
Per il quinto esperimento visita il magazzino comune con ls /usr/lib, la
directory dove il tuo sistema ripone le librerie, e scorri l'elenco alla ricerca dei nomi che
finiscono in .a e in .so, le due specie che hai imparato a distinguere in teoria, poi chiedi al
tuo salutatore di rivelare le sue dipendenze con ldd ./ciao e resta sorpreso nello
scoprire che perfino quel programmino minuscolo attinge alla libreria condivisa del C per
parlare con lo schermo. Per chiudere il cerchio compila una seconda copia con
gcc -static ciao.c -o ciao-statico, che incolla dentro l'eseguibile tutti gli
attrezzi della cassetta propria, e confronta le due creature con ls -l, notando di
quanto ingrassi la versione autosufficiente rispetto alla magra variante che attinge alla
cassetta del condominio, e avrai toccato con mano il compromesso fra autonomia e risparmio che
le due specie propongono a ogni costruttore.
Per il sesto esperimento diventa meccanico per un'ora, e comincia introducendo un guasto
voluto nel programma, per esempio usando una variabile a cui hai dimenticato di dare un valore
iniziale, poi compila con gcc -g ciao.c -o ciao, dove l'opzione chiede al
compilatore di conservare le etichette di accompagnamento, ed entra nel laboratorio del
debugger con gdb ./ciao. Dentro di esso imposta una fermata sulla riga sospetta,
fai ripartire il programma con il comando per correre, e quando l'esecuzione si ferma al
cartello cammina un passo alla volta, chiedendo a
ogni passo il valore della variabile sospetta, finché non vedi con i tuoi occhi l'istante
preciso in cui il valore impazzisce e l'insetto resta sotto la lente. Prima di uscire prova
anche la via artigiana e metti una stampa intermedia nel mezzo del programma, quella del
meccanico che appoggia il dito sul giunto, e confronta le due cacce, perché capire quando serve
lo strumento industriale e quando basta il dito esperto è la saggezza del mestiere.
Per il settimo esperimento apri il registro di classe creando con git init una
cartella di prova, copia dentro il programma del saluto, poi metti il file sotto sorveglianza
con git add ciao.c e chiudi la prima fotografia con git commit, che
ti chiederà un appunto da scrivere a mano, e sceglilo con cura come se firmassi il registro,
perché fra sei mesi quella frase sarà la tua unica testimone. Modifica poi il programma
cambiando il saluto, ripeti i due gesti della fotografia e chiedi al registro di mostrarti le
sue pagine con git log, dove compariranno data, autore e appunto di ogni
fotografia, e infine prova la magia del ritorno cancellando una riga dal file
e chiedendo all'archivio di riportarti la versione della fotografia precedente, così che tu
possa vedere la classe rientrare in aula con i banchi esattamente come erano.
Per l'ottavo e ultimo esperimento compi il rito di passaggio per intero, scaricando da
internet i sorgenti di un programmino libero e leggero, magari un gioco da terminale o un
piccolo strumento di testo, scompattalo con tar xzf seguito dal nome dell'archivio
ed entra nella cartella che nasce così. Prima di toccare nulla leggi il file di benvenuto e il
file di istruzioni del montaggio che trovi dentro, poi compi i tre gesti consacrati in ordine,
cioè ./configure per far prendere le misure della tua stanza, make
per montare i pezzi e sudo make install per trasportare il mobile finito nella
stanza di sistema, e osserva durante il viaggio i messaggi che scorrono, perché raccontano in
diretta ogni pezzo tradotto e ogni collegamento risolto. Quando il programma nuovo risponde al
suo nome da qualunque cartella ti trovi, avrai compiuto con le tue mani il percorso
che milioni di persone ripetono ogni giorno, e la prossima volta che installerai qualcosa
saprai riconoscere, dietro la cortesia di un clic, l'intero cantiere che hai visitato in questa
pagina.
Questa pagina attinge soprattutto al capitolo introduttivo dedicato al mondo secondo il C, e in particolare alla sezione 1.8.3 sui grandi progetti di programmazione, del libro Modern Operating Systems di Andrew S. Tanenbaum, dove il preprocessore, i file oggetto, il linker, le librerie e il registro del make compaiono tutti nel disegno dell'eseguibile, e in secondo luogo alla sezione 2.6 del libro Operating Systems, Design and Implementation di Andrew S. Tanenbaum e Albert S. Woodhull, che descrive l'organizzazione dell'albero dei sorgenti di MINIX 3, la disciplina delle intestazioni, i Makefile di ricostruzione del sistema e la directory delle librerie.
Il cantiere del software, adesso, ti appartiene, e la domanda che resta in piedi è dove vada a finire tutto quello che costruisci, perché un programma chiuso in una stanza sola racconta soltanto metà della sua storia, e l'altra metà comincia quando due computer imparano a parlarsi attraverso fili, onde e strade invisibili. È per questo che il percorso prosegue verso la pagina successiva, che apre il modulo sulle reti di calcolatori, dove scopriremo come i messaggi viaggiano da una macchina all'altra, come le strade della rete vengono numerate e nominate, e come il tuo piccolo programma, quello del saluto, potrebbe un giorno essere letto da una persona che si trova dall'altra parte del mondo, esattamente come tu hai appena letto il pensiero di chi ha costruito gli attrezzi che ora stanno sul tuo banco.