Apa arti simbol makefile $ @ dan $ <?

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

Apa yang dilakukan $@dan $<dilakukan dengan tepat?

Mohit Deshpande
sumber
5
Tautan di atas rusak, inilah yang lain: gnu.org/software/make/manual/html_node/Automatic-Variables.html
asciz
1
Hai apa artinya ".cpp.o:" sebagai target? (sebelum baris terakhir?).
pseudonym_127
3
".Cpp.o:" berarti membangun ".o" (file objek) dari ".cpp" (file sumber)
jaguzu
1
Saya rasa perlu dicatat ada tutorial make di link berikut dari mana saya percaya Mohit mendapatkan makefile di postingannya. mrbook.org/blog/tutorials/make
DeepDeadpool
Microsoft menyebutnya Filename Macros (untuk NMAKE) yang lebih jelas daripada Variabel Otomatis (untuk MAKE). Sangat berguna untuk melihat kedua sisi untuk tujuan pendidikan.
Ivanzinho

Jawaban:

502

$@adalah nama file yang dihasilkan, dan $<prasyarat pertama (biasanya file sumber). Anda dapat menemukan daftar semua variabel khusus ini di manual GNU Make .

Misalnya, perhatikan deklarasi berikut:

all: library.cpp main.cpp

Pada kasus ini:

  • $@ mengevaluasi ke all
  • $< mengevaluasi ke library.cpp
  • $^ mengevaluasi ke library.cpp main.cpp
omong kosong
sumber
16
Perlu dicatat bahwa $@tidak selalu harus menjadi file, itu juga bisa menjadi nama .PHONYtarget.
Ephemera
Dapatkah saya menambahkan ke opsi commandline ini: $@suntuk menghasilkan output perakitan seperti name.os?
huseyin tugrul buyukisik
4
Hati-hati ketika dependensi pertama adalah variabel yang mewakili daftar, $ <dievaluasi setelah diperluas. Jadi ketika LIST = lib1.cpp lib2.cpp, dan semuanya: $ {LIST} main.cpp, $ <dievaluasi menjadi hanya lib1.cpp. Beberapa tahun yang lalu, saya telah menghabiskan waktu mencari tahu apa yang terjadi pada hasil yang disebabkan oleh perilaku ini.
Chan Kim
Secara umum $ @ mengacu pada nama target yang ada di sebelah kiri:
Deepak Kiran
78

The $@dan $<disebut variabel otomatis . Variabel $@mewakili nama file yang telah dibuat (yaitu target) dan $<mewakili prasyarat pertama yang diperlukan untuk membuat file output.
Sebagai contoh:

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

Di sini, hello.oadalah file output. Inilah yang $@berkembang. Ketergantungan pertama adalah hello.c. Itulah yang $<berkembang.

The -cflag menghasilkan .oberkas; lihat man gccpenjelasan lebih rinci. The -omenentukan file output untuk membuat.

Untuk perincian lebih lanjut, Anda dapat membaca artikel ini tentang Linux Makefiles .

Anda juga dapat memeriksa manual GNU make . Ini akan membuatnya lebih mudah untuk membuat Makefiles dan men-debug mereka.

Jika Anda menjalankan perintah ini, itu akan menampilkan database makefile:

make -p 
tangkas
sumber
1
Jawaban Anda sepertinya $<akan diperluas ke hello.c hello.h(keduanya). Mohon klarifikasi.
Dr Beco
Ya, itu akan termasuk hello.c dan hello.h
cekatan
19
$<hanya item pertama. Untuk memasukkan semua, gunakan $^.
Dr Beco
1
Dr Beco benar. Penulis harus mengubah jawabannya.
PT Huynh
67

Dari Mengelola Proyek dengan GNU Make, Edisi ke-3, hal. 16 (ini di bawah Lisensi Dokumentasi Bebas GNU ):

Variabel otomatis ditetapkan oleh makesetelah aturan dicocokkan. Mereka memberikan akses ke elemen dari daftar target dan prasyarat sehingga Anda tidak harus secara eksplisit menentukan nama file. Mereka sangat berguna untuk menghindari duplikasi kode, tetapi sangat penting ketika mendefinisikan aturan pola yang lebih umum.

