साझा की गई वस्तुओं (.so), स्थिर पुस्तकालयों (.a), और DLL (.so) के बीच अंतर?


272

मैं लिनक्स में पुस्तकालयों के संबंध में कुछ बहस में शामिल रहा हूं, और कुछ चीजों की पुष्टि करना चाहता हूं।

यह मेरी समझ के लिए है (कृपया मुझे सही करें अगर मैं गलत हूं और मैं अपनी पोस्ट को बाद में संपादित करूंगा), कि एप्लिकेशन का निर्माण करते समय पुस्तकालयों का उपयोग करने के दो तरीके हैं:

  1. स्टेटिक लाइब्रेरी (.a फाइलें): लिंक समय पर, संपूर्ण लाइब्रेरी की एक कॉपी को अंतिम एप्लिकेशन में डाल दिया जाता है, ताकि लाइब्रेरी के भीतर कार्य हमेशा कॉलिंग एप्लिकेशन के लिए उपलब्ध रहें
  2. साझा की गई वस्तुएं (.so फाइलें): लिंक समय पर, वस्तु को उसके एपीआई के खिलाफ संबंधित हेडर (.h) फ़ाइल के माध्यम से सत्यापित किया जाता है। पुस्तकालय वास्तव में रनटाइम तक उपयोग नहीं किया जाता है, जहां इसकी आवश्यकता होती है।

स्थैतिक पुस्तकालयों का स्पष्ट लाभ यह है कि वे संपूर्ण अनुप्रयोग को स्व-निहित होने की अनुमति देते हैं, जबकि गतिशील पुस्तकालयों का लाभ यह है कि ".so" फ़ाइल को बदला जा सकता है (अर्थात: यदि सुरक्षा के कारण इसे अद्यतन करने की आवश्यकता है। बग) को बिना आधार के आवेदन को फिर से शुरू करने की आवश्यकता है।

मैंने सुना है कि कुछ लोग साझा किए गए ऑब्जेक्ट और डायनेमिक लिंक्ड लाइब्रेरी (DLL) के बीच अंतर करते हैं, भले ही वे दोनों ".so" फाइलें हों। क्या लिनक्स या किसी अन्य POSIX अनुरूप OS (यानी: MINIX, UNIX, QNX, आदि) पर C / C ++ विकास की बात आती है तो साझा वस्तुओं और DLL के बीच कोई अंतर है? मुझे बताया गया है कि एक प्रमुख अंतर (अब तक) यह है कि साझा किए गए ऑब्जेक्ट का उपयोग केवल रनटाइम पर किया जाता है, जबकि DLL को एप्लिकेशन के भीतर पहले dlopen () कॉल का उपयोग करके खोला जाना चाहिए।

अंत में, मैंने कुछ डेवलपर्स को "साझा अभिलेखागार" का उल्लेख करते हुए सुना है, जो कि मेरी समझ में, स्वयं स्थिर पुस्तकालय भी हैं, लेकिन कभी भी सीधे आवेदन द्वारा उपयोग नहीं किए जाते हैं। इसके बजाय, अन्य स्टैटिक लाइब्रेरी साझा आर्काइव से निर्मित स्टैटिक लाइब्रेरी में कुछ (लेकिन सभी नहीं) कार्यों / संसाधनों को खींचने के लिए "साझा अभिलेखागार" के खिलाफ लिंक करेंगे।

आपकी सहायता के लिए अग्रिम धन्यवाद।

अपडेट करें


