सवाल मेकफ़ाइल, हेडर निर्भरताएं


मान लें कि मेरे पास नियम के साथ मेकफ़ाइल है

%.o: %.c
 gcc -Wall -Iinclude ...

जब भी हेडर फ़ाइल बदलती है तो मैं * .o को पुनर्निर्मित करना चाहता हूं। जब भी कोई हेडर फ़ाइल में निर्भरता की एक सूची तैयार करने की बजाय /include परिवर्तन, फिर डीआईआर में सभी वस्तुओं का पुनर्निर्माण किया जाना चाहिए।

मैं इसे समायोजित करने के लिए नियम बदलने का एक अच्छा तरीका नहीं सोच सकता, मैं सुझावों के लिए खुला हूं। बोनस पॉइंट्स यदि हेडर की सूची हार्ड-कोडेड नहीं है


76
2018-03-07 00:09


मूल


नीचे मेरा जवाब लिखने के बाद मैंने संबंधित सूची में देखा और पाया: stackoverflow.com/questions/297514/... जो एक डुप्लिकेट प्रतीत होता है। क्रिस डोड का जवाब मेरा बराबर है, हालांकि यह एक अलग नामकरण सम्मेलन का उपयोग करता है। - dmckee


जवाब:


यदि आप जीएनयू कंपाइलर का उपयोग कर रहे हैं, तो संकलक आपके लिए निर्भरताओं की एक सूची एकत्र कर सकता है। मेकफ़ाइल टुकड़ा:

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ -MF  ./.depend;

include .depend

या

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ > ./.depend;

include .depend

कहा पे SRCS स्रोत फ़ाइलों की आपकी पूरी सूची को इंगित करने वाला एक चर है।

उपकरण भी है makedepend, लेकिन मुझे इसे जितना पसंद नहीं आया gcc -MM


106
2018-05-09 16:04



मुझे यह चाल पसंद है, लेकिन मैं कैसे प्राप्त कर सकता हूं depend केवल तब चलने के लिए जब स्रोत फाइलें बदल गई हों? ऐसा लगता है कि हर बार चल रहा है ... - chase
@chase: ठीक है, मैंने गलती से ऑब्जेक्ट फ़ाइलों पर निर्भरता बना दी है, जब यह स्पष्ट रूप से स्रोतों पर होना चाहिए और दोनों लक्ष्यों के लिए निर्भरता का क्रम भी गलत था। स्मृति से टाइप करने के लिए मुझे यही मिलता है। अब इसे आजमाओ। - dmckee
क्या प्रत्येक फाइल से पहले कुछ उपसर्ग को दिखाने का तरीका यह दिखाने के लिए है कि यह किसी अन्य निर्देशिका में है build/file.o ? - RiaD
मैंने एसआरसीएस को ऑब्जेक्ट्स में बदल दिया, जहां ऑब्जेक्ट्स मेरी * .o फाइलों की एक सूची है। ऐसा लगता है कि हर बार चलने से निर्भर करता है और केवल हेडर फाइलों में बदलाव भी पकड़ा जाता है। यह पिछली टिप्पणियों का मुकाबला लगता है..मैं कुछ याद कर रहा हूँ? - BigBrownBear00
बेहतर जवाब तकनीकी रूप से, लेकिन लंबे और कम व्यापक ... - m-ric


अधिकांश उत्तर आश्चर्यजनक रूप से जटिल या गलत हैं। हालांकि सरल और मजबूत उदाहरण कहीं और पोस्ट किए गए हैं [को़ड समीक्षा]। माना जाता है कि gnu प्रीप्रोसेसर द्वारा प्रदान किए गए विकल्प थोड़ा उलझन में हैं। हालांकि, निर्माण लक्ष्य से सभी निर्देशिकाओं को हटाने के साथ -MM दस्तावेज है और एक बग नहीं है [GPP]:

डिफ़ॉल्ट रूप से सीपीपी मुख्य इनपुट फ़ाइल का नाम लेता है, किसी को हटा देता है निर्देशिका घटक और किसी भी फ़ाइल प्रत्यय जैसे '.c', और संलग्न करता है   मंच की सामान्य वस्तु प्रत्यय।

(कुछ हद तक नया) -MMD विकल्प शायद आप चाहते हैं। पूर्णता के लिए एक मेकफ़ाइल का उदाहरण जो एकाधिक स्रोत डीआईआर का समर्थन करता है और कुछ टिप्पणियों के साथ डीआईआर बनाता है। निर्माण के बिना एक साधारण संस्करण के लिए dirs देखें [को़ड समीक्षा]।

CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow

# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build

# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)

# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)

# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)

# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
    # Create build directories - same structure as sources.
    mkdir -p $(@D)
    # Just link all the object files.
    $(CXX) $(CXX_FLAGS) $^ -o $@

# Include all .d files
-include $(DEP)

# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
    mkdir -p $(@D)
    # The -MMD flags additionaly creates a .d file with
    # the same name as the .o file.
    $(CXX) $(CXX_FLAGS) -MMD -c $< -o $@

.PHONY : clean
clean :
    # This should remove all generated files.
    -rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)

यह विधि काम करती है क्योंकि यदि एक ही लक्ष्य के लिए एकाधिक निर्भरता रेखाएं हैं, तो निर्भरताएं बस शामिल हो जाती हैं, उदा .:

a.o: a.h
a.o: a.c
    ./cmd

के बराबर है:

a.o: a.c a.h
    ./cmd

जैसा कि उल्लेख किया गया है: एक ही लक्ष्य के लिए मेकफ़ाइल एकाधिक निर्भरता लाइनें? 


38
2018-03-23 16:27



मुझे यह समाधान पसंद है। मैं निर्भर निर्भर कमांड टाइप नहीं करना चाहता हूं। उपयोगी !! - Robert
ओबीजे वैरिएबल वैल्यू में एक वर्तनी त्रुटि है: CPP पढ़ना चाहिए CPPS - ctrucza
यह मेरा पसंदीदा जवाब है; आपके लिए +1 इस पृष्ठ पर यह एकमात्र ऐसा है जो समझ में आता है, और कवर (जो मैं देख सकता हूं) सभी स्थितियों में जहां पुनर्मूल्यांकन आवश्यक है (अनावश्यक संकलन से बचें, फिर भी पर्याप्त) - Joost
धन्यवाद @ctrucza, अब तय किया जाना चाहिए। - Sophie
बॉक्स के बाहर, यह मेरे लिए हेडर का पता लगाने में असफल रहा, भले ही एचपीपी और सीपीपी दोनों एक ही डीआईआर पर हों। - villasv


जैसा कि मैंने पोस्ट किया था यहाँ जीसीसी निर्भरता बना सकते हैं और एक ही समय में संकलित कर सकते हैं:

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

'-एमएफ' पैरामीटर निर्भरता को स्टोर करने के लिए एक फ़ाइल निर्दिष्ट करता है।

'-Cludee' की शुरुआत में डैश बताता है कि जब .d फ़ाइल मौजूद नहीं है (उदाहरण के लिए पहले संकलन पर) जारी रखें।

नोट -ओ विकल्प के संबंध में जीसीसी में एक बग प्रतीत होता है। यदि आप ऑब्जेक्ट फ़ाइल नाम को obj / _file__c.o कहने के लिए सेट करते हैं तो उत्पन्न होता है फ़ाइलडीडी अभी भी शामिल होगा फ़ाइलओओ, obj / _file__c.o नहीं।


24
2018-03-07 00:15



जब मैं इसे आज़माता हूं तो यह मेरी सभी .o फ़ाइलों को खाली फ़ाइलों के रूप में बनाया जा रहा है। मेरे पास एक बिल्ड सबफ़ोल्डर में मेरी ऑब्जेक्ट्स हैं (इसलिए $ ऑब्जेक्ट्स में बिल्ड / main.o build / smbus.o build / etc ...) शामिल है और यह निश्चित रूप से .d फ़ाइलों को बनाता है जैसा आपने स्पष्ट बग के साथ वर्णित किया है, लेकिन यह निश्चित रूप से .o फाइलों का निर्माण नहीं कर रहा है, जबकि यह करता है अगर मैं -एमएम और -एमएफ हटा देता हूं। - bobpaul
-एमटी का उपयोग आपके उत्तर की अंतिम पंक्तियों में नोट को हल करेगा जो प्रत्येक निर्भरता सूची के लक्ष्य को अपडेट करता है। - Godric Seer
मैंने विभिन्न संयोजनों में यह कोशिश की है और यह काम नहीं कर रहा है ... - g24l
@ बॉबपॉल क्योंकि man gcc कहते हैं -MM का तात्पर्य -E, जो "प्रीप्रोकैसिंग के बाद बंद हो जाता है"। आप की जरूरत है -MMD बजाय: stackoverflow.com/a/30142139/895245 - Ciro Santilli 新疆改造中心 六四事件 法轮功


