สัญลักษณ์ makefile $ @ และ $ <หมายถึงอะไร


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

ทำอะไร$@และ$<ทำอะไรกันแน่?


5
ลิงก์ด้านบนนี้ใช้งานไม่ได้นี่คืออีกอัน: gnu.org/software/make/manual/html_node/Automatic-Variables.html
asciz

1
สวัสดี ".cpp.o:" ในฐานะเป้าหมายหมายถึงอะไร (บรรทัดสุดท้ายก่อน?)
pseudonym_127

3
".cpp.o:" หมายถึงสิ่งปลูกสร้าง ".o" (ไฟล์วัตถุ) จาก ".cpp" (ไฟล์ต้นฉบับ)
jaguzu

1
ฉันรู้สึกว่ามันควรจะมีการสอนทำที่ลิงค์ต่อไปนี้ซึ่งฉันเชื่อว่า Mohit ได้รับ makefile ในโพสต์ของเขา mrbook.org/blog/tutorials/make
DeepDeadpool

Microsoft เรียกว่าFilename Macros (สำหรับ NMAKE) ซึ่งชัดเจนกว่าตัวแปรอัตโนมัติ (สำหรับ MAKE) มันมีประโยชน์ที่จะเห็นทั้งสองด้านเพื่อการศึกษา
Ivanzinho

คำตอบ:


502

$@คือชื่อของไฟล์ที่ถูกสร้างขึ้นและ$<สิ่งที่จำเป็นต้องมีก่อน (โดยปกติคือไฟล์ต้นฉบับ) คุณสามารถค้นหารายการสินค้าทั้งหมดของตัวแปรพิเศษเหล่านี้ในที่คู่มือยี่ห้อ GNU

ตัวอย่างเช่นพิจารณาการประกาศต่อไปนี้:

all: library.cpp main.cpp

ในกรณีนี้:

  • $@ ประเมินให้ all
  • $< ประเมินให้ library.cpp
  • $^ ประเมินให้ library.cpp main.cpp

16
เป็นที่น่าสังเกตว่า$@ไม่จำเป็นต้องจบลงด้วยการเป็นไฟล์มันอาจเป็นชื่อของ.PHONYเป้าหมาย
แมลงเม่า

ฉันสามารถเพิ่มตัวเลือกบรรทัดคำสั่งนี้$@sเพื่อสร้างแอสเซมบลีเอาท์พุตเช่น name.os ได้หรือไม่
huseyin tugrul buyukisik

4
ระวังเมื่อการพึ่งพาครั้งแรกเป็นตัวแปรที่แสดงรายการ $ <จะได้รับการประเมินหลังจากมีการขยาย ดังนั้นเมื่อ LIST = lib1.cpp lib2.cpp และทั้งหมด: $ {LIST} main.cpp, $ <จะถูกประเมินเป็นเพียงแค่ lib1.cpp ไม่กี่ปีที่ผ่านมาฉันใช้เวลาหาสิ่งที่เกิดขึ้นในผลลัพธ์ที่เกิดจากพฤติกรรมนี้
Chan Kim

โดยทั่วไป $ @ หมายถึงชื่อเป้าหมายซึ่งอยู่ทางด้านซ้ายของ:
Deepak Kiran

78

$@และ$<จะเรียกว่าตัวแปรอัตโนมัติ ตัวแปร$@แสดงถึงชื่อของไฟล์ที่สร้างขึ้น (เช่นเป้าหมาย) และ$<แสดงถึงสิ่งที่จำเป็นต้องมีครั้งแรกที่จำเป็นในการสร้างไฟล์เอาต์พุต
ตัวอย่างเช่น:

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

นี่hello.oคือไฟล์ที่ส่งออก นี่คือสิ่งที่$@ขยายไป hello.cพึ่งพาแรกคือ นั่นคือสิ่งที่$<ขยายออกไป

-cธงสร้าง.oไฟล์ ดูman gccคำอธิบายโดยละเอียดเพิ่มเติม -oระบุไฟล์ที่ส่งออกเพื่อสร้าง

สำหรับรายละเอียดเพิ่มเติมคุณสามารถอ่านบทความเกี่ยวกับลินุกซ์ Makefiles

