Libstdc ++ को सांख्यिकीय रूप से लिंक करना: कोई भी गोच


90

मुझे Ubuntu 10.10 पर चलने वाले सिस्टम के लिए Ubuntu 10.10 पर निर्मित C ++ एप्लिकेशन को तैनात करने की आवश्यकता है, जो Ubuntu 10.04 पर चल रहा है, जो libstdc ++ के काफी पुराने संस्करण के साथ आता है।

वर्तमान में, मैं -static-libstdc++ -static-libgccइस ब्लॉग पोस्ट के अनुसार सुझाव दे रहा हूं : libstdc ++ को सांख्यिकीय रूप से जोड़ना । लेखक libstdc ++ को संकलित करते समय किसी भी गतिशील रूप से लोड किए गए C ++ कोड का उपयोग करने के खिलाफ चेतावनी देता है, जो कि मैंने अभी तक जाँच नहीं की है। फिर भी, अब तक सब कुछ सुचारू रूप से चल रहा है: मैं Ubuntu 10.04 पर C ++ 11 सुविधाओं का उपयोग कर सकता हूं, जो कि मैं बाद में था।

मैं ध्यान देता हूं कि यह लेख २००५ का है, और शायद तब से बहुत कुछ बदल गया है। क्या इसकी सलाह अभी भी चालू है? क्या कोई गुप्त समस्या है जिसके बारे में मुझे पता होना चाहिए?


नहीं, libstdc ++ से स्टेटिकली लिंक करने का अर्थ यह नहीं है। अगर इसका मतलब यह है कि तब -static-libstdc++विकल्प का कोई मतलब नहीं होगा, तो आप बस इस्तेमाल करेंगे-static
जोनाथन वैक्ली

@JonathanWakely -static को kernel too oldकुछ ubuntu 1404 सिस्टम में त्रुटि मिलेगी । Glibc.so kernel32.dllविंडो में जैसा है, यह ऑपरेशन सिस्टम इंटरफ़ेस का हिस्सा है, हमें इसे अपने बाइनरी में एम्बेड नहीं करना चाहिए। आप objdump -T [binary path]इसे गतिशील रूप से लोड होने libstdc++.soया नहीं देखने के लिए उपयोग कर सकते हैं । गोलंग प्रोग्रामर के लिए, आप #cgo linux LDFLAGS: -static-libstdc++ -static-libgccआयात "सी" से पहले जोड़ सकते हैं
कांस्य पुरुष

@ ब्रोनज़मैन, लेकिन हम बात -static-libstdc++नहीं कर रहे हैं-static तो libc.soस्थिर लिंक नहीं किया जाएगा।
जोनाथन वेकली

1
@NickHutchinson लिंक्ड-इन ब्लॉग पोस्ट चला गया है। यह SO प्रश्न यहां प्रासंगिक शब्दों के लिए एक लोकप्रिय खोज हिट है। क्या आप अपने प्रश्न में उस ब्लॉग पोस्ट से महत्वपूर्ण जानकारी को पुन: उत्पन्न कर सकते हैं, या यदि आप जानते हैं कि यह कहां स्थानांतरित हो गया है, तो एक नई लिंक प्रदान करें?
ब्रायन कैन

1
@BrianCain इंटरनेट संग्रह में यह है: web.archive.org/web/20160313071116/http://www.tril
लिथियम.com/

जवाबों:


134

वह ब्लॉग पोस्ट बहुत गलत है।

जहां तक ​​मुझे पता है कि C ++ ABI में बदलाव GCC की हर बड़ी रिलीज के साथ किए गए हैं (यानी अलग-अलग या दूसरे वर्जन नंबर वाले कंपोनेंट्स के साथ)।

सच नहीं। GCC 3.4 के बाद से शुरू किए गए केवल C ++ ABI परिवर्तन पिछड़े-संगत थे, जिसका अर्थ है C ++ ABI लगभग नौ वर्षों से स्थिर है।

मामलों को बदतर बनाने के लिए, अधिकांश प्रमुख लिनक्स वितरण जीसीसी स्नैपशॉट और / या अपने जीसीसी संस्करणों का उपयोग करते हैं, जिससे यह जानना लगभग असंभव हो जाता है कि क्या आप जीसीसी संस्करणों का उपयोग कर रहे हैं जब आप बायनेरिज़ वितरित करते हैं।

