วัตถุประสงค์ของ. PHYY ใน makefile คืออะไร?


คำตอบ:


1945

โดยค่าเริ่มต้นเป้าหมาย Makefile คือ "เป้าหมายไฟล์" - พวกเขาจะใช้ในการสร้างไฟล์จากไฟล์อื่น ๆ Make ถือว่าเป้าหมายเป็นไฟล์และสิ่งนี้ทำให้การเขียน Makefiles ค่อนข้างง่าย:

foo: bar
  create_one_from_the_other foo bar

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

เป้าหมายพิเศษเหล่านี้เรียกว่าของปลอมและคุณสามารถบอกได้อย่างชัดเจนว่าพวกเขาไม่เกี่ยวข้องกับไฟล์เช่น:

.PHONY: clean
clean:
  rm -rf *.o

ตอนนี้make cleanจะทำงานตามที่คาดไว้แม้ว่าคุณจะมีชื่อไฟล์cleanก็ตาม

ในแง่ของการสร้างเป้าหมายปลอมเป็นเพียงเป้าหมายที่ล้าสมัยเสมอดังนั้นเมื่อใดก็ตามที่คุณถามmake <phony_target>มันจะทำงานโดยไม่ขึ้นกับสถานะของระบบไฟล์ บางคนทั่วไปmakeเป้าหมายที่มักจะปลอมเป็น: all, install, clean, distclean, TAGS, ,infocheck


49
@eSKay: 'ทำไมจึงเรียกว่า' ปลอม '? - เพราะมันไม่ใช่เป้าหมายที่แท้จริง นั่นคือชื่อเป้าหมายไม่ใช่ไฟล์ที่สร้างโดยคำสั่งของเป้าหมายนั้น
เบอร์นาร์ด

96
@ เลเซอร์: ฉันไม่รู้ว่าคุณเป็นเจ้าของภาษาอังกฤษหรือเปล่า ฉันไม่. คำปลอมไม่ได้แปลว่าอะไร en.wiktionary.org/wiki/phonyพูดว่า: Fraudulent; ปลอม; มีลักษณะที่ทำให้เข้าใจผิด
Bahbar

57
คำตอบนี้ยังไม่เสร็จสมบูรณ์ - แม้ว่าอาจมีการระบุไว้ในบทช่วยสอนที่เชื่อมโยง .PHONY บังคับให้สร้าง label / file ใน Makefile หากมันเป็นส่วนหนึ่งของทอพอโลยีที่จัดเรียงตามเป้าหมายของคุณ กล่าวคือหากคุณมีป้ายกำกับ 'cleanup:' ที่ถูกตั้งค่าปลอมและป้ายกำกับการติดตั้งของคุณถูกกำหนดด้วยการล้างข้อมูลเป็นสิ่งที่จำเป็นต้องมี - เช่น 'install: cleanup' การล้างข้อมูลจะถูกเรียกใช้เสมอเมื่อ Makefile พยายามสร้าง 'ติดตั้ง' สิ่งนี้มีประโยชน์สำหรับขั้นตอนที่คุณต้องการโดยไม่คำนึงว่าทำได้สำเร็จหรือไม่มันจะข้ามเวลาและเพียงแค่บังคับ
synthesizerpatel

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

15
"เป้าหมายปลอมเป็นเพียงเป้าหมายที่ล้าสมัยอยู่เสมอ" - คำอธิบายที่ยอดเยี่ยม!
Danijel

730

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

อย่างไรก็ตามถ้าคุณสร้างinstallPHONY เป้าหมายมันจะบอกเครื่องมือสร้างว่าเป้าหมายเป็นตัวละครและสิ่งนั้นไม่ควรคาดหวังว่ามันจะสร้างไฟล์จริง ดังนั้นมันจะไม่ตรวจสอบว่าinstallไฟล์นั้นมีอยู่หรือไม่ความหมาย: a) พฤติกรรมของมันจะไม่เปลี่ยนแปลงหากไฟล์นั้นมีอยู่และ b) stat()จะไม่ถูกเรียกใช้เป็นพิเศษ

โดยทั่วไปเป้าหมายทั้งหมดใน Makefile ของคุณซึ่งไม่ได้สร้างไฟล์เอาต์พุตที่มีชื่อเดียวกันกับชื่อเป้าหมายควรเป็น PHONY นี้มักจะมีall, install, clean, distcleanและอื่น ๆ


6
@PineappleUndertheSea คำตอบที่ยอมรับได้รับการปรับปรุงอย่างมีนัยสำคัญจากระดับเริ่มต้นของการไร้ค่าและตอนนี้ก็ดีเหมือนคำตอบนี้ ฉันต้องดูประวัติการแก้ไขเพื่อทำความเข้าใจความคิดเห็นของคุณ
Mark Amery

