2010-12-03 15 views
20

मैं सी के सापेक्ष शुरुआतकर्ता हूं और मुझे सीखना है कि मेकफ़ाइल कैसे काम करते हैं और मैं थोड़ा उलझन में हूं कि सी फाइलों का संयोजन कैसे काम करता है। मान लें कि हमारे पास main.c, foo.c, और bar.c. है। कोड को कैसे लिखा जाना चाहिए ताकि main.c अन्य फ़ाइलों में फ़ंक्शंस को पहचान सके? साथ ही, foo.c और bar.c में, क्या मुख्य कार्य में लिखा गया सभी कोड है या क्या हमें उन कार्यों के लिए अन्य कार्यों को लिखने की आवश्यकता है जिन्हें हमें करने की आवश्यकता है? मैंने मेकफ़ाइल कैसे लिखे हैं इस पर ट्यूटोरियल पढ़े हैं, और यह अधिकांश भाग के लिए समझ में आता है, लेकिन मैं अभी भी इसके मूलभूत रसद पर उलझन में हूं।सी में एकाधिक स्रोत फ़ाइलें- मेकफ़ाइल वास्तव में कैसे काम करते हैं?

+1

बस एक ध्यान दें, नहीं एक पूर्ण जवाब: आप वास्तव में नहीं है एक से अधिक फ़ाइल में एक 'main' समारोह है कि एक ही लक्ष्य में संकलित किया जाता है, तो के रूप में चाहते हैं आपके पास एक ही नाम के साथ दो कार्य होंगे। –

उत्तर

24

आम तौर पर क्या होगा, आप हेडर फ़ाइल में अन्य फ़ाइलों के लिए अपने कार्यों को परिभाषित करेंगे, जिसे बाद में main.c. में शामिल किया जा सकता है।

main.c:

#include "foo.h" 

int main(int argc, char *argv[]) { 
    do_foo(); 
    return 0; 
} 

foo.h:

void do_foo(); 

foo.c:

#include <stdio.h> 
#include "foo.h" 

void do_foo() { 
    printf("foo was done\n"); 
} 

क्या होगा कि मुख्य है उदाहरण के लिए, इन स्निपेट पर विचार .c को ऑब्जेक्ट फ़ाइल (main.o) में बदल दिया जाएगा, और foo.c को ऑब्जेक्ट फ़ाइल (foo.o) में बदल दिया जाएगा। फिर लिंकर इन दो फाइलों को एकसाथ लिंक करेगा और वह जगह है जहां 0.cमुख्य.c में फ़ंक्शन foo.o में फ़ंक्शन के साथ 'संबद्ध' है।

उदाहरण जीसीसी आदेश: जीसीसी -ओ MyProgram main.c foo.c

उदाहरण makefile

myprogam: main.o foo.o 
    gcc -o myprogram main.o foo.o 

main.o: main.c foo.h 
    gcc -c main.c 

foo.o: foo.c foo.h 
    gcc -c foo.c 
+2

वास्तविक टैब के साथ मेकफ़ाइल इंडेंट करें जैसा कि यहां बताया गया है http://stackoverflow.com/a/9580615/1461060 – gihanchanuka

2

foo.c में कार्य foo.c से बाहर जाने की आवश्यकता है foo.h में प्रोटोटाइप होना चाहिए। उन फ़ाइलों को कॉल करने की आवश्यकता वाली बाहरी फ़ाइलों को #include "foo.h" होना चाहिए। foo.c और bar.c में main() फ़ंक्शन भी नहीं होना चाहिए यदि वे main.c के समान प्रोग्राम का हिस्सा हैं।

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

main.c:

#include "foo.h" 

int main() 
{ 
    fooprint(12); 
    return 0; 
} 

foo.c:

#include "stdio.h" 
#include "foo.h" 

void fooprint(int val) 
{ 
    printf("A value: %d\n", val); 
} 

foo.h:

void fooprint(int val); 