वितरण के GCC के पैच किए गए संस्करणों के बीच के अंतर मामूली हैं, न कि ABI बदलते हैं, जैसे फेडोरा के 4.6.3 20120306 (Red Hat 4.6.3-2) ABI अपस्ट्रीम FSF 4.6.x रिलीज़ और लगभग निश्चित रूप से किसी भी 4.6 के साथ संगत है। किसी अन्य डिस्ट्रो से एक्स।

GNU / Linux GCC के रनटाइम लाइब्रेरी में ELF सिंबल वर्जनिंग का उपयोग किया जाता है, इसलिए ऑब्जेक्ट्स और लाइब्रेरियों द्वारा आवश्यक सिंबल संस्करणों की जांच करना आसान है, और यदि आपके पास एक libstdc++.soहै जो उन चिह्नों को प्रदान करता है तो यह काम करेगा, यह कोई फर्क नहीं पड़ता कि यह थोड़ा अलग पैच वर्जन है अपने डिस्ट्रो के दूसरे संस्करण से।

लेकिन कोई C ++ कोड (या C ++ रनटाइम सपोर्ट का उपयोग करने वाला कोई भी कोड) गतिशील रूप से लिंक किया जा सकता है अगर यह काम करना है।

यह सच भी नहीं है।

कहा कि, स्टेटिकली लिंकिंग आपके लिए libstdc++.aएक विकल्प है।

इसका कारण यह नहीं हो सकता है यदि आप गतिशील रूप से एक पुस्तकालय लोड कर रहे हैं (उपयोग कर रहे हैं dlopen) यह है कि libstdc ++ प्रतीकों पर निर्भर करता है कि यह आपके आवेदन द्वारा आवश्यक नहीं हो सकता है जब आपने इसे (सांख्यिकीय रूप से) लिंक किया था, इसलिए वे प्रतीक आपके निष्पादन योग्य में मौजूद नहीं होंगे। यह साझा लाइब्रेरी को गतिशील रूप से जोड़ने के द्वारा हल किया जा सकता है libstdc++.so(जो कि इस पर निर्भर होने पर किसी भी तरह से करने के लिए सही काम है।) ईएलएफ प्रतीक पारस्परिकता का अर्थ है कि आपके निष्पादन योग्य में मौजूद प्रतीकों का उपयोग साझा पुस्तकालय द्वारा किया जाएगा, लेकिन अन्य नहीं आपके निष्पादन योग्य में जो भी libstdc++.soइसके लिंक से मिल जाएगा। यदि आपका एप्लिकेशन उपयोग नहीं करता हैdlopen तो आपको उसकी परवाह करने की आवश्यकता नहीं है।

एक अन्य विकल्प (और जिसे मैं पसंद करता हूं) libstdc++.soआपके आवेदन के साथ नए को तैनात करना है और यह सुनिश्चित करना है कि यह डिफ़ॉल्ट सिस्टम से पहले पाया जाता है libstdc++.so, जो डायनेमिक लिंकर को सही जगह देखने के लिए मजबूर करके किया जा सकता है, या तो $LD_LIBRARY_PATHरन पर पर्यावरण चर का उपयोग करके- समय, या RPATHलिंक-टाइम में निष्पादन योग्य में सेट करके । मैं उपयोग करना पसंद RPATHकरता हूं क्योंकि यह काम करने के लिए आवेदन के लिए सही ढंग से सेट किए जा रहे पर्यावरण पर निर्भर नहीं करता है। यदि आप अपने आवेदन को लिंक करते हैं '-Wl,-rpath,$ORIGIN'(विस्तार करने की कोशिश कर रहे शेल को रोकने के लिए एकल उद्धरणों पर ध्यान दें $ORIGIN) तो निष्पादन योग्य के पासRPATH की$ORIGIN जो निष्पादन को उसी निर्देशिका में साझा पुस्तकालयों के लिए देखो करने के लिए गतिशील लिंकर बताता है। यदि आप नया डालते हैंlibstdc++.soनिष्पादन योग्य के रूप में एक ही निर्देशिका में इसे रन-टाइम, समस्या हल करने पर मिलेगा। (एक अन्य विकल्प निष्पादन योग्य को /some/path/bin/और नए libstdc ++ में डालना है । इसलिए निष्पादन योग्य के सापेक्ष किसी अन्य निश्चित स्थान के /some/path/lib/साथ और उसके साथ लिंक करें '-Wl,-rpath,$ORIGIN/../lib', और RPATH के सापेक्ष सेट करें $ORIGIN)


