2012-08-15 22 views
6

मेरे पास एक स्थिर सी लाइब्रेरी है जिसे मैं विभिन्न संकलन समय विकल्पों (जैसे _BUILD_SMALL, _BUILD_FAST) के साथ बना सकता हूं। यह एक समारोह हैसी पुस्तकालय कार्यों को उपनाम कैसे करें?

void Foo(void); 

मैं बेंचमार्क "छोटे" और पुस्तकालय की "तेज" संस्करण के लिए एक बेंच मार्किंग उपकरण का एक उदाहरण का उपयोग करना चाहते हैं। मैं डीडीएस का उपयोग नहीं करना चाहता।

मैं "छोटे" और "तेज़" पुस्तकालयों और उपनाम फ़ंक्शन नामों से कैसे लिंक कर सकता हूं ताकि मैं छोटे संस्करण और तेज़ संस्करण को कॉल कर सकूं। आदर्श रूप में यह कुछ ऐसा दिखाई देगा:

void benchmark(void) 
{ 
    FAST_Foo(); 

    SMALL_Foo(); 
} 

अधिक जानकारी:

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

+2

यह प्रश्न बहुत अस्पष्ट है। – Falmarri

+0

क्यों न सिर्फ विभिन्न विकल्पों के साथ कई संस्करणों को चालू/बंद करें और प्रत्येक को बेंचमार्क करें? –

+0

यदि आप समान नामित हैं (और स्थैतिक नहीं हैं) तो आप दोनों कार्यों को एक ही लिंक में संयोजित नहीं कर सकते हैं। – mah

उत्तर

3

यह सिर्फ विधि का एक परिवर्तन के रूप में @ मीकल Górny (मैं वहाँ टिप्पणी स्थान शेष नहीं) द्वारा दिया गया है ...

आप एक निम्न रूप में फ़ाइल को शामिल बना सकते हैं:

/* Automatically created file - do not edit or ugly dinosaur will eat you */ 
#ifndef PREFIX 
# define RENAME(f) 
#else 
# define RENAME(f) PREFIX ## f 
#endif 

/* list all the function and variables you want to rename here in one place */ 
#define func_foo RENAME(func_foo) 
#define func_bar RENAME(func_bar) 
/* ... many more ... */ 

#undef RENAME 

कम से कम gcc आपको विकल्प -include rename.h विकल्प के साथ कमांड लाइन से हेडर फ़ाइल को शामिल करने की अनुमति देता है (माना जाता है कि इस फ़ाइल को rename.h कहा जाता है)। क्योंकि आप gcc लुकलाइक विकल्प (-O3 और Os) का उपयोग करते हैं, मुझे लगता है कि आप इस उत्तर के बाकी हिस्सों में gcc का उपयोग कर रहे हैं। अन्यथा, यदि आपका सी कंपाइलर उचित है, तो आप इसे किसी भी तरह से करने में सक्षम होना चाहिए।

आप बना सकते हैं आसानी से अपने पुस्तकालय के दो या यहां तक ​​कि तीन संस्करणों है कि एक ही समय में में जोड़ा जा सकता है अगर आप चाहते हैं, अपने सी संकलक के लिए विभिन्न विकल्पों प्रदान करके (CFLAGS सेटिंग के माध्यम से यहाँ):

CFLAGS += -include rename.h -DPREFIX=fast_ -D_BUILD_FAST -O3 -DBENCHMARKING 
CFLAGS += -include rename.h -DPREFIX=small_ -D_BUILD_SMALL -Os -DBENCHMARKING 
CFLAGS += -D_BUILD_FAST -O2 

