Cosa significano i simboli makefile $ @ e $ <?

CC=g++ CFLAGS=-c -Wall LDFLAGS= SOURCES=main.cpp hello.cpp factorial.cpp OBJECTS=$(SOURCES:.cpp=.o) EXECUTABLE=hello all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o [email protected] .cpp.o: $(CC) $(CFLAGS) $< -o [email protected] 

Cosa fanno [email protected] e $< esattamente?

[email protected] è il nome del file generato e $< il primo prerequisito (di solito il file sorgente). Puoi trovare un elenco di tutte queste variabili speciali nel manuale di GNU Make .

Ad esempio, prendere in considerazione la seguente dichiarazione:

 all: library.cpp main.cpp 

In questo caso:

[email protected] E $< sono chiamati variabili automatiche. [email protected] È la variabile di output. $< è la prima variabile di input. Per esempio:

 hello.o: hello.c hello.h gcc -c $< -o [email protected] 

Qui, hello.o è il file di output. Questo è ciò che [email protected] espande. La prima dipendenza è hello.c Questo è ciò che $< espande.

Il flag -c genera il file .o ; vedi man gcc per una spiegazione più dettagliata. L' -o specifica il file da esportare.

Per ulteriori dettagli, puoi leggere questo .

Inoltre, è ansible controllare i manuali GNU. C'è un modo per eseguire il debug del makefile per capirlo meglio.

Questo produrrà il database makefile:

 $make -p 

[email protected] E $< sono macro speciali.

Dove:

[email protected] è il nome del file della destinazione.

$< è il nome della prima dipendenza.

Da Managing Projects con GNU Make, 3rd Edition (è sotto GNU Free Documentation License ):

Le variabili automatiche sono impostate da make dopo che una regola è stata abbinata. Forniscono accesso agli elementi dagli elenchi di obiettivi e prerequisiti in modo da non dover specificare esplicitamente alcun nome di file. Sono molto utili per evitare la duplicazione del codice, ma sono fondamentali quando si definiscono regole di pattern più generali.

Esistono sette variabili automatiche “core”:

  • [email protected] : Il nomefile che rappresenta il target.

  • $% : L’elemento nome file di una specifica membro archivio.

  • $< : Il nome file del primo prerequisito.

  • $? : I nomi di tutti i prerequisiti più recenti della destinazione, separati da spazi.

  • $^ : I nomi dei file di tutti i prerequisiti, separati da spazi. Questo elenco ha nomi di file duplicati rimossi poiché per la maggior parte degli usi, come la compilazione, la copia, ecc., I duplicati non sono desiderati.

  • $+ : Simile a $^ , questo è il nome di tutti i prerequisiti separati da spazi, tranne che $+ include duplicati. Questa variabile è stata creata per situazioni specifiche come gli argomenti ai linker in cui i valori duplicati hanno un significato.

  • $* : La radice del nome file di destinazione. Un gambo è tipicamente un nome di file senza il suo suffisso. Il suo utilizzo al di fuori delle regole del modello è scoraggiato.

Inoltre, ciascuna delle suddette variabili ha due varianti per la compatibilità con altre marche. Una variante restituisce solo la parte della directory del valore. Ciò è indicato aggiungendo una "D" al simbolo, $(@D) , $( , ecc. L'altra variante restituisce solo la porzione di file del valore. Ciò è indicato aggiungendo una "F" al simbolo, $(@F) , $( , ecc. Si noti che questi nomi di varianti hanno più di un carattere e quindi devono essere racchiusi tra parentesi. GNU make fornisce un'alternativa più leggibile con le funzioni dir e notdir.

Il Makefile crea l’eseguibile hello se uno qualsiasi di main.cpp , hello.cpp , factorial.cpp cambiato. Il Makefile più piccolo ansible per raggiungere tale specifica avrebbe potuto essere:

 hello: main.cpp hello.cpp factorial.cpp g++ -o hello main.cpp hello.cpp factorial.cpp 
  • pro: molto facile da leggere
  • con: incubo di manutenzione, duplicazione delle dipendenze C ++
  • con: problema di efficienza, ricompiliamo tutto il C ++ anche se ne è stato modificato uno solo

Per migliorare su quanto sopra, compiliamo solo quei file C ++ che sono stati modificati. Quindi, colleghiamo solo i file object risultanti.

 OBJECTS=main.o hello.o factorial.o hello: $(OBJECTS) g++ -o hello $(OBJECTS) main.o: main.cpp g++ -c main.cpp hello.o: hello.cpp g++ -c hello.cpp factorial.o: factorial.cpp g++ -c factorial.cpp 
  • pro: risolve il problema dell’efficienza
  • con: nuovo incubo di manutenzione, potenziale errore di battitura sulle regole dei file object

Per migliorare questo, possiamo sostituire tutte le regole del file object con una singola regola .cpp.o :

 OBJECTS=main.o hello.o factorial.o hello: $(OBJECTS) g++ -o hello $(OBJECTS) .cpp.o: g++ -c $< -o [email protected] 
  • pro: torna ad avere un breve makefile, un po 'facile da leggere

Qui la regola .cpp.o definisce come anyfile.o da anyfile.cpp .

  • $< corrisponde alla prima dipendenza, in questo caso anyfile.cpp
  • [email protected] corrisponde al target, in questo caso anyfile.o .

Le altre modifiche presenti nel Makefile sono:

  • Semplificando le modifiche dei compilatori da g ++ a qualsiasi compilatore C ++.
  • Rendendo più facile cambiare le opzioni del compilatore.
  • Rendendo più facile cambiare le opzioni del linker.
  • Semplificazione della modifica dei file sorgente e dell'output di C ++.
  • Aggiunta una regola predefinita 'all' che funge da controllo rapido per garantire che tutti i file di origine siano presenti prima che venga effettuato un tentativo di creare l'applicazione.