2
ดูเหมือนว่าจะไร้ประโยชน์เพราะฉันจะไม่มีไฟล์ชื่อ 'ติดตั้ง' หรือไฟล์ที่คล้ายกันใน codebase ของฉัน ไฟล์ส่วนใหญ่จะมีนามสกุลไฟล์และไฟล์ที่ไม่มีนามสกุลมักอยู่ในตัวพิมพ์ใหญ่ทั้งหมดเช่น 'README' จากนั้นอีกครั้งหากคุณมีสคริปต์ทุบตีชื่อ 'ติดตั้ง' แทน 'install.sh' คุณจะมีเวลาที่ไม่ดี
นิวคลีโอไทด์

6
@JasonTu นี่ไม่จำเป็นต้องเป็นเรื่องจริง อนุสัญญาสคริปต์ Bash ขอให้คุณละเว้น.shหรือ.bashส่วนขยายสำหรับ "โปรแกรม" ที่ทำงานเหมือนพวกเขามีฟังก์ชั่นหลักและสำรองเพิ่มส่วนขยายสำหรับห้องสมุดที่คุณรวม ( source mylib.sh) ในความเป็นจริงฉันได้รับคำถาม SO นี้เพราะฉันมีสคริปต์ในไดเรกทอรีเดียวกันกับ Makefile ของฉันที่เรียกว่าinstall
Kyle

10
@ ไคล์ใช่ฉันไม่แน่ใจว่าตัวเองในอดีตของฉันหมายถึงอะไร วันนี้ฉันใช้.PHONYตลอดเวลา ...
นิวคลีโอไทด์

2
@JasonTu ทางออกที่นี่ง่ายมาก: สร้างเครื่องย้อนเวลาและ "แทนที่" ตัวคุณเองในอดีต ผมขอแนะนำให้สละจอบพร้อมกับคุณเพื่อให้ไม่มีใครตระหนักถึงคุณเป็น.PHONYรุ่น
Mateen Ulhaq

120

หมายเหตุ : เครื่องมือ make จะอ่าน makefile และตรวจสอบการประทับเวลาการแก้ไขของไฟล์ที่ด้านข้างของสัญลักษณ์ ':' ในกฎ

ตัวอย่าง

ในไดเรกทอรี 'ทดสอบ' มีไฟล์ต่อไปนี้:

prerit@vvdn105:~/test$ ls
hello  hello.c  makefile

ใน makefile กฎถูกกำหนดดังนี้:

hello:hello.c
    cc hello.c -o hello

ตอนนี้สมมติว่าไฟล์ 'hello' เป็นไฟล์ข้อความที่มีข้อมูลบางส่วนซึ่งสร้างขึ้นหลังจากไฟล์ 'hello.c' ดังนั้นการปรับเปลี่ยน (หรือสร้าง) ประทับเวลาของ 'สวัสดี' จะใหม่กว่า 'hello.c' ดังนั้นเมื่อเราจะเรียก 'make hello' จากบรรทัดคำสั่งมันจะพิมพ์เป็น:

make: `hello' is up to date.

ตอนนี้เข้าถึงไฟล์ 'hello.c' และใส่ช่องว่างสีขาวไว้ในนั้นซึ่งไม่ส่งผลกระทบต่อไวยากรณ์ของรหัสหรือตรรกะจากนั้นบันทึกและออก ตอนนี้การประทับเวลาการแก้ไขของ hello.c นั้นใหม่กว่าของ 'hello' ตอนนี้ถ้าคุณเรียกใช้ 'make hello' มันจะดำเนินการตามคำสั่งดังนี้

cc hello.c -o hello

และไฟล์ 'hello' (ไฟล์ข้อความ) จะถูกเขียนทับด้วยไฟล์ไบนารีใหม่ 'hello' (ผลลัพธ์ของคำสั่งการคอมไพล์ด้านบน)

ถ้าเราใช้. PHYY ใน makefile ดังต่อไปนี้:

.PHONY:hello

hello:hello.c
    cc hello.c -o hello

จากนั้นเรียกใช้ 'make hello' มันจะไม่สนใจไฟล์ใด ๆ ที่มีอยู่ใน pwd 'test' และดำเนินการคำสั่งทุกครั้ง

ทีนี้สมมติว่าเป้าหมาย 'hello' นั้นไม่มีการขึ้นต่อกัน:

hello:
    cc hello.c -o hello

และไฟล์ 'hello' มีอยู่ใน pwd 'test' แล้ว 'make hello' จะแสดงเป็น:

make: `hello' is up to date.

3
สิ่งนี้ไม่เพียง แต่ทำให้คำสั่งที่ฉันเรียกใช้สมเหตุสมผล แต่ในที่สุดมันก็ทำให้เกิดmakeความรู้สึกโดยรวมมันคือทั้งหมดที่เกี่ยวกับไฟล์! ขอบคุณสำหรับคำตอบนี้
Kzqai

80
.PHONY: install
  • หมายความว่าคำว่า "ติดตั้ง" ไม่ได้แสดงชื่อไฟล์ใน Makefile นี้
  • หมายความว่า Makefile ไม่มีส่วนเกี่ยวข้องกับไฟล์ชื่อ "ติดตั้ง" ในไดเรกทอรีเดียวกัน


33