यदि आपकी लाइब्रेरी हेडर फाइलें बहुत नियमित लगती हैं और यदि आप लाइब्रेरी निजी फ़ंक्शंस static घोषित करते हैं, तो आपके लिए rename.h फ़ाइल स्वचालित रूप से उत्पन्न करने के लिए बहुत ही सरल नियमित अभिव्यक्तियों का उपयोग करके कुछ डमी स्क्रिप्ट द्वारा उन शीर्षलेख फ़ाइलों से फ़ंक्शंस निकालना आसान है। यदि आप make या कुछ समान उपयोग कर रहे हैं तो यह एक प्राकृतिक निर्माण लक्ष्य है। सभी वैश्विक चरों को एक ही विधि का उपयोग करके एक साथ उपयोग करने की अनुमति देने के लिए भी नाम बदलना होगा।

इस समाधान के साथ तीन मुख्य बिंदु होते हैं:

  1. बदसूरत नाम व्यापार एक फ़ाइल में छिपा हो सकता है, आप वास्तविक स्रोत फ़ाइलों संपादित करने के लिए की जरूरत नहीं है - विशेष रूप से आप अव्यवस्था की जरूरत नहीं है स्रोत फाइलें लेकिन उन्हें साफ और पढ़ने में आसान रख सकती हैं।
  2. नामांकन आसानी से स्वचालित हो सकता है, यदि आप कुछ सरल सिद्धांतों का पालन करते हैं (हेडर फाइलों के लिए कोडिंग सम्मेलन कोडिंग और हेडर फाइलें सभी वैश्विक चर और कार्यों की घोषणा करेंगे)।
  3. अपने परीक्षण कार्यक्रम को कई बार चलाने की आवश्यकता के जरिए बेंचमार्किंग को और अधिक बोझिल बनाने का कोई कारण नहीं है (यह प्रासंगिक है यदि आप आलसी हैं जैसे मैं करता हूं और पुनरावृत्ति कार्यों को हिंसक तरीके से नापसंद करता हूं - मुझे पता है कि बहुत से लोग परवाह नहीं करते हैं , यह कुछ हद तक वरीयता का मामला है)।
+0

बहुत अच्छा है और सवाल फिट बैठता है, धन्यवाद! –

2

एक तरीका होगा: संकलन समय विकल्प सेट के आधार पर दोनों के लिए समान नाम रखें और उचित रूप से कॉल करें।

ifdef SMALL_FOO 
void foo() { 

/* Small foo code */ 
} 
#endif 

ifdef BIG_FOO 
void foo() { 

/* Big foo code */ 
} 
#endif 

-d साथ संकलन के दौरान SMALL_FOO/BIG_FOO सेट करें।

+0

मैंने इसे माना था। वर्तमान कार्यान्वयन के लिए ऐसा करने के लिए कुछ डुप्लिकेशन की आवश्यकता होगी, लेकिन मुझे लगता है कि यह किया जा सकता है। –

0

आप कहते हैं कि आप लाइब्रेरी का निर्माण कर सकते हैं, संकलन समय विकल्पों को बदल रहे हैं, तो कोड में प्रत्येक के कार्यों को बदलने के लिए कोड क्यों संपादित नहीं करें। (आप अपनी लाइब्रेरी के दो विभिन्न संस्करणों बनाने होगा।)

+0

संकलन समय विकल्प प्रीप्रोसेसर को पास कर दिए जाते हैं, कोड नहीं बदलता है (वैसे भी यह लक्ष्य है)। –

2

एक त्वरित समाधान के रूप में आप की तरह समारोह नाम वध करने के लिए मैक्रो का उपयोग कर सकते हैं: FAST_Foo साथ

#ifdef FAST 
# define FUNC(x) FAST_##x 
#else 
# define FUNC(x) SLOW_##x 
#endif 

void FUNC(Foo)(); 

और अब -DFAST साथ पुस्तकालय होगा निर्मित होने दें; और इसके बिना, SLOW_Foo के साथ। बस ध्यान दें कि आपको कार्यान्वयन भाग में FUNC() मैक्रो का उपयोग करने की आवश्यकता है (और जब भी आप लाइब्रेरी के अंदर से उस फ़ंक्शन का जिक्र कर रहे हों), और #ifdef FAST तेज/धीमी कोड के बीच स्विच करने के लिए।

