2009-12-04 14 views
7

मैं एक साझा लाइब्रेरी बनाना चाहता हूं जो किसी तृतीय-पक्ष स्थिर लाइब्रेरी से फ़ंक्शंस का उपयोग करे। उदाहरण के लिए, foo और barlibfoobar.a से। मुझे पता है कि मेरा मुख्य एप्लीकेशन भी foo का उपयोग कर रहा है और वह प्रतीक निर्यात करेगा। तो मैं बस कोड आकार बचाने के लिए bar में लिंक करना चाहता हूं और 'foo' को अनसुलझा छोड़ दूंगा (क्योंकि यह मुख्य एप्लिकेशन द्वारा प्रदान किया जाएगा)। अगर मैं libfoobar.a शामिल करता हूं, तो लिंकर एलडी में मेरी साझा लाइब्रेरी में दोनों फ़ंक्शन शामिल होंगे। अगर मुझे libfoobar.a शामिल नहीं है, तो मेरी लाइब्रेरी में bar फ़ंक्शन तक पहुंच नहीं होगी क्योंकि एप्लिकेशन स्वयं bar में लिंक नहीं कर रहा है। प्रश्न:साझा लाइब्रेरी में लाइब्रेरी फ़ंक्शंस का चुनिंदा स्टेटिक लिंकिंग

  • वहाँ एक रास्ता है जब शेयर की गई लाइब्रेरी का निर्माण केवल करने के लिए ld बता कुछ खास प्रतीक को हल करने है?
  • साझा की गई लाइब्रेरी में libfoobar.a चालू करें?
  • से bar फ़ंक्शन वाली फ़ाइल निकालें और लिंकर लाइन पर निर्दिष्ट करें?
  • इसके बारे में चिंता न करें, रन-टाइम लोडर आपके आवेदन से bar का उपयोग करेगा ताकि साझा लाइब्रेरी में bar की प्रति लोड नहीं की जाएगी?

उत्तर

4

निम्नलिखित बातों सवाल मैं उत्पन्न किया था जवाब देने की कोशिश:

  • ld आप एक स्थिर पुस्तकालय से कुछ खास प्रतीक में जोड़ने छोड़ करने की अनुमति नहीं लगता है। --just-symbols या --undefined (या EXTERN लिंकर स्क्रिप्ट कमांड) का उपयोग प्रतीकों को जोड़ने से ld को नहीं रोकेगा।
  • एक साझा एक, libfoobar.so.1.0 में एक स्थिर पुस्तकालय, libfoobar.a, कनवर्ट करते हैं, और सभी दृश्य प्रतीकों का निर्यात करने के लिए। आप --version-script और प्रतीकों के केवल एक उप-समूह को निर्यात करने के लिए अन्य विधियों का भी उपयोग कर सकते हैं।

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

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

  • यदि आप --pie विकल्प के साथ निष्पादन योग्य संकलित करते हैं तो अपने मुख्य निष्पादन योग्य को अपने डीएसओ के लिए साझा लाइब्रेरी के रूप में निर्दिष्ट करना संभव है। आपका डीएसओ पहले आपके निष्पादन योग्य से लिंक करेगा यदि यह लिंक कमांड में स्थैतिक लाइब्रेरी से पहले था। चेतावनी यह है कि मुख्य निष्पादन योग्य LD_LIBRARY_PATH या -rpath के माध्यम से उपलब्ध होना चाहिए। इसके अलावा, स्ट्रेस का उपयोग करके पता चलता है कि चूंकि निष्पादन योग्य आपकी लाइब्रेरी की निर्भरता है, इसलिए जब आपका डीएसओ लोड होता है तो इसे फिर से लोड किया जाता है।

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • गतिशील लिंकर RTLD_DEEPBIND ध्वज के साथ foo पहले जब तक आप dlopen फोन() के निष्पादन के संस्करण का उपयोग करेगा। स्ट्रेस का उपयोग करके पता चलता है कि संपूर्ण डीएसओ फ़ाइल को mmap2() मेमोरी में मैप किया गया है। हालांकि, विकिपीडिया का दावा है कि एमएमएपी के लिए "डिस्क से वास्तविक पठन" आलसी "तरीके से किया जाता है, एक विशिष्ट स्थान के उपयोग के बाद।" यदि यह सत्य है, तो डुप्लिकेट foo लोड नहीं किया जाएगा। ध्यान दें कि ओवरराइड केवल तब होता है जब आपका डीएसओ निर्यात किया गया foo। अन्यथा, फ़ंक्शन foo जो आपके डीएसओ में स्थिर रूप से लिंक किया गया था, तब भी उपयोग किया जाएगा जब भी आपका डीएसओ foo पर कॉल करेगा।

