कैसे एक SIMPLE C ++ मेकफाइल बनाने के लिए


302

हमें अपनी परियोजना के लिए सब कुछ एक साथ खींचने के लिए मेकफिल का उपयोग करना आवश्यक है, लेकिन हमारे प्रोफेसर ने हमें कभी नहीं दिखाया कि कैसे।

मैं सिर्फ है एक , फ़ाइल a3driver.cpp। ड्राइवर, एक स्थान से एक वर्ग का आयात करता है "/user/cse232/Examples/example32.sequence.cpp"

बस। बाकी सब कुछ के साथ निहित है .cpp

मैं एक साधारण मेकफाइल बनाने के बारे में कैसे जाऊंगा जो एक निष्पादन योग्य बनाता है a3a.exe?


9
.EXE तो इसकी निश्चित रूप से विंडोज। दूसरे विचार पर ... रास्ता यूनिक्स-शैली है। शायद मिंगव -32 का उपयोग कर रहे हैं।
नाथन उस्मान

2
आह। मुझे लगता है कि आपको हर व्यापार का मूल सीखना होगा, भले ही आप उनका उपयोग कभी नहीं करेंगे। बस यह समझना होगा कि सामान कैसे काम करता है। हालांकि, संभावनाएं अच्छी हैं, कि आप हमेशा एक आईडीई में विकसित होंगे, जैसे कि ग्रहण। आपको अपने सरल एक-लाइन मामले के लिए यहां एक उत्तर मिलेगा और बहुत सारे वेब ट्यूटोरियल हैं, लेकिन यदि आप डीपीटी ज्ञान चाहते हैं, तो आप ऑरेइली पुस्तक (अधिकांश एस / डब्ल्यू विषयों के लिए समान) को हरा नहीं सकते हैं। amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/… amazon, हाफ.कॉम, बेटरवर्ल्ड बुक्स ईबे से सेकंड हैंड कॉपी चुनें
मावग का कहना है कि मोनिका

2
@ डेनिस द्वारा पोस्ट किया गया लिंक अब मृत हो गया है, लेकिन वही सामग्री इस आर्काइव.ऑर्ग पेज में मिल सकती है ।
गुइलहर्मे सालोमे

मैं इस व्यक्ति के विचारों को पसंद करता हूं। ( hiltmon.com/blog/2013/07/03/… ) परियोजना संरचना को आसानी से सूट करने के लिए संशोधित किया जा सकता है। और मैं यह भी मानता हूं कि डेवलपर का समय ऑटोमैटिक / ऑटोकॉन्फ के अलावा अन्य चीजों पर खर्च किया जाना चाहिए। इन उपकरणों में अपना स्थान है, लेकिन शायद आंतरिक परियोजनाओं के लिए नहीं। मैं एक स्क्रिप्ट का निर्माण कर रहा हूं जो इस तरह की परियोजना संरचना का निर्माण करेगी।
Daisuke Aramaki

@ GuilhermeSalomé धन्यवाद, मेरा मानना ​​है कि यह सबसे अच्छा सरल और पूर्ण ट्यूटोरियल है।
हरेन लक्स

जवाबों:


559

चूंकि यह यूनिक्स के लिए है, इसलिए एक्जीक्यूटिव के पास कोई एक्सटेंशन नहीं है।

ध्यान देने वाली एक बात यह है कि root-configएक उपयोगिता है जो सही संकलन और लिंकिंग झंडे प्रदान करती है; और जड़ के खिलाफ अनुप्रयोगों के निर्माण के लिए सही पुस्तकालयों। यह इस दस्तावेज़ के लिए मूल श्रोताओं से संबंधित एक विवरण है।

मेक मी बेबी

या यू फर्स्ट टाइम यू गेट फॉर गॉट मेड

मेक की एक परिचयात्मक चर्चा, और सरल मेकफाइल कैसे लिखना है