जिस संदर्भ में मुझे ये शर्तें प्रदान की गई थीं, यह प्रभावी रूप से त्रुटिपूर्ण शब्द था, जिसका उपयोग विंडोज डेवलपर्स की एक टीम ने किया था, जिसे लिनक्स सीखना था। मैंने उन्हें सही करने की कोशिश की, लेकिन (गलत) भाषा के मानक अटक गए।

  1. साझा की गई वस्तु: एक पुस्तकालय जो कार्यक्रम शुरू होने पर स्वचालित रूप से एक कार्यक्रम में जुड़ा हुआ है, और एक स्टैंडअलोन फ़ाइल के रूप में मौजूद है। लाइब्रेरी को संकलन समय पर लिंकिंग सूची में शामिल किया गया है (जैसे: LDOPTS+=-lmylibएक पुस्तकालय फ़ाइल नाम के लिए mylib.so)। लाइब्रेरी को संकलन समय पर मौजूद होना चाहिए, और जब आवेदन शुरू होता है।
  2. स्टैटिक लाइब्रेरी: एक लाइब्रेरी जो कि वास्तविक समय में एक ही (बड़े) एप्लिकेशन के निर्माण के लिए वास्तविक प्रोग्राम में विलीन हो जाती है, जिसमें एप्लिकेशन कोड और लाइब्रेरी कोड होता है जो प्रोग्राम बनने पर स्वचालित रूप से एक प्रोग्राम में लिंक हो जाता है, और अंतिम बाइनरी जिसमें दोनों होते हैं मुख्य कार्यक्रम और पुस्तकालय ही एकल स्टैंडअलोन बाइनरी फ़ाइल के रूप में मौजूद हैं। लाइब्रेरी को संकलन समय पर लिंकिंग सूची में शामिल किया गया है (यानी: LDOPTS+=-lmylibmylib.a नामक लाइब्रेरी फ़ाइल के लिए)। पुस्तकालय को संकलन के समय उपस्थित होना चाहिए।
  3. डीएलएल: अनिवार्य रूप से एक साझा वस्तु के रूप में ही है, लेकिन संकलन समय पर लिंकिंग सूची में शामिल किए जाने के बजाय, लाइब्रेरी को dlopen()/ dlsym()आदेशों के माध्यम से लोड किया जाता है ताकि लाइब्रेरी को प्रोग्राम को संकलित करने के लिए बिल्ड समय पर मौजूद होने की आवश्यकता न हो। इसके अलावा, लाइब्रेरी को एप्लिकेशन स्टार्टअप या संकलित समय पर (आवश्यक रूप से) उपस्थित होने की आवश्यकता नहीं है , क्योंकि यह केवल उसी समय की आवश्यकता है जब dlopen/ dlsymकॉल किए जाते हैं।
  4. साझा संग्रह: अनिवार्य रूप से एक स्थिर पुस्तकालय के समान है, लेकिन "निर्यात-साझा" और "-fPIC" झंडे के साथ संकलित है। लाइब्रेरी को संकलन समय पर लिंकिंग सूची में शामिल किया गया है (जैसे: LDOPTS+=-lmylibSएक पुस्तकालय फ़ाइल नाम के लिए mylibS.a)। दोनों के बीच अंतर यह है कि इस अतिरिक्त ध्वज की आवश्यकता तब होती है जब एक साझा वस्तु या डीएलएल सांकेतिक रूप से साझा संग्रह को अपने कोड में लिंक करना चाहता है और साझा किए गए ऑब्जेक्ट में अन्य कार्यक्रमों के लिए उपलब्ध कराने में सक्षम है, न कि केवल उनका उपयोग करने के बजाय। DLL को आंतरिक। यह उस स्थिति में उपयोगी होता है जब कोई व्यक्ति आपको स्थैतिक पुस्तकालय प्रदान करता है, और आप इसे एसओ के रूप में फिर से तैयार करना चाहते हैं। पुस्तकालय को संकलन के समय उपस्थित होना चाहिए।

अतिरिक्त अद्यतन

" DLL" और " shared library" के बीच का अंतर केवल उस समय की कंपनी में काम किया हुआ (आलसी, गलत) बोलचाल का था (विंडोज डेवलपर्स को लिनक्स विकास में स्थानांतरित करने के लिए मजबूर किया जा रहा है, और शब्द अटक गया), ऊपर वर्णित विवरणों का पालन करना।

इसके अतिरिक्त, S"साझा अभिलेखागार" के मामले में पुस्तकालय के नाम के बाद " " शाब्दिक, केवल उस कंपनी में उपयोग किया जाने वाला एक सम्मेलन था, और सामान्य रूप से उद्योग में नहीं।


14
के लिए .aफ़ाइलें, "एक" वास्तव में "archove" के लिए खड़ा है, और यह बस वस्तु फ़ाइलों का एक संग्रह है। आधुनिक लिंकर्स को लाइब्रेरी में शामिल करने की आवश्यकता नहीं होने के लिए पर्याप्त अच्छा होना चाहिए, बस संग्रह में ऑब्जेक्ट्स फ़ाइलों की आवश्यकता होती है, और यहां तक ​​कि संदर्भित ऑब्जेक्ट फ़ाइलों में कोड / डेटा के अनुभागों का भी उपयोग कर सकते हैं।
कुछ प्रोग्रामर ने

4
DLL सिर्फ विंडोज शब्दावली है। इसका उपयोग यूनियनों पर नहीं किया जाता है।
आर .. गिटहब स्टॉप हेल्पिंग ICE



2
@DevNull "आर्च आई वे" जरूर। :)
कुछ प्रोग्रामर ने

जवाबों:


93

