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


108

जीसीसी से लिंक करने पर मैं केवल कुछ विशिष्ट पुस्तकालयों को अपने बाइनरी से कैसे जोड़ सकता हूं?

gcc ... -static ...सभी लिंक किए गए पुस्तकालयों को सांख्यिकीय रूप से लिंक करने का प्रयास करता है , लेकिन मुझे उनमें से कुछ का स्थिर संस्करण नहीं मिला है (उदाहरण: libX11)।


जवाबों:


112

gcc -lsome_dynamic_lib code.c some_static_lib.a


5
ऑब्जेक्ट फ़ाइलों के बाद लिंक लाइब्रेरी - विशेष रूप से स्थिर लाइब्रेरी। लिंक वातावरण के प्राचीन और आधुनिक संस्करणों में (नवंबर 2010 तक मामूली पुराने संस्करणों के लिए मैं यथास्थिति के बारे में निश्चित नहीं हूं), code.cफ़ाइल से पहले स्टेटिक लाइब्रेरी को सूचीबद्ध करने की गारंटी देता है कि इसमें प्रतीकों को तब तक अनदेखा किया जाएगा जब तक कि ऐसा न हो जाए main()लाइब्रेरी ऑब्जेक्ट फ़ाइलों में से एक में एक फ़ंक्शन।
जोनाथन लेफ़लर

44
कपल आप कृपया विस्तार से बताएं कि यह कैसे काम करता है? कोड केवल उत्तर शुरुआती के लिए सहायक नहीं हैं।
जेबी

8
@jb डिफ़ॉल्ट रूप से, गतिशील रूप से लिंक gcc। जब आप -lsome_dynamic_lib का उपयोग करते हैं तो यह गतिशील रूप से अपेक्षित रूप से लिंक हो जाता है। लेकिन, जब जीसीसी को स्पष्ट रूप से एक स्थिर पुस्तकालय दिया जाता है, तो यह हमेशा इसे सांख्यिकीय रूप से जोड़ने का प्रयास करेगा। हालांकि, कुछ पेचीदा विवरण उस क्रम के बारे में हैं जिसमें प्रतीक हल हो जाते हैं; मुझे यकीन नहीं है कि यह कैसे काम करता है। मैंने सीखा है कि, जब संदेह है, तो लाइब्रेरी के झंडे के क्रम को फिर से व्यवस्थित करने की कोशिश करें :-)
bchurchill

4
यदि आप उदाहरण के लिए जीपीएल लाइब्रेरी
HiB

1
@HiB GPL स्थिर और गतिशील लिंकिंग के लिए उसी तरह से लागू होता है
ऑसविन

50

आप ldविकल्प का उपयोग भी कर सकते हैं-Bdynamic

gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2

इसके बाद की सभी लाइब्रेरी (gcc द्वारा स्वचालित रूप से लिंक किए गए सिस्टम सहित) को गतिशील रूप से लिंक किया जाएगा।


19
-Wl, -Bdynamic को GNU ld की आवश्यकता होती है, इसलिए यह समाधान उन सिस्टम पर काम नहीं करता है जहाँ gcc सिस्टम ld (जैसे Mac OS X) का उपयोग करता है।
अंक

33
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

आप यह भी उपयोग कर सकते हैं: -static-libgcc -static-libstdc++जीसीसी पुस्तकालयों के लिए झंडे

ध्यान रखें कि यदि libs1.soऔर libs1.aदोनों मौजूद हैं, तो लिंकर उठाएगा libs1.soयदि यह पहले -Wl,-Bstaticया बाद में है -Wl,-Bdynamic-L/libs1-library-location/कॉल करने से पहले पास करना न भूलें -ls1


1
कम से कम, यह समाधान libgomp के खिलाफ स्थैतिक लिंक के लिए काम करता है!
जेरेम

मेरे लिए यह अच्छी तरह से काम करता है, जबकि -staticकमांड में कहीं भी उपयोग करना विफल रहता है (मुझे लगता है कि यह केवल पुस्तकालयों की तुलना में अधिक चीजों को सांख्यिकीय रूप से जोड़ने की कोशिश करता है जो मुझे चाहिए)।
nh2 12

4
एनबी। के आदेश -Wl,-Bstaticऔर -Wl,-Bdynamicमहत्वपूर्ण है।
पावेल वलसोव

27