Makefile:

यहाँ एक बहुत ही सरल उदाहरण है

main: main.c foo.o 
    gcc -o main main.c foo.o 

foo.o: foo.c 
    gcc -c foo.c 

तो फिर तुम make main चला सकते हैं और यह foo.o में foo.c संकलित कर देगा तो main.c संकलन और foo.o. के साथ लिंक यदि आप main.c संशोधित करते हैं, तो यह केवल main.c को पुन: संकलित करेगा और इसे पहले से निर्मित foo.o के विरुद्ध लिंक करेगा।

+0

क्या आपका पहला वाक्य पढ़ना चाहिए "foo.c में फ़ंक्शंस जिन्हें बाहर से बुलाया जाना चाहिए foo.c में foo.h में प्रोटोटाइप होना चाहिए", "नहीं" को छोड़कर और वास्तव में आप जो कहते हैं उसे बदल रहे हैं? Corollaries (1) कार्य हैं जिन्हें बाहर foo.c से बुलाया जाने की आवश्यकता नहीं है, स्थिर कार्यों के रूप में परिभाषित किया जाना चाहिए, और (2) समानांतर में, bar.c में कार्य जिन्हें बाहरी bar.c से बुलाया जाना चाहिए bar.h में प्रोटोटाइप है (और bar.c के अंदर फ़ंक्शंस जिन्हें बाहरी bar.c से नहीं कहा जाना चाहिए, को स्थिर कार्यों के रूप में परिभाषित किया जाना चाहिए)। –

+0

@ जोनाथन: ओह, हाँ। मैं उस बिंदु को 'स्थिर 'के बारे में बनाने जा रहा था लेकिन इसके खिलाफ फैसला किया। – nmichaels

+0

ओपी कम से कम प्रोग्राम संगठन के बारे में पूछने के बारे में पूछताछ के रूप में है; मेरा मानना ​​है कि 'स्थैतिक डिफ़ॉल्ट होना चाहिए' पर प्रारंभिक शिक्षा एक अच्छा विचार है - सबकुछ स्थिर होना चाहिए। दूसरी आम शुरुआत करने वाली गलती यह है कि 'foo.c में उपयोग की जाने वाली सभी घोषणाएं foo.h में होनी चाहिए', यह बताते हुए कि 'foo.h बाहरी दुनिया को बताता है कि उन्हें उन कार्यों का उपयोग करने के लिए क्या जानने की आवश्यकता है जिन्हें foo.c उनके लिए परिभाषित करता है उपयोग करने के लिए'। उदाहरण के लिए, केवल foo.c के अंदर उपयोग किए जाने वाले प्रकारों को foo.h में परिभाषित नहीं किया जाना चाहिए - फिर भी वे अक्सर होते हैं। –

13

बारे C/C++ संकलन

जब आपके पास एक सेट फाइलों के, आप आमतौर पर 2 चीजें करते हैं:

  • एक ऑब्जेक्ट फ़ाइल (.o)
  • सभी ऑब्जेक्ट फ़ाइलों को निष्पादन योग्य में लिंक करने के लिए प्रत्येक स्रोत फ़ाइल (.c) को संकलित करें।

स्रोत फ़ाइलें स्वतंत्र कर रहे हैं - आप हेडर फाइल जरूरत आदेश किसी अन्य मॉड्यूल उन्हें का उपयोग करने देने में किसी दिए गए मॉड्यूल में कार्यों के बारे में "जानकारी" प्रदान (घोषणाओं) सक्षम होने के लिए। शीर्षलेख फ़ाइलों को स्वयं द्वारा संकलित नहीं किया जाता है - वे #include डी स्रोत फ़ाइलों के हिस्सों के रूप में हैं।

इस पर दिखेगा कि इस तरह के आदेश कैसे दिखते हैं और make द्वारा उन्हें कैसे प्रबंधित किया जाता है।


makefiles

