यदि दो पुस्तकालय एक ही नाम के साथ एक फ़ंक्शन प्रदान करते हैं तो एक संघर्ष उत्पन्न हो सकता है?


93

यदि मेरे पास दो पुस्तकालय हैं जो समान नामों के साथ कार्य प्रदान करते हैं तो मुझे क्या करना चाहिए?


2
क्या ये स्थिर पुस्तकालय या गतिशील रूप से जुड़े हुए हैं?
अलनीतक

हमें और अधिक विवरण चाहिए ... क्या वे नाम निर्यात किए गए हैं? या वे केवल आंतरिक रूप से उपयोग किए जाते हैं? क्या आप नाम बदल सकते हैं?
जोहान्स शाउब -

वे गतिशील रूप से जुड़े हुए हैं, दोनों। मैं नाम नहीं बदल सकता, क्योंकि मेरे पास पुस्तकालय नहीं हैं।
क्विक

बड़ा सवाल है। बेशक यह इन दो पुस्तकालयों अगर सभी प्रतीकों एक अद्वितीय ID के साथ उपसर्ग रहे थे के साथ एक समस्या नहीं होगा (जैसे vorbis_..., sf_..., sdl_...)। यह अनिवार्य रूप से नामांकित कार्यों के प्रतीक नामों के लिए C ++ क्या करता है।
वोर्टिको

यह एक बहुत ही दिलचस्प सवाल है, लेकिन दुख की बात यह है कि बहुत अधिक व्यापक उत्तर होने का कारण है।
1919

जवाबों:


52
  • यदि आप एक या दोनों को नियंत्रित करते हैं: नाम बदलने के लिए एक को संपादित करें और recompile या समकक्ष बेन और अज्ञात उत्तरों को देखें जो स्रोत कोड तक पहुंच के बिना काम करेंगे ।
  • यदि आप दोनों में से किसी को भी नियंत्रित नहीं करते हैं, तो आप उनमें से एक को लपेट सकते हैं। यह एक और ( स्टैटिकली लिंक्ड !) लाइब्रेरी है जो मूल के सभी चिह्नों को फिर से निर्यात करने के अलावा कुछ नहीं करता है, जो एक वैकल्पिक नाम के साथ एक रैपर के माध्यम से पहुंचता है। क्या झंझट है।
  • बाद में जोड़ा गया: के बाद से qeek कहते हैं कि वे गतिशील पुस्तकालयों के बारे में बात कर रहा है, समाधान द्वारा सुझाए गए फारुशियो और mouviciel शायद सबसे अच्छा कर रहे हैं। (मुझे लगता है कि लंबे समय से पहले दिनों में रहने के लिए जब स्थिर संबंध डिफ़ॉल्ट था। यह मेरी सोच को रंग देता है।)

Apropos टिप्पणियाँ: "निर्यात" से मेरा मतलब है कि लाइब्रेरी से जुड़ने वाले मॉड्यूल को दृश्यमान बनाना --- externफ़ाइल स्कोप पर कीवर्ड के बराबर । यह कैसे नियंत्रित किया जाता है यह ओएस और लिंकर पर निर्भर है। और यह कुछ ऐसा है जिसे मुझे हमेशा देखना है।


यह मेरा पहला विचार था, लेकिन क्या आप एक ही टकराव की समस्या के साथ खत्म नहीं होंगे? अंत में, पूरे प्रोजेक्ट को लिंक - संकलन / लिंक समय पर या रन टाइम पर - उस समय दोनों ऑफ-लाइब्रेरियों को लोड-के रूप में लोड करना पड़ता है।
स्निग्गार्फर्डिमुंगस

@unknown: रैपर को स्थैतिक लिंकेज के साथ संकलित किया जाना चाहिए, और आपत्तिजनक प्रतीक को निर्यात नहीं करना चाहिए। फिर आप अभी भी रैपर को गतिशील रूप से लिंक कर सकते हैं। अधिक स्पष्टता के लिए संपादित, धन्यवाद।
dmckee --- पूर्व-मध्यस्थ ने बिल्ली का बच्चा

यदि qeek की समस्या ddl के साथ है और स्थिर पुस्तकालयों के साथ नहीं है, तो रैपर के साथ एक नई लाइब्रेरी बनाना कैसे संभव है? चूंकि, रैपर लाइब्रेरी को गतिशील रूप से उस लाइब्रेरी में एक फ़ंक्शन के चारों ओर लपेटना होगा जिसे आप पहली बार में लिंक नहीं करना चाहते हैं।
jeffD

