Poiché questo è per Unix, gli eseguibili non hanno estensioni.
Una cosa da notare è che root-config
è un'utilità che fornisce i corretti flag di compilazione e collegamento; e le librerie giuste per la creazione di applicazioni contro root. Questo è solo un dettaglio relativo al pubblico originale per questo documento.
Make Me Baby
o non dimentichi mai la prima volta che sei stato realizzato
Una discussione introduttiva su make e su come scrivere un semplice makefile
Cos'è Make? E perché dovrei preoccuparmi?
Lo strumento chiamato Make è un gestore delle dipendenze di compilazione. Cioè, si occupa di sapere quali comandi devono essere eseguiti nell'ordine in cui prendere il progetto software da una raccolta di file sorgente, file oggetto, librerie, intestazioni, ecc. Ecc., Alcuni dei quali potrebbero essere cambiati di recente --- e trasformandoli in una corretta versione aggiornata del programma.
In realtà, puoi usare Make anche per altre cose, ma non ne parlerò.
Un Makefile Trivial
Supponiamo di avere una directory contenente:, tool
tool.cc
tool.o
support.cc
support.hh
e support.o
che dipendono da root
e dovrebbero essere compilati in un programma chiamato tool
, e supponiamo che tu abbia hackerato i file di origine (il che significa che l'attuale non tool
è aggiornato) e vuoi compilare il programma.
Per farlo da soli potresti farlo
Controlla se uno support.cc
o support.hh
è più recente di support.o
, e in tal caso esegui un comando simile
g++ -g -c -pthread -I/sw/include/root support.cc
Controlla se uno support.hh
o tool.cc
sono più recenti di tool.o
, e in tal caso esegui un comando simile
g++ -g -c -pthread -I/sw/include/root tool.cc
Controlla se tool.o
è più recente di tool
, e in tal caso esegui un comando simile
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Accidenti! Che seccatura! C'è molto da ricordare e diverse possibilità di commettere errori. (A proposito, i dettagli delle righe di comando qui esposte dipendono dal nostro ambiente software. Questi funzionano sul mio computer.)
Naturalmente, potresti semplicemente eseguire tutti e tre i comandi ogni volta. Funzionerebbe, ma non si adatta bene a un sostanziale software (come DOGS che impiega più di 15 minuti per essere compilato da zero sul mio MacBook).
Invece potresti scrivere un file chiamato makefile
così:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
e basta digitare make
dalla riga di comando. Che eseguirà automaticamente i tre passaggi sopra indicati.
Le linee senza rientro qui hanno il formato "target: dipendenze" e indicano a Make che i comandi associati (linee rientrate) devono essere eseguiti se una qualsiasi delle dipendenze è più recente del target. Cioè, le linee di dipendenza descrivono la logica di ciò che deve essere ricostruito per adattarsi alle modifiche in vari file. Se support.cc
cambia ciò significa che support.o
deve essere ricostruito, ma tool.o
può essere lasciato solo. Quando le support.o
modifiche tool
devono essere ricostruite.
I comandi associati a ciascuna linea di dipendenza sono impostati con una scheda (vedi sotto) dovrebbe modificare la destinazione (o almeno toccarla per aggiornare il tempo di modifica).
Variabili, regole incorporate e altri gadget
A questo punto, il nostro makefile sta semplicemente ricordando il lavoro che deve essere fatto, ma dovevamo ancora capire e digitare ogni comando necessario nella sua interezza. Non deve essere così: Make è un linguaggio potente con variabili, funzioni di manipolazione del testo e un'intera serie di regole integrate che possono semplificarci molto.
Crea variabili
La sintassi per accedere a una variabile make è $(VAR)
.
La sintassi per l'assegnazione a una variabile Make è: VAR = A text value of some kind
(o VAR := A different text value but ignore this for the moment
).
Puoi usare le variabili in regole come questa versione migliorata del nostro makefile:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
che è un po 'più leggibile, ma richiede ancora molta digitazione
Crea funzioni
GNU make supporta una varietà di funzioni per l'accesso alle informazioni dal filesystem o altri comandi sul sistema. In questo caso siamo interessati a ciò $(shell ...)
che si espande nell'output degli argomenti e $(subst opat,npat,text)
che sostituisce tutte le istanze di opat
con npat
nel testo.
Sfruttare questo ci dà:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
che è più facile da scrivere e molto più leggibile.
Notare che
- Stiamo ancora dichiarando esplicitamente le dipendenze per ciascun file oggetto e l'eseguibile finale
- Abbiamo dovuto digitare esplicitamente la regola di compilazione per entrambi i file di origine
Regole implicite e modello
Generalmente ci aspettiamo che tutti i file sorgente C ++ vengano trattati allo stesso modo e Make fornisce tre modi per affermarlo:
- regole del suffisso (considerate obsolete in GNU make, ma conservate per compatibilità con le versioni precedenti)
- regole implicite
- regole del modello
Sono incorporate regole implicite e alcune saranno discusse di seguito. Le regole del modello sono specificate in una forma simile
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
ciò significa che i file oggetto vengono generati dai file sorgente C eseguendo il comando mostrato, in cui la variabile "automatica" si $<
espande al nome della prima dipendenza.
Regole integrate
Make ha un'intera serie di regole integrate che significano che molto spesso, un progetto può essere compilato da un makefile molto semplice, anzi.
La regola GNU integrata per i file sorgente C è quella mostrata sopra. Allo stesso modo creiamo file oggetto da file sorgente C ++ con una regola simile $(CXX) -c $(CPPFLAGS) $(CFLAGS)
.
I file a oggetto singolo vengono collegati utilizzando $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
, ma questo non funzionerà nel nostro caso, perché vogliamo collegare più file oggetto.
Variabili utilizzate dalle regole incorporate
Le regole integrate utilizzano un set di variabili standard che consentono di specificare le informazioni sull'ambiente locale (come dove trovare i file di inclusione ROOT) senza riscrivere tutte le regole. Quelli che molto probabilmente saranno interessanti per noi sono:
CC
- il compilatore C da usare
CXX
- il compilatore C ++ da usare
LD
- il linker da usare
CFLAGS
- flag di compilazione per i file sorgente C.
CXXFLAGS
- flag di compilazione per file sorgente C ++
CPPFLAGS
- flag per il preprocessore c (in genere includono percorsi di file e simboli definiti nella riga di comando), utilizzati da C e C ++
LDFLAGS
- flag linker
LDLIBS
- librerie da collegare
Un Makefile di base
Sfruttando le regole integrate possiamo semplificare il nostro makefile per:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
Abbiamo anche aggiunto diversi target standard che eseguono azioni speciali (come ripulire la directory di origine).
Nota che quando make è invocato senza un argomento, usa la prima destinazione trovata nel file (in questo caso tutto), ma puoi anche nominare la destinazione per ottenere qual è ciò che rende make clean
rimuovere i file oggetto in questo caso.
Abbiamo ancora tutte le dipendenze codificate.
Alcuni misteriosi miglioramenti
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Notare che
- Non ci sono più linee di dipendenza per i file sorgente!?!
- C'è qualche strana magia legata a .dipendente e dipendente
- Se lo fai
make
, allora ls -A
si vede un file di nome .depend
che contiene cose che assomigliano a linee di dipendenza make
Altra lettura
Conoscere bug e note storiche
La lingua di input per Make è sensibile agli spazi bianchi. In particolare, le linee d'azione che seguono le dipendenze devono iniziare con una scheda . Ma una serie di spazi può sembrare la stessa (e in effetti ci sono editor che convertiranno silenziosamente le schede in spazi o viceversa), il che si traduce in un file Make che sembra giusto e continua a non funzionare. Questo è stato identificato come un bug all'inizio, ma ( la storia continua ) non è stato corretto, perché c'erano già 10 utenti.
(Questo è stato copiato da un post wiki che ho scritto per studenti laureati in fisica.)