2010-11-05 8 views
25
पर काम करता है

पर विचार करें हम निम्नलिखित स्थिति है:समझना कैसे गतिशील जोड़ने यूनिक्स

  • program नाम के एक प्रोग्राम है जो libfoo.so
  • libfoo.so कि कुछ भी नहीं पर निर्भर करता है (अच्छी तरह से, यह libstdc++ और सामान लेकिन पर निर्भर करता है पर निर्भर करता है गतिशील मुझे लगता है कि हम इसे छोड़ सकते हैं)

program पूरी तरह से चलता है।

अचानक, libfoo कोड बदलते हैं, और कुछ फ़ंक्शन अब आंतरिक रूप से func_bar() का उपयोग करते हैं जो एक अन्य लाइब्रेरी libbar.so द्वारा प्रदान किया गया एक फ़ंक्शन है।

libfoo.so पुन: संकलित किया गया है और अब libbar.so पर निर्भर करता है। program अपरिवर्तित बनी हुई है, यह अभी भी libfoo.so पर निर्भर करती है।

अब जब मैं program निष्पादित करता हूं तो यह शिकायत करता है कि उसे func_bar() नहीं मिल रहा है।

  • libfoo.so इंटरफ़ेस परिवर्तन नहीं किया, केवल इसके कार्यान्वयन:

    यहाँ मेरी सवाल कर रहे हैं। program को libbar.so के साथ स्पष्ट रूप से क्यों है?

  • निर्भरता पेड़ रिकर्सिव नहीं है? मुझे लगता है कि libfoo.solibbar.so पर निर्भर करता है, libbar.so , की निर्भरता सूची में स्वचालित रूप से पुन: संकलन के बिना जोड़ा गया होगा। हालांकि, ldd program दिखाता है कि यह मामला नहीं है।

यह अजीब एक recompile (रीलिंक) हर द्विआधारी कि कुछ पुस्तकालय हर कि लाइब्रेरी की निर्भरता को बदलने पर निर्भर करता है है कि लगता है। इसे रोकने के लिए मेरे पास कौन से समाधान हैं?

+0

क्या आप एक न्यूनतम कॉन्फ़िगरेशन पोस्ट कर सकते हैं जो समस्या को पुन: उत्पन्न करता है? उनकी पोस्ट के बाद विटॉट की टिप्पणियां एक ही प्रक्रिया का वर्णन करती हैं और एक ही समस्या पर नहीं पहुंचती हैं। हो सकता है कि यदि आप सरल कदम उठाते हैं, तो हम सवाल का जवाब देने में मदद कर सकते हैं? –

उत्तर

17

समस्या तब उत्पन्न होती है जब आपने libbar के विरुद्ध लिंक नहीं किया है। जब आप निष्पादन योग्य संकलित कर रहे होते हैं, तो डिफ़ॉल्ट रूप से लिंकर आपको अपरिभाषित संदर्भ छोड़ने नहीं देगा। हालांकि, जब आप किसी साझा लाइब्रेरी को संकलित कर रहे हैं, तो यह होगा - और यह उन्हें लिंक समय पर संतुष्ट होने की उम्मीद करेगा। ऐसा इसलिए है कि libfooprogram द्वारा निर्यात किए गए कार्यों का उपयोग कर सकते हैं - जब आप इसे चलाने का प्रयास करते हैं, तो गतिशील लिंकर func_bar()program द्वारा आपूर्ति की जा रही है। समस्या इतनी तरह दर्शाया गया है:

(foo.c selfcontained है)

export LD_RUN_PATH=`pwd` 
gcc -Wall -shared foo.c -o libfoo.so 
gcc -Wall -L. p.c -lfoo -o p 

इस बिंदु पर, ./p रन सही ढंग से, जैसा कि आप उम्मीद करेंगे। हम तो libbar.so बना सकते हैं और इसका इस्तेमाल करने के foo.c संशोधित:

gcc -Wall -shared bar.c -o libbar.so 
gcc -Wall -shared foo.c -o libfoo.so 