क्या है मेक? और मैं क्यों परवाह करूं?

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

वास्तव में, आप अन्य चीजों के लिए भी मेक का उपयोग कर सकते हैं, लेकिन मैं इसके बारे में बात नहीं करने जा रहा हूं।

एक तुच्छ मेकफाइल

मान लीजिए कि आपके पास एक निर्देशिका है: tool tool.cc tool.o support.cc support.hhऔर support.oजो निर्भर करता है rootऔर कहलाने वाले प्रोग्राम में संकलित किया जाता है tool, और मान लीजिए कि आप स्रोत फ़ाइलों पर हैकिंग कर रहे हैं (जिसका मतलब है कि मौजूदा toolतारीख से बाहर है) और चाहते हैं कार्यक्रम को संकलित करें।

यह अपने आप करने के लिए आप कर सकते हैं

  1. यदि या तो चेक support.ccया support.hhसे अधिक नया support.oहै, और यदि ऐसा है तो तरह एक आदेश चला

    g++ -g -c -pthread -I/sw/include/root support.cc
  2. यदि या तो चेक support.hhया tool.ccकी तुलना में नए हैं tool.o, और यदि हां की तरह एक आदेश चला

    g++ -g  -c -pthread -I/sw/include/root tool.cc
  3. जाँच करें कि tool.oक्या नया है tool, और यदि ऐसा है तो जैसे कमांड चलाते हैं

    g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
    -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
    -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl

ओह! क्या झंझट है! याद करने के लिए बहुत कुछ है और गलतियाँ करने के कई मौके हैं। (BTW-- यहाँ प्रदर्शित कमांड लाइनों के विवरण हमारे सॉफ्टवेयर वातावरण पर निर्भर करते हैं। ये लोग मेरे कंप्यूटर पर काम करते हैं।)

बेशक, आप हर बार सभी तीन कमांड चला सकते हैं। यह काम करेगा, लेकिन यह सॉफ्टवेयर के एक बड़े टुकड़े (जैसे DOGS जो मेरे मैकबुक पर जमीन से संकलित होने में 15 मिनट से अधिक समय लेता है) के लिए अच्छी तरह से पैमाने पर नहीं है।

इसके बजाय आप makefileइस तरह नामक एक फ़ाइल लिख सकते हैं :

tool: tool.o support.o
    g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
        -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
        -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl

tool.o: tool.cc support.hh
    g++ -g  -c -pthread -I/sw/include/root tool.cc

support.o: support.hh support.cc
    g++ -g -c -pthread -I/sw/include/root support.cc

और makeकमांड लाइन पर टाइप करें । जो ऊपर दिखाए गए तीन चरणों को स्वचालित रूप से प्रदर्शित करेगा।

यहाँ की अनइंस्टाल्ड लाइन्स में "टारगेट: डिपेंडेंसीज़" फॉर्म होता है और यह बताएं कि संबंधित कमांड्स (इंडेंटेड लाइन्स) को रन किया जाना चाहिए, यदि कोई भी डिपेंडेंसी टारगेट की तुलना में नई हो। यही है, विभिन्न फ़ाइलों में परिवर्तन को समायोजित करने के लिए निर्भरता रेखाओं के तर्क का वर्णन किया जाना चाहिए। यदि support.ccपरिवर्तन है कि इसका मतलब है कि support.oपुनर्निर्माण किया जाना चाहिए, लेकिन tool.oअकेले छोड़ दिया जा सकता है। जब support.oपरिवर्तन toolका पुनर्निर्माण किया जाना चाहिए।

प्रत्येक निर्भरता रेखा से जुड़ी कमांड को एक टैब के साथ सेट किया गया है (नीचे देखें) लक्ष्य को संशोधित करना चाहिए (या कम से कम इसे संशोधन समय को अपडेट करने के लिए स्पर्श करें)।

चर, नियमों में निर्मित, और अन्य उपहार

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

चर करें