Makefile बारे में लक्ष्य और नियम उन्हें निर्माण करने के लिए का एक सेट है। लक्ष्य "कुछ ऐसा बनाया जा सकता है जिसे किसी दिए गए फ़ाइल में बनाया जा सकता है"। (वहां "फोनी" लक्ष्य भी मौजूद हैं जिनके परिणामस्वरूप फ़ाइल नहीं होती है और केवल आदेश निष्पादित करने के लिए होते हैं - संकलन परिणामों को हटाने के लिए एक सामान्य को clean कहा जाता है)।

प्रत्येक लक्ष्य 2 हिस्से होते हैं: निर्भरता की

  • सूची, "संवेदनशीलता सूची" (अन्य फ़ाइलों और लक्ष्य जो इस लक्ष्य के लिए आवश्यक हैं) (: के बाद, अल्पविराम से अलग),
  • शैल कमांड की सूची जो इस लक्ष्य को बनाने के लिए निष्पादित की जाती हैं (उपरोक्त, इंडेंट के नीचे)

इस उदाहरण पर विचार:

main: main.o module1.o module2.o 
    g++ main.o module1.o module2.o -o main 

इसका मतलब है कि: "फ़ाइल main बनाने के लिए, मैं सबसे पहले यह सुनिश्चित लक्षित करता है कि main.o, module1.o और module2.o अद्यतित हैं बनाने की जरूरत है; तो मुझे निम्नलिखित कमांड को कॉल करने की आवश्यकता है ... "।

यह भी लिखा जा सकता है के रूप में:

main: main.o module1.o module2.o 
    gcc $^ -o [email protected] 

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

आप अपनी खुद की चर को परिभाषित करने और उन्हें विस्तार इस प्रकार कर सकते हैं:

main.o: main.c 
    gcc -c $< -o [email protected] 
    # note the -c option, which means: "compile, but don't link" 
    # $< will expand to the first source file 

आप के पुनर्निर्माण के लिए शीर्ष लेख निर्भरता जोड़ सकते हैं:

OBJS = main.o module1.o module2.o 

main: $(OBJS) 
    # code goes here 

आप इस प्रकार अलग-अलग अनुवाद इकाइयों संकलन main.o जब या तो main.c या उसके किसी भी शीर्षलेख बदलते हैं:

main.o: main.c module1.h module2.h 
    gcc -c $< -o [email protected] 

आदेश पर एक ही आदेश लिख नहीं करने के लिए और फिर से, आप एक सामान्य नियम बना सकते हैं और बस निर्भरता की आपूर्ति (अगर आप चाहते हैं) में:

%.o: %.c 
    gcc -c $< -o [email protected] 

main.o: main.c module1.h module2.h 
module1.o: module1.c module1.h module2.h 

वहाँ भी कुछ जादू dependencies automatically (see link) उत्पन्न करने के लिए है । मेक का उपयोग करने के डाउनसाइड्स में से एक यह है कि यह स्वयं ही ऐसा नहीं करता है (जैसा कि कुछ बिल्डिंग सिस्टम करते हैं - जैसे स्कैन जिन्हें मैं सी/सी ++ के लिए पसंद करता हूं)।

1

सी प्रोग्राम की संरचना के साथ बहुत कम करना है। सभी मेक एक निर्भरता पेड़ को परिभाषित करते हैं और कमांड को निष्पादित करते समय कमांड को निष्पादित करते समय कमांड निष्पादित करते हैं। मेरे कहावत है, एक makefile में:

foo.exe : foo.c bar.c baz.c 

बस एसईजेड: foo.exe foo.c, bar.c और baz.c. पर निर्भर है यह, Sotto vocce, विस्तार किया जाता है, मेकअप के डिफ़ॉल्ट नियम सेट का उपयोग, की तरह कुछ करने के लिए:

foo.exe : foo.obj bar.obj baz.obj 

foo.obj : foo.c 

bar.obj : bar.c 

baz.obj : baz.c 