इस बिंदु पर, ./p त्रुटि आप का वर्णन देता है। अगर हम ldd libfoo.so चेक करते हैं, तो हम देखते हैं कि पर libbar.so पर निर्भरता है - यह त्रुटि है। त्रुटि को दूर करने के लिए हम सही ढंग से libfoo.so लिंक करना होगा:

gcc -Wall -L. -lbar -shared foo.c -o libfoo.so 

इस बिंदु पर, ./p फिर से सही ढंग से चलाता है, और ldd libfoo.solibbar.so पर निर्भरता को दर्शाता है।

+0

आप सही थे: मैं 'libbar.so' से लिंक नहीं कर रहा था। अब आकर्षक के रूप में काम करता है ! बहुत धन्यवाद ! – ereOn

2

आपने कोई सिस्टम जानकारी नहीं दी है, क्या आप glibc का उपयोग कर रहे हैं? यदि हाँ इस आदेश के उत्पादन में क्या है:

LD_DEBUG = फ़ाइलों कार्यक्रम

यह भी जांच "How to write shared (ELF) libraries" (पीडीएफ) (चाहे आप glibc उपयोग कर रहे हैं या नहीं)

1

आपका कार्यक्रम के साथ लिंक करने के लिए नहीं है libbar.so।

मुझे लगता है कि समस्या libbar.so को बाद में निर्माण करते समय libfoo.so की निर्भरता के रूप में निर्दिष्ट करने में विफल होने के कारण होती है। मुझे यकीन है कि क्या निर्माण सिस्टम प्रयोग कर रहे नहीं कर रहा हूँ लेकिन CMake में यह इस प्रकार के रूप में किया जा सकता है:

add_library(bar SHARED bar.c) 

add_library(foo SHARED foo.c) 
target_link_libraries(foo bar) 

add_executable(program program.c) 
target_link_libraries(program foo) 

आप program देख सकते हैं केवल bar (libbar.so) के साथ केवल foo (libfoo.so) और foo साथ जुड़ा हुआ है।

या यह हो सकता है कि libbar.so नहीं मिला। LD_LIBRARY_PATH पर्यावरण चर में अपनी निर्देशिका के पथ निर्दिष्ट करने का प्रयास करें।

+1

सवाल यह है कि सीएमके दृश्यों के पीछे क्या करता है, यह प्रोग्राम –

+0

@ पीयर स्ट्रिटज़िंगर के लिए सही लिंक कमांड बनाने के लिए पर्याप्त स्मार्ट हो सकता है: अच्छा सवाल। मैंने इसके बारे में सोचा और कुछ प्रयोग किए ('कार्यक्रम' का निर्माण किया, जबकि 'फू' के पास 'बार' का लिंक नहीं था, फिर 'foo' और' bar' 'बनाना, लेकिन' प्रोग्राम 'नहीं) और यह काम किया। तो सेमेक पक्ष से जादू इस मामले में असंभव लगता है, हालांकि यह वास्तव में स्मार्ट है =)। – vitaut

+1

क्या यह वास्तव में प्रश्न का उत्तर देता है? बेशक, 'libfoo' के साथ' libbar' को लिंक करना और * फिर * 'प्रोग्राम' से लिंक करना, निर्माण प्रणाली के स्वतंत्र रूप से काम करने जा रहा है। हालांकि, यदि 'प्रोग्राम'' libfoo' से जुड़ा हुआ है और फिर 'libfoo' को' libbar' से लिंक करने के लिए अपडेट किया गया है तो यह मामला नहीं हो सकता है। यदि आपकी सीएमके स्क्रिप्ट है, तो यह स्पष्ट है कि 'libfoo'' libfoo' किसी भी जादू के बिना 'libbar'' के साथ लिंक करने के लिए 'libfoo' परिवर्तन' के साथ 'प्रोग्राम' रिलिकिंक हो जाता है। –

8

फेडोरा गतिशील लिंकिंग पर ld-linux.so.2 द्वारा किया जाता है। डायनामिक लिंकर लाइब्रेरी फ़ाइलों को खोजने के लिए /etc/ld.so.cache और /etc/ld.so.preload का उपयोग करें।

सिस्टम को बताने के लिए ldconfig चलाएं जहां libfoo को libbar के लिए देखना चाहिए।

ldconfig/lib,/usr/lib और /etc/ld.so.conf में सूचीबद्ध किसी भी निर्देशिका में दिखता है। आप जांच सकते हैं कि कौन से पुस्तकालय एक प्रोग्राम ldd के साथ उपयोग करते हैं।

प्रत्येक विवरण के लिए मैन्युअल पृष्ठों पर अधिक जानकारी उपलब्ध है।

यहां साझा पुस्तकालयों का उपयोग करके एक एप्लिकेशन का एक उदाहरण दिया गया है।
Program.cc

#include "foo.h" 
#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    for (int i = 0; i < argc; ++i) { 
     std::cout << func_foo(argv[i]) << std::endl; 
    } 
} 

