Si tratta di una utility che permette di compilare automaticamente una serie di files sorgente per creare un eseguibile, puo' anche svolgere compiti ausiliari nello sviluppo e mantenimento di software.
Cosa fa make e' definito da un file di configurazione : Makefile
Una volta preparato il file basta dare il comando make per eseguire
tutto quanto indicato nel makefile.
il file Makefile contiene:
Il make analizza le dipendenze fra l'eseguibile ed i sorgenti tenendo conto della data di ultimo accesso dei files, e ricrea un target solo quando e' meno recente dei files da cui dipende.
Targets possono dipendere da altri targets, si viene quindi a creare una catena di dipendenze e di azioni, il make la analizza e decide quali azioni compiere, in modo da rendere tutti i targets piu' recenti delle "dependencies".
Di utility make ne esistono diverse versioni, con piu' o meno piccole differenze
# ----------------------------------------------------------- # Esempio di Makefile, semplice: compila un # programma fortran, il cui source e' in una serie di files # questi files hanno istruzioni include, con cui includono # files con commons di uso comune # # ----------------------------------------------------------- # #Il carattere: # serve per introdurre commenti, righe bianche vengono ignorate.
# definisco il default target def : barre ; @echo " =======> OK, tutto compilato. " # alias del target barre all : barre
Ecco una serie di definizioni di variabili che saranno usate poi,
si noti come il valore della variabile possa contenere spazi bianchi.
Qui vengono definiti i flag usati per il compilatore ed il nome
del compilatore
# definizione delle variabili FC = g77 FFLAGS = -w -fvxt -finit-local-zero -O3 LDFLAGS = # # ------- Flag del compilatore usati : -------- # # -g -O0 : per il debug , altrimenti con -O3 ottimizzo la compilazione # -w : warnings # -finit-local-zero : inizializza a 0 le variabili del fortran # -fvxt : interpreta certi costrutti coerentemente col fortran del vax # # ----------------------------------------- # # ------- Variabili che dicono dove sono le librerie che uso----
Definisco quindi una serie di variabili per identificare le librerie che uso.
L'espressione $(variabile) sostituisce alla variabile il suo valore.
cernlib e' una procedura, in /cern/new/bin , che restituisce i nomi delle
librerie, col giusto path, separate da spazi, aggiungendo i nomi di
librerie ausiliarie.
CERN = /cern CERN_LEVEL = new CERN_ROOT = $(CERN)/$(CERN_LEVEL) CERN_BIN = $(CERN_ROOT)/bin CERN_LIBS = $(CERN_BIN)/cernlib geant321 pawlib graflib/Motif packlib mathlib
Le variabili seguenti contengono i nomi dei files col source.
Notare l'uso di \ prima del carriage return, in modo che sia come
se tutti i nomi fossero su una stessa linea
# # ------------------------------------------------------------ # ------ files con il source del programma ------- # ------------------------------------------------------------ # INCLUSI = parametri.inc \ letti.inc \ canali.inc \ fisica.inc FORTRAN = barre.f \ uginit.f \ uhinit.f \ sorgenti.f \ ugeom.f \ gukine.f\ gustep.f \ guout.f \ uglast.f \ fisica.f OUTPUT = summary.out \ phlist.out \ ehist.out \ fis.out OBJECTS = $(FORTRAN:.f=.o) # nella variabile FORTRAN sostituisce .f con .o
Seguono regole di dipendenza, con le righe seguenti si
specifica che i files fortran dipendono dagli include files,
l'azione e' un touch, cioe' si rendono i files fortran piu'
recenti degli objects, in modo che il make nel considerare
le dipendenze dei files object sia portato a ricompilarli.
Notare come l'azione possa essere preceduta da ; oppure essere nella linea seguente,
preceduta da un tab.
# ----------------------------------------------------- # -------- regole di dipendenza ---------- # ----------------------------------------------------- # # # I files fortran dipendono dagli include files e dal file Makefile # l'azione e' un touch, cioe' rendo i files fortran piu' # recenti degli objects, il make quindi li ricompilera' # $(FORTRAN) : $(INCLUSI) touch $(FORTRAN) #
Un approccio migliore, siccome non tutti i file fortran includono
tutti i files *.inc, e' di fare una lista esplicita di tutte le
dipendenze.
$@ indica i targets
#barre.f : B_ugeo_cm.txt B_comm_edep.inc common_geant.dat common_geo_cm.dat common_user.dat \ # B_init.f B_kine.f B_step.f B_out.f B_last.f # touch $@ # #B_init.f : B_comm_edep.inc B_comm_tape.inc common_user.dat common_geo_cm.dat B_comm_sorgente.inc B_histset.f B_fits.f ; touch $@ #B_histset.f : B_comm_edep.inc ; touch $@ #B_kine.f : B_comm_edep.inc B_comm_tape.inc B_comm_sorgente.inc; touch $@ #B_out.f : B_comm_edep.inc B_comm_tape.inc B_fits.f ; touch $@ # %.o : %.f ; $(FC) $(FFLAGS) -c $< -o $@
Nell'ultima riga si vede l'uso di una sintassi compatta :
l'istruzione dice che tutti i files che finiscono con .o
dipendono dai corrispondenti , che finiscono in .f,
l'azione e' compilarli col compilatore nella variabile FC , utilizzando
i flags in FFLAGS.
$< indica le dipendenze , $@ i targets
L'espressione e' equivalente a:
B_kine.o : B_kine.f ; g77 -w -fvxt -finit-local-zero -c B_kine.f -o B_kine.o
ripetuta per tutti i files object
Di seguito si indica come fare il target barre, cioe' l'eseguibile finale.
il file barre dipende dai files objects, la regola e' di usare g77,
LDFLAGS sono eventuali flag per il linker, CERN_LIBS contiene i nomi
delle librerie
Ci sono poi indicazioni per altri targets,
as esempio posso eliminare i files object con:
make clear
eliminare i files di output con :
make outdel
barre : $(OBJECTS) $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(CERN_LIBS) # reset : ; touch $(INCLUSI) # this target deletes object files clear : ; rm *.o # this target deletes output files outdel : ; rm $(OUTPUT)