जिस क्रम में पुस्तकालयों को जोड़ा जाता है वह क्रम कभी-कभी जीसीसी में त्रुटियों का कारण बनता है?


449

जिस क्रम में पुस्तकालयों को जोड़ा जाता है वह क्रम कभी-कभी जीसीसी में त्रुटियों का कारण बनता है?


अभी भी देखें stackoverflow.com/questions/7826448/… - TLDR gccहाल ही में और अधिक सख्त व्यवहार (अपेक्षाकृत) में बदल गया।
६:१५ बजे त्रिपली

जवाबों:


558

(अधिक विस्तृत पाठ प्राप्त करने के लिए इस उत्तर पर इतिहास देखें, लेकिन अब मुझे लगता है कि पाठक के लिए वास्तविक कमांड लाइन देखना आसान है)।


सभी सामान्य कमांड द्वारा साझा की गई फ़ाइलें

$ cat a.cpp
extern int a;
int main() {
  return a;
}

$ cat b.cpp
extern int b;
int a = b;

$ cat d.cpp
int b;

स्थैतिक पुस्तकालयों से जोड़ना

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o

$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

लिंकर बाईं से दाईं ओर खोजता है, और जाते समय अनसुलझे प्रतीकों को नोट करता है। अगर कोई लाइब्रेरी सिंबल को हल करता है, तो सिंबल को हल करने के लिए उस लाइब्रेरी की ऑब्जेक्ट फाइल्स लेता है (इस मामले में libb.a से बाहर)।

एक दूसरे के खिलाफ स्थिर पुस्तकालयों की निर्भरता एक ही काम करती है - जिस पुस्तकालय को प्रतीकों की आवश्यकता होती है वह पहले होना चाहिए, फिर पुस्तकालय जो प्रतीक का समाधान करता है।

यदि एक स्थिर पुस्तकालय किसी अन्य पुस्तकालय पर निर्भर करता है, लेकिन अन्य पुस्तकालय फिर से पूर्व पुस्तकालय पर निर्भर करता है, तो एक चक्र है। आप द्वारा चक्रीय निर्भर पुस्तकालयों बंद करके इस हल कर सकते हैं -(और -)इस तरह के रूप में, -( -la -lb -)(आप इस तरह के रूप कोष्ठक, से बचने के लिए आवश्यकता हो सकती है -\(और -\))। लिंकर फिर साइकल निर्भरता को हल करने के लिए कई बार संलग्न परिवाद की खोज करता है। वैकल्पिक रूप से, आप पुस्तकालयों को कई बार निर्दिष्ट कर सकते हैं, इसलिए प्रत्येक एक दूसरे से पहले है -la -lb -la:।

गतिशील पुस्तकालयों से जोड़ना

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!

$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

यह यहाँ भी ऐसा ही है - पुस्तकालयों को कार्यक्रम की ऑब्जेक्ट फ़ाइलों का पालन करना चाहिए। स्थैतिक पुस्तकालयों के साथ तुलना में यहाँ अंतर यह है कि आपको एक दूसरे के खिलाफ पुस्तकालयों की निर्भरता के बारे में परवाह करने की आवश्यकता नहीं है, क्योंकि गतिशील पुस्तकालयों ने अपनी निर्भरता को स्वयं हल किया है

कुछ हाल के वितरण --as-neededलिंकर ध्वज का उपयोग करने के लिए स्पष्ट रूप से डिफ़ॉल्ट हैं , जो इस बात को लागू करता है कि प्रोग्राम की ऑब्जेक्ट फाइलें गतिशील पुस्तकालयों से पहले आती हैं। यदि वह झंडा पास हो जाता है, तो लिंकर उन पुस्तकालयों से लिंक नहीं होगा, जिन्हें वास्तव में निष्पादन योग्य की आवश्यकता नहीं है (और यह बाएं से दाएं का पता लगाता है)। मेरे हाल के आर्च्लिनक्स वितरण में डिफ़ॉल्ट रूप से इस ध्वज का उपयोग नहीं किया गया है, इसलिए यह सही क्रम का पालन नहीं करने के लिए एक त्रुटि नहीं देता है।

