2014-05-01 5 views
5

पर लोड साझा लाइब्रेरी देरी मैं किसी साझा लाइब्रेरी बनाने के लिए एक तरह से खोज कर रहा है बनाने के लिए देरी लिनक्स पर लोड (के पुस्तकालय " libbar.so" नाम है) और यह उम्मीद है कि एहसास होना चाहिए से केवल एक लिंकर की मदद से, सी ++ में लिखे गए स्रोत कोड पर कुछ भी संशोधित नहीं किया गया; मेरा मतलब है मैं dlopen आह्वान करने के लिए नहीं करना चाहते हैं() है और न ही dlsym() माता पिता पुस्तकालय के स्रोत कोड में libbar.so के एक समारोह को लागू करने (इसे " libfoo.so" नाम हैं) क्योंकि वे स्रोत कोड गन्दा बनाते हैं और रखरखाव प्रक्रिया मुश्किल होती है।कैसे लिनक्स

वैसे भी, मैं अब तक इंटरनेट पर अपने प्रश्न से संबंधित कुछ अनिश्चित जानकारी टुकड़े मिल गया है (संक्षेप में, मैं दृश्य स्टूडियो के /DELAYLOAD भी लिनक्स पर विकल्प के समान रास्ते पर जाने के लिए उम्मीद कर रहा हूँ), तो सूचना को स्पष्ट करने के लिए निम्नलिखित प्रश्नों के लिए आप सभी के जवाबों को बहुत अच्छा लगेगा।

  1. जीएनयू ld समर्थन लिनक्स पर किसी देरी लोड हो रहा है तंत्र करता है?
  2. यदि यह नहीं है, तो क्लैंग के बारे में कैसे?
  3. dlopen() परिवार लिनक्स पर साझा लाइब्रेरी विलंब को लोड करने का एकमात्र तरीका है?

मैं जीसीसी (छ ++) पुस्तकालय के लिए एक पथ के साथ करने के लिए -zlazy ध्वज पारित करने के लिए परीक्षण किया है, यह ध्वज स्वीकार करने के लिए लग रहा था, लेकिन व्यवहार देरी लोड libbar.so बनाने मुड़कर नहीं देखा (के न होने का libbar.so, मुझे libbar.so की पहली कॉल में अपवाद होने की उम्मीद थी, लेकिन वास्तव में libfoo.so में प्रवेश करने से पहले अपवाद उठाया गया था)। दूसरी तरफ, क्लैंग (क्लैंग ++) ने एक चेतावनी छोड़ी कि उसने विकल्प ध्वज को नजरअंदाज कर दिया।

सादर,

+0

बजना जोड़ने के लिए जीएनयू ld का उपयोग करता है (कम से कम 3.4 के लिए और पुराने) ऐसा है, आपको वहां कोई मदद नहीं मिलेगी। –

+0

@ मैट्स, आपकी टिप्पणी के लिए धन्यवाद। ठीक है, मैं इस सवाल पर क्लैंग को कभी भी याद नहीं रखूंगा और बाद में मूल विवरण संपादित करूंगा। – Doofah

+0

पहले पूछा गया था: http://stackoverflow.com/questions/2957292/delay-load-equivalent-in-unix-based-systems – oakad

उत्तर

4

देरी लोड हो रहा है एक क्रम सुविधा नहीं है। एमएसवीसी ++ ने विंडोज़ से मदद के बिना इसे लागू किया। और dlopen लिनक्स पर एकमात्र तरीका है, GetProcAddress विंडोज पर एकमात्र रनटाइम विधि है।

तो, देरी लोडिंग क्या है? यह बहुत आसान है: किसी डीएलएल को किसी भी कॉल को पॉइंटर से गुज़रना पड़ता है (क्योंकि आप नहीं जानते कि यह कहां लोड होगा)। यह हमेशा आपके लिए कंपाइलर और लिंकर द्वारा संभाला गया बेन है। लेकिन देरी लोडिंग के साथ, एमएसवीसी ++ इस पॉइंटर को शुरुआत में एक स्टब पर सेट करता है जो आपके लिए LoadLibrary और GetProcAddress पर कॉल करता है।

क्लैंग ld से सहायता के बिना ऐसा ही कर सकता है। रनटाइम पर, यह सिर्फ एक सामान्य dlopen कॉल है, और लिनक्स यह निर्धारित नहीं कर सकता कि क्लैंग ने इसे डाला है।

+0

@ एमएसल्टर्स, धन्यवाद। क्या आपका मतलब है कि क्लैंग अपने आप में देरी लोड कर सकती है? मैं वास्तव में असल में एक सहायक कार्य करने की उम्मीद कर रहा हूं जैसे कि एमएसवीसी ++ हमें कंपाइलर या लिंकर के लिए एक विकल्प झंडे पास करके प्रदान करता है (हालांकि मैं सहायक कार्य का नाम भूल गया) क्योंकि तंत्र विलंब लोड किए गए कार्यों के कॉल के पीछे सबकुछ छुपाता है (इसलिए उपयोगकर्ता को इस तरह के एक सहायक समारोह की देखभाल करने की ज़रूरत नहीं है जिसे हमारे स्रोत कोड के नीचे बुलाया जाता है)। – Doofah