मैंने हमेशा सोचा है कि DLL और साझा की गई वस्तुएं एक ही चीज़ के लिए बस अलग-अलग शब्द हैं - Windows उन्हें DLL कहता है, जबकि UNIX सिस्टम पर वे सामान्य साझा शब्द के साथ ऑब्जेक्ट साझा करते हैं - गतिशील रूप से लिंक की गई लाइब्रेरी - दोनों को कवर करना (यहां तक ​​कि फ़ंक्शन भी) UNIX पर एक .so को dlopen()'डायनेमिक लाइब्रेरी' के बाद कहा जाता है )।

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

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


1
ऐसा क्यों है कि कुछ परियोजनाएं जो मैं लिनक्स पर देखता हूं, उन्हें ".so" फ़ाइल के भीतर फ़ंक्शन को एक्सेस करने के लिए dlopen () कॉल का उपयोग करना पड़ता है, और कुछ को ऐसा करने की ज़रूरत नहीं है? धन्यवाद, वैसे!
क्लाउड

9
जो ऐसा नहीं करते हैं, वे प्रक्रिया लोडर द्वारा उन्हें सौंपे गए कार्यों को प्राप्त करते हैं, अर्थात लिनक्स के योगिनी लोडर। dlopen मौजूद है यदि अनुप्रयोग किसी .so या .dll को खोलना और उपयोग करना चाहता है जो कि संकलन में है या प्लगइन्स की तरह अतिरिक्त कार्यक्षमता जोड़ें।
रैपादुरा

लेकिन अगर बिल बिल्ट समय पर मौजूद नहीं है, तो क्या आवेदन बिल्कुल भी संकलित नहीं होगा? क्या यह संभव है कि लिंकर को अंतिम कार्यक्रम के निर्माण के लिए बाध्य करना संभव नहीं है। धन्यवाद।
क्लाउड

1
मेरा मानना ​​है कि यह इस बात पर निर्भर करता है कि आप किस तरह से कार्यों का उपयोग करते हैं। लेकिन यहां इस जानकारी का मेरा ज्ञान है: / अच्छे प्रश्न।
रैपादुरा १३'१२

1
Dlopen () और उसके परिवार के कार्यों के बारे में, यह मेरी समझ है कि इसका उपयोग प्रोग्राम को dll को खोलने / बंद करने के लिए किया जाता है ताकि इसे एप्लिकेशन के पूरे रन के दौरान मेमोरी में लोड न करना पड़े। अन्यथा, आपको लिंकर को उसके कमांड लाइन तर्कों (उर्फ आपके मेकफाइल) में बताना होगा कि आप पुस्तकालय को लोड करना चाहते हैं। इसे रनटाइम पर लोड किया जाएगा और तब तक मेमोरी में लोड किया जाएगा जब तक कि एप्लिकेशन से बाहर न निकल जाए। अधिक चीजें हैं जो ओएस स्तर पर हो सकती हैं, लेकिन यह लगभग वही है जो आपके आवेदन का संबंध है।
टेलर मूल्य

197

एक स्थैतिक पुस्तकालय (.a) एक पुस्तकालय है जिसे सीधे लिंकर द्वारा उत्पादित अंतिम निष्पादन योग्य में जोड़ा जा सकता है, यह इसमें निहित है और पुस्तकालय में उस प्रणाली को रखने की कोई आवश्यकता नहीं है जहां निष्पादन योग्य तैनात किया जाएगा।

एक साझा पुस्तकालय (.so) एक पुस्तकालय है जो जुड़ा हुआ है, लेकिन अंतिम निष्पादन योग्य में एम्बेडेड नहीं है, इसलिए जब निष्पादन योग्य लॉन्च किया जाता है तो लोड किया जाएगा और उस सिस्टम में मौजूद होने की आवश्यकता होती है जहां निष्पादन योग्य तैनात किया जाता है।

विंडोज़ (.dll) पर एक गतिशील लिंक लाइब्रेरी लिनक्स पर एक साझा लाइब्रेरी (.so) की तरह है, लेकिन दो कार्यान्वयन के बीच कुछ अंतर हैं जो ओएस (विंडोज बनाम लिनक्स) से संबंधित हैं:

एक DLL दो प्रकार के कार्यों को परिभाषित कर सकता है: निर्यात और आंतरिक। निर्यात किए गए कार्यों को अन्य मॉड्यूलों के साथ-साथ डीएलएल के भीतर से बुलाया जाता है, जहां उन्हें परिभाषित किया जाता है। आंतरिक कार्यों को आम तौर पर केवल डीएलएल के भीतर से ही बुलाया जाता है जहां वे परिभाषित होते हैं।