foo.h

#ifndef FOO_H 
#define FOO_H 
#include <string> 
std::string func_foo(std::string const &); 
#endif 

foo.cc

#include "foo.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__; 
} 

bar.h

#ifndef BAR_H 
#define BAR_H 
#include <string> 
std::string func_bar(); 
#endif 

bar.cc

#include "bar.h" 

std::string func_bar() 
{ 
    return __func__; 
} 

libfoo.so के साथ साझा लाइब्रेरी के रूप में बनाएं।
जी ++ -Wall -Wextra -fPIC कमरा साझा foo.cc -ओ libfoo.so
जी ++ -lfoo -L./ -Wall -Wextra program.cc foo.h -ओ कार्यक्रम
ldd कार्यक्रम
...
libfoo.so => ​​नहीं मिला

अद्यतन /etc/ld.so.cache
sudo ldconfig/घर/टोबियास/परियोजनाओं/स्टब्स/तो/

ldd कि गतिशील लिंकर पाता चलता libfoo.so
ldd प्रोग्राम
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)

libfoo.so
न्यू foo.cc में libbar.so के लिए एक कॉल जोड़ें

#include "foo.h" 
#include "bar.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__ + "|" + func_bar(); 
} 

libbar.so बिल्ड और libfoo.so
जी ++ -Wall -Wextra -fPIC कमरा साझा bar.cc -ओ libbar.so
जी ++ -Wall -Wextra -fPIC कमरा साझा libbar.so foo के पुनर्निर्माण .cc -o libfoo.so
ldd libfoo.so
...
libbar.so => ​​नहीं मिला

ldd कार्यक्रम
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so => ​​नहीं मिला
यह दिखाता है कि गतिशील लिंकर अभी भी libfoo.so लेकिन libbar नहीं पाता है। तो
फिर से /etc/ld.so.cache अपडेट करें और पुनः जांचें।
sudo ldconfig/घर/टोबियास/परियोजनाओं/स्टब्स/तो/
ldd libfoo.so
...
libbar.so => ​​/home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)

ldd कार्यक्रम
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so => ​​/ घर/टोबियास/परियोजनाओं/स्टब्स/तो/libbar.so (0x00007f2be4d0e000)

बी oth libfoo.so और libbar.so पाए जाते हैं।

नोट करें कि इस अंतिम चरण के आवेदन कार्यक्रम पर कोई प्रभाव नहीं पड़ता है। यदि आप वास्तव में सख्त चल रहे हैं ldconfig तरह का रिंकंकिंग है। अजीब या नहीं, लिंकर को पुस्तकालयों की निर्भरताओं को जानने की आवश्यकता है। इसे लागू करने के कई अन्य तरीके हैं लेकिन यह चुना गया था।

+0

जानकारी के लिए धन्यवाद :) – ereOn

1

यह तब तक नहीं होना चाहिए जब तक कि bar_func प्रतीक के बारे में कुछ नहीं बदला गया। अपने प्रोग्राम दोनों में प्रतीकों का डंप प्राप्त करने के लिए "एनएम" कमांड का उपयोग करें, और साझा ऑब्जेक्ट - देखें कि कोई मेल नहीं है और क्यों।

+1

प्रश्न का मेरा पठन यह है कि 'bar_func() 'में परिवर्तन यह है कि पहले इसका उपयोग नहीं किया गया था, लेकिन अब इसका उपयोग किया जाता है। –