पूर्व बनाते समय के b.soखिलाफ निर्भरता को छोड़ना सही नहीं है d.so। लिंक करते समय आपको लाइब्रेरी निर्दिष्ट करने की आवश्यकता होगी a, लेकिन aवास्तव में पूर्णांक की आवश्यकता नहीं bहै, इसलिए इसे bस्वयं की निर्भरता के बारे में ध्यान नहीं दिया जाना चाहिए ।

यदि आप के लिए निर्भरता को निर्दिष्ट करने से चूक जाते हैं तो यहाँ निहितार्थ का एक उदाहरण है libb.so

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)

$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"

यदि आप अब देखते हैं कि बाइनरी के पास क्या निर्भरता है, तो आप ध्यान दें कि बाइनरी खुद पर भी निर्भर करता है libd, न कि libbजैसा कि यह होना चाहिए। बाइनरी को रिंकल करने की आवश्यकता होगी यदि libbबाद में किसी अन्य लाइब्रेरी पर निर्भर करता है, अगर आप इसे इस तरह से करते हैं। और यदि कोई अन्य रनटाइम पर libbउपयोग dlopenकरता है (गतिशील रूप से प्लगइन्स लोड करने के बारे में सोचता है), तो कॉल विफल हो जाएगी। तो "right"वास्तव में एक के wrongरूप में अच्छी तरह से होना चाहिए ।


10
जब तक सभी प्रतीकों को हल नहीं किया जाता तब तक दोहराएँ, एह - आपको लगता है कि वे एक सामयिक प्रकार का प्रबंधन कर सकते हैं। LLVM के पास खुद पर 78 स्टैटिक लाइब्रेरियां हैं, जो जानते हैं कि कौन-सी निर्भरताएं हैं। यह सच है कि इसके पास संकलन / लिंक विकल्पों का पता लगाने के लिए एक स्क्रिप्ट भी है - लेकिन आप सभी परिस्थितियों में इसका उपयोग नहीं कर सकते।
स्टीव 314

6
@ यह बताएं कि प्रोग्राम lorder+ tsortक्या करते हैं। लेकिन कभी-कभी कोई आदेश नहीं होता है, यदि आपके पास चक्रीय संदर्भ हैं। तब आपको बस पुस्तकालयों की सूची के माध्यम से साइकिल चलाना होगा जब तक कि सब कुछ हल न हो जाए।
जोहान्स शाउब -

10
@ जोहान्स - अधिकतम दृढ़ता से जुड़े घटकों (जैसे टारजन एल्गोरिथ्म) का निर्धारण करते हैं, फिर पुर्जों के रूप में (अंतर्निहित गैर-चक्रीय) घटकों को खोदते हैं। प्रत्येक घटक को एक पुस्तकालय के रूप में माना जा सकता है - यदि घटक में से किसी एक पुस्तकालय की आवश्यकता है, तो निर्भरता चक्र (ओं) से उस घटक के सभी पुस्तकालयों की आवश्यकता होगी। तो नहीं, वास्तव में सब कुछ हल करने के लिए सभी पुस्तकालयों के माध्यम से साइकिल चलाने की आवश्यकता नहीं है, और अजीब कमांड-लाइन विकल्पों की आवश्यकता नहीं है - दो प्रसिद्ध एल्गोरिदम का उपयोग करने वाली एक विधि सभी मामलों को सही ढंग से संभाल सकती है।
स्टीव ३४

4
मैं इस उत्कृष्ट उत्तर में एक महत्वपूर्ण विवरण जोड़ना चाहूंगा: "- (अभिलेखागार -)" या "--स्टार्ट-समूह अभिलेखागार --end- समूह" का उपयोग हर बार के बाद से परिपत्र निर्भरता को हल करने का एकमात्र निश्चित-अग्नि मार्ग है। लिंकर एक संग्रह का दौरा करता है, यह (और अनसुलझे प्रतीकों का पंजीकरण करता है) केवल ऑब्जेक्ट फ़ाइलों को पंजीकृत करता है जो वर्तमान में अनसुलझे प्रतीकों को हल करता है । इस वजह से, निर्भरता ग्राफ में जुड़े घटकों को दोहराने के CMake के एल्गोरिथ्म कभी-कभी विफल हो सकते हैं। ( अधिक विस्तार के लिए लिंकर्स पर इयान लांस टेलर का उत्कृष्ट ब्लॉग पोस्ट भी देखें ।)
जॉर्गेन

