2010-06-22 9 views
15

मेरे सॉफ़्टवेयर में सामान्य उपयोग के लिए एक मुख्य और यूनिट परीक्षणों के लिए एक अलग है। यदि मैं निर्दिष्ट करने के लिए "मुख्य" फ़ंक्शन निर्दिष्ट करने के लिए gcc का कोई विकल्प था तो मैं इसे बस पसंद करूंगा।क्या मुख्य नाम बदलने के लिए कोई जीसीसी कंपाइलर/लिंकर विकल्प है?

+0

क्या यह एक कंपाइलर पास के साथ किया जा सकता है? यानी "मेक-डी परीक्षण के बिना; साफ करें; बनाना"? मुझे "उसी कोड" को शिपिंग में कुछ आराम मिलता है जिसे मैंने परीक्षण किया था। –

+0

आपको केवल उस फ़ाइल के लिए '-D' की आवश्यकता है जिसमें आपके मुख्य भाग हों। मेरे पास एक मेकफ़ाइल होगा जो मुख्य फ़ाइल को दो बार समेत बनाता है (एक बार बिना और एक बार-डी ... ध्यान दें कि इसे दो अलग-अलग आउटपुट फ़ाइल नामों के साथ संकलित करना होगा)। फिर इसे दो बार एक साथ लिंक करें: परीक्षण के निर्माण के लिए, एक बार सामान्य निर्माण के लिए। – mschaef

उत्तर

8

उन्हें अलग फ़ाइलों में रखें, और सामान्य उपयोग के लिए एक .c फ़ाइल निर्दिष्ट करें, और परीक्षण के लिए एक .c फ़ाइल निर्दिष्ट करें।

वैकल्पिक रूप से, कमांडलाइन परीक्षण का उपयोग पर #define परीक्षण बनाता है और की तरह कुछ का उपयोग करें:

int main(int argc, char *argv[]) 
{ 
#ifdef TESTING 
    return TestMain(argc, argv); 
#else 
    return NormalMain(argc, argv); 
#endif 
} 

int TestMain(int argc, char *argv[]) 
{ 
    // Do testing in here 
} 

int NormalMain(int argc, char *argv[]) 
{ 
    //Do normal stuff in here 
} 
+7

इसके अलावा, ओपी को केवल एफवाईआई, जीसीसी में तर्कों की सूची में केवल '-DTESTING' जोड़ें। –

+0

प्रवेश बिंदु या स्ट्रिप - स्ट्रिप-प्रतीक –

+0

@Alex के लिए उपयोग करने के लिए बेहतर है: "आप एक स्वीकृत उत्तर को हटा नहीं सकते हैं" :( –

2

संपादित करें: बिली मुझे जवाब देने के लिए हरा, लेकिन यहां थोड़ा और पृष्ठभूमि

अधिक सीधे है, मुख्य रूप से मानक पुस्तकालय का एक समारोह है। main पर कॉल करने वाली चीज़ सी नहीं है, बल्कि मानक लाइब्रेरी है। ओएस एप्लिकेशन लोड करता है, पुस्तकालय के प्रवेश बिंदु (_start जीसीसी में नियंत्रण) पर नियंत्रण स्थानांतरित करता है, और लाइब्रेरी अंततः main पर कॉल करती है। यही कारण है कि एक विंडोज़ अनुप्रयोग के लिए प्रवेश बिंदु WinMain हो सकता है, और सामान्य नहीं। एम्बेडेड प्रोग्रामिंग एक ही तरह की चीज हो सकती है। यदि आपके पास मानक लाइब्रेरी नहीं है, तो आपको उस प्रविष्टि बिंदु को लिखना होगा जो लाइब्रेरी सामान्य रूप से प्रदान करता है (अन्य चीजों के साथ), और आप इसे जो कुछ भी चाहते हैं उसका नाम दे सकते हैं।

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


को अपनी बनाएं: आप ifdef पसंद नहीं है, तो दो मुख्य मॉड्यूल है कि केवल मुख्य होते हैं लिखने

int main(int argc, char *argv[]) 
{ 
#if defined(BUILD_UNIT_TESTS) 
    return main_unittest(argc, argv); 
#endif 
#if defined(BUILD_RUNTIME) 
    return main_run(argc, argv); 
#endif 
} 

। यूनिट परीक्षणों के लिए एक और दूसरे को सामान्य उपयोग के लिए लिंक करें।

7

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

normal: main_normal.c file1.c file2.c 
unittest: main_unittest.c file1.c file2.c 

जब तक "सामान्य" लक्ष्य के रूप में makefile के शीर्ष के पास है, तो टाइप "बनाने के" डिफ़ॉल्ट रूप से यह चयन करेंगे। आपको अपने परीक्षण लक्ष्य को बनाने के लिए "अनजान बनाएं" टाइप करना होगा।

+0

autotools –

+4

+1 के साथ बनाता है: मैं इस दोनों दृष्टिकोणों को क्रैक करने की कोशिश करने के लिए इस दृष्टिकोण को काफी पसंद करता हूं वही मुख्य दिनचर्या है और प्रीप्रोसेसर परिभाषित करता है या लिंकर विकल्प उनके बीच स्विच करते हैं। –

0
#ifdef TESTING 

int main() 

{ 

/* testing code here */ 

} 

#else 

int main() 

{ 

/* normal code here */ 

} 

#endif 

$ gcc -DTESTING=1 -o a.out filename.C#building for testing

$ gcc -UTESTING -o a.out filename.C#building for normal purposes

man gcc मुझे डी और यू

+1

इसका एकमात्र नकारात्मक पक्ष यह है कि आपको 'परिभाषित' के अंदर 'मुख्य' का पूरा कोड होना चाहिए ... कुछ आईडीई के कुछ सिंटैक्स रंग ग्रे होंगे सभी परीक्षण कोड (क्योंकि इसे सामान्य रूप से परिभाषित नहीं किया जाता है) जो काफी परेशान हो सकता है। –

7

आप मुख्य करने के लिए एक समारोह का नाम बदलने के मैक्रो का उपयोग कर सकते हैं पता चला है।

#ifdef TESTING 
#define test_main main 
#else 
#define real_main main 
#endif 

int test_main(int argc, char *argv[]) { ... } 
int real_main(int argc, char *argv[]) { ... } 
14

यहाँ अन्य उत्तर काफी उचित हैं, लेकिन सख्ती से समस्या आप बोल वास्तव में जीसीसी के साथ एक नहीं है, बल्कि सी क्रम के साथ। आप -e ध्वज ld पर अपने प्रोग्राम में एक प्रविष्टि बिंदु निर्दिष्ट कर सकते हैं।मेरे प्रलेखन कहते हैं:

-e symbol_name

एक मुख्य निष्पादन के प्रवेश बिंदु निर्दिष्ट करता है। डिफ़ॉल्ट रूप से प्रविष्टि का नाम "प्रारंभ" होता है जो crt1.o में पाया जाता है जिसमें गोंद कोड को स्थापित करने और मुख्य() को कॉल करने की आवश्यकता होती है।

इसका मतलब है कि यदि आप चाहें तो आप प्रवेश बिंदु ओवरराइड कर सकते हैं, लेकिन आप ऐसा करने के लिए, एक सी कार्यक्रम आप अपने मशीन पर सामान्य रूप से चलाना चाहते हैं के लिए है कि चूंकि start ओएस विशिष्ट सामान है कि सभी प्रकार की हो सकती नहीं चाहते हो सकता है आपके कार्यक्रम चलाने से पहले आवश्यक है। यदि आप अपना खुद का start कार्यान्वित कर सकते हैं, तो आप जो भी चाहते हैं वह कर सकते हैं।

+3

लिनक्स पर: 1) आपको जीसीसी के लिए 'नोस्टार्टफाइल' की भी आवश्यकता है, या फिर 'crt1.o' में 'मुख्य' अपरिभाषित होगा और यह लिंक नहीं करेगा 2) आपको एक स्पष्ट 'निकास() 'से बाहर निकलना होगा, या फिर' वापसी 'कहीं भी segfault 3 नहीं होगा)' argv' आपके लिए –

