सवाल निष्पादन योग्य के रूप में एक ही निर्देशिका में नहीं मिल सकता है?


मेरे पास एक निष्पादन योग्य है जिसके साथ लिंक करने की आवश्यकता है libtest.so गतिशील रूप से, इसलिए मैंने उन्हें एक ही निर्देशिका में रखा, फिर:

cd path_to_dir
./binary

लेकिन यह मिला:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

यह कैसे ढूंढने में असमर्थ हो सकता है libtest.so जो पहले से ही निष्पादन योग्य के रूप में एक ही निर्देशिका में है?


36
2018-06-10 08:54


मूल




जवाब:


लोडर कभी भी साझा ऑब्जेक्ट्स के लिए वर्तमान निर्देशिका की जांच नहीं करता है जब तक कि इसे स्पष्ट रूप से निर्देशित नहीं किया जाता है $LD_LIBRARY_PATH। देखें ld.so(8) अधिक जानकारी के लिए मैन पेज।


22
2018-06-10 08:56



echo $LD_LIBRARY_PATH मेरी मशीन पर खाली है :( - linuxer
यह आमतौर पर है। - Ignacio Vazquez-Abrams
यह पुस्तकालयों के लिए देखने के लिए लोडर के लिए अतिरिक्त निर्देशिका निर्दिष्ट करता है। - Ignacio Vazquez-Abrams
* निक्स में पथ को कोलन द्वारा अलग किया जाता है (:), अर्धविराम नहीं। - Ignacio Vazquez-Abrams
एलडी_LIBRARY_PATH आम तौर पर उत्पादन में एक खराब विकल्प है। यह त्वरित हैक्स के लिए अच्छा है, और अनइंस्टॉल किए गए बाइनरी की मदद जैसी चीजें यूनिट परीक्षण चलाते समय अपने साझा पुस्तकालयों को ढूंढती हैं (सोचें ./configure; बनाना; जांच करें)। अपनी बाइनरी बनाते समय, आप या तो अपनी लाइब्रेरी को एक मानक स्थान (/etc/ld.so.conf पर सूचीबद्ध) में डाल सकते हैं या बाइनरी को कहां देखना है, ताकि लिंकर को -R ध्वज पास कर सकें। - automatthias


जबकि आप गतिशील लिंकर को कहां देखना है, उसे देखने के लिए LD_LIBRARY_PATH सेट कर सकते हैं, बेहतर विकल्प हैं। आप अपनी साझा लाइब्रेरी को मानक स्थानों में से एक में डाल सकते हैं, देखें /etc/ld.so.conf (लिनक्स पर) और /usr/bin/crle (सोलारिस पर) इन स्थानों की सूची के लिए

आप पास कर सकते हैं -R <path> अपनी बाइनरी बनाने के दौरान लिंकर को, जो जोड़ देगा <path> आपकी साझा लाइब्रेरी के लिए स्कैन की गई निर्देशिकाओं की सूची में। यहां एक उदाहरण दिया गया है। सबसे पहले, समस्या दिखा रहा है:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

नमस्ते सी:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

मेकफ़ाइल (टैब का उपयोग किया जाना चाहिए):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

आइए इसे चलाएं:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

इसे कैसे जोड़ेंगे? जोड़ना -R <path> लिंकर झंडे के लिए (यहां, सेटिंग द्वारा LDFLAGS)।

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

बाइनरी को देखते हुए, आप देख सकते हैं कि इसकी आवश्यकता है libtest.so.0:

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

निर्दिष्ट निर्देशिका में, बाइनरी मानक स्थानों के अलावा, इसके पुस्तकालयों की तलाश करेगा:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

यदि आप बाइनरी को वर्तमान निर्देशिका में देखना चाहते हैं, तो आप RPATH को सेट कर सकते हैं $ORIGIN। यह थोड़ा मुश्किल है, क्योंकि आपको यह सुनिश्चित करने की ज़रूरत है कि डॉलर के चिह्न को बनाने के द्वारा व्याख्या नहीं की जाती है। ऐसा करने का एक तरीका यहां दिया गया है:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!

53
2018-06-18 09:14



यदि उपयोग नहीं कर रहा है make, जैसे मैन्युअल रूप से कॉल करते समय g++, प्रयत्न -Wl,-rpath='$ORIGIN' (एकल उद्धरण नोट करें) रोकने के लिए $ORIGINएक खाली स्ट्रिंग में विस्तार से। - Morpork


साझा निष्पादन योग्य निर्देशिका को उसी निष्पादन योग्य के रूप में लोड करने के लिए, बस निष्पादित करें:

$ LD_LIBRARY_PATH=. ./binary

नोट: यह आपके सिस्टम के LD_LIBRARY_PATH चर को संशोधित नहीं करेगा। परिवर्तन केवल इस पर प्रभाव डालता है, और केवल यह, आपके कार्यक्रम का निष्पादन।


9
2017-08-29 00:06





किसी भी व्यक्ति के लिए जो अभी भी उत्तर के बिना संघर्ष करता है, मैंने खुद को निम्नलिखित सुझाव के साथ पाया:

आप ld.so.cache को अद्यतन करने का प्रयास कर सकते हैं: sudo ldconfig -v

मेरे लिए काम किया


3
2017-08-12 23:24





किसी के भी उपयोग के लिए CMake उनके निर्माण के लिए, आप सेट कर सकते हैं CMAKE_EXE_LINKER_FLAGS निम्नलिखित के लिए:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

यह मौजूदा कार्यशील निर्देशिका में .so फ़ाइलों को देखने के लिए सभी निर्माण प्रकारों (उदा।, डीबग, रिलीज, आदि ...) के लिए लिंकर झंडे को सही ढंग से प्रचारित करेगा।


0