मेक वैरिएबल एक्सेस करने का सिंटैक्स है $(VAR)

एक चर बनाने के लिए वाक्यविन्यास है: VAR = A text value of some kind (या VAR := A different text value but ignore this for the moment)।

आप हमारे मेकफाइल के इस उन्नत संस्करण जैसे नियमों में चर का उपयोग कर सकते हैं:

CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
       -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
       -Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
       -lm -ldl

tool: tool.o support.o
    g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

जो थोड़ा अधिक पठनीय है, लेकिन फिर भी बहुत टाइपिंग की आवश्यकता है

कार्य करें

GNU मे सिस्टम पर फाइलसिस्टम या अन्य कमांड्स से जानकारी हासिल करने के लिए कई प्रकार के कार्य करता है। इस मामले में हम में रुचि रखने वाले कर रहे हैं $(shell ...)जो तर्क (रों) के उत्पादन के लिए विस्तारित, और $(subst opat,npat,text)जो की सभी आवृत्तियों की जगह opatके साथ npatपाठ में।

इसका लाभ उठाकर हमें:

CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

tool: $(OBJS)
    g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

जो टाइप करना आसान है और बहुत अधिक पठनीय है।

नोटिस जो

  1. हम अभी भी प्रत्येक ऑब्जेक्ट फ़ाइल और अंतिम निष्पादन योग्य के लिए निर्भरता स्पष्ट रूप से बता रहे हैं
  2. हमें दोनों स्रोत फ़ाइलों के लिए संकलन नियम को स्पष्ट रूप से लिखना होगा

लागू और पैटर्न नियम

हम आम तौर पर उम्मीद करेंगे कि सभी सी ++ स्रोत फ़ाइलों को उसी तरह से व्यवहार किया जाना चाहिए, और मेक इसे राज्य करने के तीन तरीके प्रदान करता है:

  1. प्रत्यय नियम (जीएनयू में अप्रचलित माना जाता है, लेकिन पीछे की संगतता के लिए रखा गया है)
  2. निहित नियम
  3. पैटर्न नियम

अंतर्निहित नियम बनाए गए हैं, और कुछ पर नीचे चर्चा की जाएगी। पैटर्न नियमों को एक रूप में निर्दिष्ट किया जाता है

%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c $<

जिसका मतलब है कि ऑब्जेक्ट फाइलें सी स्रोत फाइलों से दिखाई गई कमांड को चलाकर उत्पन्न की जाती हैं, जहां "स्वचालित" चर $<पहले निर्भरता के नाम पर फैलता है।

बिल्ट-इन रूल्स

मेक इन बिल्ट इन रूल्स की एक पूरी मेज़बानी है जिसका मतलब है कि बहुत बार, एक प्रोजेक्ट को बहुत ही साधारण मेकफाइल द्वारा संकलित किया जा सकता है।

C स्रोत फ़ाइलों के लिए नियम में निर्मित GNU मेक अप एक प्रदर्शनी है। इसी तरह हम C ++ सोर्स फाइल्स से ऑब्जेक्ट फाइल बनाते हैं जैसे रूल $(CXX) -c $(CPPFLAGS) $(CFLAGS)

सिंगल ऑब्जेक्ट फाइल्स का उपयोग करके लिंक किया गया है $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS), लेकिन यह हमारे मामले में काम नहीं करेगा, क्योंकि हम कई ऑब्जेक्ट फाइल्स को लिंक करना चाहते हैं।

अंतर्निहित नियम द्वारा प्रयुक्त चर

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

  • CC - सी संकलक का उपयोग करने के लिए
  • CXX - उपयोग करने के लिए C ++ कंपाइलर
  • LD - उपयोग करने के लिए लिंकर
  • CFLAGS - सी स्रोत फ़ाइलों के लिए संकलन ध्वज
  • CXXFLAGS - सी ++ स्रोत फ़ाइलों के लिए संकलन झंडे
  • CPPFLAGS - सी-प्रीप्रोसेसर के लिए झंडे (आमतौर पर कमांड लाइन पर परिभाषित फ़ाइल पथ और प्रतीक शामिल हैं), C और C ++ द्वारा उपयोग किए गए
  • LDFLAGS - लिंकर झंडे
  • LDLIBS - लिंक करने के लिए पुस्तकालय

