Não consegue encontrar .so no mesmo diretório que o executável?


45

Eu tenho um executável que precisa vincular libtest.sodinamicamente, então eu os coloco no mesmo diretório e, em seguida:

cd path_to_dir
./binary

Mas entendi:

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

Como ele não consegue encontrar o libtest.soque já está no mesmo diretório que o próprio executável?

Respostas:


25

O carregador não verifica o diretório atual para objetos compartilhados a menos que seja explicitamente dirigida a via $LD_LIBRARY_PATH. Veja a ld.so(8)página de manual para mais detalhes.


echo $LD_LIBRARY_PATHestá vazio na minha máquina :(
linuxer

Geralmente é.
Ignacio Vazquez-Abrams

2
Ele especifica diretórios adicionais para o carregador procurar bibliotecas.
Ignacio Vazquez-Abrams

1
Os caminhos no * nix são separados por dois pontos ( :), não um ponto e vírgula.
Ignacio Vazquez-Abrams

3
LD_LIBRARY_PATH geralmente é uma má escolha na produção. É bom para hacks rápidos, e coisas como ajudar os binários desinstalados a encontrar suas bibliotecas compartilhadas ao executar testes de unidade (pense em ./configure; make; make check). Ao criar seu binário, você pode colocar sua biblioteca em um local padrão (listado em /etc/ld.so.conf) ou passar o sinalizador -R para o vinculador para que o binário saiba onde procurar.
automatthias

57

Embora você possa definir LD_LIBRARY_PATH para permitir que o vinculador dinâmico saiba onde procurar, há opções melhores. Você pode colocar sua biblioteca compartilhada em um dos locais padrão, consulte /etc/ld.so.conf(no Linux) e /usr/bin/crle(no Solaris) para obter a lista desses locais

Você pode passar -R <path>para o vinculador ao criar seu binário, que será adicionado <path>à lista de diretórios verificados para sua biblioteca compartilhada. Aqui está um exemplo. Primeiro, mostrando o problema:

libtest.h:

void hello_world(void);

libtest.c:

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

hello.c:

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

Makefile (as guias devem ser usadas):

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

Vamos executá-lo:

$ 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

Como corrigi-lo? Adicione -R <path>aos sinalizadores do vinculador (aqui, configurando 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!

Olhando para o binário, você pode ver que ele precisa libtest.so.0:

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

O binário procurará suas bibliotecas, além dos locais padrão, no diretório especificado:

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

Se você deseja que o binário procure no diretório atual, pode configurar o RPATH para $ORIGIN. Isso é um pouco complicado, porque você precisa garantir que o cifrão não seja interpretado pelo make. Aqui está uma maneira de fazer isso:

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

1
Se não estiver usando make, como ao chamar manualmente g++, tente -Wl,-rpath='$ORIGIN'(observe as aspas simples) para impedir a $ORIGINexpansão para uma sequência vazia.
Morpork

14

Para carregar os objetos compartilhados do mesmo diretório que o executável, basta executar:

$ LD_LIBRARY_PATH=. ./binary

Nota: Não modificará a variável LD_LIBRARY_PATH do seu sistema. A alteração afeta apenas a isso e somente a execução do seu programa.


4

Para quem ainda luta sem resposta, encontrei uma com a seguinte sugestão:

Você pode tentar atualizar o ld.so.cache usando: sudo ldconfig -v

Trabalhou para mim.


Trabalhou para mim também.
Joel

3

Para qualquer pessoa que use o CMake para sua compilação, você pode definir CMAKE_EXE_LINKER_FLAGSo seguinte:

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

Isso propaga adequadamente os sinalizadores do vinculador para todos os tipos de compilação (por exemplo, Debug, Release, etc ...) para procurar arquivos .so no diretório de trabalho atual primeiro.


0

O vinculador dinâmico decidirá onde procurar por bibliotecas. No caso do Linux, o vinculador dinâmico geralmente é GNU ld.so(ou uma alternativa que normalmente se comportará idêntica por motivos de compatibilidade).

Para citações da Wikipedia:

O vinculador dinâmico da Biblioteca GNU C procura bibliotecas compartilhadas nos seguintes locais:

  1. Os caminhos (separados por dois pontos) no DT_RPATHatributo de seção dinâmica do binário, se presente, e o DT_RUNPATHatributo não existe.
  2. Os caminhos (separados por dois pontos) na variável de ambiente LD_LIBRARY_PATH, a menos que o executável seja a setuid/ setgidbinário, caso em que é ignorado. LD_LIBRARY_PATHpode ser substituído chamando o vinculador dinâmico com a opção --library-path (por exemplo, /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram).
  3. Os caminhos (separados por dois pontos) no DT_RUNPATHatributo de seção dinâmica do binário, se presente.
  4. Pesquisa baseada no arquivo de cache ldconfig (geralmente localizado em /etc/ld.so.cache) que contém uma lista compilada de bibliotecas candidatas encontradas anteriormente no caminho de biblioteca aumentada (definido por /etc/ld.so.conf). Se, no entanto, o binário -z nodefaultlibestiver vinculado à opção vinculador, as bibliotecas nos caminhos padrão da biblioteca serão ignoradas.
  5. No caminho padrão confiável /libe, em seguida /usr/lib. Se o binário foi vinculado à opção -z nodefaultlib linker, esta etapa será ignorada.

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.