@ डमी - आपको "निर्यात" से क्या मतलब है?

4
शायद कोई इस तकनीक का एक सरल उदाहरण प्रदान कर सकता है? एक निर्वासन, दो पुस्तकालय जिनमें से प्रत्येक में एक ही नाम के साथ एक फ़ंक्शन होता है।

52

किसी ऑब्जेक्ट फ़ाइल का उपयोग करके प्रतीकों का नाम बदलना संभव है objcopy --redefine-sym old=new file(देखें आदमी objcopy)।

फिर बस अपने नए नामों का उपयोग करके फ़ंक्शन को कॉल करें और नई ऑब्जेक्ट फ़ाइल के साथ लिंक करें।


1
अच्छा लगा। यह एक मेकफाइल में जोड़ने के लिए तुच्छ होगा। यदि पुस्तकालयों को कभी भी अपडेट किया जाता है, तो एक ओब्जेक्टोपी झुकाव अन्य कुछ समाधानों की तुलना में अपडेट करना बहुत आसान होगा।
सिगाजाइस

8
हेडर फ़ाइलों में प्रतीकों का नाम बदलना न भूलें।
मौविसील

^ sed / awk / perl को हेडर में प्रतीकों का नाम बदलना भी उपयोगी होगा,
एलेक्स रिंकिंग

16

विंडोज के तहत, आप उन लाइब्रेरियों में से एक को मेमोरी में लोड करने के लिए LoadLibrary () का उपयोग कर सकते हैं और फिर एक फ़ंक्शन पॉइंटर के माध्यम से फ़ंक्शन को कॉल करने और कॉल करने के लिए आवश्यक प्रत्येक फ़ंक्शन का पता प्राप्त करने के लिए GetProcAddress () का उपयोग करें।

जैसे

HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);

foo.dll में बार नामक फ़ंक्शन का पता मिलेगा और उसे कॉल करें।

मुझे पता है कि यूनिक्स सिस्टम समान कार्यक्षमता का समर्थन करते हैं, लेकिन मैं उनके नामों के बारे में नहीं सोच सकता।


dlopen dlsym, और dlclose। हालाँकि, यूनिक्स पर एनकैप्सुलेशन विंडोज पर उतना प्रभावी नहीं हो सकता है।
user877329


8

यहाँ एक विचार है। एक हेक्स संपादक में आपत्तिजनक पुस्तकालयों में से एक को खोलें और आपत्तिजनक तारों के सभी घटनाओं को कुछ और में बदल दें। फिर आपको भविष्य के सभी कॉल में नए नामों का उपयोग करने में सक्षम होना चाहिए।

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


वास्तव में एक भयानक समाधान नहीं है। एक बिट हैक, लेकिन आप सभी कर रहे हैं प्रतीक तालिका में तार बदल रहा है। उस में कोई वास्तविक कार्यात्मक नुकसान नहीं।
इवान टेरान

आप शायद पुस्तकालय का नाम बदलना चाहते हैं, साथ ही - किसी और के साथ आया था, फिर से बात को लोड करने की कोशिश कर रहा है। आप एक संघर्ष से दर्जनों या सैकड़ों तक जाएंगे। =] मुझे स्टैकओवरफ्लो के बारे में यह पसंद है: हमारे पास एक प्रश्न का एक परीक्षण किया गया उत्तर है और इसमें 3 वोट हैं। पहला (अपूर्ण) उत्तर: 17. =]
स्निग्गरफर्डिमुंगस

नाम बदलने के अवसर सीमित हैं क्योंकि आप केवल नाम कम कर पाएंगे । इसके अलावा लिनक्स पर आपको ईएलएफ हैश टेबल को अपडेट करने में मुश्किल समय होगा।
yugr

7

यह मानते हुए कि आप लिनक्स का उपयोग करते हैं, जिसे आपको सबसे पहले जोड़ना होगा

#include <dlfcn.h>

उचित संदर्भ में फ़ंक्शन पॉइंटर चर की घोषणा करें, उदाहरण के लिए,

int (*alternative_server_init)(int, char **, char **);

जैसा कि फेरुस्कोयो ने https://stackoverflow.com/a/678453/1635364 में कहा है , स्पष्ट रूप से उस लाइब्रेरी को लोड करें जिसे आप निष्पादित करना चाहते हैं (अपने पसंदीदा झंडे उठाएं)

