ไม่พบ. ดังนั้นในไดเรกทอรีเดียวกันกับไฟล์ที่เรียกทำงานได้หรือไม่


45

ฉันมีไฟล์ปฏิบัติการที่ต้องการเชื่อมโยงกับ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ที่มีอยู่แล้วในไดเรกทอรีเดียวกันกับตัวปฏิบัติการได้อย่างไร

คำตอบ:


25

$LD_LIBRARY_PATHโหลดไม่เคยตรวจสอบไดเรกทอรีปัจจุบันสำหรับวัตถุที่ใช้ร่วมกันจนกว่าจะมีการกำกับอย่างชัดเจนที่จะผ่าน ดูld.so(8)หน้าคนสำหรับรายละเอียดเพิ่มเติม


echo $LD_LIBRARY_PATHว่างเปล่าในเครื่องของฉัน :(
linuxer

มันมักจะเป็น
Ignacio Vazquez-Abrams

2
มันระบุไดเรกทอรีเพิ่มเติมสำหรับโหลดเดอร์ที่จะค้นหาในห้องสมุด
Ignacio Vazquez-Abrams

1
พา ธ ใน * ระวังจะถูกคั่นด้วยเครื่องหมายโคลอน ( :) ไม่ใช่เครื่องหมายอัฒภาค
Ignacio Vazquez-Abrams

3
LD_LIBRARY_PATH โดยทั่วไปแล้วเป็นตัวเลือกที่ไม่ดีในการผลิต เป็นการดีสำหรับแฮ็กที่รวดเร็วและสิ่งต่าง ๆ เช่นช่วยให้ไบนารีที่ถอนการติดตั้งค้นหาไลบรารีที่แชร์เมื่อใช้การทดสอบหน่วย (คิดว่า. / กำหนดค่า; สร้าง; ตรวจสอบ) เมื่อสร้างไบนารี่ของคุณคุณสามารถใส่ไลบรารี่ของคุณลงในตำแหน่งมาตรฐาน (อยู่ที่ /etc/ld.so.conf) หรือส่งแฟล็ก -R ไปยังลิงเกอร์เพื่อให้ไบนารี่รู้ตำแหน่งที่จะมอง
automatthias

57

ในขณะที่คุณสามารถตั้งค่า LD_LIBRARY_PATH เพื่อให้ตัวเชื่อมโยงแบบไดนามิกทราบตำแหน่งที่จะดู แต่ก็มีตัวเลือกที่ดีกว่า คุณสามารถใส่ไลบรารี่ที่แชร์ไว้ในหนึ่งในสถานที่มาตรฐานดู/etc/ld.so.conf(บน Linux) และ/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();
}

Makefile (ต้องใช้แท็บ):

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!

1
หากไม่ได้ใช้makeงานเช่นเมื่อโทรด้วยตนเองให้g++ลอง-Wl,-rpath='$ORIGIN'(สังเกตเครื่องหมายคำพูดเดี่ยว) เพื่อป้องกันไม่ให้$ORIGINขยายเป็นสตริงว่าง
Morpork

14

ในการโหลดออบเจ็กต์ที่แชร์จากไดเรกทอรีเดียวกันกับไฟล์ที่รันได้ของคุณเพียงแค่ดำเนินการ:

$ LD_LIBRARY_PATH=. ./binary

หมายเหตุ: มันจะไม่แก้ไขตัวแปร LD_LIBRARY_PATH ของระบบของคุณ การเปลี่ยนแปลงมีผลกับสิ่งนี้และการดำเนินการของโปรแกรมของคุณเท่านั้น


4

สำหรับทุกคนที่ยังคงดิ้นรนโดยไม่มีคำตอบฉันพบตัวเองด้วยคำแนะนำต่อไปนี้:

คุณสามารถลองอัปเดต ld.so.cache โดยใช้: sudo ldconfig -v

ทำงานให้ฉัน


ทำงานให้ฉันเช่นกัน
Joel

3

สำหรับทุกคนที่ใช้CMakeสำหรับงานสร้างคุณสามารถตั้งค่าCMAKE_EXE_LINKER_FLAGSต่อไปนี้:

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

สิ่งนี้จะทำการเผยแพร่แฟล็กเกอร์ลิงก์อย่างถูกต้องสำหรับบิลด์ทุกประเภท (เช่นดีบั๊ก, รีลีส, ฯลฯ ... ) เพื่อค้นหาไฟล์. so ในไดเรกทอรีการทำงานปัจจุบันก่อน


0

ตัวเชื่อมโยงแบบไดนามิกจะเป็นตัวกำหนดว่าจะค้นหาไลบรารีใด ในกรณีของ Linux ตัวเชื่อมโยงแบบไดนามิกมักจะเป็นGNU ld.so(หรือตัวเลือกที่ปกติจะทำงานเหมือนกันด้วยเหตุผลความเข้ากันได้

เพื่ออ้างอิงจาก Wikipedia:

ตัวเชื่อมโยงแบบไดนามิกของ GNU C Library ค้นหาห้องสมุดสาธารณะในสถานที่ดังต่อไปนี้:

  1. เส้นทาง (คั่นด้วยโคลอน) ในDT_RPATHแอตทริบิวต์ส่วนไดนามิกของไบนารีหากมีอยู่และDT_RUNPATHไม่มีแอตทริบิวต์
  2. พา ธ (คั่นด้วยโคลอน) ในตัวแปรสภาพแวดล้อมLD_LIBRARY_PATHยกเว้นว่าไฟล์สั่งการจะเป็นsetuid/ setgidไบนารีซึ่งในกรณีนั้นจะถูกละเว้น LD_LIBRARY_PATHสามารถแทนที่ได้โดยการเรียกตัวเชื่อมโยงแบบไดนามิกด้วยตัวเลือก --library-path (เช่น /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram)
  3. เส้นทาง (คั่นด้วยโคลอน) ในDT_RUNPATHแอตทริบิวต์ส่วนไดนามิกของไบนารีหากมีอยู่
  4. ค้นหาตามไฟล์แคช ldconfig (มักจะอยู่ที่/etc/ld.so.cache) ซึ่งมีรายการที่รวบรวมของไลบรารีผู้สมัครที่พบก่อนหน้านี้ในเส้นทางไลบรารีเพิ่มเติม (ตั้งค่าโดย /etc/ld.so.conf) อย่างไรก็ตามหากไบนารีนั้นเชื่อมโยงกับ-z nodefaultlibตัวเลือกตัวเชื่อมโยงไลบรารีในเส้นทางไลบรารีเริ่มต้นจะถูกข้ามไป
  5. ในเส้นทางเริ่มต้นที่เชื่อถือได้แล้ว/lib /usr/libหากไบนารีถูกลิงก์กับตัวเลือก -z nodefaultlib linker ขั้นตอนนี้จะถูกข้ามไป

ที่มา: https://en.wikipedia.org/wiki/Rpath

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.