अंत में, mmap() एक आलसी पढ़ने का उपयोग करता है, तो सबसे अच्छा समाधान सामान्य तरीके से अपने DSO लिंक और गतिशील लिंकर और लिनक्स बाकी की देखभाल देना है।

1

मैं साझा पुस्तकालयों में सबसे बड़ा विशेषज्ञ नहीं हूं, इसलिए मैं यहां गलत हो सकता हूं!

यदि मैं जो करने का प्रयास कर रहा हूं उसके बारे में सही अनुमान लगा रहा हूं, तो बस libc.so के खिलाफ अपने साझा lib को लिंक करें। आप अपनी लाइब्रेरी में एम्बेडेड sscanf की एक अतिरिक्त प्रति नहीं चाहते हैं।

मैंने जवाब में रुचि रखने के मामले में, जो कुछ भी हो रहा था, उससे पहले मैंने आपके प्रश्नों का उत्तर दिया था।

क्या साझा पुस्तकालय बनाने के दौरान केवल कुछ प्रतीकों को हल करने के लिए एलडी को बताने का कोई तरीका है?

केवल बाहरी, स्थिर, कार्य और चर साझा लाइब्रेरी की प्रतीक तालिका में नहीं जाते हैं।

जब आप अपनी साझा लाइब्रेरी बनाते हैं, तो लिंकर कमांड लाइन पर ऑब्जेक्ट्स में कोई भी प्रतीक नहीं मिला है। यदि लिंकर इसके बारे में शिकायत करता है, तो आपको शायद साझा libc के विरुद्ध साझा साझा lib को लिंक करने की आवश्यकता है। आप साझा किए गए libs साझा कर सकते हैं जो अन्य साझा libs पर निर्भर करते हैं, और ld.so निर्भरता श्रृंखलाओं से निपट सकते हैं।

यदि मेरे पास अधिक प्रतिनिधि था, तो मैं इसे एक टिप्पणी के रूप में पूछूंगा: क्या आपके पास sprintf/sscanf का एक अनुकूलित संस्करण है, या आपके साझा lib के लिए -lc में कार्यान्वयन का उपयोग करना ठीक होगा? अगर -एलसी ठीक है, तो मेरा जवाब शायद आपकी समस्या हल करता है। यदि नहीं, तो आपको उन वस्तुओं के अपने साझा lib को बनाने की आवश्यकता है जिनके पास केवल आपके लिए आवश्यक फ़ंक्शन हैं। यानी इसे /usr/lib/libc.a से लिंक न करें।

शायद मैं अपने

libc.a (नहीं वास्तव में "असली" libc) लाइन से उलझन में हो रही। /usr/lib/libc.a वास्तव में glibc (लिनक्स पर) है। यह libc.so में एक ही कोड की एक स्थिर रूप से जुड़ी प्रति है। जब तक आप अपने स्वयं के libc.a के बारे में बात नहीं कर रहे हैं (जो मैं पहले सोच रहा था) ...

libc.a को साझा लाइब्रेरी में बदलें? आप शायद कर सकते हैं, लेकिन ऐसा नहीं करते हैं, क्योंकि संभवतः यह स्थिति-स्वतंत्र कोड के रूप में संकलित नहीं है, इसलिए इसे रन समय पर ld.so द्वारा बहुत से स्थानान्तरण की आवश्यकता होगी।

libc.a से sscanf निकालें और लिंकर लाइन पर निर्दिष्ट करें?

संभव हो सकता है। सामग्रियों की सूची के लिए ar t /usr/lib/libc.a। (आरआर के तर्क टैर के समान हैं। टैप टेप के लिए ar था .... पुराना स्कूल यूनिक्स यहाँ।) शायद यह इतना आसान नहीं है, क्योंकि एसएसकेएनएफ शायद .a में अन्य फ़ाइलों में प्रतीकों पर निर्भर करता है।

+0