void* dlhandle;
void* sym;

dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);

उस फ़ंक्शन का पता पढ़ें जिसे आप बाद में कॉल करना चाहते हैं

sym = dlsym(dlhandle, "conflicting_server_init");

निम्नानुसार असाइन करें और कास्ट करें

alternative_server_init = (int (*)(int, char**, char**))sym;

मूल की तरह ही कॉल करें। अंत में, निष्पादित करके अनलोड करें

dlclose(dlhandle);


6

आपको उन्हें एक साथ उपयोग नहीं करना चाहिए। अगर मुझे सही से याद है, तो लिंकर ऐसे मामले में त्रुटि जारी करता है।

मैंने कोशिश नहीं की, लेकिन एक समाधान के साथ हो सकता है dlopen(), dlsym()और dlclose()जो आपको प्रोग्राम को गतिशील पुस्तकालयों को संभालने की अनुमति देता है। यदि आपको एक ही समय में दो कार्यों की आवश्यकता नहीं है, तो आप पहली लाइब्रेरी खोल सकते हैं, पहले फ़ंक्शन का उपयोग कर सकते हैं और दूसरी लाइब्रेरी / फ़ंक्शन का उपयोग करने से पहले पहली लाइब्रेरी को बंद कर सकते हैं।


धन्यवाद। इस बारे में नहीं सोचा था। हालाँकि, मैं एक ही समय में दोनों करना चाहूँगा।
क्विक

यदि मैं एक ही समय में दोनों का उपयोग करना चाहूँ तो क्या होगा?
क्झुआ

@ क्वेज़ुआ: अन्य एनीवर्स (जैसे, प्रतीक का नामकरण शामिल) आपकी समस्या को हल करना चाहिए।
मौविइल २

6

अगर आपके पास .o फाइलें हैं, तो यहां एक अच्छा जवाब है: https://stackoverflow.com/a/6940389/4707057

सारांश:

  1. objcopy --prefix-symbols=pre_string test.o .o फ़ाइल में प्रतीकों का नाम बदलने के लिए

या

  1. objcopy --redefine-sym old_str=new_str test.o .o फ़ाइल में विशिष्ट प्रतीक का नाम बदलने के लिए।

4

यह समस्या कारण है c ++ में नाम स्थान है। वास्तव में एक ही नाम होने वाले 2 तीसरे पक्ष के काम के लिए सी में एक महान समाधान नहीं है।

यदि यह एक गतिशील वस्तु है, तो आप स्पष्ट रूप से साझा किए गए ऑब्जेक्ट्स (लोडलॉड / dlopen / etc) को लोड करने में सक्षम हो सकते हैं और इसे उस फैशन में कॉल कर सकते हैं। वैकल्पिक रूप से, यदि आपको एक ही कोड में एक ही समय में दोनों लिबास की आवश्यकता नहीं है, तो आप शायद स्थैतिक लिंकिंग के साथ कुछ कर सकते हैं (यदि आपके पास .lib / .a फाइलें हैं)।

इनमें से कोई भी समाधान निश्चित रूप से सभी परियोजनाओं पर लागू नहीं होता है।


1
अरे हाँ। इस सामान्य प्रश्न के लिए यह एक अच्छा उत्तर लगता है। हालाँकि - यदि आप एक ही कंपाइलर में एक साथ सब कुछ संकलित करते हैं तो नामस्थान शांत हैं। हुर्रे, कोई नाम नहीं टकराता। लेकिन अगर आपको द्विआधारी रूप में एक पुस्तकालय मिलता है, और इसे किसी अन्य संकलक के साथ एकीकृत करना चाहते हैं, तो - सौभाग्य। ऑब्जेक्ट फ़ाइलों में नाम प्रबंधन नियम सिर्फ पहला ऑब्स्टेकल हैं (एक्सटर्नल "सी" मदद कर सकता है, जो नेमस्पेस के 'इफेक्ट्स' को खोल देता है)।
टॉमस गैंडर

3

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


12
शपथ निश्चित रूप से पहला कदम है। कोई संदेह नही।
dmckee --- पूर्व-मध्यस्थ ने बिल्ली को

1
"बहुत कुछ नहीं है जो आप कर सकते हैं" - क्या यह अभी भी प्रासंगिक है? अन्य उत्तर कई अलग-अलग समाधान प्रदान करते हैं।
1919

2

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