3
आपके उत्तर ने मुझे मेरी लिंकिंग त्रुटियों को हल करने में मदद की और आपने बहुत स्पष्ट रूप से समझाया कि परेशानी में पड़ने से कैसे बचा जाए, लेकिन क्या आपको पता है कि यह इस तरह से काम करने के लिए क्यों बनाया गया था?
एंटन डेनेको

102

GNU ld लिंकर एक तथाकथित स्मार्ट लिंकर है। यह स्थैतिक पुस्तकालयों से पहले के कार्यों का ट्रैक रखेगा, स्थायी रूप से उन कार्यों को बाहर निकाल देगा जो इसके लुकअप तालिकाओं से उपयोग नहीं किए जाते हैं। इसका परिणाम यह होता है कि यदि आप किसी स्थैतिक पुस्तकालय को बहुत जल्दी लिंक कर देते हैं, तो उस पुस्तकालय में कार्य स्थैतिक पुस्तकालयों से लिंक लाइन पर बाद में उपलब्ध नहीं होते हैं।

ठेठ UNIX लिंकर बाएं से दाएं काम करता है, इसलिए अपने सभी आश्रित पुस्तकालयों को बाईं ओर रखें, और जो लिंक लाइन के दाईं ओर उन निर्भरता को पूरा करते हैं। आप पा सकते हैं कि कुछ पुस्तकालय दूसरों पर निर्भर होते हैं जबकि उसी समय अन्य पुस्तकालय उन पर निर्भर होते हैं। यह वह जगह है जहाँ यह जटिल हो जाता है। जब यह परिपत्र संदर्भों की बात आती है, तो अपना कोड ठीक करें!


2
क्या यह केवल ग्नू ld / gcc के साथ कुछ है? या लिंकर्स के साथ यह कुछ सामान्य है?
माइक

2
जाहिरा तौर पर अधिक यूनिक्स संकलक के समान मुद्दे हैं। MSVC पूरी तरह से इन मुद्दों से मुक्त नहीं है, एहीर, लेकिन वे इतने बुरे नहीं दिखते हैं।
एमएसल्टर्स

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

16
MSVC लिंकर इस मुद्दे के लिए कम संवेदनशील है क्योंकि यह एक अप्रमाणित प्रतीक के लिए सभी पुस्तकालयों की खोज करेगा। लाइब्रेरी ऑर्डर अभी भी प्रभावित कर सकता है कि यदि एक से अधिक लाइब्रेरी का प्रतीक है तो कौन सा प्रतीक हल हो जाएगा। MSDN से: "पुस्तकालयों को कमांड लाइन के क्रम में भी खोजा जाता है, निम्न चेतावनी के साथ: किसी लाइब्रेरी से ऑब्जेक्ट फ़ाइल में लाते समय प्रतीक अनसुलझे हैं जो पहले उस लाइब्रेरी में खोजे जाते हैं, और फिर कमांड लाइन से निम्न लाइब्रेरीज़ और / DEFAULTLIB (डिफ़ॉल्ट लाइब्रेरी निर्दिष्ट करें) निर्देश, और फिर कमांड लाइन की शुरुआत में किसी भी पुस्तकालयों के लिए "
माइकल ब्यूर

4
"... स्मार्ट लिंकर ..." - मेरा मानना ​​है कि इसे "सिंगल पास" लिंकर के रूप में वर्गीकृत किया गया है, न कि "स्मार्ट लिंकर" के रूप में।
jww

54

