2013-10-10 6 views
9

मेरे पास निम्नलिखित सरलीकृत मेकफ़ाइल है और मैं विभिन्न लक्ष्यों के आधार पर अलग-अलग पथ सेट करने का प्रयास कर रहा हूं। दुर्भाग्यवश, मुझे उन परिणामों को नहीं मिल रहा है जिन्हें मैं उम्मीद करता हूं। यह संस्करण 3.81 बनाने के साथ है।यह मेकफ़ाइल लक्ष्य विशिष्ट चर को अपेक्षित रूप से क्यों विस्तारित नहीं करता है?

echo Compile: /DirUtil.o 

अगर मैं "OBJDIR = wrongdirectory" लाइन uncomment, मैं निम्नलिखित परिणाम है, जो भ्रमित कर रहे हैं के बाद से मैं देख रहा हूँ मिल जाएगा:

.SECONDEXPANSION: 
all: Debug32 

# Object directory set by target 
Debug32: OBJDIR = objdir32 
#OBJDIR = wrongdirectory 

# ObjDir is empty here. :(
OBJS = $(addprefix $(OBJDIR)/,DirUtil.o) 

$(OBJDIR)/%.o : %.cpp 
      echo Compile: [email protected] 

Debug32: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
      echo mkdir $(OBJDIR) - [email protected] 

परिणाम OBJDIR का कोई सेटिंग के साथ इस प्रकार हैं चर के दोनों मूल्यों मैं कहाँ लगता है कि मैं केवल एक ही देखना चाहिए:

echo mkdir objdir32 - wrongdirectory - 
echo Compile: wrongdirectory/DirUtil.o 

मैं यह सोचते हैं रहा है कि चर विस्तार किया जा रहा नहीं कर रहे हैं जब मुझे लगता है कि उन्हें करना चाहिए, लेकिन मैं समझ नहीं कैसे इस beh को बदलने के लिए एवियर।

उत्तर

11

जीएनयू जानकारी पुस्तिका

चर और एक makefile के सभी भागों में कार्यों से, विस्तार कर रहे हैं जब पढ़ने व्यंजनों में, '=' का उपयोग कर चर परिभाषाओं के दाएँ हाथ पक्षों के लिए छोड़कर, और 'परिभाषित' निर्देश का उपयोग कर परिवर्तनीय परिभाषाओं के निकायों।

लक्ष्य-विशिष्ट चर केवल व्यंजनों के भीतर लागू होता है। भीतर

$(OBJS): | $(OBJDIR) 

और

$(OBJDIR): 

यह वैश्विक चर हो रही है।

तो make Debug32 चलाते समय क्या होता है, इसके माध्यम से यह काम करता है, यह OBJS की सामग्री को पूर्व शर्त के रूप में देखता है, जो ऊपर के पहले नियम की ओर जाता है। $(OBJDIR) को पहले से ही वैश्विक मूल्य के साथ प्रतिस्थापित कर दिया गया है, और यह दूसरे नियम में लक्ष्य-नाम से मेल खाता है जिसे भी वैसे ही प्रतिस्थापित किया गया है।

हालांकि

, जब हम नुस्खा के लिए मिलता है:

echo mkdir $(OBJDIR) - [email protected] 

$(OBJDIR), फिर भी प्रतिस्थापित नहीं किया गया है तो यह लक्ष्य-विशिष्ट चर मूल्य हो जाता है।

एक कार्यरत वर्शन

.SECONDEXPANSION: 
all: Debug32 

# Object directory set by target 
Debug32: OBJDIR = objdir32 
OBJDIR = wrongdirectory 

Debug32: OBJS = $(addprefix $(OBJDIR)/,obj.o) 
OBJS = wrongobjs 

Debug32: $$(OBJS) 
    echo OBJS are $(OBJS) 
    echo OBJDIR is $(OBJDIR) 

%/obj.o: | % 
    touch [email protected] 

OBJDIRS = objdir32 wrongdirectory anotherdirectory 
$(OBJDIRS): 
# mkdir $(OBJDIR) 
    mkdir [email protected] 

मुख्य परिवर्तन इस पंक्ति में $$ उपयोग कर रहा है:

Debug32: $$(OBJS) 

केवल एक ही $ के साथ, मैं त्रुटि संदेश मिलता है

make: *** No rule to make target `wrongobjs', needed by `Debug32'. Stop. 

हालांकि, $$ के साथ, मैं