0

आप हो सकता है उन्हें प्रयोग करने के लिए अलग से ld चलाने के लिए है, लेकिन ld कई (प्रवेश बिंदु भी शामिल है) आउटपुट फ़ाइल के पहलुओं को परिभाषित करने के scripts का समर्थन करता है।

+0

सेटअप नहीं होगा लेकिन 'मुख्य' प्रविष्टि नहीं है बिंदु (कम से कम मो पर सेंट सिस्टम)। –

5

मैं अलग फ़ाइलों का उपयोग और परीक्षण के लिए बना देती हैं चाहते हैं और उत्पादन बनाता है, पर यदि आप एक का चयन करने

int test_main (int argc, char*argv[]) 

और

int prod_main (int argc, char*argv[]) 

तो संकलक विकल्पों के साथ एक फ़ाइल है या दूसरा मुख्य रूप से -Dtest_main=main और -Dprod_main=main

+1

शायद यह इंगित करने लायक है कि यदि आप किसी कारण से उत्पादन फ़ाइल में मुख्य नाम का नाम नहीं बदल सकते हैं (जैसा कि मेरे मामले में हुआ), तो आप-डी स्विच में प्रतीक नामों को स्वैप कर सकते हैं, यानी इसे '-Dmain = ignored_main' उत्पादन मुख्य संकलन करते समय। – ttreitlinger

0

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

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

0

आप में उपयोग करते हैं LD "-e symbol_name" (जहां symbol_name, अपने मुख्य कार्य है निश्चित रूप से) आप भी जरूरत "-nostartfiles" अन्यथा "undefined reference to main" की त्रुटि का उत्पादन किया जाएगा।

+3

मुझे नहीं लगता कि इससे ओपी की समस्या में मदद मिलेगी। स्टार्ट फाइलों को छोड़कर आपको एक टूटे हुए वातावरण के साथ छोड़ दिया जाएगा जिसमें मानक लाइब्रेरी ठीक से काम नहीं करेगी। मुझे लगता है कि सिर्फ '-मेमेन' और इसी तरह की आवश्यकता है। –

5

मुझे आज भी यही समस्या थी: m1.c और m2.c दोनों में एक मुख्य कार्य था, लेकिन उन्हें जोड़ने और उनमें से एक चलाने की आवश्यकता थी। समाधान: उपयोगकर्ता पट्टी संकलन के बाद, लेकिन लिंक करने से पहले उनमें से एक से मुख्य प्रतीक दूर करने के लिए:

gcc -c m1.c m2.c; strip --strip-symbol main m1.o; gcc m1.o m2.o; ./a.out 

एम 2 से मुख्य चलेंगे

gcc -c m1.c m2.c; strip --strip-symbol main m2.o; gcc m1.o m2.o; ./a.out 

एम 1

से मुख्य चलेंगे पट्टी के बिना :

gcc - m1.c m2.c 
m2.o: In function `main': 
m2.c:(.text+0x0): multiple definition of `main' 
m1.o:m1.c:(.text+0x0): first defined here 
collect2: ld returned 1 exit status 
संबंधित मुद्दे