Äîêóìåíò âçÿò èç êýøà ïîèñêîâîé ìàøèíû. Àäðåñ
îðèãèíàëüíîãî äîêóìåíòà
: http://www.arcetri.astro.it/irlab/doc/library/linux/AppLinux/al169.htm
Äàòà èçìåíåíèÿ: Tue Sep 21 18:08:48 1999 Äàòà èíäåêñèðîâàíèÿ: Sat Dec 22 13:24:11 2007 Êîäèðîâêà: Ïîèñêîâûå ñëîâà: ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï ï |
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.
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
(quest'ultimo, con l'iniziale maiuscola, Õ quello preferito). 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 singolo sorgente, e in questo caso, tenta di determinare l'operazione piÛ adatta da compiere in base all'estensione del sorgente stesso. Per esempio, se esiste il file prova.c
nella directory corrente, il comando
$
make prova
fa sË che make
avvii in pratica il comando seguente:
$
cc
-
o prova prova.c
Se invece esistesse un file-make, lo stesso comando, make prova
, avrebbe un significato diverso, corrispondendo alla ricerca di un obbiettivo con il nome prova
all'interno del file-make stesso.
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 obbiettivi 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.
La definizione di una macro avviene in modo molto semplice, indicando l'assegnamento di una stringa a un nome che da quel momento la rappresenterÞ.
<nome> = <stringa> |
La stringa non deve essere delimitata, e il funzionamento Õ molto simile alle variabili di ambiente dichiarate all'interno di uno script di shell. Per esempio,
prefix=/usr/local |
definisce la macro prefix
che da quel punto in poi equivale a /usr/local
. La sostituzione di una macro si indica attraverso due modi possibili:
$(<nome>) |
oppure
${<nome>} |
come nell'esempio seguente, dove 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 132.1.
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, e quindi eseguire 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 vedrÞ in seguito.
Macro | Significato |
$< | Il nome del file per il quale Õ stato scelto l'obbiettivo per deduzione. |
$* | Il nome dell'obbiettivo senza suffisso. |
$@ | L'obbiettivo della regola specificata. |
Le regole sono il fondamento dei file-make. Attraverso di esse si stabiliscono degli obbiettivi abbinati ai comandi necessari per ottenerli.
<obbiettivo>... : [<dipendenza>...] <HT><comando>[; <comando>]... |
La sintassi indica un comando che deve essere eseguito per raggiungere uno degli obbiettivi nominati all'inizio, e 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 obbiettivo, 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:
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.
Make prevede alcune regole predefinite, o deduttive, riferite ai suffissi dei file indicati come obbiettivo. Si distingue tra due tipi di regole deduttive: a singolo e a doppio suffisso. La tabella 132.3 ne riporta alcune per chiarire il concetto.
Obbiettivo | Comando corrispondente |
.c | $(CC) $(CFLAGS) $(LDFLAGS) - o $@ $< |
.f | $(FC) $(FFLAGS) $(LDFLAGS) - o $@ $< |
.c.o | $(CC) $(CFLAGS) - o $< |
.f.o | $(FC) $(FFLAGS) - o $< |
Il file-make tipico, permette di automatizzare tutte le fasi legate alla ricompilazione di un programma e alla sua installazione. Si distinguono alcuni obbiettivi comuni, usati di frequente:
all
utile per definire l'azione da compiere quando non si indica alcun obbiettivo;
clean
per eliminare i file oggetto e i binari giÞ compilati;
install
per installare il programma eseguibile dopo la compilazione.
Si ricorderÞ che le fasi tipiche di un'installazione di un programma distribuito in forma sorgente sono appunto:
#
make
che richiama automaticamente l'obbiettivo all
del file-make, coincidente con i comandi necessari per la compilazione del programma, e
#
make install
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'obbiettivo 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 Linux 1999.09.21 --- Copyright © 1997-1999 Daniele Giacomini -- daniele @ pluto.linux.it