लिनक्स पर एक एसओ पुस्तकालय को निर्यात करने योग्य प्रतीकों को इंगित करने के लिए विशेष निर्यात विवरण की आवश्यकता नहीं है, क्योंकि सभी प्रतीक एक पूछताछ प्रक्रिया के लिए उपलब्ध हैं।


1
+1 अच्छा सरल विवरण। यदि किसी DLL में किसी फ़ंक्शन को "आंतरिक" घोषित किया जाता है, तो इसका मतलब है कि उसे लाइब्रेरी के बाहर से नहीं बुलाया जा सकता है?
माइक

23
यह जरूरी नहीं है कि सभी प्रतीक एसओ लाइब्रेरी में उपलब्ध हों। छिपे हुए प्रतीकों को संभव और अनुशंसित किया जाता है क्योंकि लाइब्रेरी उपयोगकर्ताओं के लिए आपके सभी प्रतीकों को देखने का कोई अच्छा कारण नहीं है।
ज़ैन लिंक्स

3
FYI करें: g ++ में __attribute__चुनिंदा 'निर्यात' प्रतीकों के लिए वाक्यविन्यास है:#define DLLEXPORT __attribute__ ((visibility("default"))) #define DLLLOCAL __attribute__ ((visibility("hidden")))
ब्रायन हक

33

मैं यहाँ अपने दोस्तों को * NIX-land ... में उन रहस्यों को स्पष्ट करने में मदद करने के लिए Windows में DLL के विवरण पर विस्तार से बता सकता हूँ ...

एक DLL एक साझा ऑब्जेक्ट फ़ाइल की तरह है। दोनों चित्र हैं, जो संबंधित ओएस के प्रोग्राम लोडर द्वारा मेमोरी में लोड करने के लिए तैयार हैं। लिंक और लोडर को आवश्यक संघ बनाने और कोड के पुस्तकालय का उपयोग करने में मदद करने के लिए चित्र मेटाडेटा के विभिन्न बिट्स के साथ हैं।

Windows DLL में एक निर्यात तालिका है। निर्यात नाम या तालिका स्थिति (संख्यात्मक) द्वारा किया जा सकता है। उत्तरार्द्ध विधि को "पुराना स्कूल" माना जाता है और बहुत अधिक नाजुक है - डीएलएल का पुनर्निर्माण और तालिका में एक फ़ंक्शन की स्थिति को बदलना आपदा में समाप्त हो जाएगा, जबकि प्रवेश बिंदुओं के लिंक नाम से होने पर कोई वास्तविक मुद्दा नहीं है। इसलिए, इसे एक मुद्दे के रूप में भूल जाएं, लेकिन बस इस बात से अवगत रहें कि यदि आप "डायनासोर" कोड के साथ काम करते हैं जैसे कि 3-पार्टी विक्रेता के लिबास।

Windows DLL को कंपाइल और लिंक करके बनाया जाता है, जैसे आप एक EXE (निष्पादन योग्य एप्लिकेशन) के लिए करते हैं, लेकिन DLL अकेले खड़े नहीं होने के लिए है, ठीक वैसे ही जैसे SO का उपयोग एप्लिकेशन द्वारा किया जाता है, या तो डायनेमिक लोडिंग के माध्यम से, या लिंक-टाइम बाइंडिंग द्वारा (एसओ का संदर्भ अनुप्रयोग बाइनरी मेटाडेटा में एम्बेडेड है, और ओएस प्रोग्राम लोडर संदर्भित एसओ को ऑटो-लोड करेगा)। DLL अन्य DLL को संदर्भित कर सकते हैं, जैसे SOs अन्य SO को संदर्भित कर सकते हैं।

विंडोज में, DLL केवल विशिष्ट प्रवेश बिंदु उपलब्ध कराएगा। इन्हें "निर्यात" कहा जाता है। डेवलपर या तो प्रतीक को बाहरी रूप से (अन्य लिंकर्स और गतिशील लोडर को) बनाने के लिए एक विशेष संकलक कीवर्ड का उपयोग कर सकता है, या निर्यात को एक मॉड्यूल-परिभाषा फ़ाइल में सूचीबद्ध किया जा सकता है जो लिंक समय पर उपयोग किया जाता है जब डीएलएल ही होता है बनाया जा रहा है। आधुनिक अभ्यास प्रतीक नाम को निर्यात करने के लिए कीवर्ड के साथ फ़ंक्शन परिभाषा को सजाने के लिए है। कीवर्ड के साथ हेडर फाइलें बनाना भी संभव है, जो उस प्रतीक को वर्तमान संकलन इकाई के बाहर डीएलएल से आयात किए जाने के रूप में घोषित करेगा। अधिक जानकारी के लिए __declspec (dllexport) और __declspec (dllimport) कीवर्ड देखें।