एक बेसिक मेकफाइल

अंतर्निहित नियमों का लाभ उठाकर हम अपने मेकफाइल को सरल बना सकते हैं:

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh

support.o: support.hh support.cc

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) tool

हमने कई मानक लक्ष्य भी जोड़े हैं जो विशेष क्रियाएं करते हैं (जैसे स्रोत निर्देशिका की सफाई)।

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

हमारे पास अभी भी सभी निर्भरताएं हार्ड-कोडेड हैं।

कुछ रहस्यमय सुधार

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

depend: .depend

.depend: $(SRCS)
    $(RM) ./.depend
    $(CXX) $(CPPFLAGS) -MM $^>>./.depend;

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) *~ .depend

include .depend

नोटिस जो

  1. स्रोत फ़ाइलों के लिए अब कोई निर्भरता रेखाएँ नहीं हैं!?!
  2. कुछ अजीब जादू से संबंधित है। निर्भरता और निर्भरता
  3. यदि आप करते हैं makeतो ls -Aआपको एक फ़ाइल दिखाई देती है, .dependजिसमें ऐसी चीज़ें होती हैं जो निर्भरता रेखाएँ बनाती हैं

अन्य पढ़ना

जानिए कीड़े और ऐतिहासिक नोट

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

(यह मैंने भौतिकी स्नातक छात्रों के लिए लिखे एक विकि पोस्ट से कॉपी किया था।)


9
निर्भरता उत्पन्न करने का यह तरीका अप्रचलित है और वास्तव में हानिकारक है। उन्नत ऑटो-निर्भरता पीढ़ी देखें ।
मैक्सिम इगोरुशिन

5
-pthreadध्वज gccआवश्यक मैक्रो को परिभाषित करने का कारण बनता है, -D_REENTRANTअनावश्यक है।
मैक्सिम इगोरुस्किन

8
@jcoe यह निर्भरता उत्पन्न करने के लिए एक अनावश्यक अतिरिक्त प्रीप्रोसेसर पास करता है। अनावश्यक काम करना यह सिर्फ बर्फ के खंभे को पिघलाने वाली गर्मी को नष्ट करता है और बड़े पैमाने पर, हमारे ब्रह्मांड की गर्मी की मृत्यु के करीब है।
मैक्सिम Egorushkin

2
संभवतः "हानिकारक" एक बहुत अधिक कठिन है, लेकिन यह देखते हुए कि स्पष्ट निर्भरता-पीढ़ी के चरण या लक्ष्य बहुत कम से कम जीसीसी 3 के बाद से पुराने हैं, मुझे वास्तव में लगता है कि हम सभी को उनके अतीत से आगे बढ़ना चाहिए। bruno.defraine.net/techtips/makefile-auto-d dependencies
gcc/

2
वास्तव में, स्वीकृत उत्तर सॉफ़्टवेयर के बहुत विशिष्ट टुकड़े पर निर्भर नहीं होना चाहिए ( root-config)। एक ही क्षमता के साथ एक अधिक सामान्य विकल्प प्रस्तावित किया जाना चाहिए यदि कोई है या इसे बस छोड़ दिया जाना चाहिए। सबसे अधिक इस्तेमाल किए जाने वाले मैक्रोज़ की लिस्टिंग और स्पष्टीकरण के कारण मैंने इसे कम नहीं किया।
हरी डायोड

56

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

