एक Makefile में .PHONY का उद्देश्य क्या है?


1734

.PHONYMakefile में क्या मतलब है? मैं माध्यम से चले गए इस है, लेकिन यह भी जटिल है।

क्या कोई इसे सरल शब्दों में मुझे समझा सकता है?

जवाबों:


1944

डिफ़ॉल्ट रूप से, मेकफाइल लक्ष्य "फ़ाइल लक्ष्य" हैं - उनका उपयोग अन्य फ़ाइलों से फ़ाइलें बनाने के लिए किया जाता है। बनाओ मान लें कि इसका लक्ष्य एक फ़ाइल है, और इससे मेकफाइल्स लिखना अपेक्षाकृत आसान हो गया है:

foo: bar
  create_one_from_the_other foo bar

हालांकि, कभी-कभी आप चाहते हैं कि आपका मेकफाइल कमांड चलाए जो फ़ाइल सिस्टम में भौतिक फ़ाइलों का प्रतिनिधित्व नहीं करता है। इसके लिए अच्छे उदाहरण सामान्य लक्ष्य "साफ" और "सभी" हैं। संभावना है कि यह मामला नहीं है, लेकिन आपके पास संभवतः आपके मुख्य निर्देशिका में एक फ़ाइल का नाम हो सकता हैclean । ऐसे मामले में मेक भ्रमित हो जाएगा क्योंकि डिफ़ॉल्ट रूप से cleanलक्ष्य इस फ़ाइल के साथ जुड़ा होगा और मेक इसे केवल तभी चलाएगा जब फ़ाइल निर्भरता के संबंध में अप-टू-डेट प्रतीत नहीं होगी।

इन विशेष लक्ष्य कहा जाता है जाली और आप स्पष्ट रूप से वे फ़ाइलें, जैसे के साथ जुड़े नहीं कर रहे हैं बता सकते हैं:

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

अब make cleanउम्मीद के मुताबिक चलेगा, भले ही आपके पास कोई फाइल हो clean

मेक के संदर्भ में, एक टारगेट टारगेट बस एक लक्ष्य होता है जो हमेशा आउट-ऑफ-डेट होता है, इसलिए जब भी आप पूछेंगे make <phony_target>, तो यह चलेगा, फ़ाइल सिस्टम की स्थिति से स्वतंत्र। कुछ आम makeलक्ष्य है कि अक्सर जाली हैं: all, install, clean, distclean, TAGS, info, check


49
@eSKay: 'इसे' फोनी 'क्यों कहा जाता है?' - क्योंकि यह एक वास्तविक लक्ष्य नहीं है। यही है, लक्ष्य नाम एक फ़ाइल नहीं है जो उस लक्ष्य के कमांड द्वारा निर्मित है।
बर्नार्ड

96
@ लेज़र: मुझे नहीं पता कि आप एक देशी अंग्रेजी बोलने वाले हैं। मैं नहीं। शब्द फोनी का मतलब यह नहीं है कि यह कैसा लगता है। en.wiktionary.org/wiki/phony कहता है: धोखाधड़ी; उल्लू बनाना; भ्रामक उपस्थिति होना।
बाहबर

57
यह उत्तर बिल्कुल पूर्ण नहीं है - हालांकि इसे लिंक किए गए ट्यूटोरियल में संबोधित किया जा सकता है। .PHONY मेकफाइल में एक लेबल / फ़ाइल बनाने के लिए बाध्य करता है, यदि यह आपके लक्ष्य का जो भी हो, टोपोलॉजिकल-प्रकार का हिस्सा है। कहने का तात्पर्य यह है कि, यदि आपके पास 'क्लीनअप:' लेबल है, जो कि सेट फोनी है, और आपके इंस्टॉल लेबल को क्लीनअप के साथ एक पूर्वापेक्षा के रूप में परिभाषित किया गया है - यानी 'क्लीन: क्लीन', क्लीनअप हमेशा चलेगा जब मेकफाइल बनाने का प्रयास होगा 'इंस्टॉल'। यह उन कदमों के लिए उपयोगी है जो आप हमेशा चाहते हैं, भले ही वे सफल हों - यह टाइमस्टैम्प को नजरअंदाज कर देगा और इसे मजबूर कर देगा।
सिंथेसाइजरपटेल

9
ध्यान दें कि आपको तब तक उपयोग करने की आवश्यकता नहीं है। जब तक आपके पास कार्य के समान नाम वाली फ़ाइल नहीं है। कार्य को हमेशा वैसे भी निष्पादित किया जाएगा, और मेकफाइल अधिक पठनीय होगा।
बर्नार्ड

15
"एक टट्टू लक्ष्य बस एक लक्ष्य है जो हमेशा आउट-ऑफ-डेट होता है" - महान स्पष्टीकरण!
दानिजेल

729

