कम से कम स्थिर पुस्तकालयों के मामले में आप इसके चारों ओर काफी आसानी से काम कर सकते हैं।
पुस्तकालयों फू और बार के उन हेडर पर विचार करें । इस ट्यूटोरियल के लिए मैं आपको सोर्स फाइल्स भी दूंगा
उदाहरण / ex01 / foo.h
int spam(void);
double eggs(void);
उदाहरण / ex01 / foo.c (यह अपारदर्शी / उपलब्ध नहीं हो सकता है)
int the_spams;
double the_eggs;
int spam()
{
return the_spams++;
}
double eggs()
{
return the_eggs--;
}
उदाहरण / ex01 / bar.h
int spam(int new_spams);
double eggs(double new_eggs);
उदाहरण / ex01 / bar.c (यह अपारदर्शी / उपलब्ध नहीं हो सकता है)
int the_spams;
double the_eggs;
int spam(int new_spams)
{
int old_spams = the_spams;
the_spams = new_spams;
return old_spams;
}
double eggs(double new_eggs)
{
double old_eggs = the_eggs;
the_eggs = new_eggs;
return old_eggs;
}
हम एक प्रोग्राम फ़ॉबर में उन का उपयोग करना चाहते हैं
उदाहरण / ex01 / foobar.c
#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main()
{
const int new_bar_spam = 3;
const double new_bar_eggs = 5.0f;
printf("foo: spam = %d, eggs = %f\n", spam(), eggs() );
printf("bar: old spam = %d, new spam = %d ; old eggs = %f, new eggs = %f\n",
spam(new_bar_spam), new_bar_spam,
eggs(new_bar_eggs), new_bar_eggs );
return 0;
}
एक समस्या तुरंत स्पष्ट हो जाती है: सी ओवरलोडिंग नहीं जानता। इसलिए हमारे पास समान नाम के साथ दो बार दो कार्य हैं लेकिन विभिन्न हस्ताक्षर हैं। इसलिए हमें कुछ अलग करने की जरूरत है। वैसे भी, देखते हैं कि इस बारे में एक संकलक का क्या कहना है:
example/ex01/ $ make
cc -c -o foobar.o foobar.c
In file included from foobar.c:4:
bar.h:1: error: conflicting types for ‘spam’
foo.h:1: note: previous declaration of ‘spam’ was here
bar.h:2: error: conflicting types for ‘eggs’
foo.h:2: note: previous declaration of ‘eggs’ was here
foobar.c: In function ‘main’:
foobar.c:11: error: too few arguments to function ‘spam’
foobar.c:11: error: too few arguments to function ‘eggs’
make: *** [foobar.o] Error 1
ठीक है, यह कोई आश्चर्य की बात नहीं थी, यह सिर्फ हमें बताया गया था, जिसे हम पहले से जानते थे, या कम से कम संदेह था।
तो क्या हम किसी तरह मूल पुस्तकालयों के स्रोत कोड या हेडर को संशोधित किए बिना उस पहचानकर्ता टकराव को हल कर सकते हैं? वास्तव में हम कर सकते हैं।
पहले संकलन समय समस्याओं को हल करने देता है। इसके लिए हम शीर्षलेख को घेरते हैं जिसमें प्रीप्रोसेसर #define
निर्देशों का एक समूह शामिल है जो पुस्तकालय द्वारा निर्यात किए गए सभी प्रतीकों को उपसर्ग करता है। बाद में हम कुछ अच्छे आरामदायक आवरण-हेडर के साथ ऐसा करते हैं, लेकिन केवल यह प्रदर्शित करने के लिए कि फ़ोबार.सी . सी। स्रोत फ़ाइल में इसे क्या किया जा रहा है :
उदाहरण / ex02 / foobar.c
#include <stdio.h>
#define spam foo_spam
#define eggs foo_eggs
# include "foo.h"
#undef spam
#undef eggs
#define spam bar_spam
#define eggs bar_eggs
# include "bar.h"
#undef spam
#undef eggs
int main()
{
const int new_bar_spam = 3;
const double new_bar_eggs = 5.0f;
printf("foo: spam = %d, eggs = %f\n", foo_spam(), foo_eggs() );
printf("bar: old spam = %d, new spam = %d ; old eggs = %f, new eggs = %f\n",
bar_spam(new_bar_spam), new_bar_spam,
bar_eggs(new_bar_eggs), new_bar_eggs );
return 0;
}
अब अगर हम इसे संकलित करते हैं ...
example/ex02/ $ make
cc -c -o foobar.o foobar.c
cc foobar.o foo.o bar.o -o foobar
bar.o: In function `spam':
bar.c:(.text+0x0): multiple definition of `spam'
foo.o:foo.c:(.text+0x0): first defined here
bar.o: In function `eggs':
bar.c:(.text+0x1e): multiple definition of `eggs'
foo.o:foo.c:(.text+0x19): first defined here
foobar.o: In function `main':
foobar.c:(.text+0x1e): undefined reference to `foo_eggs'
foobar.c:(.text+0x28): undefined reference to `foo_spam'
foobar.c:(.text+0x4d): undefined reference to `bar_eggs'
foobar.c:(.text+0x5c): undefined reference to `bar_spam'
collect2: ld returned 1 exit status
make: *** [foobar] Error 1
... यह पहली बार लगता है कि चीजें बदतर हो गईं। लेकिन बारीकी से देखो: वास्तव में संकलन चरण ठीक चला गया। यह सिर्फ लिंकर है जो अब शिकायत कर रहा है कि प्रतीक टकरा रहे हैं और यह हमें उस स्थान (स्रोत फ़ाइल और रेखा) को बताता है जहां ऐसा होता है। और जैसा कि हम देख सकते हैं कि वे प्रतीक उपसर्ग हैं।
आइए एनएम उपयोगिता के साथ प्रतीक तालिकाओं पर एक नज़र डालें :
example/ex02/ $ nm foo.o
0000000000000019 T eggs
0000000000000000 T spam
0000000000000008 C the_eggs
0000000000000004 C the_spams
example/ex02/ $ nm bar.o
0000000000000019 T eggs
0000000000000000 T spam
0000000000000008 C the_eggs
0000000000000004 C the_spams
तो अब हम कुछ अपारदर्शी बाइनरी में उन प्रतीकों को उपसर्ग करने के लिए व्यायाम के साथ चुनौती दी है। हां, मुझे पता है कि इस उदाहरण के अनुसार हमारे पास स्रोत हैं और हम इसे बदल सकते हैं। लेकिन अभी के लिए, बस मान लें कि आपके पास केवल .o फाइलें, या a .a (जो वास्तव में सिर्फ .o का एक गुच्छा है )।
बचाव के लिए objcopy
हमारे लिए विशेष रूप से दिलचस्प एक उपकरण है: objcopy
objcopy अस्थायी फ़ाइलों पर काम करती है, इसलिए हम इसका उपयोग कर सकते हैं जैसे कि यह इन-प्लेस काम कर रहा हो। एक विकल्प / ऑपरेशन है - जिसे - उपसर्ग-प्रतीक कहा जाता है और आपके पास 3 अनुमान हैं कि यह क्या करता है।
तो आइए इस हलाला को हमारे जिद्दी पुस्तकालयों पर फेंक दें:
example/ex03/ $ objcopy --prefix-symbols=foo_ foo.o
example/ex03/ $ objcopy --prefix-symbols=bar_ bar.o
एनएम हमें पता चलता है कि यह काम करने के लिए लग रहा था:
example/ex03/ $ nm foo.o
0000000000000019 T foo_eggs
0000000000000000 T foo_spam
0000000000000008 C foo_the_eggs
0000000000000004 C foo_the_spams
example/ex03/ $ nm bar.o
000000000000001e T bar_eggs
0000000000000000 T bar_spam
0000000000000008 C bar_the_eggs
0000000000000004 C bar_the_spams
इस पूरी चीज़ को जोड़ने की कोशिश करें:
example/ex03/ $ make
cc foobar.o foo.o bar.o -o foobar
और वास्तव में, यह काम किया:
example/ex03/ $ ./foobar
foo: spam = 0, eggs = 0.000000
bar: old spam = 0, new spam = 3 ; old eggs = 0.000000, new eggs = 5.000000
अब मैं इसे एक उपकरण / स्क्रिप्ट को लागू करने के लिए पाठक के लिए एक अभ्यास के रूप में छोड़ देता हूं जो स्वचालित रूप से एनएम का उपयोग करके पुस्तकालय के प्रतीकों को निकालता है , संरचना का एक आवरण हेडर फ़ाइल लिखता है
#define spam foo_spam
#define eggs foo_eggs
#include <foo.h>
#undef spam
#undef eggs
और objcopy का उपयोग करके स्थिर लायब्रेरी की ऑब्जेक्ट फ़ाइलों के लिए प्रतीक उपसर्ग लागू करता है ।
साझा पुस्तकालयों के बारे में क्या?
सिद्धांत रूप में साझा पुस्तकालयों के साथ भी ऐसा ही किया जा सकता है। हालाँकि साझा लाइब्रेरी, यह नाम बताता है, कई कार्यक्रमों में साझा किया जाता है, इसलिए इस तरह से साझा लाइब्रेरी के साथ खिलवाड़ करना इतना अच्छा विचार नहीं है।
आपको एक ट्रैंपोलिन आवरण लिखने के आसपास नहीं मिलेगा। इससे भी बदतर आप ऑब्जेक्ट फ़ाइल स्तर पर साझा पुस्तकालय के खिलाफ लिंक नहीं कर सकते हैं, लेकिन गतिशील लोडिंग करने के लिए मजबूर हैं। लेकिन यह इसके अपने लेख के योग्य है।
देखते रहें, और खुश कोडिंग।