Ada tujuh variabel otomatis "inti":

  • $@: Nama file yang mewakili target.

  • $%: Elemen nama file dari spesifikasi anggota arsip.

  • $<: Nama file prasyarat pertama.

  • $?: Nama semua prasyarat yang lebih baru dari target, dipisahkan oleh spasi.

  • $^: Nama file semua prasyarat, dipisahkan oleh spasi. Daftar ini memiliki nama file duplikat dihapus karena untuk sebagian besar menggunakan, seperti kompilasi, menyalin, dll. Duplikat tidak diinginkan.

  • $+: Mirip dengan $^, ini adalah nama dari semua prasyarat yang dipisahkan oleh spasi, kecuali itu $+termasuk duplikat. Variabel ini dibuat untuk situasi tertentu seperti argumen untuk tautan di mana nilai duplikat memiliki arti.

  • $*: Batang nama file target. Batang biasanya nama file tanpa akhiran. Penggunaannya di luar aturan pola tidak disarankan.

Selain itu, masing-masing variabel di atas memiliki dua varian untuk kompatibilitas dengan merek lain. Satu varian mengembalikan hanya bagian direktori dari nilai. Hal ini ditunjukkan dengan menambahkan “D” untuk simbol, $(@D), $(<D), dll lain kembali varian hanya bagian file nilai. Hal ini ditunjukkan dengan menambahkan sebuah “F” untuk simbol, $(@F), $(<F), dll Perhatikan bahwa nama-nama varian ini lebih dari satu karakter lama dan begitu harus diapit tanda kurung. GNU make menyediakan alternatif yang lebih mudah dibaca dengan fungsi dir dan notdir.

alex
sumber
37

The $@dan $<macro khusus.

Dimana:

$@ adalah nama file target.

$< adalah nama ketergantungan pertama.

Eric
sumber
19

Makefile membangun hellodieksekusi jika salah satu dari main.cpp, hello.cpp, factorial.cppberubah. Makefile sekecil mungkin untuk mencapai spesifikasi itu adalah:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • pro: sangat mudah dibaca
  • con: maintenance nightmare, duplikasi dependensi C ++
  • con: masalah efisiensi, kami mengkompilasi ulang semua C ++ walaupun hanya satu yang diubah

Untuk meningkatkan di atas, kami hanya mengkompilasi file C ++ yang telah diedit. Kemudian, kita hanya menautkan file objek yang dihasilkan bersama.

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: memperbaiki masalah efisiensi
  • con: mimpi buruk pemeliharaan baru, kesalahan ketik potensial pada aturan file objek

Untuk memperbaiki ini, kita bisa mengganti semua aturan file objek dengan aturan tunggal .cpp.o:

OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@
  • pro: kembali ke makefile pendek, agak mudah dibaca

Di sini .cpp.oaturan mendefinisikan bagaimana membangun anyfile.odari anyfile.cpp.

  • $< cocok dengan ketergantungan pertama, dalam hal ini, anyfile.cpp
  • $@cocok dengan target, dalam hal ini anyfile.o,.

Perubahan lain yang ada di Makefile adalah:

  • Mempermudah untuk mengubah kompiler dari g ++ ke kompiler C ++.
  • Mempermudah untuk mengubah opsi kompiler.
  • Mempermudah untuk mengubah opsi tautan.
  • Sehingga lebih mudah untuk mengubah file sumber C ++ dan output.
  • Menambahkan aturan default 'semua' yang bertindak sebagai pemeriksaan cepat untuk memastikan semua file sumber Anda ada sebelum upaya untuk membangun aplikasi Anda dibuat.
Stephen Quan
sumber
1

sebagai contoh jika Anda ingin mengkompilasi sumber tetapi memiliki objek di direktori yang berbeda:

Yang perlu Anda lakukan:

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

tetapi dengan sebagian besar makro hasilnya adalah semua objek diikuti oleh semua sumber, seperti:

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

jadi ini tidak akan mengkompilasi apa pun ^^ dan Anda tidak akan dapat menempatkan file objek Anda di dir yang berbeda :(

solusinya adalah menggunakan macro khusus ini

$@ $<

ini akan menghasilkan file .o (obj / file.o) untuk setiap file .c di SRC (src / file.c)

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

itu berarti :

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

tetapi baris demi baris BUKAN semua baris OBJ diikuti oleh semua baris SRC

Aominé
sumber
Saya bertanya-tanya, apa yang Anda lakukan dengan semua waktu yang Anda hemat dengan mengetikkan "u" alih-alih "Anda"?
Ivanzinho