C ++ में क्लास लाइब्रेरी बनाते समय, आप डायनेमिक ( .dll
, .so
) और स्टैटिक ( .lib
, .a
) लाइब्रेरी के बीच चयन कर सकते हैं । उनके बीच क्या अंतर है और कब कौन सा उपयोग करना उचित है?
C ++ में क्लास लाइब्रेरी बनाते समय, आप डायनेमिक ( .dll
, .so
) और स्टैटिक ( .lib
, .a
) लाइब्रेरी के बीच चयन कर सकते हैं । उनके बीच क्या अंतर है और कब कौन सा उपयोग करना उचित है?
जवाबों:
स्टेटिक लाइब्रेरी आपके बाइनरी में कोड का आकार बढ़ाती हैं। वे हमेशा लोड होते हैं और आपके द्वारा संकलित कोड का कोई भी संस्करण उस कोड का संस्करण होता है जो चलेगा।
गतिशील पुस्तकालयों को अलग से संग्रहीत और संस्करणित किया जाता है। डायनामिक लाइब्रेरी के एक संस्करण को लोड किया जाना संभव है जो कि मूल नहीं था जो कि आपके कोड के साथ भेज दिया गया हो अगर अपडेट को मूल संस्करण के साथ बाइनरी संगत माना जाता है।
इसके अतिरिक्त डायनेमिक लाइब्रेरियों को आवश्यक रूप से लोड नहीं किया जाता है - वे आमतौर पर लोड होते हैं जब पहली बार कहा जाता है - और उन घटकों के बीच साझा किया जा सकता है जो एक ही लाइब्रेरी (कई डेटा लोड, एक कोड लोड) का उपयोग करते हैं।
डायनेमिक पुस्तकालयों को ज्यादातर समय बेहतर दृष्टिकोण माना जाता था, लेकिन मूल रूप से उनमें एक प्रमुख दोष (गूगल डीएलएल नरक) था, जिसे सभी को खत्म कर दिया गया है, लेकिन हाल के विंडोज ओएस (विशेष रूप से विंडोज एक्सपी) द्वारा समाप्त कर दिया गया है।
दूसरों ने पर्याप्त रूप से समझाया है कि एक स्थिर पुस्तकालय क्या है, लेकिन मैं स्टैटिक लाइब्रेरीज़ का उपयोग करने के कुछ संकेतों को इंगित करना चाहता हूं, जैसे कि विंडोज़ पर:
एकमात्र: यदि किसी चीज़ को वैश्विक / स्थिर और अद्वितीय होना चाहिए, तो उसे स्थिर पुस्तकालय में रखने के बारे में बहुत सावधानी बरतें। यदि कई डीएलएल उस स्थिर पुस्तकालय से जुड़े होते हैं, तो वे एकल की अपनी प्रति प्राप्त करेंगे। हालाँकि, यदि आपका एप्लिकेशन एक एकल EXE है जिसमें कोई कस्टम DLL नहीं है, तो यह समस्या नहीं हो सकती है।
अपरिष्कृत कोड हटाना: जब आप किसी स्थैतिक पुस्तकालय से लिंक करते हैं, तो केवल आपके DLL / EXE द्वारा संदर्भित स्थिर पुस्तकालय के भाग आपके DLL / EXE में लिंक हो जाएंगे।
उदाहरण के लिए, यदि mylib.lib
इसमें a.obj
और b.obj
आपका DLL / EXE केवल संदर्भ फ़ंक्शन या चर हैं a.obj
, b.obj
तो लिंकर द्वारा संपूर्णता को छोड़ दिया जाएगा। यदि b.obj
वैश्विक / स्थिर वस्तुएं हैं, तो उनके निर्माता और विध्वंसक निष्पादित नहीं होंगे। यदि उन निर्माणकर्ताओं / विध्वंसक के दुष्प्रभाव होते हैं, तो आप उनकी अनुपस्थिति से निराश हो सकते हैं।
इसी तरह, अगर स्टैटिक लाइब्रेरी में विशेष एंट्रीपॉइंट होते हैं, तो आपको ध्यान रखना होगा कि वे वास्तव में शामिल हैं। एम्बेडेड प्रोग्रामिंग में इसका एक उदाहरण (ठीक है, विंडोज नहीं) एक बाधा हैंडलर होगा जो एक विशिष्ट पते पर होने के रूप में चिह्नित है। आपको यह सुनिश्चित करने के लिए कि इसे खारिज नहीं किया जाता है, यह सुनिश्चित करने के लिए आपको एक इंटरप्रेन्योर के रूप में इंटरप्ट हैंडलर को भी चिह्नित करना होगा।
इसका एक और परिणाम यह है कि एक स्थिर लाइब्रेरी में ऑब्जेक्ट फाइलें हो सकती हैं जो कि अनसुलझे संदर्भों के कारण पूरी तरह से अनुपयोगी होती हैं, लेकिन जब तक आप उन ऑब्जेक्ट फ़ाइलों से किसी फ़ंक्शन या चर का संदर्भ नहीं देते हैं, तब तक यह लिंकर त्रुटि का कारण नहीं होगा। यह लाइब्रेरी लिखे जाने के लंबे समय बाद हो सकता है।
डिबग प्रतीक: आप प्रत्येक स्थिर पुस्तकालय के लिए एक अलग पीडीबी चाहते हैं, या आप डिबग प्रतीकों को ऑब्जेक्ट फ़ाइलों में रखना चाह सकते हैं ताकि वे डीएलएल / एक्सई के लिए पीडीबी में लुढ़क जाएं। विजुअल C ++ डॉक्यूमेंटेशन आवश्यक विकल्पों की व्याख्या करता है ।
RTTI:type_info
यदि आप एक ही स्थिर पुस्तकालय को कई DLL में जोड़ते हैं तो आप एक ही वर्ग के लिए कई वस्तुओं के साथ समाप्त हो सकते हैं । यदि आपका प्रोग्राम मानता है कि type_info
"सिंगलटन" डेटा और उपयोग करता है &typeid()
या type_info::before()
, आपको अवांछनीय और आश्चर्यजनक परिणाम मिल सकते हैं।
एक lib कोड की एक इकाई है जिसे आपके एप्लिकेशन निष्पादन योग्य के भीतर बंडल किया जाता है।
एक dll निष्पादन योग्य कोड की एक स्वसंपूर्ण इकाई है। यह उस प्रक्रिया में लोड होता है, जब उस कोड में कॉल किया जाता है। एक dll का उपयोग कई अनुप्रयोगों द्वारा किया जा सकता है और कई प्रक्रियाओं में लोड किया जा सकता है, जबकि हार्ड ड्राइव पर अभी भी कोड की केवल एक ही कॉपी है।
Dll पेशेवरों : कई उत्पादों के बीच कोड का पुन: उपयोग / साझा करने के लिए इस्तेमाल किया जा सकता है; मांग पर प्रक्रिया मेमोरी में लोड और जब ज़रूरत नहीं हो तो अनलोड किया जा सकता है; कार्यक्रम के बाकी हिस्सों से स्वतंत्र रूप से उन्नत किया जा सकता है।
Dll विपक्ष : dll लोडिंग और कोड रिबासिंग का प्रदर्शन प्रभाव; वर्जनिंग समस्याएं ("dll नरक")
लीब पेशेवरों : कोई प्रदर्शन प्रभाव नहीं क्योंकि कोड हमेशा प्रक्रिया में लोड होता है और छूट नहीं दी जाती है; कोई संस्करण समस्याओं।
Lib cons : निष्पादन योग्य / प्रक्रिया "ब्लोट" - सभी कोड आपके निष्पादन योग्य हैं और प्रक्रिया शुरू होने पर लोड किए गए हैं; कोई पुन: उपयोग / साझा नहीं - प्रत्येक उत्पाद कोड की अपनी प्रति है।
स्थिर बनाम गतिशील पुस्तकालयों के तकनीकी निहितार्थ के अलावा (स्थिर फाइलें एक बड़े बाइनरी बनाम गतिशील पुस्तकालयों में सब कुछ बंडल करती हैं जो कई अलग-अलग निष्पादनयोग्य के बीच कोड साझा करने की अनुमति देती हैं), कानूनी निहितार्थ हैं ।
उदाहरण के लिए, यदि आप LGPL लाइसेंस कोड का उपयोग कर रहे हैं और आप LGPL लाइब्रेरी के खिलाफ स्टेटिकली लिंक करते हैं (और इस तरह एक बड़ा बाइनरी बनाते हैं), तो आपका कोड अपने आप ही ओपन सॉरर्ड ( फ्रीडम इन फ्रीडम) LGPL कोड बन जाता है । यदि आप एक साझा वस्तुओं के खिलाफ लिंक करते हैं, तो आपको केवल एलजीपीएल पुस्तकालय में किए गए सुधार / बग फिक्स को एलजीपीएल करने की आवश्यकता है।
यह एक और अधिक महत्वपूर्ण मुद्दा बन जाता है यदि आप यह तय कर रहे हैं कि उदाहरण के लिए आपको मोबाइल एप्लिकेशन कैसे संकलित करने हैं (एंड्रॉइड में आपके पास स्थिर बनाम गतिशील का विकल्प है, तो आईओएस में आप ऐसा नहीं करते हैं - यह हमेशा स्थिर होता है)।
C ++ प्रोग्राम दो चरणों में बनाए जाते हैं
स्टेटिक लाइब्रेरी (.lib) सिर्फ .obj फाइलों का एक बंडल है और इसलिए यह एक संपूर्ण कार्यक्रम नहीं है। यह एक कार्यक्रम के निर्माण के दूसरे (लिंकिंग) चरण से नहीं गुजरा है। दूसरी ओर, Dlls, exe की तरह हैं और इसलिए पूर्ण कार्यक्रम हैं।
यदि आप एक स्थैतिक पुस्तकालय का निर्माण करते हैं, तो यह अभी तक जुड़ा नहीं है और इसलिए आपके स्थैतिक पुस्तकालय के उपभोक्ताओं को उसी संकलक का उपयोग करना होगा जो आपने उपयोग किया था (यदि आपने g ++ का उपयोग किया है, तो उन्हें g ++ का उपयोग करना होगा)।
यदि इसके बजाय आपने एक dll बनाया (और इसे सही तरीके से बनाया है ), तो आपने एक पूरा प्रोग्राम बनाया है, जिसका उपयोग सभी उपभोक्ता कर सकते हैं, चाहे वह कोई भी कंपाइलर इस्तेमाल कर रहे हों। हालांकि, कई प्रतिबंध हैं, एक dll से निर्यात करने पर, यदि क्रॉस कंपाइलर संगतता वांछित है।
consumers of your static library will have to use the same compiler that you used
यदि स्टैटिक लाइब्रेरी C ++ लाइब्रेरी का उपयोग करती है, जैसे #include <iostream>
।
$$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/static [37]> cat makefile
hello: hello.o libtest.a
cc -o hello hello.o -L. -ltest
hello.o: hello.c
cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
ar cr libtest.a foo.o foo2.o
foo.o:foo.c
cc -c foo.c
foo2.o:foo.c
cc -c foo2.c
clean:
rm -f foo.o foo2.o libtest.a hello.o
$$:~/static [38]>
$$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
cc -o hello hello.o -L`pwd` -ltest
hello.o:
cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
cc -c -b foo.c
foo2.o:foo.c
cc -c -b foo2.c
clean:
rm -f libtest.sl foo.o foo
2.o hello.o
$$:~/dynamic [50]>
एक स्थिर पुस्तकालय क्लाइंट में संकलित हो जाता है। A .lib का संकलन समय पर किया जाता है और लाइब्रेरी की सामग्री उपभोग्य निष्पादन योग्य हो जाती है।
एक गतिशील लाइब्रेरी को रनटाइम पर लोड किया जाता है और क्लाइंट निष्पादन योग्य में संकलित नहीं किया जाता है। डायनेमिक लाइब्रेरी अधिक लचीली होती हैं क्योंकि कई क्लाइंट एक्जीक्यूटिव एक DLL लोड कर सकते हैं और इसकी कार्यक्षमता का उपयोग कर सकते हैं। यह आपके ग्राहक कोड की समग्र आकार और स्थिरता को न्यूनतम रखता है।
आपको समय, परिवर्तन, स्थिरता, अनुकूलता आदि के परिवर्तनों के बारे में ध्यान से सोचना चाहिए।
यदि साझा कोड का उपयोग करने वाले दो ऐप हैं, तो क्या आप उन ऐप्स को एक साथ बदलने के लिए मजबूर करना चाहते हैं, यदि उन्हें एक-दूसरे के साथ संगत होने की आवश्यकता है? फिर dll का उपयोग करें। एक्सई के सभी एक ही कोड का उपयोग करेंगे।
या क्या आप उन्हें एक-दूसरे से अलग करना चाहते हैं, ताकि आप एक को बदल सकें और आश्वस्त रहें कि आपने दूसरे को नहीं तोड़ा है। फिर स्थैतिक परिवाद का उपयोग करें।
DLL नरक है जब आप शायद एक स्थिर काम का इस्तेमाल किया है, लेकिन आप बजाय एक dll का इस्तेमाल किया है, और सभी exes इसके साथ अनुकूल नहीं हैं।
एक स्थिर पुस्तकालय को अंतिम निष्पादन योग्य में जोड़ा जाना चाहिए; यह निष्पादन योग्य का हिस्सा बन जाता है और जहां भी जाता है, उसका अनुसरण करता है। हर बार निष्पादन योग्य निष्पादित होने पर एक डायनेमिक लाइब्रेरी लोड की जाती है और DLL फ़ाइल के रूप में निष्पादन योग्य से अलग रहती है।
आप DLL का उपयोग तब करेंगे जब आप निष्पादन योग्य को फिर से लिंक किए बिना लाइब्रेरी द्वारा प्रदान की गई कार्यक्षमता को बदलना चाहते हैं (बस DLL फ़ाइल को बदलें, निष्पादन योग्य फ़ाइल को बदलने के बिना)।
जब भी आपके पास डायनेमिक लाइब्रेरी का उपयोग करने का कोई कारण नहीं है, तो आप एक स्थिर पुस्तकालय का उपयोग करेंगे।
उलरिक ड्रेपर का पेपर " हाउ टू राइट शेयरेड लाइब्रेरीज़ " पर भी अच्छा संसाधन है जो यह बताता है कि साझा पुस्तकालयों का लाभ उठाने के लिए सबसे अच्छा विवरण क्या है, या वह "डायनामिक साझा ऑब्जेक्ट्स" (डीएसओ) के रूप में क्या संदर्भित करता है। यह ईएलएफ बाइनरी प्रारूप में साझा पुस्तकालयों पर अधिक ध्यान केंद्रित करता है, लेकिन कुछ चर्चाएं विंडोज डीएलएल के लिए भी उपयुक्त हैं।
इस विषय की एक उत्कृष्ट चर्चा के लिए सूर्य के इस लेख को पढ़ें।
यह सभी लाभों में चला जाता है जिसमें इंटरपोज़िंग लाइब्रेरी सम्मिलित करने में सक्षम है। इंटरपोज़िंग पर अधिक विवरण यहां इस लेख में पाया जा सकता है ।
वास्तव में आप जो व्यापार कर रहे हैं (एक बड़ी परियोजना में) प्रारंभिक लोड समय में है, पुस्तकालयों को एक या दूसरे समय में लिंक किया जा रहा है, जो निर्णय लेना है, वह लिंक काफी लंबा समय लेगा, जिसे कंपाइलर की आवश्यकता है बुलेट को काटने के लिए और इसे आगे बढ़ाएं, या डायनेमिक लिंकर लोड समय पर कर सकते हैं।
यदि आपकी लाइब्रेरी को कई निष्पादकों के बीच साझा किया जा रहा है, तो यह अक्सर निष्पादकों के आकार को कम करने के लिए इसे गतिशील बनाने के लिए समझ में आता है। अन्यथा, निश्चित रूप से इसे स्थिर करें।
एक dll का उपयोग करने के कई नुकसान हैं। इसे लोड करने और उतारने के लिए अतिरिक्त ओवरहेड है। एक अतिरिक्त निर्भरता भी है। यदि आप इसे अपने निष्पादकों के साथ असंगत बनाने के लिए dll को बदलते हैं, तो वे काम करना बंद कर देंगे। दूसरी ओर, यदि आप एक स्थिर पुस्तकालय बदलते हैं, तो पुराने संस्करण का उपयोग करने वाले आपके संकलित निष्पादनयोग्य प्रभावित नहीं होंगे।
यदि लाइब्रेरी स्थिर है, तो लिंक समय पर कोड आपके निष्पादन योग्य के साथ जुड़ा हुआ है। यह आपके निष्पादन योग्य को बड़ा बनाता है (यदि आप गतिशील मार्ग से चले गए हैं)।
यदि लाइब्रेरी गतिशील है, तो लिंक समय पर आवश्यक तरीकों के संदर्भ आपके निष्पादन योग्य में बनाए जाते हैं। इसका मतलब है कि आपको अपने निष्पादन योग्य और गतिशील पुस्तकालय को शिप करना होगा। आपको यह भी विचार करना चाहिए कि क्या अन्य सामानों के बीच पुस्तकालय में कोड का साझा उपयोग सुरक्षित, पसंदीदा लोड पता है।
यदि आप स्थैतिक पुस्तकालय के साथ रह सकते हैं, तो स्थैतिक पुस्तकालय के साथ जाएं।
हम अपने प्रोजेक्ट में बहुत सारे DLL (> 100) का उपयोग करते हैं। इन DLL की एक-दूसरे पर निर्भरता है और इसलिए हमने डायनेमिक लिंकिंग का सेटअप चुना। हालाँकि इसके निम्नलिखित नुकसान हैं:
शायद एक बेहतर सेटअप सब कुछ एक स्थिर पुस्तकालय बनाने के लिए था (और इसलिए आपके पास बस एक निष्पादन योग्य है)। यह तभी काम करता है जब कोई कोड दोहराव न हो। इस धारणा का समर्थन करने के लिए एक परीक्षण लगता है, लेकिन मुझे एक आधिकारिक MSDN उद्धरण नहीं मिला। तो उदाहरण के लिए 1 के साथ निर्वासित करें:
साझा_लिब 2 का कोड और चर अंतिम विलयित निष्पादन योग्य में केवल एक बार मौजूद होना चाहिए। क्या कोई इस सवाल का समर्थन कर सकता है?
स्टेटिक लाइब्रेरी ऐसे अभिलेखागार होते हैं जिनमें लाइब्रेरी के लिए ऑब्जेक्ट कोड होता है, जब एक एप्लिकेशन में लिंक किया जाता है जो कोड निष्पादन योग्य में संकलित होता है। साझा लाइब्रेरी अलग हैं कि वे निष्पादन योग्य में संकलित नहीं हैं। डायनेमिक लिंकर के बजाय कुछ निर्देशिकाओं को खोजता है जो लाइब्रेरी (ओं) को खोजता है, इसकी आवश्यकता होती है, फिर उसे मेमोरी में लोड करता है। फिर एक निष्पादन योग्य एक ही समय में एक ही साझा पुस्तकालय का उपयोग कर सकता है, इस प्रकार मेमोरी उपयोग और निष्पादन योग्य आकार को कम कर सकता है। हालांकि, निष्पादन योग्य के साथ वितरित करने के लिए फिर अधिक फाइलें हैं। आपको यह सुनिश्चित करने की आवश्यकता है कि लाइब्रेरी का उपयोग सिस्टम पर कहीं पर स्थापित है जहां लिंकर इसे पा सकता है, स्थैतिक लिंकिंग इस समस्या को समाप्त करता है लेकिन एक बड़ी निष्पादन योग्य फ़ाइल में परिणाम होता है।
यदि आपका एम्बेडेड प्रोजेक्ट्स या विशेष प्लेटफ़ॉर्म पर काम करने वाले स्टैटिक लाइब्रेरीज़ ही जाने का एकमात्र तरीका हैं, तो भी कई बार वे आपके आवेदन में संकलित करने की परेशानी से कम नहीं होते हैं। इसके अलावा परियोजनाओं और मेकफाइल जिसमें सब कुछ शामिल है, जीवन को खुशहाल बनाता है।
मैं अंगूठे का एक सामान्य नियम देता हूं कि यदि आपके पास एक बड़ा कोडबेस है, जो सभी निचले स्तर के पुस्तकालयों (जैसे एक यूटिल्स या गुई फ्रेमवर्क) के ऊपर बनाया गया है, जिसे आप अधिक प्रबंधनीय पुस्तकालयों में विभाजित करना चाहते हैं, तो उन्हें स्थिर लाइब्रेरी बनाएं। डायनामिक लाइब्रेरी वास्तव में आपको कुछ भी नहीं खरीदती हैं और कम आश्चर्य नहीं होता है - उदाहरण के लिए केवल एकल उदाहरणों का एक उदाहरण होगा।
यदि आपके पास एक पुस्तकालय है जो बाकी के कोडबेस (उदाहरण के लिए एक तीसरा पक्ष पुस्तकालय) से पूरी तरह से अलग है, तो इसे एक dll बनाने पर विचार करें। यदि लाइब्रेरी LGPL है, तो आपको लाइसेंस शर्तों के कारण किसी भी समय dll का उपयोग करने की आवश्यकता हो सकती है।