La programmazione in Linux: MAKE | ALTRI capitoli | |||
Compilare piccoli programmi, composti da uno o pochi altri file, è semplice. Compilare, invece, progetti più ampi, composti da decine e decine di file può rivelarsi un vero incubo. A meno che non si riesca, in qualche modo, ad automatizzarne il processo di compilazione. L'idea su cui si fonda l'utility make è semplice: il programmatore dice a make quali file desidera compilare e come compilarli, specificando anche eventuali dipendenze: make farà il resto. Il programmatore deve, semplicemente, scrivere e salvare le informazioni utili a make in un file di configurazione, che, se make viene lanciato senza alcun ulteriore parametro:
viene ricercato in uno dei tre file di default:
Il file Makefile è la chiave del processo di compilazione e di installazione di un package. Nella sua forma più elementare, il file Makefile è uno script il cui fine è la compilazione dei file "binari" di un package, che ne rappresentano la porzione eseguibile. Il file Makefile può, inoltre, eseguire l'aggiornamento di un package, senza dover necessariamente ricompilare ogni singolo file sorgente. In un qualche punto, il file Makefile lancia il compilatore cc o gcc. In realtà, si tratta di un preprocessore, di un compilatore C (o C++) e di un linker, invocati in quest'ordine. Questo processo converte il sorgente in file binari, i veri file eseguibili
( Using Make ). E' possibile specificare un diverso file di configurazione, utilizzando l'opzione
e/o indicare una directory in cui cercare il file Makefile:
È possibile includere più opzioni
Questo semplice comando compilerà tutti i file eseguibili necessari al package in questione. È bene ricordare, tuttavia, che make può anche servire ad installare i file nelle directory corrette:
oppure a rimuovere i file object obsoleti:
È possibile chiedere a make di non eseguire alcuna azione, ma di stampare i comandi che verrebbero eseguiti, con una delle seguenti opzioni:
È possibile chiedere a make di spostarsi in un'altra directory, prima di eseguire qualsiasi comando:
Per ottenere informazioni di debug, è possibile utilizzare l'opzione:
oppure:
È possibile chiedere a make di stampare il database delle regole e dei valori delle variabili, risultante dalla lettura del makefile, per poi:
Per usare make, è necessario scrivere un file, chiamato makefile, in cui si descrivono le relazioni esistenti tra i vari file che compongono il programma, oltre a pubblicare i comandi da eseguire per l'aggiornamento di ciascun file. In un programma, normalmente, il file eseguibile viene aggiornato a partire dagli object file, compilati, a loro volta, a partire dai file sorgente. Una volta creato il file makefile, ad ogni modifica apportata ai file sorgente sarà sufficiente eseguire:
per rieseguire le necessarie ricompilazioni. Il file di configurazione
Il file
dove
target può anche rappresentare un'azione da eseguire, quale:
Target, dipendenze e comando compongono una regola. Una regola può avere più di un comando: in questo caso, ogni comando occuperà una riga del file. Ciascuna riga dedicata ad un comando, deve iniziare con un carattere TAB. Se il file
A causa della enorme varietà di ambienti di compilazione, però, questo approccio diventerebbe a breve ingestibile. Il GNU Build System, o Autotools, è un insieme di strumenti di programmazione il cui compito è di aiutare il programmatore a rendere i package software portabili per la maggior quantità possibile di sistemi Unix o Unix-like. Il GNU Build System permette di compilare più programmi in soli due passi:
ed è composto da tre utility:
Se si dovesse eseguire lo script configure, ricordarsi di invocarlo come:
per essere certi di eseguire lo script corretto, quello presente nella directory corrente. Torniamo, ora, al file Makefile, vedendone un esempio. Ipotizziamo di avere un programma, composto dai seguenti file:
E' possibile inserire le informazioni relative alla compilazione del programma
Nella prima regola, informo make che il file new è da creare dai tre object file dichiarati ( main, display, prices ), mentre nelle regole successive informo make su come generare i tre object file. In questo modo, make ricompilerà il file main.c anche nel caso in cui fosse stato modificato uno dei file header dai quali dipende. L'utility make, infatti, inizia la sua indagine dal target della prima regola, presente nel file: nel nostro esempio, new, per verificare se le sue dipendenze sono soggette ad una qualche regola. Se scopre che per una dipendenza è stata scritta una regola, make esegue quella regola. La compilazione o la ricompilazione avviene solo nel caso in cui un file sorgente o uno dei file header presenti tra le dipendenze di una regola è più recente dell'object file corrispondente, oppure se l'object file non esiste. Nel nostro esempio, esiste una regola per ciascuna dipendenza di new. Quindi, nel nostro caso, eseguendo:
make leggerà il makefile presente nella directory corrente ed eseguirà la regola con target:
poi la regola con target:
poi la regola con target:
per poi tornare alla regola conclusiva, con target new (in realtà, la prima regola, chiamata default goal). Se make riceve un errore, interrompe immediatamente la compilazione, a meno che non sia stato lanciato con l'opzione
Affinchè tutto questo funzioni correttamente, i file target:
devono essere scritti e compilati nella corretta sequenza: in caso contrario, il processo di compilazione verrebbe interrotto. Ora che abbiamo informato make su come generare gli object file (
Poichè clean non è una dipendenza di new, quest'ultima regola non verrà mai eseguita, dando il comando make. Affinchè questa regola venga eseguita, dovremo scrivere:
Nel file di configurazione,
Un'osservazione importante: make sa che un object file ( .o ), normalmente, viene compilato da un file sorgente ( .c ) con lo stesso nome. Questo rende inutili le regole che contengono i comandi di compilazione di un sorgente nel suo object file. Il nostro makefile di esempio, quindi, potrebbe essere riscritto nel modo seguente:
|
||||
La programmazione in Linux: MAKE | Le guide di .bit: contenuto originale |