मेक बस निर्भरता पेड़ की जड़ से शुरू (इस मामले में, foo.exe) चलता है। यदि कोई लक्ष्य मौजूद नहीं है या यदि किसी ऑब्जेक्ट पर निर्भर करता है तो लक्ष्य से नया है, संबंधित आदेश निष्पादित किए जाते हैं। निर्भरता को सही बनाने के लिए।

O'Reilly से Managing Projects with Make देखें और शायद आप जानना चाहते हैं।

जहां तक ​​आपके प्रश्न का दूसरा भाग जाता है, उत्तर केवल दो अक्षर है: K and R। उनके The C Programming Language तर्कसंगत रूप से लिखे गए सर्वोत्तम कंप्यूटर प्रोग्रामिंग पुस्तकों में से एक है।

alt text

2

संक्षेप में एक makefile प्रपत्र के नियमों के शामिल हैं:

<this file> : <needs these files> 
    <and is created by this command> 

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

एक मेक फ़ाइल हो सकती है पैटर्न के आधार पर 'डिफ़ॉल्ट नियम', और विभिन्न फ़ाइल मिलान परिदृश्यों के साथ-साथ उपयोगकर्ता मैक्रोज़ को परिभाषित करने और नेस्टेड मेकफ़ाइल को शामिल करने के लिए अंतर्निहित मैक्रोज़ हैं।

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

निश्चित रूप से कई सूक्ष्मताएं और बारीकियों को बनाने के लिए, the manual में विस्तृत विवरण (जीएनयू विशेष रूप से, अन्य बनाने की सुविधाएं हैं)।

1

मेकफ़ाइल कैसे काम करता है?

=> जब टर्म कमांड पर मेक कमांड निष्पादित किया जाता है, तो यह वर्तमान निर्देशिका में मेकफ़ाइल या मेकफ़ाइल नाम की एक फ़ाइल की तलाश करता है और एक निर्भरता पेड़ बनाता है।

आप कई Makefiles है, तो आप विशिष्ट आदेश के साथ निष्पादित कर सकते हैं:

      make -f MyMakefile 

=> makefile में निर्दिष्ट कर लक्ष्य के आधार पर इसकी जांच करता है कि लक्ष्य की निर्भरता फ़ाइलें मौजूद हैं। और यदि वे मौजूद हैं, चाहे वे फ़ाइल टाइमस्टैम्प की तुलना करके लक्ष्य से भी नए हों।

Here our first and default target is “all” which looks for main.o and function.o file dependencies. Second and third target is main.o and function.o respectively which have dependencies of main.c and function.c respectively. 

=> इसी लक्ष्य के आदेशों को क्रियान्वित करने से पहले, अपनी निर्भरता पूरा किया जाना चाहिए, जब वे पूरी नहीं होती, उन निर्भरता के लक्ष्य को देखते हुए कर लक्ष्य से पहले क्रियान्वित कर रहे हैं याद आ रही निर्भरता की आपूर्ति।

=> जब कोई लक्ष्य फ़ाइल नाम होता है, तो लक्ष्य फ़ाइल और इसकी निर्भरता फ़ाइलों के समय-टिकटों की तुलना करें। यदि निर्भरता फ़ाइल लक्ष्य फ़ाइल से नई है, तो लक्ष्य निष्पादित करें अन्यथा निष्पादित नहीं करें।

In our case, when first target “all” start executing it looks for main.o file dependency, if its not met. Then it goes to second target main.o which check for its dependency main.c and compare time-stamp with it. If target found main.c dependency is updated, then target execute else not. Same process is follow for next target function.o. 

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

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

In our Makefile, special targets are “all” and “clean”. As we discussed target “all” earlier, but we not discuss target clean. Target clean removes the all object files created during compilation and binary executable files according to command. 

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

स्रोत: - http://www.firmcodes.com/linux/write-first-makefile-c-source-code-linux-tutorial/

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