8
यह स्पष्टीकरण, विशेष रूप से RPATH के बारे में, शानदार है।
nilweed

3
लिनक्स पर आपके ऐप के साथ शिपिंग libstdc ++ बुरी सलाह है। "स्टीम लिबस्टीडीसी ++" के लिए Google सभी ड्रामा देखने के लिए जो यह लाता है। संक्षेप में, यदि आपके exe ने बाहरी libs (जैसे, opengl) को लोड किया है, जो libstdc ++ को फिर से dlopen करना चाहते हैं (जैसे, radeon ड्राइवर), तो वह lib आपके libstdc ++ का उपयोग कर रहा होगा क्योंकि यह पहले से ही लोड है, अपने बजाय, जो उन्हें चाहिए और उम्मीद करते हैं। तो आप एक वर्ग को वापस कर रहे हैं।

7
@cap, ओपी विशेष रूप से एक डिस्ट्रो को तैनात करने के बारे में पूछ रहा है जहां सिस्टम libstdc ++ अधिक पुराना है। स्टीम की समस्या यह है कि उन्होंने एक libstdc ++ को बंडल किया। इसलिए यह सिस्टम एक से अधिक पुराना था (संभवतः यह उस समय नया था जब उन्होंने इसे बंडल किया था, लेकिन डिस्ट्रो ने नए लोगों को भी स्थानांतरित कर दिया)। RPATH बिंदु को एक निर्देशिका से सम्‍मिलित करके हल किया जा सकता है libstdc++.so.6, जो संस्थापन के समय बंडल किए गए लिब को इंगित करता है या सिस्टम में एक है यदि यह नया है। अधिक जटिल मिश्रित-लिंकेज मॉडल हैं, जैसा कि Red Hat DTS द्वारा उपयोग किया जाता है, लेकिन वे स्वयं को करना कठिन हैं।
जोनाथन वेकली

5
अरे यार, मुझे खेद है अगर मैं नहीं चाहता कि मेरे मॉडल को बैकवर्ड-कम्पीटर बायनेरीज़ के लिए "अन्य लोगों को भरोसा रखने के लिए" libstdc ++ ABI कंप्रेशर्स को रखने के लिए "या" सशर्त रूप से libstdc ++ को रनटाइम में जोड़ने के लिए "शामिल किया जाए ... तो अगर यहाँ कुछ पंख लग जाएँ। और वहां, मैं क्या कर सकता हूं, मेरा मतलब कोई अनादर नहीं है। और अगर आपको memcpy@GLIBC_2.14 नाटक याद है, तो आप वास्तव में इस के साथ विश्वास करने के लिए मुझे दोष नहीं दे सकते :)

6
मुझे '-Wl, -rpath, $ ORIGIN' (rpath के सामने '-' नोट करें) का उपयोग करना था। मैं उत्तर को संपादित नहीं कर सकता क्योंकि संपादन कम से कम 6 वर्णों का होना चाहिए ....
user368507

11

जोनाथन वैक्ली के उत्कृष्ट उत्तर के अलावा, क्यों डोपेन () समस्याग्रस्त है:

जीसीसी 5 ( पीआर 64535 और पीआर 65434 देखें ) में नए अपवाद हैंडलिंग पूल के कारण , यदि आप लाइब्रेरी और डीएलक्लास करते हैं, जो एक पुस्तकालय है जो कि libstdc ++ से जुड़ा हुआ है, तो आपको हर बार मेमोरी लीक (पूल ऑब्जेक्ट का रिसाव) मिलेगा। इसलिए अगर ऐसा कोई मौका है जो आप कभी भी डोपेन का उपयोग करेंगे, तो ऐसा लगता है कि यह वास्तव में एक बुरा विचार है जैसे कि libstdc ++ लिंक करना। ध्यान दें कि यह पीआर 65434 में वर्णित सौम्य के विपरीत एक वास्तविक रिसाव है ।