विकल्प के संदर्भ में ld(इस gcc के साथ काम नहीं करता है) के मैनपेज से --static:

आप कमांड लाइन पर कई बार इस विकल्प का उपयोग कर सकते हैं: यह पुस्तकालय के लिए -l विकल्पों की खोज को प्रभावित करता है जो इसका पालन करते हैं।

एक समाधान यह है --staticकि कमांड लाइन पर विकल्प से पहले अपनी गतिशील निर्भरता डालें ।

एक अन्य संभावना का उपयोग नहीं करना है --static, लेकिन इसके बजाय एक विशिष्ट पुस्तकालय में स्टेटिकली लिंकिंग के लिए स्टेटिक ऑब्जेक्ट फ़ाइल का पूर्ण फ़ाइल नाम / पथ (यानी -l विकल्प का उपयोग नहीं करना) प्रदान करना है। उदाहरण:

# echo "int main() {}" > test.cpp
# c++ test.cpp /usr/lib/libX11.a
# ldd a.out
linux-vdso.so.1 =>  (0x00007fff385cc000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f9a5b233000)
libm.so.6 => /lib/libm.so.6 (0x00007f9a5afb0000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f9a5ad99000)
libc.so.6 => /lib/libc.so.6 (0x00007f9a5aa46000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a5b53f000)

जैसा कि आप उदाहरण में देख सकते हैं, libX11गतिशील रूप से जुड़े पुस्तकालयों की सूची में नहीं है, क्योंकि यह सांख्यिकीय रूप से जुड़ा हुआ था।

खबरदार: एक .soफ़ाइल हमेशा डायनामिक रूप से जुड़ी होती है, यहां तक ​​कि जब एक पूर्ण फ़ाइल नाम / पथ के साथ निर्दिष्ट किया जाता है।


LibX11.a और आउटपुट के बीच संबंध क्या है ldd a.out?
रफी खाचदौरेन

1
ओह समझा। lddआवश्यक साझा किए गए पुस्तकालयों और libX11 को उस सूची में प्रदर्शित नहीं करता है।
रफ़ी खाचदौरेन

यह स्पष्ट नहीं है। आप 'यह विकल्प' और 'वह विकल्प' कहते हैं। क्या विकल्प है?
ऑक्टोपस

19

जो समस्या मुझे समझ में आ रही है वह इस प्रकार है। आपके पास कई पुस्तकालय, कुछ स्थिर, कुछ गतिशील और कुछ स्थिर और गतिशील दोनों हैं। gcc का डिफ़ॉल्ट व्यवहार "ज्यादातर डायनामिक" लिंक करना है। यही कारण है, जीसीसी गतिशील पुस्तकालयों के लिए लिंक जब संभव है, लेकिन अन्यथा स्थिर पुस्तकालयों के लिए वापस गिर जाता है। आप का उपयोग करते हैं स्थैतिक विकल्प के लिए जीसीसी व्यवहार एक उपयुक्त गतिशील पुस्तकालय नहीं है, भले ही यदि कोई स्थिर पुस्तकालय पाया जा सकता है एक त्रुटि के साथ ही लिंक स्थिर पुस्तकालयों और बाहर निकलने के लिए है।

एक अन्य विकल्प है, जो मैं कई मौकों कामना पर है जीसीसी था, मैं क्या कहते हैं -mostly स्थैतिक और अनिवार्य रूप के विपरीत है -dynamic (डिफ़ॉल्ट)। -अत्यंत-स्थैतिक होगा, अगर यह अस्तित्व में है, स्थैतिक पुस्तकालयों के खिलाफ लिंक करना पसंद करते हैं, लेकिन गतिशील पुस्तकालयों में वापस आ जाएगा।

यह विकल्प मौजूद नहीं है लेकिन इसे निम्नलिखित एल्गोरिथ्म के साथ अनुकरण किया जा सकता है:

  1. लिंक कमांड लाइन का निर्माण-साथ-साथ बाहर करना

  2. डायनेमिक लिंक विकल्पों पर Iterate करें।

  3. लाइब्रेरी पथों को संकलित करें, अर्थात फॉर्म के वे विकल्प -L <lib_dir> एक चर <lib_pkath> में

  4. प्रत्येक डायनेमिक लिंक विकल्प के लिए, यानी फॉर्म -l <lib_name> , कमांड gcc <lib_path> -print-file-name = lib <lib_name> .a चलाएं और आउटपुट कैप्चर करें।

  5. यदि कमांड आपके द्वारा पारित किए गए के अलावा कुछ और प्रिंट करता है, तो यह स्टैटिक लाइब्रेरी का पूर्ण पथ होगा। डायनामिक लाइब्रेरी विकल्प को पूर्ण पथ के साथ स्थिर लाइब्रेरी में बदलें।