คำอธิบายที่ดีที่สุดคือการทำให้ GNU คู่มือตัวเอง: 4.6 ปลอมเป้าหมายส่วน

.PHONYเป็นหนึ่งในการแต่งหน้าของพิเศษ Built-in ชื่อเป้าหมาย มีเป้าหมายอื่น ๆ ที่คุณอาจสนใจดังนั้นจึงควรอ่านข้อมูลอ้างอิงเหล่านี้

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

นอกจากนี้คุณยังอาจจะสนใจในการแต่งหน้าของเป้าหมายมาตรฐานเช่นและallclean


11

นอกจากนี้ยังมีการรักษา ".PHONY" ที่สำคัญอย่างหนึ่ง - เมื่อเป้าหมายทางกายภาพขึ้นอยู่กับเป้าหมายปลอมที่ขึ้นอยู่กับเป้าหมายทางกายภาพอื่น:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

คุณเพียงแค่คาดหวังว่าหากคุณอัปเดต TARGET2 ดังนั้น TARGET1 ควรได้รับการพิจารณาว่าเก่ากับ TARGET1 ดังนั้น TARGET1 จึงควรสร้างใหม่ และมันใช้งานได้จริงด้วยวิธีนี้

ส่วนที่ยุ่งยากคือเมื่อ TARGET2 ไม่ได้ค้างกับ TARGET1 ซึ่งในกรณีนี้คุณควรคาดหวังว่า TARGET1 ไม่ควรสร้างใหม่

นี้น่าแปลกใจไม่ได้เพราะ: เป้าหมายปลอมที่กำลังวิ่งอยู่แล้ว (เป็นเป้าหมายของปลอมทำตามปกติ)ซึ่งหมายความว่าเป้าหมายของปลอมได้รับการพิจารณาการปรับปรุง และเนื่องจากการที่target1 ถือว่าเก่ากับเป้าหมายปลอม

พิจารณา:

all: fileall

fileall: file2 filefwd
    echo file2 file1 >fileall


file2: file2.src
    echo file2.src >file2

file1: file1.src
    echo file1.src >file1
    echo file1.src >>file1

.PHONY: filefwd
.PHONY: filefwd2

filefwd: filefwd2

filefwd2: file1
    @echo "Produced target file1"


prepare:
    echo "Some text 1" >> file1.src
    echo "Some text 2" >> file2.src

คุณสามารถเล่นกับสิ่งนี้:

  • ก่อนอื่นให้ทำการเตรียมพร้อมเพื่อเตรียม "ไฟล์ต้นฉบับ"
  • เล่นกับสิ่งนั้นด้วยการแตะไฟล์เฉพาะเพื่อดูการอัปเดต

ท่านสามารถเข้าดู fileall ที่ขึ้นอยู่กับ file1 ทางอ้อมผ่านเป้าหมายปลอม - แต่ก็มักจะได้รับการสร้างขึ้นมาใหม่เนื่องจากการพึ่งพานี้ หากคุณเปลี่ยนการพึ่งพาในfileallจากfilefwdเป็นfileตอนนี้fileallจะไม่ได้รับการสร้างขึ้นมาใหม่ทุกครั้ง แต่เฉพาะเมื่อเป้าหมายที่พึ่งพาใด ๆ นั้นค้างอยู่กับไฟล์นั้นเป็นไฟล์


5

เป้าหมายพิเศษ.PHONY:ช่วยให้สามารถประกาศเป้าหมายปลอมได้ซึ่งmakeจะไม่ตรวจสอบว่าเป็นชื่อไฟล์จริง: มันจะทำงานตลอดเวลาแม้ว่าไฟล์ดังกล่าวจะยังคงอยู่

คุณสามารถใส่หลายอย่าง.PHONY:ในMakefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

มีวิธีอื่นในการประกาศเป้าหมายปลอม: เพียงใส่ '::'

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

'::' มีความหมายพิเศษ: เป้าหมายเป็นของปลอมและสามารถปรากฏได้หลายครั้ง:

clean ::
    rm file1

...


clean ::
    rm file2

บล็อกคำสั่งจะถูกเรียกหนึ่งบล็อกอื่น ๆ


3

ฉันมักจะใช้พวกเขาเพื่อบอกเป้าหมายเริ่มต้นที่จะไม่ยิง

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

โดยไม่ต้องปลอมmake supercleanจะยิงclean, andsomethingelseและcatcher superclean; แต่มีการปลอมจะไม่ยิงmake supercleancatcher superclean

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

อย่างไรก็ตามsupercleanเป้าหมายนั้นเป็นของปลอมจริงๆดังนั้น make จะพยายามที่จะรวมกับสิ่งอื่น ๆ ที่ให้การสนับสนุนสำหรับsupercleanเป้าหมาย - ซึ่งรวมถึงsupercleanเป้าหมายอื่น ๆและ%เป้าหมาย

โปรดทราบว่าเราไม่พูดอะไรเลยเกี่ยวกับandsomethingelseหรือblahดังนั้นพวกเขาจึงไปที่ตัวจับอย่างชัดเจน

ผลลัพธ์มีลักษณะดังนี้:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.