.So dosyasını çalıştırılabilir dosyayla aynı dizinde bulamıyor musunuz?


45

libtest.soDinamik olarak bağlanması gereken bir çalıştırılabilir dosyam var, bu yüzden onları aynı dizine koydum, sonra:

cd path_to_dir
./binary

Ama şunu anladım:

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

libtest.soYürütülebilir dizinin kendisi ile aynı dizinde olanı bulamıyor nasıl olabilir ?

Yanıtlar:


25

Yükleyici, açıkça yönlendirilmediği sürece mevcut dizini paylaşılan nesneler için asla kontrol etmez $LD_LIBRARY_PATH. Daha ld.so(8)fazla bilgi için man sayfasına bakınız.


echo $LD_LIBRARY_PATHmakinemde boş :(
linuxer 10:11

Bu genellikle.
Ignacio Vazquez-Abrams

2
Yükleyicinin kitaplıkları arayacağı ek dizinleri belirtir.
Ignacio Vazquez-Abrams

1
* Nix içindeki yollar :noktalı virgülle değil, iki noktayla ( ) ayrılır.
Ignacio Vazquez-Abrams,

3
LD_LIBRARY_PATH, genellikle üretimde kötü bir seçimdir. Hızlı kesmek için iyidir ve kaldırılan ikili dosyaların, birim sınamaları yaparken paylaşılan kitaplıklarını bulmasına yardımcı olmak gibi şeyler (düşünün ./configure; make; check-out). İkili dosyalarınızı oluştururken, kitaplığınızı standart bir konuma (/etc/ld.so.conf adresinde listelenebilir) koyabilir ya da ikiliye nereye bakacağını bildirmek için -R bayrağını linker'a iletebilirsiniz.
automatthias

57

Dinamik bağlayıcının nereye bakacağını bilmesini sağlamak için LD_LIBRARY_PATH öğesini ayarlayabilseniz de, daha iyi seçenekler var. Paylaşılan kütüphanenizi standart yerlerden birine yerleştirebilirsiniz, bkz. /etc/ld.so.conf(Linux'ta) ve /usr/bin/crle(Solaris'te) bu yerlerin listesi için.

-R <path>İkili dosyalarınızı oluştururken, <path>paylaşılan kitaplığınız için taranan dizinlerin listesine eklenecek bağlayıcıya geçebilirsiniz . İşte bir örnek. İlk olarak, sorunu gösteren:

libtest.h:

void hello_world(void);

libtest.c:

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

Merhaba C:

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

Makefile (sekmeler kullanılmalı):

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

Hadi koşalım:

$ 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

Nasıl düzeltilir? -R <path>Bağlayıcı bayrakları ekleyin (burada, ayarlayarak 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!

İkili dosyaya baktığımızda, ihtiyacı olduğunu görebilirsiniz libtest.so.0:

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

İkili kitaplık, belirtilen dizindeki standart yerlerden ayrı olarak kitaplıklarını arayacaktır:

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

İkilinin geçerli dizine bakmasını istiyorsanız, RPATH'yi ayarlayabilirsiniz $ORIGIN. Bu biraz zor, çünkü dolar işaretinin make tarafından yorumlanmadığından emin olmanız gerekiyor. İşte bunu yapmanın bir yolu:

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

1
Kullanmıyorsanız make, örneğin el ile arama yaparken g++, boş bir dizeye genişlemeyi -Wl,-rpath='$ORIGIN'önlemek için deneyin (tek tırnaklara dikkat edin) $ORIGIN.
Morpork

14

Paylaşılan nesneleri yürütülebilir dizininizle aynı dizinden yüklemek için, sadece yürütün:

$ LD_LIBRARY_PATH=. ./binary

Not: Sisteminizin LD_LIBRARY_PATH değişkenini değiştirmeyecektir. Değişiklik, yalnızca bunu ve programın yürütülmesini etkiler.


4

Hala cevap vermeden mücadele eden herkes için kendimi şu öneriyle buldum:

Ld.so.cache dosyasını kullanarak güncellemeyi deneyebilirsiniz: sudo ldconfig -v

Benim için çalıştı.


Benim için de çalıştı.
Joel,

3

CMake'i yapılarında kullanan herkes CMAKE_EXE_LINKER_FLAGSiçin, aşağıdakini ayarlayabilirsiniz :

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

Bu, geçerli çalışma dizinindeki .so dosyalarını aramak için bağlayıcı bayraklarını tüm yapı türleri için (ör. Debug, Release, vb ...) düzgün şekilde yayar.


0

Dinamik linker, kütüphaneleri nerede arayacağınıza karar verecektir. Linux durumunda, dinamik bağlayıcı genellikle GNU ld.so(veya uyumluluk nedenleriyle genellikle aynı davranacak olan bir alternatiftir).

Vikipedi'den alıntı yapmak için:

GNU C Kütüphanesinin dinamik bağlayıcısı, aşağıdaki konumlardaki paylaşılan kütüphaneleri arar:

  1. DT_RPATHVarsa ve DT_RUNPATHözniteliği yoksa , ikilinin dinamik bölüm özniteliğindeki (iki noktadan ayrılmış) yollar .
  2. LD_LIBRARY_PATHYürütülebilir dosya bir setuid/ setgidikili olmadıkça , ortam değişkenindeki (iki noktadan ayrılmış) yollar , bu durumda dikkate alınmaz. LD_LIBRARY_PATHDinamik bağlayıcıyı --library-path seçeneğiyle çağırarak geçersiz kılınabilir (örneğin /lib/ld-linux.so.2 - library-path $ HOME / mylibs myprogram).
  3. DT_RUNPATHVarsa, binaryin dinamik bölüm niteliğindeki (iki nokta üstüste ayrılmış) yollar .
  4. Önceden artırılmış kütüphane yolunda (ayarlanan ) bulunan derlenmiş bir aday kitaplık listesi içeren ldconfig önbellek dosyasına (genellikle bulunur /etc/ld.so.cache) dayalı arama /etc/ld.so.conf. Bununla birlikte, ikili -z nodefaultliblinker seçeneğiyle bağlanmışsa , varsayılan kütüphane yollarındaki kütüphaneler atlanır.
  5. Güvenilir varsayılan yolda /libve sonra /usr/lib. İkili -z nodefaultlib linker seçeneğiyle bağlantılıysa, bu adım atlanır.

Kaynak: https://en.wikipedia.org/wiki/Rpath

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.