यहां यह स्पष्ट करने के लिए एक उदाहरण है कि स्थैतिक पुस्तकालयों के शामिल होने पर जीसीसी के साथ चीजें कैसे काम करती हैं। तो चलिए मान लेते हैं कि हमारे पास निम्नलिखित परिदृश्य हैं:

  • myprog.o- main()समारोह युक्त , पर निर्भरlibmysqlclient
  • libmysqlclient- स्थिर, उदाहरण के लिए (आप साझा पुस्तकालय को पसंद करेंगे, ज़ाहिर है, जैसा कि libmysqlclientबहुत बड़ा है); में /usr/local/lib; और सामान पर निर्भर हैlibz
  • libz (गतिशील)

हम इसे कैसे लिंक करते हैं? (नोट: gg 4.3.4 का उपयोग करके सिगविन पर संकलन से उदाहरण)

gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too

gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works

31

यदि आप -Wl,--start-groupलिंकर झंडे में जोड़ते हैं, तो यह परवाह नहीं करता है कि वे किस क्रम में हैं या यदि परिपत्र निर्भरताएं हैं।

Qt पर इसका अर्थ है जोड़ना:

QMAKE_LFLAGS += -Wl,--start-group

समय के भार को गड़बड़ कर देता है और यह लिंकिंग को धीमा नहीं करता है (जो कि संकलन की तुलना में बहुत कम समय लेता है)।


8

पुस्तकालयों की सूची दो बार निर्दिष्ट करने के लिए एक और विकल्प होगा:

gcc prog.o libA.a libB.a libA.a libB.a -o prog.x

ऐसा करने से, आपको सही अनुक्रम से परेशान नहीं होना पड़ेगा क्योंकि संदर्भ दूसरे ब्लॉक में हल हो जाएगा।


5

आप -Xlinker विकल्प का उपयोग कर सकते हैं।

g++ -o foobar  -Xlinker -start-group  -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a  -Xlinker -end-group 

ALMOST के बराबर है

g++ -o foobar  -Xlinker -start-group  -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a  -Xlinker -end-group 

सावधान!

  1. एक समूह के भीतर आदेश महत्वपूर्ण है! यहां एक उदाहरण है: एक डिबग लाइब्रेरी में एक डिबग रूटीन होता है, लेकिन गैर-डीबग लाइब्रेरी का एक कमजोर संस्करण होता है। आपको डिबग लाइब्रेरी FIRST को समूह में रखना होगा या आप गैर-डीबग संस्करण के लिए हल करेंगे।
  2. -Xlinker के साथ आपको समूह सूची में प्रत्येक पुस्तकालय से पहले आने की आवश्यकता है

5

एक त्वरित टिप जिसने मुझे उलझा दिया: यदि आप लिंकर को "gcc" या "g ++" के रूप में आमंत्रित कर रहे हैं, तो "--start-group" और "--end-group" का उपयोग करके उन विकल्पों को पास नहीं करेंगे लिंकर - और न ही यह एक त्रुटि चिह्नित करेगा। यदि आपके पास लाइब्रेरी ऑर्डर गलत था, तो यह अपरिभाषित प्रतीकों के साथ लिंक को विफल कर देगा।

आपको लिंक के माध्यम से तर्क पारित करने के लिए GCC को बताने के लिए उन्हें "-Wl, - start-group" आदि के रूप में लिखने की आवश्यकता है।


2

लिंक आदेश निश्चित रूप से कुछ प्लेटफार्मों पर, कम से कम मायने रखता है। मैंने पुस्तकालयों से जुड़े अनुप्रयोगों के लिए क्रैश को गलत क्रम में देखा है (जहाँ गलत का अर्थ B से पहले जुड़ा हुआ है लेकिन B A पर निर्भर करता है)।


2

मैंने इसे बहुत देखा है, हमारे कुछ मॉड्यूल हमारे कोड प्लस सिस्टम और तीसरी पार्टी के कामों के 100 पुस्तकालयों से अधिक हैं।

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

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

एक बार जब आप एक समाधान दस्तावेज़ पर हिट करते हैं तो अगले डेवलपर को इसे फिर से काम करने की आवश्यकता नहीं होती है।

मेरे पुराने व्याख्याता कहते थे, " उच्च सामंजस्य और कम युग्मन ", यह आज भी सच है।

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