echo OBJS are objdir32/obj.o 
OBJS are objdir32/obj.o 
echo OBJDIR is objdir32 
OBJDIR is objdir32 

माध्यमिक विस्तार के उपयोग आवश्यक शर्तें में लक्ष्य-विशिष्ट चर तक पहुँचने की अनुमति दी है मिलता है।

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

%/obj.o: | % 

प्रत्येक वस्तु फ़ाइल के लिए एक अलग लाइन से बचने के लिए, आप के बजाय निम्न कर सकता है:

OBJ_BASENAMES=obj.o obj2.o obj3.o 

$(addprefix %/,$(OBJ_BASENAMES)): | % 
    touch [email protected] # Replace with the proper recipe 

%/obj.o %/obj2.o %/obj3.o: | % 

फिर make anotherdirectory/obj2.o चलाने के लिए addprefix मैक्रो फैलता युक्त लाइन एक निर्देशिका "anotherdirectory" देवदार कहा जाता है बनाता है सेंट, और इसके अंदर "obj2.o" नामक फ़ाइल बनाता है।

नोट सभी संभावित निर्देशिकाओं को OBJDIRS में सूचीबद्ध किया जाना है। ओबीजेडीआईआर के सभी नियम-विशिष्ट मूल्यों को इकट्ठा करने का कोई तरीका नहीं है, इसलिए उन्हें सूचीबद्ध करना सबसे अच्छा विकल्प है। विकल्प % : कोई भी निर्देशिका बनाने के लिए नियम है, जो किसी भी लक्ष्य को मिलान करने और बनाने में सक्षम है, जो जोखिम भरा हो सकता है। (यदि आप लक्ष्य-विशिष्ट चर के उपयोग को छोड़ देते हैं, तो निर्देशिकाओं की एक सूची प्राप्त करने का एक और तरीका है जिसे बनाया जा सकता है: इसके बजाय Debug32_OBJDIR जैसे अनुमानित नामों के साथ चर का उपयोग करें, और फ़ंक्शंस का उपयोग करके उनके मूल्यों की एक सूची उत्पन्न करें।)

वैकल्पिक रूप से

, एक सामान्य नियम वस्तु फ़ाइलों लिस्टिंग की आवश्यकता नहीं है कि:

SOURCE=$(basename $(notdir [email protected])).cpp 
DIR=$(patsubst %/,%,$(dir [email protected])) 

%.o: $$(SOURCE) | $$(DIR) 
    touch [email protected] # Replace with proper recipe 

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

+0

यह काम करता है की आवश्यकता हो सकती है किसी भी लक्ष्य के लिए है, लेकिन ऐसा प्रतीत होता है कि मुझे ऑब्जेक्ट डायरेक्टरी दो बार और प्रत्येक .o फ़ाइल को दो बार फ़ाइल निर्दिष्ट करना होगा, जिसमें प्रति स्रोत फ़ाइल पैटर्न पैटर्न शामिल है।क्या मैं इस सब गलत के बारे में जा रहा हूँ? दो या दो से अधिक लक्ष्यों के लिए एक साधारण जेनेरिक मेकफ़ाइल बनाना बहुत मुश्किल लगता है। – Jeff

+0

मैंने सभी ऑब्जेक्ट फ़ाइलों को कवर करने का एक तरीका जोड़ा है। मुझे उम्मीद है कि उन सभी को सूचीबद्ध किए बिना यह संभव है (कुछ% 'o: $$ (बेसनाम%)। Cpp | $$ (dir $$ @) ') लेकिन मुझे अभी तक काम करने के लिए यह नहीं मिला है। –

+0

मैंने निर्देशिकाओं को सूचीबद्ध करने के लिए संस्करण और नोट्स का उपयोग करना आसान बना दिया है। निर्देशिका बनाने के लिए मार्क गैलेक की विधि ऐसा लगता है कि यह बेहतर हो सकता है। –

3

एक अच्छा तरीका

%/obj.o: | % 
    touch [email protected] 

OBJDIRS = objdir32 wrongdirectory anotherdirectory 
$(OBJDIRS): 
    mkdir [email protected] 

को संभालने के लिए है:

%/.: 
    mkdir -p [email protected] 

.SECONDEXPANSION: 

फिर बाद में आप सिर्फ लिख सकते हैं, कि एक निर्देशिका

target: prerequisites | $$(@D)/. 
    normal recipe for target 
संबंधित मुद्दे