जब तक आपने पूरी लिंक कमांड लाइन को संसाधित नहीं किया है तब तक कुल्ला और दोहराएं। वैकल्पिक रूप से स्क्रिप्ट स्थिर लिंकिंग से बाहर करने के लिए लाइब्रेरी नामों की सूची भी ले सकती है।

निम्नलिखित बैश स्क्रिप्ट चाल करने के लिए लगता है:

#!/bin/bash

if [ $# -eq 0 ]; then
    echo "Usage: $0 [--exclude <lib_name>]. . . <link_command>"
fi

exclude=()
lib_path=()

while [ $# -ne 0 ]; do
    case "$1" in
        -L*)
            if [ "$1" == -L ]; then
                shift
                LPATH="-L$1"
            else
                LPATH="$1"
            fi

            lib_path+=("$LPATH")
            echo -n "\"$LPATH\" "
            ;;

        -l*)
            NAME="$(echo $1 | sed 's/-l\(.*\)/\1/')"

            if echo "${exclude[@]}" | grep " $NAME " >/dev/null; then
                echo -n "$1 "
            else
                LIB="$(gcc $lib_path -print-file-name=lib"$NAME".a)"
                if [ "$LIB" == lib"$NAME".a ]; then
                    echo -n "$1 "
                else
                    echo -n "\"$LIB\" "
                fi
            fi
            ;;

        --exclude)
            shift
            exclude+=(" $1 ")
            ;;

        *) echo -n "$1 "
    esac

    shift
done

echo

उदाहरण के लिए:

mostlyStatic gcc -o test test.c -ldl -lpthread

मेरे सिस्टम रिटर्न पर:

gcc -o test test.c "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libdl.a" "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"

या अपवर्जन के साथ:

mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread

मैं तब मिलता हूं:

gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"

7

