जवाबों:
(अधिक विस्तृत पाठ प्राप्त करने के लिए इस उत्तर पर इतिहास देखें, लेकिन अब मुझे लगता है कि पाठक के लिए वास्तविक कमांड लाइन देखना आसान है)।
सभी सामान्य कमांड द्वारा साझा की गई फ़ाइलें
$ 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
रूप में अच्छी तरह से होना चाहिए ।
lorder
+ tsort
क्या करते हैं। लेकिन कभी-कभी कोई आदेश नहीं होता है, यदि आपके पास चक्रीय संदर्भ हैं। तब आपको बस पुस्तकालयों की सूची के माध्यम से साइकिल चलाना होगा जब तक कि सब कुछ हल न हो जाए।
GNU ld लिंकर एक तथाकथित स्मार्ट लिंकर है। यह स्थैतिक पुस्तकालयों से पहले के कार्यों का ट्रैक रखेगा, स्थायी रूप से उन कार्यों को बाहर निकाल देगा जो इसके लुकअप तालिकाओं से उपयोग नहीं किए जाते हैं। इसका परिणाम यह होता है कि यदि आप किसी स्थैतिक पुस्तकालय को बहुत जल्दी लिंक कर देते हैं, तो उस पुस्तकालय में कार्य स्थैतिक पुस्तकालयों से लिंक लाइन पर बाद में उपलब्ध नहीं होते हैं।
ठेठ UNIX लिंकर बाएं से दाएं काम करता है, इसलिए अपने सभी आश्रित पुस्तकालयों को बाईं ओर रखें, और जो लिंक लाइन के दाईं ओर उन निर्भरता को पूरा करते हैं। आप पा सकते हैं कि कुछ पुस्तकालय दूसरों पर निर्भर होते हैं जबकि उसी समय अन्य पुस्तकालय उन पर निर्भर होते हैं। यह वह जगह है जहाँ यह जटिल हो जाता है। जब यह परिपत्र संदर्भों की बात आती है, तो अपना कोड ठीक करें!
यहां यह स्पष्ट करने के लिए एक उदाहरण है कि स्थैतिक पुस्तकालयों के शामिल होने पर जीसीसी के साथ चीजें कैसे काम करती हैं। तो चलिए मान लेते हैं कि हमारे पास निम्नलिखित परिदृश्य हैं:
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
यदि आप -Wl,--start-group
लिंकर झंडे में जोड़ते हैं, तो यह परवाह नहीं करता है कि वे किस क्रम में हैं या यदि परिपत्र निर्भरताएं हैं।
Qt पर इसका अर्थ है जोड़ना:
QMAKE_LFLAGS += -Wl,--start-group
समय के भार को गड़बड़ कर देता है और यह लिंकिंग को धीमा नहीं करता है (जो कि संकलन की तुलना में बहुत कम समय लेता है)।
आप -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
सावधान!
एक त्वरित टिप जिसने मुझे उलझा दिया: यदि आप लिंकर को "gcc" या "g ++" के रूप में आमंत्रित कर रहे हैं, तो "--start-group" और "--end-group" का उपयोग करके उन विकल्पों को पास नहीं करेंगे लिंकर - और न ही यह एक त्रुटि चिह्नित करेगा। यदि आपके पास लाइब्रेरी ऑर्डर गलत था, तो यह अपरिभाषित प्रतीकों के साथ लिंक को विफल कर देगा।
आपको लिंक के माध्यम से तर्क पारित करने के लिए GCC को बताने के लिए उन्हें "-Wl, - start-group" आदि के रूप में लिखने की आवश्यकता है।
लिंक आदेश निश्चित रूप से कुछ प्लेटफार्मों पर, कम से कम मायने रखता है। मैंने पुस्तकालयों से जुड़े अनुप्रयोगों के लिए क्रैश को गलत क्रम में देखा है (जहाँ गलत का अर्थ B से पहले जुड़ा हुआ है लेकिन B A पर निर्भर करता है)।
मैंने इसे बहुत देखा है, हमारे कुछ मॉड्यूल हमारे कोड प्लस सिस्टम और तीसरी पार्टी के कामों के 100 पुस्तकालयों से अधिक हैं।
विभिन्न लिंकर्स एचपी / इंटेल / जीसीसी / सन / एसजीआई / आईबीएम / आदि के आधार पर आप अनसुलझे कार्यों / चर आदि प्राप्त कर सकते हैं, कुछ प्लेटफार्मों पर आपको पुस्तकालयों को दो बार सूचीबद्ध करना होगा।
अधिकांश भाग के लिए हम पुस्तकालयों, कोर, मंच, अमूर्त की विभिन्न परतों की संरचित पदानुक्रम का उपयोग करते हैं, लेकिन कुछ प्रणालियों के लिए आपको अभी भी लिंक कमांड में आदेश के साथ खेलना होगा।
एक बार जब आप एक समाधान दस्तावेज़ पर हिट करते हैं तो अगले डेवलपर को इसे फिर से काम करने की आवश्यकता नहीं होती है।
मेरे पुराने व्याख्याता कहते थे, " उच्च सामंजस्य और कम युग्मन ", यह आज भी सच है।
gcc
हाल ही में और अधिक सख्त व्यवहार (अपेक्षाकृत) में बदल गया।