कुछ इस तरह के बारे में:

includes = $(wildcard include/*.h)

%.o: %.c ${includes}
    gcc -Wall -Iinclude ...

आप सीधे वाइल्डकार्ड का भी उपयोग कर सकते हैं, लेकिन मुझे लगता है कि मुझे उन्हें एक से अधिक स्थानों में चाहिए।

ध्यान दें कि यह केवल छोटी परियोजनाओं पर अच्छा काम करता है, क्योंकि यह मानता है कि प्रत्येक ऑब्जेक्ट फ़ाइल प्रत्येक शीर्षलेख फ़ाइल पर निर्भर करती है।


21
2018-04-01 00:05



धन्यवाद, मैं इसे आवश्यकतानुसार बहुत अधिक जटिल बनाने के लिए बाहर कर रहा था - Mike
हालांकि, यह समस्या यह है कि प्रत्येक ऑब्जेक्ट फ़ाइल को फिर से संकलित किया जाता है, हर बार जब कोई छोटा बदलाव होता है, यानी, यदि आपके पास 100 स्रोत / हेडर फाइलें हैं, और आप केवल एक में एक छोटा बदलाव करते हैं, तो सभी 100 पुनः संकलित हो जाते हैं । - Nicholas Hamilton
आपको वास्तव में यह कहने के लिए अपना उत्तर अपडेट करना चाहिए कि यह ऐसा करने का एक बहुत ही अक्षम तरीका है क्योंकि यह हर बार किसी भी शीर्षलेख फ़ाइल को बदलने के बाद सभी फ़ाइलों का पुनर्निर्माण करता है। अन्य उत्तरों बहुत बेहतर हैं। - xaxxon
यह एक बहुत बुरा समाधान है। निश्चित रूप से यह एक छोटी परियोजना पर काम करेगा, लेकिन किसी भी उत्पादन आकार टीम और निर्माण के लिए, यह भयानक संकलन समय का कारण बन जाएगा और दौड़ने के बराबर बन जाएगा make clean all हर बार। - Julien Guertault


उपरोक्त मार्टिन का समाधान बहुत अच्छा काम करता है, लेकिन उपनिर्देशिका में रहने वाली फ़ाइलों को संभाल नहीं करता है। गॉड्रिक बताता है कि -एमटी ध्वज उस समस्या का ख्याल रखता है, लेकिन साथ ही यह .o फ़ाइल को सही तरीके से लिखा जाने से रोकता है। निम्नलिखित उन दोनों समस्याओं का ख्याल रखेगा:

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) -o $@ $<

4
2017-12-15 12:36





यह नौकरी ठीक करेगी, और यहां तक ​​कि निर्दिष्ट उपनिवेशों को भी संभालेगा:

    $(CC) $(CFLAGS) -MD -o $@ $<

जीसीसी 4.8.3 के साथ इसका परीक्षण किया


3
2018-06-16 12:44





मैं माइकल विलियमसन द्वारा स्वीकृत उत्तर पर इस समाधान को प्राथमिकता देता हूं, यह स्रोतों + इनलाइन फ़ाइलों में परिवर्तन करता है, फिर स्रोत + शीर्षलेख, और अंत में केवल स्रोत। यहां लाभ यह है कि अगर कुछ बदलाव किए जाते हैं तो पूरी लाइब्रेरी को पुन: संकलित नहीं किया जाता है। दो फाइलों के साथ एक परियोजना के लिए एक बड़ा विचार नहीं है, अगर आपके पास 10 या 100 स्रोत हैं, तो आप अंतर देखेंगे।

COMMAND= gcc -Wall -Iinclude ...

%.o: %.cpp %.inl
    $(COMMAND)

%.o: %.cpp %.hpp
    $(COMMAND)

%.o: %.cpp
    $(COMMAND)

0
2017-12-15 19:34



यह तभी काम करता है जब आपके पास अपनी हेडर फाइलों में कुछ भी न हो, जिसके लिए किसी भी सीपीपी-फाइलों के पुनर्मूल्यांकन की आवश्यकता होगी, फिर अन्य कार्यान्वयन फ़ाइल। - matec