Gcc में -l:libstatic1.a(minus l कोलन) वैरिएंट -l ऑप्शन भी है जिसे स्टैटिक लाइब्रेरी ( https://stackoverflow.com/a/20728782 पर धन्यवाद ) लिंक करने के लिए इस्तेमाल किया जा सकता है । क्या यह प्रलेखित है? जीसीसी के आधिकारिक दस्तावेज में नहीं (जो साझा कार्यों के लिए भी सटीक नहीं है): https://gcc.gnu.org/oniltocs/gcc/Link-Options.html

-llibrary
-l library 

लिंक करते समय लाइब्रेरी नाम की लाइब्रेरी खोजें। (एक अलग तर्क के रूप में पुस्तकालय के साथ दूसरा विकल्प केवल पॉसिक्स अनुपालन के लिए है और अनुशंसित नहीं है।) ... एक-एल विकल्प का उपयोग करने और एक फ़ाइल नाम निर्दिष्ट करने के बीच एकमात्र अंतर यह है कि -'कार्य के साथ पुस्तकालय को घेरता है और '.A' और कई निर्देशिकाएं खोजता है।

Binutils ld doc इसका वर्णन करता है। -lnameविकल्प के लिए खोज करना होगा libname.soके लिए तो libname.aऔर lib उपसर्ग जोड़ने .so(पल में सक्षम है) या .aप्रत्यय। लेकिन -l:nameविकल्प केवल निर्दिष्ट नाम के लिए ही खोज करेगा: https://sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

namespecलिंक करने के लिए फ़ाइलों की सूची द्वारा निर्दिष्ट संग्रह या ऑब्जेक्ट फ़ाइल जोड़ें । यह विकल्प किसी भी समय उपयोग किया जा सकता है। यदि namespecफ़ॉर्म है :filename, तो ld नामक फ़ाइल के लिए लाइब्रेरी पथ खोजेगा filename, अन्यथा वह फ़ाइल नामक लाइब्रेरी के लिए लाइब्रेरी पथ खोजेगा libnamespec.a

साझा पुस्तकालयों का समर्थन करने वाली प्रणालियों पर, ld इसके अलावा अन्य फ़ाइलों की खोज भी कर सकता है libnamespec.a। विशेष रूप से, एलएलएफ और सनोस सिस्टम पर, एलडी एक लाइब्रेरी के लिए एक निर्देशिका खोजेगा, जिसे कॉल करने libnamespec.soसे पहले बुलाया जाएगा libnamespec.a। (कन्वेंशन द्वारा, एक .soएक्सटेंशन एक साझा लाइब्रेरी को इंगित करता है।) ध्यान दें कि यह व्यवहार उस पर लागू नहीं होता है :filename, जो हमेशा एक फ़ाइल को निर्दिष्ट करता है जिसे कहा जाता है filename

लिंकर केवल एक बार आर्काइव खोजेगा, उस स्थान पर जहां यह कमांड लाइन पर निर्दिष्ट है। यदि संग्रह एक प्रतीक को परिभाषित करता है जो कि किसी वस्तु में अपरिभाषित था, जो कमांड लाइन पर संग्रह से पहले दिखाई देता था, तो लिंकर संग्रह से उपयुक्त फ़ाइल (ओं) को शामिल करेगा। हालाँकि, कमांड लाइन पर बाद में दिखाई देने वाली एक वस्तु में एक अपरिभाषित प्रतीक लिंकर को फिर से आर्काइव खोजने का कारण नहीं बनेगा।

-(कई बार अभिलेखागार को खोजने के लिए लिंकर को बाध्य करने का एक तरीका के लिए विकल्प देखें ।

आप कमांड लाइन पर एक ही संग्रह को कई बार सूचीबद्ध कर सकते हैं।

इस प्रकार का संग्रह खोज यूनिक्स लिंकर्स के लिए मानक है। हालाँकि, यदि आप AIX पर ld का उपयोग कर रहे हैं, तो ध्यान दें कि यह AIX लिंकर के व्यवहार से अलग है।

इस -l:namespecसंस्करण को २.१ of बिनुतिल (२००)) संस्करण के बाद से प्रलेखित किया गया है: https://sourceware.org/binutils/docs-2.18/ld/Options.html


यह विकल्प काम करने लगता है जहां बाकी सब विफल हो जाता है। हम सिर्फ एक मामले पर लड़खड़ा गए हैं जहाँ हमें static-link libjsoncpp.a की आवश्यकता थी, क्योंकि हमारी बिल्ड मशीनें libjsocpp.so.0 के खिलाफ लिंक की गई बायनेरिज़ का उत्पादन करेंगी, जबकि लक्ष्य OS केवल libjsoncpp.so.1 प्रदान करता है। जब तक हम इस अंतर को साफ कर सकते हैं, यह एकमात्र समाधान था जो हमारे मामले में उचित परिणाम देता था।
टॉमाज़ डब्ल्यू

4

कुछ लोडर (लिंकर) गतिशील लोडिंग को चालू और बंद करने के लिए स्विच प्रदान करते हैं। यदि जीसीसी ऐसी प्रणाली (सोलारिस - और संभवतः अन्य) पर चल रही है, तो आप प्रासंगिक विकल्प का उपयोग कर सकते हैं।

यदि आप जानते हैं कि आप किन पुस्तकालयों को सांख्यिकीय रूप से लिंक करना चाहते हैं, तो आप लिंक लाइब्रेरी में पूर्ण पथ द्वारा - बस स्टैटिक लाइब्रेरी फ़ाइल निर्दिष्ट कर सकते हैं।


6
भले ही यह जवाब स्वीकार कर लिया गया था लेकिन यह समस्या को पूरी तरह से संबोधित नहीं करता है। जैसा कि @peoro ने बताया कि वह जिस समस्या को हल करने का प्रयास कर रहा है, वह यह है कि उसके पास सभी पुस्तकालयों के स्थिर संस्करण नहीं हैं, जिसका अर्थ है कि वह यथासंभव अधिक से अधिक पुस्तकालयों को लिंक करना चाहेगा। मेरा जवाब देखिए।
jcoffland

2

डायनेमिक और स्टैटिक लाइब्रेरी को एक लाइन में जोड़ने के लिए, आपको डायनेमिक लिबास और ऑब्जेक्ट फाइल्स के बाद स्टैटिक लिम को रखना होगा , जैसे:

gcc -lssl main.o -lFooLib -o main

अन्यथा, यह काम नहीं करेगा। मुझे यह पता लगाने के लिए कुछ समय लगता है।

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