นอกจากนี้คุณยังสามารถตรวจสอบGNU makeคู่มือ มันจะทำให้ง่ายขึ้นในการสร้าง Makefiles และตรวจแก้จุดบกพร่อง

หากคุณเรียกใช้คำสั่งนี้จะส่งออกฐานข้อมูล makefile:

make -p 

1
คำตอบของคุณดูเหมือน$<จะขยายเป็นhello.c hello.h(ทั้งคู่) กรุณาอธิบาย
ดร. เบโก

ใช่มันจะมีทั้ง hello.c และ hello.h
คล่องแคล่ว

19
$<เป็นเพียงรายการแรก $^จะรวมทุกการใช้งาน
ดร. เบโก

1
ดร. เบโกะพูดถูก ผู้เขียนควรแก้ไขคำตอบของเขา
PT Huynh

67

จากการจัดการโครงการด้วย GNU Make, 3rd Edition, p. 16 (อยู่ภายใต้ลิขสิทธิ์เอกสาร GNU ฟรี ):

ตัวแปรอัตโนมัติถูกตั้งค่าโดยmakeหลังจากจับคู่กฎแล้ว พวกเขาให้การเข้าถึงองค์ประกอบจากเป้าหมายและรายการที่จำเป็นต้องมีเพื่อให้คุณไม่ต้องระบุชื่อไฟล์ใด ๆ อย่างชัดเจน มีประโยชน์มากสำหรับการหลีกเลี่ยงการทำสำเนารหัส แต่มีความสำคัญเมื่อกำหนดกฎรูปแบบทั่วไปมากขึ้น

มีตัวแปรอัตโนมัติเจ็ดส่วน:

  • $@: ชื่อไฟล์แสดงถึงเป้าหมาย

  • $%: องค์ประกอบชื่อไฟล์ของข้อกำหนดคุณสมบัติสมาชิกไฟล์เก็บถาวร

  • $<: ชื่อไฟล์ของสิ่งที่จำเป็นต้องมีครั้งแรก

  • $?: ชื่อของสิ่งที่จำเป็นต้องมีทั้งหมดที่ใหม่กว่าเป้าหมายคั่นด้วยช่องว่าง

  • $^: ชื่อไฟล์ของสิ่งที่จำเป็นต้องมีทั้งหมดคั่นด้วยช่องว่าง รายการนี้มีการลบชื่อไฟล์ที่ซ้ำกันเนื่องจากการใช้งานส่วนใหญ่เช่นการรวบรวมการคัดลอก ฯลฯ ไม่ต้องการรายการที่ซ้ำกัน

  • $+: คล้ายกับ$^นี่คือชื่อของสิ่งที่จำเป็นต้องมีทั้งหมดที่คั่นด้วยช่องว่างยกเว้นที่$+มีรายการที่ซ้ำกัน ตัวแปรนี้ถูกสร้างขึ้นสำหรับสถานการณ์เฉพาะเช่นการขัดแย้งกับ linkers ที่ค่าที่ซ้ำกันมีความหมาย

  • $*: ต้นกำเนิดของชื่อไฟล์เป้าหมาย ลำต้นมักเป็นชื่อไฟล์โดยไม่มีคำต่อท้าย การใช้งานนอกกฎรูปแบบนั้นไม่ได้รับการสนับสนุน

นอกจากนี้ตัวแปรข้างต้นแต่ละตัวยังมีตัวแปรอีกสองตัวที่เข้ากันได้กับตัวแปรอื่น ๆ หนึ่งตัวแปรส่งคืนเฉพาะส่วนไดเรกทอรีของค่า นี่คือการแสดงโดยการผนวก“d” เพื่อสัญลักษณ์$(@D), $(<D)ฯลฯ ผลตอบแทนที่แตกต่างอื่น ๆ เท่านั้นส่วนไฟล์ของค่า นี่คือการแสดงโดยการผนวก“f” เพื่อสัญลักษณ์$(@F), $(<F)ฯลฯ หมายเหตุว่าชื่อตัวแปรเหล่านี้มีมากกว่าหนึ่งตัวยาวและอื่น ๆ จะต้องอยู่ในวงเล็บ GNU make เป็นทางเลือกที่อ่านได้ง่ายกว่าด้วยฟังก์ชั่น dir และ notdir


37

