[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [volume] [parte]


Capitolo 540.   Automazione della compilazione: Make e file-make

La compilazione di un programma, in qualunque linguaggio sia scritto, può essere un'operazione molto laboriosa, soprattutto se si tratta di aggregare un sorgente suddiviso in più parti. Una soluzione potrebbe essere quella di predisporre uno script che esegue sequenzialmente tutte le operazioni necessarie, ma la tradizione impone di utilizzare il programma Make.

Uno dei vantaggi più appariscenti sta nella possibilità di evitare che vengano ricompilati i file sorgenti che non sono stati modificati, abbreviando quindi il tempo di compilazione necessario quando si procede a una serie di modifiche limitate.

540.1   Make

Make, per la precisione l'eseguibile make, viene utilizzato normalmente assieme a un file, il file-make (o makefile), il cui nome può essere generalmente makefile o Makefile, dove tra i due si tende a preferire l'ultimo con l'iniziale maiuscola. Il file-make serve a elencare a Make le operazioni da compiere e le interdipendenze che ci sono tra le varie fasi.

Make può anche essere usato da solo, senza file-make, per compilare un solo sorgente; in questo caso, tenta di determinare l'operazione da compiere più adatta, in base all'estensione del sorgente stesso. Per esempio, se esiste il file prova.c nella directory corrente, il comando

make prova[Invio]

fa sì che make avvii in pratica il comando seguente:

cc -o prova prova.c[Invio]

Se invece esistesse un file-make, lo stesso comando, make prova, avrebbe un significato diverso, corrispondendo alla ricerca di un obiettivo con il nome prova all'interno del file-make stesso.

540.2   File-make

Un file-make è uno script specializzato per l'automazione della compilazione attraverso Make. Contiene la definizione di macro, simili alle variabili di ambiente di uno script di shell, e di obiettivi che rappresentano le varie operazioni da compiere.

All'interno di questi file, il simbolo # rappresenta l'inizio di un commento, cioè di una parte di testo che non viene interpretata da Make.

540.2.1   Macro

La definizione di una macro avviene in modo molto semplice, indicando l'assegnamento di una stringa a un nome che da quel momento la rappresenta.

nome = stringa

La stringa non deve essere delimitata. Il funzionamento è molto simile alle variabili di ambiente dichiarate all'interno di uno script di shell. L'esempio seguente definisce la macro prefix che da quel punto in poi equivale a /usr/local:

prefix=/usr/local

La sostituzione di una macro si indica attraverso due modi possibili:

$(nome)

Oppure:

${nome}

Nell'esempio seguente, la macro exec_prefix viene generata a partire dal contenuto di prefix.

prefix=/usr/local
exec_prefix=$(prefix)

Esistono alcune macro predefinite il cui contenuto può anche essere modificato. Le più importanti sono elencate nella tabella 540.3.

Tabella 540.3. Elenco di alcune macro predefinite di Make.

Nome Contenuto
MAKE make
AR ar
ARFLAGS rw
YACC yacc
YFLAGS
LEX lex
LFLAGS
LDFLAGS
CC cc
CFLAGS
FC f77
FFLAGS

Per verificare il contenuto delle macro predefinite, si può predisporre un file-make simile a quello seguente, eseguendo poi semplicemente make (i vari comandi echo sono rientrati con un carattere di tabulazione).

all:
        @echo MAKE $(MAKE) ; \
        echo AR $(AR) ; \
        echo ARFLAGS $(ARFLAGS) ; \
        echo YACC $(YACC) ; \
        echo YFLAGS $(YFLAGS) ; \
        echo LEX $(LEX) ; \
        echo LFLAGS $(LFLAGS) ; \
        echo LDFLAGS $(LDFLAGS) ; \
        echo CC $(CC) ; \
        echo CFLAGS $(CFLAGS) ; \
        echo FC $(FC) ; \
        echo FFLAGS $(FFLAGS)

Oltre alle macro predefinite ne esistono altre, la cui utilità si può comprendere in seguito.

Tabella 540.5. Elenco di alcune macro interne.

Macro Significato
$<
Il nome del file per il quale è stato scelto l'obiettivo per deduzione.
$*
Il nome dell'obiettivo senza suffisso.
$@
L'obiettivo della regola specificata.

540.2.2   Regole

Le regole sono il fondamento dei file-make. Attraverso di esse si stabiliscono degli obiettivi abbinati ai comandi necessari per ottenerli.

obiettivo... : [dipendenza...]
<HT>comando[; comando]...

La sintassi indica un comando che deve essere eseguito per raggiungere uno degli obiettivi nominati all'inizio, con le dipendenze che devono essere soddisfatte. In pratica, non si può eseguire il comando se prima non esistono i file indicati nelle dipendenze.

La dichiarazione inizia a partire dalla prima colonna, con il nome del primo obiettivo, mentre i comandi devono iniziare dopo un carattere di tabulazione.

L'esempio seguente mostra una regola attraverso cui si dichiara il comando necessario a eseguire il link di un programma oggetto, specificando che questo può essere eseguito solo quando esiste già il file oggetto in questione.

mio_prog: prova.o
        cc -o prova prova.o

Il comando indicato in una regola, può proseguire su più righe successive, basta concludere la riga, prima del codice di interruzione di riga, con una barra obliqua inversa (nella sezione precedente è già stato mostrato un esempio di questo tipo). Quello che conta è che le righe aggiuntive inizino sempre dopo un carattere di tabulazione.

Il comando di una regola può iniziare con un prefisso particolare:

Prefisso Significato
-
fa in modo che gli errori vengano ignorati;
+
fa in modo che il comando venga eseguito sempre;
@
fa in modo che il testo del comando non venga mostrato.

540.3   Regole deduttive

Make prevede alcune regole predefinite, o deduttive, riferite ai suffissi dei file indicati come obiettivo. Si distingue tra due tipi di regole deduttive: a suffisso singolo e a suffisso doppio. La tabella 540.8 ne riporta alcune per chiarire il concetto.

Tabella 540.8. Elenco di regole deduttive a singolo e a doppio suffisso.

Obiettivo Comando corrispondente
.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
.f $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<
.c.o $(CC) $(CFLAGS) -o $<
.f.o $(FC) $(FFLAGS) -o $<

540.4   File-make tipico

Il file-make tipico, permette di automatizzare tutte le fasi legate alla ricompilazione di un programma e alla sua installazione. Si distinguono alcuni obiettivi comuni, usati di frequente:

Prefisso Significato
all
utile per definire l'azione da compiere quando non si indica alcun obiettivo;
clean
per eliminare i file oggetto e i binari già compilati;
install
per installare il programma eseguibile dopo la compilazione.

Si può ricordare che le fasi tipiche di un'installazione di un programma distribuito in forma sorgente sono appunto:

make[Invio]

che richiama automaticamente l'obiettivo all del file-make, coincidente con i comandi necessari per la compilazione del programma, e

make install[Invio]

che provvede a installare gli eseguibili compilati nella loro destinazione prevista.

Supponendo di avere realizzato un programma, denominato mio_prog.c, il cui eseguibile debba essere installato nella directory /usr/local/bin/, si potrebbe utilizzare un file-make composto come l'esempio seguente:

prefix=/usr/local
bindir=${prefix}/bin

all:
        cc -o mio_prog mio_prog.c

clean:
        rm -f core *.o mio_prog

install:
        cp mio_prog $(bindir)

Come si può osservare, sono state definire le macro prefix e bindir in modo da facilitare la modifica della destinazione del programma installato, senza intervenire sui comandi.

L'obiettivo clean elimina un eventuale file core, generato da un errore irreversibile durante l'esecuzione del programma, probabilmente mentre lo si prova tra una compilazione e l'altra, quindi elimina gli eventuali file oggetto e infine l'eseguibile generato dalla compilazione.

Appunti di informatica libera 2007.02 --- Copyright © 2000-2007 Daniele Giacomini -- <daniele (ad) swlibero·org>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome automazione_della_compilazione_make_e_file_make.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico]

Valid ISO-HTML!

CSS validator!