मान लेते हैं कि आपके पास installलक्ष्य है, जो मेकफाइल्स में बहुत आम है। यदि आप उपयोग नहीं करते हैं .PHONY, और एक फ़ाइल नाम installमेकफाइल के समान निर्देशिका में मौजूद है, तो कुछ भी नहींmake install करेगा । ऐसा इसलिए है क्योंकि मेक ने नियम का अर्थ है "फ़ाइल का नाम बनाने के लिए इस तरह के और इस तरह के नुस्खा को निष्पादित करें "। चूंकि फ़ाइल पहले से ही है, और इसकी निर्भरता नहीं बदली है, कुछ भी नहीं किया जाएगा।install

हालाँकि यदि आप installलक्ष्य PHONY बनाते हैं, तो यह मेक टूल को बताएगा कि लक्ष्य काल्पनिक है, और इससे वास्तविक फ़ाइल बनाने की अपेक्षा नहीं करनी चाहिए। इसलिए यह जाँच नहीं करेगा कि installफ़ाइल मौजूद है या नहीं , इसका अर्थ: क) इसके व्यवहार में परिवर्तन नहीं किया जाएगा यदि फ़ाइल मौजूद है और ख) अतिरिक्त stat()नहीं कहा जाएगा।

आपके Makefile में आम तौर पर सभी लक्ष्य जो आउटपुट नाम के समान नाम के साथ आउटपुट फ़ाइल नहीं बनाते हैं, उन्हें PHONY होना चाहिए। यह आमतौर पर शामिल all, install, clean, distclean, और इतने पर।


6
@PineappleUndertheSea स्वीकार किए गए उत्तर को अपने शुरुआती स्तर के मूल्य में काफी सुधार किया गया है, और अब यह उतना ही अच्छा है। मुझे आपकी टिप्पणी समझने के लिए इसके पुनरीक्षण इतिहास को देखना होगा।
मार्क एमी डे

2
यह थोड़े व्यर्थ लगता है क्योंकि मेरे पास मेरे कोडबेस में 'इंस्टॉल' या लाइक नाम की फाइल कभी नहीं होगी। अधिकांश फ़ाइलों में फ़ाइल एक्सटेंशन होने वाला है, और फ़ाइल एक्सटेंशन के बिना फ़ाइलें आमतौर पर सभी कैप्स में होती हैं, जैसे 'README'। फिर, यदि आपके पास 'install.sh' के बजाय 'इंस्टॉल' नाम की बैश स्क्रिप्ट है, तो आपके पास बुरा समय आने वाला है।
न्यूक्लियराइड

6
@JasonTu यह जरूरी सच नहीं है। बैश स्क्रिप्टिंग कन्वेंशन आपको "कार्यक्रमों" के लिए .shया .bashएक्सटेंशन को छोड़ने के लिए कहते हैं, जैसे कि वे एक मुख्य कार्य करते हैं और आपके द्वारा शामिल किए गए पुस्तकालयों के लिए एक्सटेंशन जोड़ते हुए आरक्षित होते हैं ( source mylib.sh)। वास्तव में, मैं यह तो सवाल करने के लिए मिला है, क्योंकि मैं एक ही निर्देशिका में एक स्क्रिप्ट था के रूप में मेरे Makefile बुलायाinstall
केली

10
@ काइल हां, मुझे यकीन नहीं है कि मेरे अतीत का क्या मतलब है। इन दिनों मैं .PHONYहर समय का उपयोग करता हूँ ...
नाभिकीय

2
@JasonTu यहां समाधान सरल है: एक टाइम मशीन बनाएं और अपने पिछले स्वयं को "बदलें"। मैं आपके साथ एक फावड़ा लेने की सलाह देता हूं, ताकि किसी को पता न चले कि आप .PHONYसंस्करण हैं।
मतीन उल्हाक

120

ध्यान दें : मेक टूल मेकफाइल को पढ़ता है और एक नियम में ':' प्रतीक के दोनों ओर फाइलों के संशोधन समय-टिकटों की जांच करता है।

उदाहरण

एक निर्देशिका 'परीक्षण' में निम्नलिखित फाइलें मौजूद हैं:

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

मेकफाइल में एक नियम निम्नानुसार परिभाषित किया गया है:

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

अब मान लें कि फ़ाइल 'हैलो' एक पाठ फ़ाइल है जिसमें कुछ डेटा होते हैं, जो 'hello.c' फ़ाइल के बाद बनाया गया था। अतः 'हैलो' का संशोधन (या निर्माण) टाइम-स्टैंप 'हैलो' की तुलना में नया होगा। इसलिए जब हम कमांड लाइन से 'हेलो हेलो' लागू करेंगे, तो यह निम्नानुसार प्रिंट होगा:

