Cosa significano i simboli di makefile $ @ e $ <?


416
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 $@

.cpp.o:
    $(CC) $(CFLAGS) $< -o $@

Cosa fanno esattamente $@e $<cosa?


5
Il link sopra è rotto, eccone un altro: gnu.org/software/make/manual/html_node/Automatic-Variables.html
asciz

1
Ciao, cosa significa ".cpp.o:" come target? (pre ultima riga?).
pseudonym_127,

3
".Cpp.o:" significa costruire ".o" (file oggetto) da ".cpp" (file sorgente)
jaguzu

1
Sento che dovrebbe essere notato che c'è un tutorial di make al seguente link dal quale credo che Mohit abbia ottenuto il makefile nel suo post. mrbook.org/blog/tutorials/make
DeepDeadpool

Microsoft lo chiama Macro dei nomi di file (per NMAKE) che è più chiaro delle variabili automatiche (per MAKE). È utile vedere entrambe le parti a scopo educativo.
Ivanzinho

Risposte:


502

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

Ad esempio, considera la seguente dichiarazione:

all: library.cpp main.cpp

In questo caso:

  • $@ valuta all
  • $< valuta library.cpp
  • $^ valuta library.cpp main.cpp

16
Vale la pena notare che $@non deve necessariamente finire per essere un file, potrebbe anche essere il nome di un .PHONYtarget.
Ephemera,

Posso aggiungere alle opzioni della riga di comando questo: $@sper generare output di assembly come name.os?
huseyin tugrul buyukisik,

4
Fai attenzione quando la prima dipendenza è una variabile che rappresenta un elenco, $ <viene valutato dopo che è stato espanso. Quindi quando LIST = lib1.cpp lib2.cpp e all: $ {LIST} main.cpp, $ <viene valutato solo in lib1.cpp. Qualche anno fa, avevo trascorso un po 'di tempo a capire cosa fosse successo nel risultato causato da questo comportamento.
Chan Kim,

In generale $ @ si riferisce al nome di destinazione che si trova sul lato sinistro di:
Deepak Kiran

78

Le $@e $<sono chiamate variabili automatiche . La variabile $@rappresenta il nome del file creato (ovvero la destinazione) e $<rappresenta il primo prerequisito richiesto per creare il file di output.
Per esempio:

hello.o: hello.c hello.h
         gcc -c $< -o $@

Ecco hello.oil file di output. Questo è ciò che si $@espande. La prima dipendenza è hello.c. Questo è quello che$< espande.

Il -cflag genera il .ofile; vedere man gccper una spiegazione più dettagliata. Il-o specifica il file di output per creare.

Per ulteriori dettagli, puoi leggere questo articolo sui Makefile di Linux .

Inoltre, puoi controllare i manuali GNU make . Semplifica la creazione di Makefile e il debug.

Se si esegue questo comando, verrà generato il database makefile:

make -p 

1
La tua risposta sembra $<espandersi in hello.c hello.h(entrambi). Si prega di precisare.
Dr Beco,

Sì, includerà sia hello.c che hello.h
abile

19
$<è solo il primo oggetto. Per includere tutto, utilizzare $^.
Dr Beco,

1
Il dott. Beco ha ragione. L'autore dovrebbe modificare la sua risposta.
PT Huynh,

67

Da Managing Projects with GNU Make, 3rd Edition, p. 16 (è sotto licenza GNU Free Documentation ):

Le variabili automatiche vengono impostate makedopo la corrispondenza di una regola. Forniscono accesso agli elementi dall'elenco di destinazione e dai 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 modello più generali.

Esistono sette variabili automatiche "core":

  • $@: Il nome file che rappresenta la destinazione.

  • $%: L'elemento del nome file di una specifica del membro di 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. In questo elenco sono stati rimossi nomi di file duplicati poiché per la maggior parte degli usi, come la compilazione, la copia, ecc., Non sono richiesti duplicati.

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

  • $*: La radice del nome file di destinazione. Una radice è in genere un nome file senza il suo suffisso. Il suo uso al di fuori delle regole del modello è sconsigliato.

Inoltre, ciascuna delle variabili sopra ha due varianti per la compatibilità con altre marche. Una variante restituisce solo la parte della directory del valore. Questo è indicato aggiungendo una “D” per il simbolo, $(@D), $(<D), ecc Le altre dichiarazioni variante solo la porzione di file del valore. Questo è indicato da aggiungendo una “F” per il simbolo, $(@F), $(<F), ecc Si noti che questi nomi variante sono lunghi più di un carattere e così deve essere racchiuso tra parentesi. GNU make fornisce un'alternativa più leggibile con le funzioni dir e notdir.


37

Le $@e $<sono macro speciali.

Dove:

$@ è il nome del file della destinazione.

$< è il nome della prima dipendenza.


19

Il Makefile costruisce l' helloeseguibile se uno qualsiasi dei main.cpp, hello.cpp, factorial.cppcambiato. Il Makefile più piccolo possibile per raggiungere quella 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 viene modificato solo uno

Per migliorare quanto sopra, compiliamo solo quei file C ++ che sono stati modificati. Quindi, colleghiamo semplicemente insieme i file degli oggetti 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, errore di battitura potenziale sulle regole dei file oggetto

Per migliorare questo, possiamo sostituire tutte le regole del file oggetto con una singola .cpp.oregola:

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

.cpp.o:
    g++ -c $< -o $@
  • pro: torna ad avere un breve makefile, un po 'facile da leggere

Qui la .cpp.oregola definisce come costruire anyfile.oda anyfile.cpp.

  • $< corrisponde alla prima dipendenza, in questo caso, anyfile.cpp
  • $@corrisponde al target, in questo caso anyfile.o,.

Le altre modifiche presenti nel Makefile sono:

  • Semplificare la modifica dei compilatori da g ++ a qualsiasi compilatore C ++.
  • Semplificare la modifica delle opzioni del compilatore.
  • Semplificare la modifica delle opzioni del linker.
  • Semplificare la modifica dei file sorgente e dell'output C ++.
  • Aggiunta una regola predefinita "all" che funge da controllo rapido per assicurarsi che tutti i file di origine siano presenti prima che venga effettuato un tentativo di compilazione dell'applicazione.

1

ad esempio, se si desidera compilare origini ma si hanno oggetti in una directory diversa:

Devi fare:

gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...

ma con la maggior parte delle macro il risultato saranno tutti gli oggetti seguiti da tutte le fonti, come:

gcc -c -o <all OBJ path> <all SRC path>

quindi questo non compilerà nulla ^^ e non sarai in grado di mettere i tuoi file di oggetti in una directory diversa :(

la soluzione è utilizzare queste macro speciali

$@ $<

questo genererà un file .o (obj / file.o) per ogni file .c in SRC (src / file.c)

$(OBJ):$(SRC)
   gcc -c -o $@ $< $(HEADERS) $(FLAGS)

significa :

    $@ = $(OBJ)
    $< = $(SRC)

ma linee per linee INSTEAD di tutte le linee di OBJ seguite da tutte le linee di SRC


Mi chiedo, cosa fai con tutto quel tempo che risparmi digitando "u" anziché "tu"?
Ivanzinho,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.