2009-02-26 3 views
11

मैं परीक्षण चलाने के लिए एक से थोड़ा hackish makefile मिल गया है हटाना पड़ता है:क्यों ग्नू एक फ़ाइल

### Run the tests 

tests := tests/test1 tests/test2 ... 

test: $(tests) 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

यह काम करता है, लेकिन यह कुछ मैं इसे पहले कभी नहीं देखा है ऐसा बनाओ बनाता है। मेरा परीक्षण वर्तमान में टूटा हुआ है, और बस त्रुटि का कारण बनता है। निम्नलिखित आउटपुट देता है:

gcc -o tests/test1 [flags blah blah] tests/test1.c 
tests/test1 
make: *** [tests/test1] Bus error 
make: *** Deleting file `tests/test1' 

मैं आखिरी पंक्ति के बारे में उत्सुक हूं। मैंने कभी नहीं देखा है कि पहले ऐसा करें। संकलित परीक्षण को हटाएं क्यों?

नोट: मैंने इसे आसान बनाने के लिए इस उदाहरण को काफी भारी संपादित किया। मैंने कुछ गलतियों को पेश किया होगा।

उत्तर

14

क्योंकि लक्ष्य सही ढंग से बनाया नहीं गया है। अगली बार जब आप make प्रोजेक्ट करेंगे, तो यह लक्ष्य को पुनर्निर्माण करने का प्रयास करेगा। अगर फ़ाइल को हटा नहीं दिया गया था, तो make में कुछ गलत होने का कोई तरीका नहीं होगा। make यह नहीं पता कि विफलता उस प्रक्रिया की बजाय परीक्षण से आ रही है जो लक्ष्य बनाता है।


चाहे यह व्यवहार आपके मामले में वांछनीय है परीक्षणों की प्रकृति पर निर्भर करता है या नहीं। यदि आप परीक्षण को ठीक करने की योजना बना रहे हैं ताकि यह Bus error का कारण न हो, लक्ष्य को हटा देना एक बड़ा सौदा नहीं है। यदि आप बाद में डिबगिंग के लिए लक्ष्य का उपयोग करना चाहते हैं, तो आपको अपनी मेक प्रक्रिया में बदलाव करना होगा।

लक्ष्य हटाने के लिए एक तरीका .PRECIOUS लक्ष्य का उपयोग करना है।


एक और हो सकता है:

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

जांची नहीं है, लेकिन documentation इंगित करता है लक्ष्य को निकाला नहीं जाएगा:

एक त्रुटि होता है जब कि मेकअप की अनदेखी करने के लिए कहा था नहीं किया गया है , इसका तात्पर्य है कि वर्तमान लक्ष्य को सही ढंग से रीमेड नहीं किया जा सकता है, और न ही कोई अन्य जो सीधे या परोक्ष रूप से निर्भर करता है। इन लक्ष्यों के लिए कोई और आदेश निष्पादित नहीं किया जाएगा, क्योंकि उनकी पूर्व शर्त हासिल नहीं की गई है।

और:

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

11

एक तरीका यह व्यवहार से बचने के लिए दो चरणों में निर्माण और परीक्षण निष्पादन विभाजित करने के लिए है:

tests := tests/test1 tests/test2 ... 

test: $(tests) runtests 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 

runtests: %.out: % 
    $< | tee [email protected] 

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

+1

+1 यह इंगित करने का एकमात्र उत्तर है कि व्यवहार एक बग्गी मेकफ़ाइल के कारण हुआ था जो परीक्षण कार्यक्रम उत्पन्न करने और इसे एक नियम में चलाने के लिए था। –

+0

आईएमओ यह बेहतर समाधान है: क्लीनर, और अधिक "मेक-जैसा"। हालांकि, विवरण अधिक साफ तरीके से संभाला जा सकता है। सबसे पहले मेकफ़ाइल लेखक को यह तय करना होगा: क्या आप परीक्षणों को _always_ करना चाहते हैं, या केवल परीक्षण चलाएं यदि परीक्षण फ़ाइल का पुनर्निर्माण किया गया था (बाद वाला मूल उदाहरण क्या था)। – MadScientist

6

यह बनाने का डिफ़ॉल्ट व्यवहार है। जब कोई आदेश एक त्रुटि कोड देता है (उदा। गैर-शून्य रिटर्न) तो लक्ष्य लक्ष्य हटा दिया जाता है। प्रैक्टिस और इग्नोर मेकफ़ाइल निर्देश इस व्यवहार को बदल सकते हैं।

संबंधित मुद्दे