बस कृपया उत्पादन कोड में इसका उपयोग न करें।

+0

मैं एक '#ifdef ALIAS' भी जोड़ूंगा जो झूठी उपरोक्त को बाईपास करेगा और '# else' खंड में' # FFC (x) x' परिभाषित करेगा। फिर आपको कार्यान्वयन भाग में मैक्रो का उपयोग करने की आवश्यकता नहीं होगी। –

+0

मैं इसके बारे में सोच रहा था। मैं एक एलियासिंग समाधान की तलाश में था, लेकिन मैंने विशिष्ट "उलझन" लाइब्रेरी फ़ंक्शंस बनाने पर विचार किया था, फिर #ifdef फास्ट # डिफाईन Foo FAST_Foo() #endif –

+0

मैं नामकरण के साथ सहमत हूं लेकिन मुझे व्यक्तिगत रूप से सुझाए गए तरीके को पसंद नहीं है यहाँ। मैं फ़ंक्शन प्रोटोटाइप कैसे दिखता हूं इसे बदलना नापसंद करता हूं। आप नियमित अभिव्यक्तियों का उपयोग करके उनके लिए खोज नहीं कर सकते हैं, सी फाइलों से निपटने के लिए कुछ टूल्स भ्रमित हो जाएंगे, और यह दृश्य को अव्यवस्थित कर देगा। मैं फ़ंक्शन परिभाषा/घोषणा से पहले करना पसंद करूंगा। उदाहरण के लिए, उदाहरण के लिए, 'Foo FUNC (Foo) परिभाषित करें' (अपने 'FUNC() 'मैक्रो और' Foo() 'फ़ंक्शंस का उपयोग करके, जहां' FUNC()' मैक्रो को अलग-अलग नाम दिया जाना चाहिए, हालांकि अगर इस तरह उपयोग किया जाता है) । फिर आप सामान्य दिखने वाले फ़ंक्शन प्रोटोटाइप कर सकते हैं। – FooF

2

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

/* x.c */ 
extern void Y_Bar(); 
extern void Z_Bar(); 
int main() 
{ 
    Y_Bar(); 
    Z_Bar(); 
} 

यह मुख्य कॉल अद्वितीय आवरण काम करता है, जो liby.a और libz.a में प्रदान की जाती हैं।

/* y.c in liby.a */ 
#include <stdio.h> 
void Y_Bar() { 
    extern void Foo(); 
    Foo(); 
} 
void Foo() { 
    printf("%s\n", "that Foo"); 
} 

/* z.c in libz.a */ 
#include <stdio.h> 
void Z_Bar() { 
    extern void Foo(); 
    Foo(); 
} 
void Foo() { 
    puts("this foo"); 
} 

-ly -lz के साथ निष्पादन योग्य लिंक करने का प्रयास विफल हो जाएगा।

आपके लिए सबसे आसान काम दो अलग-अलग निष्पादन योग्य बनाना है। तब आपका बेंचमार्क ड्राइवर अपने रिश्तेदार प्रदर्शन की तुलना करने के लिए निष्पादन योग्य दोनों निष्पादित कर सकता था।

+0

मैंने इसे उत्पादन कोड के लिए सबसे आसान समाधान के रूप में चुना है। –

0

शायद तुम -D option when call gcc, like -D_FAST_, -D_SMALL_, उपयोग कर सकते हैं या अपने कर सकते हैं एक इनपुट पैरामीटर जब बनाने का उपयोग कर उपयोग की तरह प्राप्त किया, अपने makefile में CFG=FAST, make CFG=SMALL, बनाने के लिए, आप को परिभाषित कर सकते हैं, जब प्राप्त पैरामीटर FAST, link to FAST library

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