+0

हां, ** __ देरीLoadHelper2 ** सहायक कार्य है! शायद कुछ कंपाइलर या लिंकर्स (जैसे सन की कुछ या ऐप्पल के एलडी 64) ने इस तरह के एक सहायक कार्य प्रदान किया होगा लेकिन मुझे नहीं पता कि लिनक्स पर क्या चल रहा है। (और मैं लिनक्स के लिए बहुत नया हूं;) – Doofah

+0

@ user3591878: लिनक्स पर जीसीसी में ओएस और कंपाइलर के बीच भेदभाव की दुर्भाग्यपूर्ण आदत है, लेकिन यह यूनिक्स परंपरा है। ('Ld' बनाम' ld.so' देखें)। यह वास्तव में कोई फर्क नहीं पड़ता कि आप लिनक्स के लिए नए हैं, क्योंकि लिनक्स को कोई फर्क नहीं पड़ता। जीसीसी और क्लांग डू। वे _could_ किसी भी ओएस पर देरी लोडिंग लागू करते हैं जिसमें 'dlopen' है। इसका मतलब यह नहीं है कि उन्होंने वास्तव में ऐसा किया है। – MSalters

4

यह कार्यक्षमता Proxy design pattern का उपयोग कर एक पोर्टेबल तरीके से हासिल की जा सकती है।एक छोटे से स्थिर ठूंठ पुस्तकालय कि dlopen जरूरत करने की कोशिश करेगा बनाने के द्वारा करने के लिए MSalters का जवाब

#include <memory> 

// SharedLibraryProxy.h 
struct SharedLibraryProxy 
{ 
    virtual ~SharedLibraryProxy() = 0; 

    // Shared library interface begin. 
    virtual void foo() = 0; 
    virtual void bar() = 0; 
    // Shared library interface end. 

    static std::unique_ptr<SharedLibraryProxy> create(); 
}; 

// SharedLibraryProxy.cc 
struct SharedLibraryProxyImp : SharedLibraryProxy 
{ 
    void* shared_lib_ = nullptr; 
    void (*foo_)() = nullptr; 
    void (*bar_)() = nullptr; 

    SharedLibraryProxyImp& load() { 
     // Platform-specific bit to load the shared library at run-time. 
     if(!shared_lib_) { 
      // shared_lib_ = dlopen(...); 
      // foo_ = dlsym(...) 
      // bar_ = dlsym(...) 
     } 
     return *this; 
    } 

    void foo() override { 
     return this->load().foo_(); 
    } 

    void bar() override { 
     return this->load().bar_(); 
    } 
}; 

SharedLibraryProxy::~SharedLibraryProxy() {} 

std::unique_ptr<SharedLibraryProxy> SharedLibraryProxy::create() { 
    return std::unique_ptr<SharedLibraryProxy>{new SharedLibraryProxyImp}; 
} 

// main.cc 
int main() { 
    auto shared_lib = SharedLibraryProxy::create(); 
    shared_lib->foo(); 
    shared_lib->bar(); 
} 
+0

@ मैक्सिम, व्यावहारिक छद्म कोड छोड़ने के लिए धन्यवाद। वह डिजाइन पैटर्न दोनों पुस्तकालयों को पुल करने के लिए बहुत उपयोगी लगता है :) – Doofah

+0

यह केवल कार्यों के लिए काम करता है। वैरिएबल के लिए कोई रास्ता नहीं है जब तक कि इसे रनटाइम लिंकर में लागू नहीं किया जाता है। सवाल अभी भी है अगर यह संभव है। – Lothar

+0

@ लोथर आप इस निष्कर्ष पर कैसे आए? यह तंत्र दोनों कार्यों और वस्तुओं के लिए काम करता है। –

0

जोड़ने के लिए, एक कर सकते हैं लिनक्स पर आलसी लोड हो रहा है के लिए आसानी से नकल विंडोज दृष्टिकोण:

कोड में यह कुछ इस तरह लग सकता है लाइब्रेरी इसके किसी भी फ़ंक्शन पर पहली कॉल पर (डायग्नोस्टिक संदेश उत्सर्जित करना और डॉपन विफल होने पर समाप्त करना) और उसके बाद सभी कॉल अग्रेषित करना।

इस तरह के ठूंठ पुस्तकालयों, हाथ से लिखा जा सकता है परियोजना/पुस्तकालय विशेष स्क्रिप्ट द्वारा उत्पन्न या सार्वभौमिक उपकरण Implib.so द्वारा उत्पन्न:

$ gen-implib.py libxyz.so 
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...