libc भ्रम के बारे में क्षमा करें। मैं बस किसी तीसरे पक्ष की स्थिर पुस्तकालय का मतलब था और उदाहरण के रूप में libc का इस्तेमाल किया। मैं इसे स्पष्ट करने के लिए अपने प्रश्न को संशोधित करने जा रहा हूं। – KlaxSmashing

1

आपके संशोधित अधिक स्पष्ट प्रश्न का उत्तर दें।

ध्यान रखें कि आम तौर पर एक साझा lib का बिंदु यह है कि कई प्रोग्राम इसके खिलाफ लिंक कर सकते हैं। इसलिए आपको आवश्यक फ़ंक्शन के लिए मुख्य प्रोग्राम के प्रतीक का उपयोग करने का आपका अनुकूलन केवल तभी काम करेगा जब मुख्य कार्यक्रम हमेशा उस प्रतीक को प्रदान करता है (एक स्थिर lib या अन्यथा के माध्यम से)। आमतौर पर यह नहीं होता कि लोग क्या करना चाहते हैं।

यदि यह केवल कुछ छोटे कार्य हैं, तो शायद आपको इसे होने देना चाहिए। आप शायद कार्यों के लिए कोड की दो प्रतियों, अपने श्लिब में से एक, और मुख्य कार्यक्रम में से एक के साथ समाप्त हो जाएगा। यदि वे छोटे होते हैं (या कम से कम नहीं), या अक्सर नहीं कहा जाता है और प्रदर्शन-महत्वपूर्ण नहीं है, तो दो प्रतियों वाले कोड-आकार/आई-कैश के बारे में चिंता करने की कोई बात नहीं है। (अनुवाद: मुझे नहीं पता कि यह मेरे सिर के ऊपर से कैसे बचें, इसलिए मुझे इसे देखने के लिए समय नहीं लगेगा और इसे और अधिक जटिल बनाने के लिए मेकफ़ाइल बनाना होगा।)

मेरा अन्य उत्तर देखें एक स्थिर पुस्तकालय से सामान निकालने के लिए ar के साथ गड़बड़ करने पर कुछ टिप्पणियों के लिए। सारांश: शायद गैर-तुच्छ, क्योंकि आप .a में विभिन्न .o फ़ाइलों के बीच निर्भरताओं को नहीं जानते हैं।

यह साझा करना संभव हो सकता है कि आप अपनी साझा लाइब्रेरी को स्थिर पुस्तकालय से खींचने वाले प्रतीकों को निर्यात करके उम्मीद कर रहे हों। फिर, जब आप मुख्य ऐप को लिंक करते हैं, तो अपनी साझा लाइब्रेरी को लिंकर कमांड लाइन पर स्थिर lib से पहले रखें। ld को आपके shlib में "foo" मिलेगा, और उस प्रतिलिपि का उपयोग करें (यदि यह पुनः निर्यात करने की चाल संभव है), लेकिन "बार" के लिए इसे स्थिर lib से एक प्रति शामिल करना होगा।

ld --export-dynamic हो सकता है कि आपको गतिशील प्रतीक तालिका में सभी प्रतीकों को निर्यात करने की आवश्यकता हो। उसकी कोशिश करो। और दस्तावेज़/मैन पेज में "निर्यात" की खोज करें। पुस्तकालय में एक प्रतीक दिखाई देने के लिए "निर्यात" शब्दकोष है। - निर्यात-सब-प्रतीकों i386 पीई (विंडोज़ डीएलएल) खंड में है, अन्यथा यह संभवतः चाल करेगा।

+0

एलडी मैन पेज में कुछ नोटिस: --just-symbols = फ़ाइल नाम: "फ़ाइल नाम से प्रतीक नाम और उनके पते पढ़ें, लेकिन इसे स्थानांतरित न करें या इसे आउटपुट में शामिल न करें। इससे आपकी आउटपुट फ़ाइल प्रतीकात्मक रूप से पूर्ण स्थानों पर संदर्भित हो सकती है अन्य कार्यक्रमों में परिभाषित स्मृति की। " –

+0

चूंकि साझा लाइब्रेरी एक 'प्लगइन' है (यानी, हमेशा लोड नहीं होती), यह अन्य कोड विशेष रूप से मुख्य एप्लिकेशन के लिए प्रतीक प्रदान नहीं कर सकती है। सबसे आसान संभवतः तृतीय पक्ष स्थैतिक पुस्तकालय को एक गतिशील पुस्तकालय में बदल देता है। – KlaxSmashing

संबंधित मुद्दे