make: `hello' is up to date.

अब 'hello.c' फ़ाइल तक पहुँचें और इसमें कुछ सफ़ेद स्थान डालें, जो कोड सिंटैक्स या लॉजिक को प्रभावित नहीं करता है और फिर सेव करें और छोड़ दें। अब hello.c का संशोधन समय-मोहर 'हैलो' की तुलना में नया है। अब यदि आप 'हेलो' बनाते हैं, तो यह कमांड को निष्पादित करेगा:

cc hello.c -o hello

और फाइल over हैलो ’(टेक्स्ट फाइल) एक नई बाइनरी फाइल 'हैलो’ (उपरोक्त कंप्लीट कमांड का परिणाम) के साथ लिखी जाएगी।

अगर हम निम्नलिखित के रूप में मेकफाइल में .PHONY का उपयोग करते हैं:

.PHONY:hello

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

और फिर 'मेक हेलो' का आह्वान करें, यह pwd 'परीक्षण' में मौजूद किसी भी फाइल को अनदेखा कर देगा और हर बार कमांड को निष्पादित करेगा।

अब मान लीजिए, 'हैलो' लक्ष्य की कोई निर्भरता घोषित नहीं की गई है:

hello:
    cc hello.c -o hello

और 'हैलो' फ़ाइल पहले से ही pwd 'टेस्ट' में मौजूद है, फिर 'हेलो' हमेशा की तरह दिखाई देगा:

make: `hello' is up to date.

3
न केवल यह मेरे द्वारा चलाए जाने वाले आदेशों को बनाता है, यह अंत में समझ में आने का कारण बनता makeहै, यह सभी फाइलों के बारे में है! इस उत्तर के लिए धन्यवाद।
21

80
.PHONY: install
  • का अर्थ है "इंस्टॉल" शब्द इस मेकफाइल में एक फ़ाइल नाम का प्रतिनिधित्व नहीं करता है;
  • मतलब मेकफाइल का उसी डायरेक्टरी में "इंस्टॉल" नामक फाइल से कोई लेना-देना नहीं है।

45

यह एक बिल्ड टारगेट है जो कि एक फ़ाइल नाम नहीं है।


33

सबसे अच्छा स्पष्टीकरण GNU मेनुअल मेनुअल है: 4.6 फोनी टार्गेट्स सेक्शन

.PHONYएक मेक इन स्पेशल बिल्ट-इन टार्गेट नेम्स है । ऐसे अन्य लक्ष्य हैं जिन्हें आप में रुचि हो सकती है, इसलिए इन संदर्भों के माध्यम से इसे संक्षिप्त करने लायक है।

जब यह एक .PHONY लक्ष्य पर विचार करने का समय होता है, तो यह बताए बिना कि उसका कोई फ़ाइल मौजूद है या उसका अंतिम-संशोधन समय क्या है, इसकी परवाह किए बिना, अपना नुस्खा बिना शर्त चलाएगा।

आप भी इस तरह के और के रूप में मानक लक्ष्य बनाने में रुचि हो सकती है ।allclean


11

".PHONY" का एक महत्वपूर्ण मुश्किल इलाज भी है - जब एक भौतिक लक्ष्य, फॉनी लक्ष्य पर निर्भर करता है जो दूसरे भौतिक लक्ष्य पर निर्भर करता है:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

आप बस उम्मीद करेंगे कि यदि आपने TARGET2 को अपडेट किया है, तो TARGET1 को TARGET1 के खिलाफ बासी माना जाना चाहिए, इसलिए TARGET1 का पुनर्निर्माण किया जाना चाहिए। और यह वास्तव में इस तरह से काम करता है

मुश्किल हिस्सा तब है जब TARGET1 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

आप इसके साथ खेल सकते हैं:

  • "स्रोत फ़ाइलें" तैयार करने के लिए पहले 'तैयारी करें' करें
  • उन्हें अद्यतन देखने के लिए विशेष फ़ाइलों को छूने के साथ उस के चारों ओर खेलते हैं

आप देख सकते हैं कि फ़ाइलल अप्रत्यक्ष रूप से एक फोनी लक्ष्य के माध्यम से फ़ाइल 1 पर निर्भर करता है - लेकिन यह हमेशा इस निर्भरता के कारण पुनर्निर्माण करता है। आप में निर्भरता को बदलते हैं 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 supercleanआग नहीं होगा catcher superclean

हमें यह बताने की चिंता करने की जरूरत नहीं है कि cleanलक्ष्य PHONY है, क्योंकि यह पूरी तरह से नहीं है। हालाँकि यह कभी भी साफ फ़ाइल नहीं बनाता है, लेकिन इसमें आग लगने की आज्ञा है इसलिए यह अंतिम लक्ष्य होगा।

हालाँकि, supercleanलक्ष्य वास्तव में बहुत ही कम है, इसलिए इसे supercleanलक्ष्य के लिए डिप्स प्रदान करने वाली किसी भी चीज़ के साथ ढेर करने की कोशिश करेंगे - इसमें अन्य supercleanलक्ष्य और %लक्ष्य शामिल हैं।

ध्यान दें कि हम andsomethingelseया के बारे में कुछ भी नहीं कहते हैं blah, इसलिए वे स्पष्ट रूप से पकड़ने वाले के पास जाते हैं।

आउटपुट कुछ इस तरह दिखता है:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.