यहां एक त्वरित उदाहरण है (ध्यान रखें कि मैं 4 स्थानों का उपयोग कर रहा हूं, जहां मुझे एक टैब का उपयोग करना चाहिए, स्टैक ओवरफ्लो मुझे अपने कंप्यूटर का उपयोग नहीं करने देगा:

a3driver: a3driver.o
    g++ -o a3driver a3driver.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

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

चूंकि केवल एक फ़ाइल है, इसलिए इसे भी कम किया जा सकता है:

a3driver: a3driver.cpp
    g++ -o a3driver a3driver.cpp

पहला उदाहरण मैंने जो दिखाया, वह यह है कि यह मेकअप की शक्ति को दर्शाता है। यदि आपको किसी अन्य फ़ाइल को संकलित करने की आवश्यकता है, तो आप बस एक और अनुभाग जोड़ सकते हैं। यहाँ एक दूसरेFile.cpp के साथ एक उदाहरण दिया गया है (जो सेकंडफाइल.एच नामक हेडर में लोड होता है):

a3driver: a3driver.o secondFile.o
    g++ -o a3driver a3driver.o secondFile.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

secondFile.o: secondFile.cpp secondFile.h
    g++ -c secondFile.cpp

इस तरह अगर आप secondFile.cpp या secondFile.h और recompile में कुछ बदलते हैं, तो यह केवल secondFile.cpp (a3driver.cpp नहीं) को recompile करेगा। या वैकल्पिक रूप से, यदि आप a3driver.cpp में कुछ बदलते हैं, तो यह दूसरी फ़ाइल recompile नहीं होगा।

अगर आपको इसके बारे में कोई प्रश्न पूछना है तो मुझे बताएं।

"सभी" नाम का एक खंड और "स्वच्छ" नाम का एक खंड शामिल करना भी पारंपरिक है। "सभी" आमतौर पर सभी निष्पादन योग्य वस्तुओं का निर्माण करेगा, और "स्वच्छ" जैसे "निर्माण कलाकृतियों" को हटा देगा। जैसे फाइलें और निष्पादनकर्ता:

all: a3driver ;

clean:
    # -f so this will succeed even if the files don't exist
    rm -f a3driver a3driver.o

संपादित करें: मैंने ध्यान नहीं दिया कि आप विंडोज पर हैं। मुझे लगता है कि केवल अंतर बदल रहा -o a3driverहै -o a3driver.exe


पूर्ण कोड मैं उपयोग करने की कोशिश कर रहा हूं: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp BUT, यह मुझे "लापता विभाजक" बताता है। मैं TAB का उपयोग कर रहा हूं, लेकिन यह अभी भी मुझे बताता है। कोई उपाय?
बीतना

2
जहाँ तक मैं बता सकता हूँ, वह त्रुटि संदेश केवल तभी आता है जब आपके पास रिक्त स्थान हों। सुनिश्चित करें कि आपके पास रिक्त स्थान से शुरू होने वाली कोई रेखा नहीं है (स्पेस + टैब उस त्रुटि को देगा)। यही एक चीज है जिसके बारे में मैं सोच सकता हूं ..
ब्रेंडन लॉन्ग

भविष्य के संपादकों पर ध्यान दें: StackOverflow टैब को रेंडर नहीं कर सकता है, भले ही आप उन्हें उत्तर में संपादित करें, इसलिए कृपया उस बारे में मेरे नोट को "ठीक" करने की कोशिश न करें।
ब्रेंडन लॉन्ग

35

हर कोई स्रोत फ़ाइलों को सूचीबद्ध करना क्यों पसंद करता है? एक साधारण खोज कमांड आसानी से देखभाल कर सकता है।

यहाँ एक गंदगी सरल C ++ मेकफाइल का उदाहरण दिया गया है। बस इसे एक निर्देशिका में छोड़ दें जिसमें .Cफाइलें हों और फिर टाइप करें make...

appname := myapp

CXX := clang++
CXXFLAGS := -std=c++11

srcfiles := $(shell find . -name "*.C")
objects  := $(patsubst %.C, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

2
स्रोत फ़ाइलों को ऑटो-खोजने के लिए नहीं होने का एक कारण यह है कि किसी व्यक्ति को अलग-अलग फ़ाइलों की आवश्यकता वाले अलग-अलग निर्माण लक्ष्य हो सकते हैं।
हमीज़ेल ने

सहमत @mijail, साथ ही सबमॉड्यूल्स जिसमें एक टन स्रोत / हेडर होते हैं जिन्हें आप संकलित / लिंक नहीं करना चाहते हैं ... और निस्संदेह कई अन्य परिस्थितियां जहां संपूर्ण खोज / उपयोग अनुपयुक्त है।
इंजीनियर

इसके बजाय "शेल फाइंड" और "वाइल्डकार्ड" का उपयोग क्यों करें?
नोलन

1
एक स्रोत निर्देशिका वृक्ष में स्रोत फ़ाइलों को खोजने के लिए @Nolan
AlejandroVD

13

आपके पास दो विकल्प थे।

विकल्प 1: सरलतम मेकफाइल = कोई निर्माण नहीं।

"A3driver.cpp" को "a3a.cpp" का नाम दें, और फिर कमांड लाइन पर लिखें:

nmake a3a.exe

और बस। यदि आप GNU मेक का उपयोग कर रहे हैं, तो "मेक" या "गमेक" या जो भी उपयोग करें।

विकल्प 2: एक 2-लाइन मेकफाइल।

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj

3
यह एक उत्कृष्ट उत्तर होगा यदि यह ओपी के पर्यावरण के विवरण के बारे में इतनी सारी चीजों को निर्धारित नहीं करता है। हां, वे विंडोज पर हैं, लेकिन इसका मतलब यह नहीं है कि वे उपयोग कर रहे हैं nmakelinkकमांड लाइन भी बहुत कम से कम दस्तावेज है जो एक पर एक विशेष संकलक करने के लिए बहुत ही विशेष लग रहा है, और ऐसा करना चाहिए।
ट्रिपलआई

6

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

निर्भरता नियमों का एक पेड़ है जो इस तरह दिखता है (ध्यान दें कि इंडेंट को TAB होना चाहिए):

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

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

तो आपका मेकफाइल कुछ इस तरह दिखेगा।

a3a.exe : a3driver.obj 
    link /out:a3a.exe a3driver.obj

a3driver.obj : a3driver.cpp
    cc a3driver.cpp

6

मेरा सुझाव है (ध्यान दें कि इंडेंट एक TAB है):

tool: tool.o file1.o file2.o
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

या

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
tool: tool.o file1.o file2.o

बाद का सुझाव थोड़ा बेहतर है क्योंकि यह GNU मेक इंप्लिकेट नियमों का पुन: उपयोग करता है। हालांकि, काम करने के लिए, स्रोत फ़ाइल में अंतिम निष्पादन योग्य (यानी: tool.cऔर tool) के समान नाम होना चाहिए ।

ध्यान दें, स्रोतों को घोषित करना आवश्यक नहीं है। इंटरमीडिएट ऑब्जेक्ट फाइलें निहित नियम का उपयोग करके उत्पन्न होती हैं। नतीजतन, यह Makefileकाम सी और सी ++ (और फोरट्रान, आदि के लिए भी ...)।

यह भी ध्यान दें, डिफ़ॉल्ट रूप से, मेकफाइल $(CC)लिंकर के रूप में उपयोग करता है। $(CC)C ++ ऑब्जेक्ट फ़ाइलों को लिंक करने के लिए काम नहीं करता है। हम LINK.oकेवल उसी के कारण संशोधित करते हैं। यदि आप C कोड संकलित करना चाहते हैं, तो आपको LINK.oमान को बाध्य करने की आवश्यकता नहीं है ।

ज़रूर, आप चर के साथ अपने संकलन झंडे भी जोड़ सकते हैं CFLAGSऔर अपने पुस्तकालयों को जोड़ सकते हैं LDLIBS। उदाहरण के लिए:

CFLAGS = -Wall
LDLIBS = -lm

एक तरफ ध्यान दें: यदि आपको बाहरी पुस्तकालयों का उपयोग करना है, तो मैं सही ढंग से सेट करने के लिए pkg-config का उपयोग करने का सुझाव देता हूं CFLAGSऔर LDLIBS:

CFLAGS += $(shell pkg-config --cflags libssl)
LDLIBS += $(shell pkg-config --libs libssl)

चौकस पाठक ध्यान देगा कि Makefileएक हेडर बदले जाने पर यह ठीक से पुनर्निर्माण नहीं करता है। समस्या को ठीक करने के लिए इन पंक्तियों को जोड़ें:

override CPPFLAGS += -MMD
include $(wildcard *.d)

-MMDहेडर निर्भरता के बारे में Makefile टुकड़े शामिल है कि .d फ़ाइलों का निर्माण करने की अनुमति देता है। दूसरी पंक्ति सिर्फ उनका उपयोग करती है।

यकीन के लिए, एक अच्छी तरह से लिखा मेकफाइल भी शामिल होना चाहिए cleanऔर distcleanनियम:

clean:
    $(RM) *.o *.d

distclean: clean
    $(RM) tool

नोटिस, $(RM)के बराबर है rm -f, लेकिन rmसीधे कॉल न करने के लिए यह एक अच्छा अभ्यास है ।

allनियम भी सराहना की है। काम करने के लिए, यह आपकी फ़ाइल का पहला नियम होना चाहिए:

all: tool

आप एक installनियम भी जोड़ सकते हैं :

PREFIX = /usr/local
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

DESTDIRडिफ़ॉल्ट रूप से खाली है। उपयोगकर्ता इसे एक वैकल्पिक प्रणाली (क्रॉस-संकलन प्रक्रिया के लिए अनिवार्य) पर आपके प्रोग्राम को स्थापित करने के लिए सेट कर सकता है। PREFIXआपके पैकेज को स्थापित करने के लिए कई वितरण के लिए पैकेज अनुरक्षक भी बदल सकते हैं/usr

एक अंतिम शब्द: स्रोत फ़ाइलों को उप-निर्देशिकाओं में न रखें। यदि आप वास्तव में ऐसा करना चाहते हैं, तो इसे Makefileरूट डायरेक्टरी में रखें और अपनी फ़ाइलों (यानी) की पहचान करने के लिए पूर्ण पथों का उपयोग करेंsubdir/file.o ) की ।

इसलिए संक्षेप में, आपका पूरा मेकफाइल ऐसा दिखना चाहिए:

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)

all: tool
tool: tool.o file1.o file2.o
clean:
    $(RM) *.o *.d
distclean: clean
    $(RM) tool
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

अंत के पास: नियमों के बीच खाली लाइनें नहीं होनी चाहिए? जॉन नोएलर के जवाब ने दावा किया कि।
पीटर मोर्टेनसेन

makeमुझे पता है कि जीएनयू मेक और बीएसडी मेक को लागू करने के लिए नियमों के बीच खाली लाइनों की जरूरत नहीं है। हालांकि, यह makeउनके खुद के कीड़े ^ Wspecificities के साथ कार्यान्वयन के टन मौजूद है ।
जेरेम पुइलर

5

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

appname := myapp

CXX := g++
CXXFLAGS := -Wall -g

srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects  := $(patsubst %.cpp, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

मेकफाइल्स बहुत जटिल प्रतीत होते हैं। मैं एक का उपयोग कर रहा था, लेकिन यह जी ++ पुस्तकालयों में लिंक नहीं करने से संबंधित एक त्रुटि उत्पन्न कर रहा था। इस कॉन्फ़िगरेशन ने उस समस्या को हल किया।

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