$@และ$<มีแมโครพิเศษ

ที่ไหน:

$@ เป็นชื่อไฟล์ของเป้าหมาย

$< เป็นชื่อของการพึ่งพาครั้งแรก


19

Makefile สร้างhelloปฏิบัติการหากใด ๆmain.cpp, hello.cpp, factorial.cppการเปลี่ยนแปลง Makefile ที่เล็กที่สุดที่เป็นไปได้เพื่อให้บรรลุข้อกำหนดนั้นอาจเป็นไปได้:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • pro: อ่านง่ายมาก
  • con: การบำรุงรักษาฝันร้ายการทำซ้ำการอ้างอิง C ++
  • ข้อเสีย: ปัญหาเรื่องประสิทธิภาพเราคอมไพล์ C ++ ใหม่อีกครั้งแม้ว่าจะมีการเปลี่ยนแปลงเพียงอันเดียว

ในการปรับปรุงข้างต้นเรารวบรวมเฉพาะไฟล์ C ++ ที่ถูกแก้ไข จากนั้นเราเพียงเชื่อมโยงไฟล์ออบเจ็กต์ผลลัพธ์เข้าด้วยกัน

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
  • โปร: แก้ไขปัญหาประสิทธิภาพ
  • con: ฝันร้ายการบำรุงรักษาใหม่พิมพ์ผิดที่มีศักยภาพในกฎไฟล์วัตถุ

เพื่อปรับปรุงในเรื่องนี้เราสามารถแทนที่กฎไฟล์อ็อบเจ็กต์ทั้งหมดด้วย.cpp.oกฎเดียว:

OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@
  • pro: กลับไปที่มี makefile สั้น ๆ ค่อนข้างง่ายต่อการอ่าน

ที่นี่มี.cpp.oกฎกำหนดวิธีการที่จะสร้างจากanyfile.oanyfile.cpp

  • $< ตรงกับการพึ่งพาครั้งแรกในกรณีนี้ anyfile.cpp
  • $@ตรงกับเป้าหมายในกรณีanyfile.oนี้

การเปลี่ยนแปลงอื่น ๆ ที่มีอยู่ใน Makefile คือ:

  • ทำให้การเปลี่ยนคอมไพเลอร์ง่ายขึ้นจาก g ++ เป็นคอมไพเลอร์ C ++
  • ทำให้การเปลี่ยนตัวเลือกคอมไพเลอร์ง่ายขึ้น
  • ทำให้การเปลี่ยนตัวเลือกลิงเกอร์ง่ายขึ้น
  • ทำให้ง่ายต่อการเปลี่ยนไฟล์ต้นฉบับและเอาต์พุต C ++
  • เพิ่มกฎเริ่มต้น 'ทั้งหมด' ซึ่งทำหน้าที่ตรวจสอบอย่างรวดเร็วเพื่อให้แน่ใจว่าไฟล์ต้นฉบับทั้งหมดของคุณมีอยู่ก่อนที่จะพยายามสร้างแอปพลิเคชันของคุณ

1

เป็นแบบอย่างถ้าคุณต้องการคอมไพล์ซอร์ส แต่มีออบเจ็กต์ในไดเรกทอรีอื่น:

คุณต้องทำ:

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

แต่ด้วยมาโครส่วนใหญ่ผลลัพธ์จะเป็นวัตถุทั้งหมดตามด้วยแหล่งที่มาทั้งหมดเช่น:

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

ดังนั้นสิ่งนี้จะไม่รวบรวมอะไรเลย ^^ และคุณจะไม่สามารถวางไฟล์ออบเจ็กต์ของคุณใน dir อื่น :(

การแก้ปัญหาคือการใช้มาโครพิเศษเหล่านี้

$@ $<

สิ่งนี้จะสร้างไฟล์. o (obj / file.o) สำหรับไฟล์. c แต่ละไฟล์ใน SRC (src / file.c)

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

มันหมายถึง:

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

แต่บรรทัดทีละบรรทัดแทนที่ของทุกบรรทัดของ OBJ ตามด้วยทุกบรรทัดของ SRC


ฉันสงสัยว่าคุณทำอะไรกับเวลาทั้งหมดที่คุณบันทึกโดยพิมพ์ "u" แทน "you"
Ivanzinho
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.