1
फ़ंक्शन __gnu_cxx::__freeres()इस समस्या के साथ कम से कम कुछ मदद प्रदान करता है, क्योंकि यह पूल ऑब्जेक्ट के आंतरिक बफर को मुक्त करता है। लेकिन मेरे लिए यह स्पष्ट नहीं है कि इस फ़ंक्शन के लिए कॉल का निहितार्थ गलती से बाद में फेंके गए अपवादों के संबंध में है।
phlipsy

3

RPATH के बारे में जोनाथन वेकली के जवाब में एड-ऑन:

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

उदाहरण के लिए, मान लें कि आपके पास एक एप्लिकेशन है। App.exe जिसमें GST 4.9 के लिए libstdc ++ पर डायनेमिक रूप से जुड़ा निर्भरता है। App.exe इस निर्भरता RPATH के माध्यम से हल किया है, यानी

App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)

अब कहते हैं कि एक और लाइब्रेरी है डिपेंडेंसी। एसओ, जिसमें लिब्स्टडेक ++ पर गतिशील रूप से जुड़ा हुआ निर्भरता है। इसलिए जीसीसी 5.5 के लिए। यहाँ निर्भरता का समाधान पुस्तकालय के RPATH के माध्यम से किया जाता है, अर्थात

Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)

जब App.exe, Dependency.so को लोड करता है, तो यह न तो पुस्तकालय के RPATH को जोड़ता है और न ही प्रीपेन्ड करता है । यह बिल्कुल सलाह नहीं करता है। केवल RPATH जो माना जाता है कि इस उदाहरण में रनिंग एप्लिकेशन या App.exe होगा। इसका मतलब है कि अगर पुस्तकालय gcc5_5 / libstdc ++ में मौजूद प्रतीकों पर निर्भर करता है। so.y लेकिन gcc4_9 / libstdc ++ में नहीं। so.x, तो पुस्तकालय लोड करने में विफल हो जाएगा।

यह सिर्फ चेतावनी के एक शब्द के रूप में है, क्योंकि मैं इन मुद्दों को अतीत में खुद चला चुका हूं। RPATH एक बहुत ही उपयोगी उपकरण है, लेकिन इसके कार्यान्वयन में अभी भी कुछ गौचे हैं।


इसलिए साझा पुस्तकालयों के लिए RPATH निरर्थक है! और मैं उम्मीद कर रहा था, कि उन्होंने पिछले 2 दशकों में इस संबंध में लिनक्स में थोड़ा सुधार किया ...
फ्रैंक पक

2

आपको यह सुनिश्चित करने की भी आवश्यकता हो सकती है कि आप गतिशील ग्लिबक पर निर्भर नहीं हैं। भागो lddअपने निष्पादन योग्य जिसके परिणामस्वरूप पर और किसी भी गतिशील निर्भरता ध्यान दें (libc / libm / libpthread उसल संदिग्धों हैं)।

अतिरिक्त अभ्यास इस पद्धति का उपयोग करके शामिल सी ++ 11 उदाहरणों का एक गुच्छा बना रहा होगा और वास्तव में परिणामी बायनेरिज़ को वास्तविक 10.04 सिस्टम पर आज़माएगा। ज्यादातर मामलों में, जब तक आप डायनेमिक लोडिंग के साथ कुछ अजीब नहीं करते, आपको तुरंत पता चल जाएगा कि प्रोग्राम काम करता है या क्रैश।


1
डायनेमिक ग्लिबैक के आधार पर क्या समस्या है?
निक हचिंसन

मेरा मानना ​​है कि कम से कम कुछ समय पहले libstdc ++ ने glibc पर निर्भरता का अनुमान लगाया था। यकीन नहीं होता कि चीजें आज कहां खड़ी हैं।
अलेक्जेंडर एल। बेलिकॉफ

