आप किसी लक्ष्य को फिर से बनाने के लिए मेकफिल को कैसे मजबूर करते हैं


184

मेरे पास एक मेकफाइल है जो बनाता है और फिर एक और मेकफाइल कहता है। चूंकि यह मेकफाइल अधिक मेकफाइल्स को कॉल करता है जो वह काम करता है जो वास्तव में नहीं बदलता है। इस प्रकार यह सोचता रहता है कि यह परियोजना निर्मित और अद्यतित है।

dnetdev11 ~ # make
make: `release' is up to date.

मैं लक्ष्य को फिर से बनाने के लिए मेकफिल को कैसे मजबूर करूं?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

नोट: मासूमों की सुरक्षा के लिए नाम हटाए गए

संपादित करें: अंतिम निश्चित संस्करण:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib

लॉडल, चूंकि यह अक्सर देखा जाने वाला प्रश्न है, तो क्या आप प्रश्न को अधिक आधुनिक बनाने के लिए संपादित करना चाहेंगे? (ऐसा लगता है .PHONYकि यह आपकी एकमात्र समस्या नहीं थी, और आप वास्तव में प्रश्न में समाधान को संपादित करने के लिए नहीं हैं, या कम से कम अब और नहीं।)
कीथ एम

जवाबों:


23

आप अपने लक्ष्यों में से एक या एक से अधिक की घोषणा हो सकती है जाली

एक लक्ष्य लक्ष्य वह है जो वास्तव में किसी फ़ाइल का नाम नहीं है; जब आप स्पष्ट अनुरोध करते हैं तो इसे निष्पादित करने के लिए केवल एक नाम है। एक फोनी लक्ष्य का उपयोग करने के दो कारण हैं: एक ही नाम की फ़ाइल के साथ संघर्ष से बचने के लिए, और प्रदर्शन में सुधार करने के लिए।

...

एक टारगेट लक्ष्य एक वास्तविक लक्ष्य फ़ाइल की शर्त नहीं होना चाहिए; अगर ऐसा है, तो उस फ़ाइल को अपडेट करने के लिए हर बार इसकी रेसिपी चलाई जाएगी। जब तक कि एक टारगेट टारगेट कभी वास्तविक लक्ष्य की पूर्वापेक्षा न हो, तब तक फोनी टारगेट रेसिपी तभी निष्पादित की जाएगी जब फॉनी टारगेट एक निर्धारित लक्ष्य हो


68
यह उत्तर, जबकि यह "स्वीकृत" है और अत्यधिक "अपवित्र" वास्तव में ऑफ-द-मार्क है। पहले, यह कहता है कि "लक्ष्य को ध्वनिहीन घोषित करें" लेकिन फिर यह कहता है कि "ध्वनि लक्ष्य वास्तव में एक फ़ाइल का नाम नहीं है"। ठीक है, अगर आपका लक्ष्य एक फ़ाइल है, तो यह उत्तर में विरोधाभास है। दूसरा, यह कहता है कि "फोनी टारगेट वास्तविक की शर्त नहीं होनी चाहिए" - ठीक है, अगर यह हो तो क्या होगा? मूल प्रश्न, यह निर्दिष्ट नहीं करता है कि यह है या यह नहीं है। सही उत्तर है, अपने लक्ष्यों को ध्वनिहीन घोषित नहीं करना है, बल्कि, एक अतिरिक्त स्वर लक्ष्य घोषित करना है, और फिर, उन लक्ष्यों पर निर्भर करें जिन्हें आप फिर से बनाना चाहते हैं।
मार्क गैलेक

2
@MarkGaleck। जब जवाब में कहा गया है कि "एक टोने टारगेट वह है जो वास्तव में किसी फ़ाइल का नाम नहीं है" तो यह सीधे gcc से मैन्युअल रूप से उद्धृत किया जाता है। यह पूरी तरह से सही है।
डॉली

"टारगेट" एक मेक टर्म है जो टेक्स्ट को कॉलन के बाईं ओर संदर्भित करता है :, न कि केवल अंतिम परिणाम जो आप बनाना चाहते हैं (जैसे कि आपकी बाइनरी फ़ाइल)। सवाल में, release, debug, clean, और installमेक लक्ष्य, नहीं कर रहे हैं xxx_utilया xxxcore.soया कुछ और।
कीथ एम

728

-Bबनाने के लिए स्विच, जिसका लंबे रूप है --always-make, बताता है makeउपेक्षा टाइम स्टाम्प्स के लिए और निर्दिष्ट लक्ष्य बनाते हैं। यह मेक का उपयोग करने के उद्देश्य को हरा सकता है, लेकिन हो सकता है कि आपको इसकी आवश्यकता हो।


4
@MarkKowan मैं पूरी तरह से सहमत हूँ! यह विकल्प वास्तव में वही है जो मैं देख रहा था, न कि कुछ हल हैक जैसा कि डेव सुझाव देता है।
मार्टेन बेमेलिस

8
इस दृष्टिकोण के साथ चेतावनी यह है कि यह बहुत सी चीजों का निर्माण करता है। विशेष रूप से ऑटोटूलस के साथ, मैंने देखा कि यह फिर से कॉन्फ़िगर किया गया है .. काश कि LD_PRELOAD आधारित समाधान का निर्माण किया जा सके !!
व्रध्न

हाँ, और यह उन फ़ाइलों को भी फिर से लिख सकता है जिन्हें आप नहीं चाहते थे! वैश्विक प्रणाली पुस्तकालयों के रूप में निर्भरता में दिखाई देते हैं और फिर से निर्मित और अधिलेखित हो जाते हैं ...
जूलियो गुएरा

18

एक चाल जिसे सूर्य मैनुअल में प्रलेखित किया जाता था, makeवह है (गैर-मौजूद) लक्ष्य '.FORCE' का उपयोग करना। आप ऐसा एक फ़ाइल बनाकर कर सकते हैं, जिसमें। Pk शामिल है:

.FORCE:
$(FORCE_DEPS): .FORCE

फिर, अपने मौजूदा मेकफाइल को कहा जाता है makefile, आप चला सकते हैं:

make FORCE_DEPS=release -f force.mk -f makefile release

चूंकि .FORCEअस्तित्व में नहीं है, इस पर निर्भर होने वाली कोई भी चीज़ पुरानी हो जाएगी और फिर से बनाई जाएगी।

यह सब किसी भी संस्करण के साथ काम करेगा make; लिनक्स पर, आपके पास GNU मेक है और इसलिए चर्चा के अनुसार .PHONY लक्ष्य का उपयोग कर सकते हैं।

यह भी विचार करने योग्य है कि makeरिलीज को अद्यतित क्यों माना जाता है। ऐसा इसलिए हो सकता है क्योंकि आपके पास touch releaseनिष्पादित कमांडों के बीच एक कमांड है; ऐसा इसलिए हो सकता है क्योंकि कोई फ़ाइल या निर्देशिका है जिसे 'रिलीज़' कहा जाता है जो मौजूद है और जिसकी कोई निर्भरता नहीं है और इसलिए अद्यतित है। फिर इसका वास्तविक कारण है ...


14

किसी और ने सुझाया ।PHONY जो निश्चित रूप से सही है। .PHONY का उपयोग किसी भी नियम के लिए किया जाना चाहिए, जिसके लिए इनपुट और आउटपुट के बीच की तारीख अमान्य है। चूँकि आपके पास उस फॉर्म का कोई लक्ष्य नहीं है जिसका output: inputआपको उपयोग करना चाहिए। उन सभी के लिए .ONONY!

उस सभी ने कहा, आपको संभवतः विभिन्न फाइलनामों के लिए अपने बदलाव के शीर्ष पर कुछ चर को परिभाषित करना चाहिए, और वास्तविक मेक रूल्स को परिभाषित करना चाहिए जिसमें इनपुट और आउटपुट दोनों अनुभाग हैं ताकि आप मेक के लाभों का उपयोग कर सकें, अर्थात आप केवल वास्तव में संकलन करेंगे। नकल करने के लिए आवश्यक चीजें!

संपादित करें: जोड़ा गया उदाहरण। अप्रमाणित है, लेकिन यह है कि आप कैसे करते हैं

.PHONY: clean    
clean:
    $(clean)

1
यदि आप मुझे एक उदाहरण दिखा सकते हैं तो यह अच्छा होगा। Atm im बस इसे हैक करने की कोशिश कर रहा है कि डैम काम करने की कोशिश कर रहा है: P
Lodle

1
.PHONYलक्ष्य का स्थान मायने नहीं रखता। यह कहीं भी हो सकता है Makefile
एड्रियन डब्ल्यू

5

यदि मैं सही तरीके से याद करता हूं, तो 'मेक' टाइमस्टैम्प (फ़ाइल संशोधन समय) का उपयोग यह निर्धारित करने के लिए करता है कि कोई लक्ष्य निर्धारित किया गया है या नहीं। री-बिल्ड को बाध्य करने का एक सामान्य तरीका है कि 'टच' कमांड का उपयोग करके उस टाइमस्टैम्प को अपडेट करना। आप किसी भी लक्ष्य (शायद उन सब-मेकफाइल्स में से एक) के टाइमस्टैम्प को अपडेट करने के लिए अपने मेकफाइल में 'टच' लगाने की कोशिश कर सकते हैं, जो मेक को उस कमांड को निष्पादित करने के लिए मजबूर कर सकता है।


5

यह सरल तकनीक मेकफाइल को सामान्य रूप से कार्य करने की अनुमति देगा जब मजबूर नहीं किया जाता है। अपने मेकफाइल के अंत में एक नया लक्ष्य बनाएं जिसे बल कहा जाता है । बल लक्ष्य एक फ़ाइल स्पर्श करेगा कि आपकी डिफ़ॉल्ट लक्ष्य पर निर्भर करता है। नीचे दिए गए उदाहरण में, मैंने टच myprogram.cpp जोड़ा है । मैंने बनाने के लिए एक पुनरावर्ती कॉल भी जोड़ा । यह हर बार आपके द्वारा बल बनाने के लिए डिफ़ॉल्ट लक्ष्य प्राप्त करने का कारण होगा ।

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make

आपको makeमेकफाइल के अंदर कभी भी उपयोग नहीं करना चाहिए । $(MAKE)इसके बजाय उपयोग करें ।
बेंजामिन क्रॉफर्ड Ctrl-Alt-Tut

3

मैंने यह कोशिश की और यह मेरे लिए काम कर गया

इन पंक्तियों को Makefile में जोड़ें

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

बचाओ और अब बुलाओ

make new 

और यह फिर से सब कुछ recompile करेगा

क्या हुआ?

1) 'नई' कॉल साफ। 'क्लीन' डू 'आरएम' जो उन सभी ऑब्जेक्ट फ़ाइलों को हटा देता है जिनमें '.o' का विस्तार होता है।

2) 'नई' कॉल 'मेक'। 'make' देखें कि कोई '.o' फाइल नहीं है, इसलिए यह फिर से '.o' बनाता है। तब लिंकर सभी .o फ़ाइल int एक निष्पादन योग्य आउटपुट से जोड़ता है

सौभाग्य


1
की तुलना में newबेहतर उपयोग के लिए नुस्खा में$(MAKE)make
बेसिल स्टैरनेवविच

1

मिलर के रिकर्सिव मेकओवर के अनुसार हानिकारक आपको कॉल करने से बचना चाहिए $(MAKE)! आपके द्वारा दिखाए जाने के मामले में, यह हानिरहित है, क्योंकि यह वास्तव में मेकफाइल नहीं है, बस एक आवरण लिपि है, जो शायद शेल में भी लिखी गई है। लेकिन आप कहते हैं कि आप इस तरह के गहरे पुनरावृत्ति स्तरों पर जारी रखते हैं, इसलिए आपने शायद उस आंख खोलने वाले निबंध में दिखाई गई समस्याओं का सामना किया है।

जीएनयू के साथ बेशक इससे बचना बोझिल है। और भले ही वे इस समस्या के बारे में जानते हों, लेकिन यह चीजों को करने का उनका प्रलेखित तरीका है।

OTOH, मेकप इस समस्या के समाधान के रूप में बनाया गया था। आप प्रति डायरेक्टरी स्तर पर अपने मेकफाइल्स लिख सकते हैं, फिर भी वे सभी आपके प्रोजेक्ट के पूर्ण दृश्य में एक साथ आ जाते हैं।

लेकिन विरासत मेकफाइल्स को पुनरावर्ती लिखा जाता है। तो वहाँ एक समाधान है, जहां $(MAKE)कुछ भी नहीं है, लेकिन उपप्रकार को मुख्य मेकप प्रक्रिया में वापस कर दें। केवल अगर आप निरर्थक या अपने सबमेक के बीच बदतर, विरोधाभासी चीजें करते हैं, तो आपको अनुरोध करना चाहिए --traditional-recursive-make(जो मेकप के इस लाभ को तोड़ता है)। मुझे आपके अन्य मेकफाइल्स का पता नहीं है, लेकिन अगर वे साफ-सुथरे तरीके से लिखे गए हैं, तो मेकप के साथ आवश्यक रीबिल्ड्स अपने आप हो जाना चाहिए, बिना किसी हैक की आवश्यकता के बिना यहां दूसरों द्वारा सुझाए गए हैं।


प्रश्न का उत्तर नहीं दिया: मुख्य बिंदु के लिए स्पर्शरेखा और एक टिप्पणी होनी चाहिए एक उत्तर नहीं।
फ्लंगो

शायद मैं पर्याप्त स्पष्ट नहीं था। मेकप के साथ इस पूरे रैपर मेकफाइल की जरूरत नहीं है। सटीक आश्रितों को जानकर (उन सभी को, जो अभी के बाद सूचीबद्ध नहीं है :) यह हमेशा आवश्यक होने पर पुनर्निर्माण होगा।
डैनियल

1

यदि आपको पहले से सफलतापूर्वक संकलित किसी भी आउटपुट को संरक्षित करने की आवश्यकता नहीं है

nmake /A 

सभी का पुनर्निर्माण करता है


0

यह वास्तव में इस बात पर निर्भर करता है कि लक्ष्य क्या है। यदि यह एक फोनी टारगेट है (यानी लक्ष्य किसी फाइल से संबंधित नहीं है) तो आपको इसे .PHONY घोषित करना चाहिए।

यदि लक्ष्य लक्ष्य नहीं है, तो यह एक लक्ष्य है, लेकिन आप इसे किसी कारण से पुनर्निर्माण करना चाहते हैं (एक उदाहरण यह है कि जब आप __TIME__ प्रीप्रोसेसिंग मैक्रो का उपयोग करते हैं), तो आपको यहां उत्तर में वर्णित बल योजना का उपयोग करना चाहिए।



0

यह पहले से ही उल्लेख किया गया था, लेकिन मुझे लगा कि मैं उपयोग करने के लिए जोड़ सकता हूं touch

यदि आप touchसभी स्रोत फ़ाइलों को संकलित किया जाना है, तो touchकमांड एक फ़ाइल के टाइमस्टैम्प को सिस्टम टाइम में बदल देता है जिसे touchकमांड निष्पादित किया गया था।

स्रोत फ़ाइल टाइमस्टैम्प वह है जो makeएक फ़ाइल को "जानने" के लिए उपयोग करता है, एक फ़ाइल बदल गई है, और फिर से संकलित करने की आवश्यकता है

उदाहरण के लिए: यदि प्रोजेक्ट c ++ प्रोजेक्ट था, तो करें touch *.cpp, फिर चलाएं make, और पूरे प्रोजेक्ट को फिर से तैयार करना चाहिए।


0

जैसा कि एब्नियरियर ने कहा, जीएनयू मेक मैनुअल में एक अनुशंसित समाधान है, जो लक्ष्य के पुनर्निर्माण के लिए मजबूर करने के लिए 'नकली' लक्ष्य का उपयोग करता है:

clean: FORCE
        rm $(objects)
FORCE: ; 

यह साफ चलेगा, किसी भी अन्य निर्भरता की परवाह किए बिना।

मैंने मैनुअल से समाधान में अर्धविराम को जोड़ा, अन्यथा एक खाली लाइन की आवश्यकता है।


-1

मेरे लिनक्स सिस्टम (सेंटोस 6.2) पर, लक्ष्य घोषित .PHONY और फोर्स पर एक नकली निर्भरता बनाने के बीच एक महत्वपूर्ण अंतर है, जब नियम वास्तव में लक्ष्य से मेल खाती एक फाइल बनाता है। जब फ़ाइल को हर बार पुनर्जीवित किया जाना चाहिए, तो इसके लिए फ़ाइल पर दोनों नकली निर्भरता बल की आवश्यकता होती है, और नकली निर्भरता के लिए .PHONY।

गलत:

date > $@

सही:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE

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