आपका अन्य विकल्प हैडर फ़ाइल में फ़ंक्शन नाम का नाम बदलना, और लाइब्रेरी ऑब्जेक्ट आर्काइव में प्रतीक का नाम बदलना है।

किसी भी तरह से, दोनों का उपयोग करने के लिए, यह एक हैक काम होने वाला है।



1

यह सवाल एक दशक पुराना है, लेकिन हर समय नई खोजें होती रहती हैं ...

जैसा कि पहले ही उत्तर दिया गया है, - theredefine-sym झंडा के साथ objcopy लिनक्स में एक अच्छा विकल्प है। उदाहरण के लिए, पूर्ण प्रलेखन के लिए https://linux.die.net/man/1/objcopy देखें । यह थोड़ा क्लिंकी है क्योंकि आप बदलाव करते समय अनिवार्य रूप से पूरी लाइब्रेरी की नकल कर रहे हैं और हर अपडेट के लिए इस काम को दोहराया जाना आवश्यक है। लेकिन कम से कम यह काम करना चाहिए।

विंडोज के लिए, गतिशील रूप से लाइब्रेरी को लोड करना एक समाधान है और लिनक्स में ड्लोपेन विकल्प की तरह एक स्थायी होगा। हालाँकि, दोनों dlopen () और LoadLibrary () अतिरिक्त कोड जोड़ते हैं, जिनसे बचा जा सकता है यदि केवल समस्या डुप्लिकेट नाम है। यहां विंडोज समाधान ओब्जेक्टोपी दृष्टिकोण से अधिक सुरुचिपूर्ण है: बस लिंकर को बताएं कि एक पुस्तकालय में प्रतीकों को किसी अन्य नाम से जाना जाता है और उस नाम का उपयोग करें। वहाँ कुछ कदम यह करने के लिए। आपको एक def फ़ाइल बनाने और EXPORTS अनुभाग में नाम अनुवाद प्रदान करने की आवश्यकता है। देखें https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, यह अंततः नए संस्करणों के द्वारा बदल दिया जाएगा) या http://www.digitalmars.com/ctg/ctgDefFiles.html(शायद अधिक स्थायी) एक डीफ़ल फ़ाइल के पूर्ण वाक्यविन्यास विवरण के लिए। यह प्रक्रिया पुस्तकालयों में से किसी एक के लिए एक डिफ फ़ाइल बनाने के लिए होगी, फिर इस डीब फाइल का उपयोग एक लिबास फाइल बनाने के लिए करें और फिर उस लिबास फाइल के साथ लिंक करें। (विंडोज डीएलएल के लिए, लिब फाइल केवल लिंक करने के लिए उपयोग की जाती है, कोड निष्पादन के लिए नहीं।) देखें कि लिब फाइल बनाने की प्रक्रिया के लिए .dll फाइल और हेडर फाइल के लिए .lib फाइल कैसे बनाएं । यहाँ केवल अंतर एलियास को जोड़ रहा है।

लिनक्स और विंडोज दोनों के लिए, लाइब्रेरी के हेडर में उन कार्यों का नाम बदलें जिनके नाम अलियास किए जा रहे हैं। एक अन्य विकल्प जो काम करना चाहिए, वह होगा नए नामों के संदर्भ में, #define old_name new_name के लिए, # लायब्रेरी के हेडर को हटा दें, जिसका निर्यात अलियास किया जा रहा है, और फिर #undef old_name कॉलर में। यदि लाइब्रेरी का उपयोग करते हुए बहुत सारी फाइलें हैं, तो एक आसान विकल्प हैडर या हेडर बनाना जो डिफाइन, कवर और अनडेफ को लपेटता है और फिर उस हेडर का उपयोग करें।

आशा है कि यह जानकारी उपयोगी थी!


0

मैंने कभी भी dlsym, dlopen, dlerror, dlclose, dlvsym इत्यादि का उपयोग नहीं किया है, लेकिन मैं मैन पेज देख रहा हूं, और यह libm.so खोलने और कॉस फ़ंक्शन को निकालने का एक उदाहरण देता है। क्या dlopen टकरावों की तलाश की प्रक्रिया से गुजरता है? यदि ऐसा नहीं होता है, तो ओपी दोनों पुस्तकालयों को मैन्युअल रूप से लोड कर सकता है और उनके पुस्तकालयों द्वारा प्रदान किए जाने वाले सभी कार्यों को नए नाम प्रदान कर सकता है।

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