DLL की दिलचस्प विशेषताओं में से एक यह है कि वे "लोड / अनलोड" हैंडलर फ़ंक्शन पर एक मानक घोषित कर सकते हैं। जब भी DLL लोड या अनलोड किया जाता है, DLL कुछ इनिशियलाइज़ेशन या क्लीनअप कर सकता है, जैसा भी मामला हो। यह एक DLL को ऑब्जेक्ट-ओरिएंटेड संसाधन प्रबंधक, जैसे डिवाइस ड्राइवर या साझा ऑब्जेक्ट इंटरफ़ेस के रूप में अच्छी तरह से करता है।

जब कोई डेवलपर पहले से निर्मित DLL का उपयोग करना चाहता है, तो उसे या तो DLL डेवलपर द्वारा बनाई गई "निर्यात लाइब्रेरी" (* .LIB) का संदर्भ देना चाहिए जब उसने DLL बनाया हो, या उसे रन टाइम में DLL को स्पष्ट रूप से लोड करना होगा और अनुरोध करना होगा। LoadLibrary () और GetProcAddress () तंत्र के माध्यम से नाम से प्रवेश बिंदु पता। ज्यादातर समय, एक एलआईबी फ़ाइल के खिलाफ लिंक करना (जिसमें डीएलएल के निर्यात किए गए प्रवेश बिंदुओं के लिए लिंकर मेटाडेटा शामिल है) डीएलएल का उपयोग करने का तरीका है। डायनामिक लोडिंग आमतौर पर प्रोग्राम व्यवहार में "पॉलीमॉर्फिज्म" या "रनटाइम कॉन्फ़िगरेशन" को लागू करने के लिए आरक्षित है (ऐड-ऑन या बाद में परिभाषित कार्यक्षमता, उर्फ ​​"प्लगइन्स" तक पहुंच)।

चीजों को करने का विंडोज तरीका कई बार कुछ भ्रम पैदा कर सकता है; सिस्टम .LIB एक्सटेंशन का उपयोग दोनों सामान्य स्थिर पुस्तकालयों (अभिलेखागार, जैसे POSIX * .A फाइलें) को संदर्भित करने के लिए करता है और लिंक समय पर एक DLL के लिए एक आवेदन को बांधने के लिए आवश्यक "निर्यात स्टब" पुस्तकालयों के लिए। इसलिए, किसी को यह देखने के लिए हमेशा देखना चाहिए कि क्या * .LIB फ़ाइल में समान नाम वाली * .DLL फ़ाइल है; यदि नहीं, तो संभावना अच्छी है कि * .LIB फ़ाइल एक स्थिर लाइब्रेरी संग्रह है, और DLL के लिए बाध्यकारी मेटाडेटा निर्यात नहीं करता है।


4

आप सही हैं कि स्थैतिक फ़ाइलों को लिंक-टाइम पर एप्लिकेशन में कॉपी किया जाता है, और उस साझा फ़ाइलों को लिंक समय पर सत्यापित किया जाता है और रनटाइम पर लोड किया जाता है।

ड्लोपेन कॉल केवल साझा किए गए ऑब्जेक्ट्स के लिए नहीं है, यदि एप्लिकेशन अपनी ओर से रनटाइम में ऐसा करना चाहता है, अन्यथा एप्लिकेशन शुरू होने पर साझा ऑब्जेक्ट्स स्वचालित रूप से लोड हो जाते हैं। DLLS और .so एक ही बात है। dlopen प्रक्रियाओं के लिए और भी अधिक बारीक गतिशील लोडिंग क्षमताओं को जोड़ने के लिए मौजूद है। आपको DLLs को खोलने / उपयोग करने के लिए अपने आप को dlopen का उपयोग करने की आवश्यकता नहीं है, जो कि एप्लिकेशन स्टार्टअप पर भी होता है।


अधिक लोडिंग नियंत्रण के लिए dlopen () का उपयोग करने का एक उदाहरण क्या होगा? यदि SO / DLL स्टार्टअप पर स्वत: लोड हो जाता है, तो उदाहरण के लिए, इसे अलग-अलग अनुमतियों या प्रतिबंधों के साथ बंद (फिर से) करें और खोलें? धन्यवाद।
क्लाउड

1
मेरा मानना ​​है कि dlopen प्लगइन्स या समान कार्यक्षमता के लिए है। अनुमतियाँ / प्रतिबंध स्वचालित लोडिंग के लिए समान होने चाहिए, और वैसे भी एक dlopen पुनरावर्ती निर्भर पुस्तकालयों को लोड करेगा।
रैपदुरा

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