9
libstdc ++ glibc पर निर्भर करता है (उदाहरण के लिए iostreams को लागू किया जाता है printf) लेकिन जब तक Ubuntu 10.04 पर glibc नए libstdc ++ द्वारा आवश्यक सभी सुविधाएँ प्रदान करता है, तब तक गतिशील glacc के आधार पर कोई समस्या नहीं होती है, वास्तव में इसे लिंक करने के लिए अत्यधिक अनुशंसित नहीं है। स्टेटिक रूप से ग्लिब करने के लिए
जोनाथन वेकली

1

मैं जोनाथन Wakely जवाब निम्नलिखित के लिए जोड़ना चाहते हैं।

-static-libstdc++लिनक्स पर चारों ओर खेलते हुए , मैंने समस्या का सामना किया है dlclose()। मान लीजिए कि हमारे पास एक एप्लिकेशन 'ए' स्टेटिक रूप से जुड़ा हुआ है libstdc++और यह libstdc++रनटाइम के दौरान प्लगइन 'पी' से गतिशील रूप से जुड़ा हुआ है। कोई बात नहीं। लेकिन जब segment A ’'P’ को उतारता है, तो विभाजन दोष होता है। मेरी धारणा यह है कि उतारने के बाद libstdc++.so, 'ए' अब संबंधित प्रतीकों का उपयोग नहीं कर सकता है libstdc++। ध्यान दें कि यदि 'A' और 'P' दोनों ही सांख्यिकीय रूप से जुड़े हैं libstdc++, या यदि 'A' को गतिशील रूप से और 'P' को सांख्यिकीय रूप से जोड़ा गया है, तो समस्या उत्पन्न नहीं होती है।

सारांश: यदि आपका एप्लिकेशन उन प्लगइन्स को लोड / अनलोड करता है जो गतिशील रूप से लिंक कर सकते हैं libstdc++, तो एप्लिकेशन को गतिशील रूप से भी लिंक होना चाहिए। यह सिर्फ मेरा अवलोकन है और मैं आपकी टिप्पणियाँ प्राप्त करना चाहूंगा।


1
यह संभवतः libc कार्यान्वयन को मिलाने के लिए है (गतिशील रूप से एक प्लगइन से लिंक करने के लिए कहें जो गतिशील रूप से लिंक को glibc करता है, जबकि अनुप्रयोग स्वयं सांख्यिकीय रूप से musl-libc से जुड़ा होता है)। मस्क-लिबक के लेखक रिच फेलकर का दावा है कि इस तरह के परिदृश्य में मुद्दा यह है कि ग्लिबक मेमोरी मैनेजमेंट (उपयोग sbrk) कुछ धारणा और एक प्रक्रिया के भीतर अकेले होने की बहुत उम्मीद करता है ... सुनिश्चित नहीं है कि यह एक तक सीमित है या नहीं विशेष glibc संस्करण या जो भी, हालांकि।
0xC0000022L

और लोग अभी भी विंडोज़ हीप इंटरफ़ेस के फायदे नहीं देखते हैं, जो कि एक ही प्रक्रिया के अंदर libc ++ / libc की कई स्वतंत्र प्रतियों से निपटने में सक्षम है। ऐसे लोगों को सॉफ्टवेयर डिजाइन नहीं करना चाहिए।
फ्रैंक पक

@FrankPuck में विंडोज और लिनक्स दोनों तरह के अनुभव की एक अच्छी मात्रा है, मैं आपको बता सकता हूं कि जिस तरह से "विंडोज" यह आपकी मदद नहीं करेगा जब एमएसवीसी वह पार्टी है जो यह तय करती है कि किस आवंटनकर्ता का उपयोग किया जाता है और कैसे। मुख्य लाभ जो मैं विंडोज पर ढेर के साथ देखता हूं वह यह है कि आप बिट्स और टुकड़ों को बाहर कर सकते हैं और फिर उन्हें एक झटके में मुक्त कर सकते हैं। लेकिन MSVC के साथ आप अभी भी ऊपर वर्णित समस्या में भाग लेंगे, उदाहरण के लिए जब किसी अन्य वीसी रनटाइम द्वारा जारी किए गए पॉइंटर्स के आस-पास से गुजरना (रिलीज बनाम डिबग या स्टेटिक बनाम डायनामिक रूप से जुड़ा हुआ)। तो "विंडोज" प्रतिरक्षा नहीं है। दोनों प्रणालियों पर ध्यान रखना होगा।
0xC0000022L
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.