O carregador nunca verifica o diretório atual em busca de objetos compartilhados, a menos que seja explicitamente direcionado para via $LD_LIBRARY_PATH
. Veja a página ld.so(8)
man para mais detalhes.
Eu tenho um executável que precisa vincular com libtest.so
dinamicamente, então eu os coloco no mesmo diretório, então:
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 pode ser impossível encontrar o libtest.so
, que já está no mesmo diretório do próprio executável?
Embora você possa definir LD_LIBRARY_PATH para permitir que o vinculador dinâmico saiba onde procurar, existem opções melhores. Você pode colocar sua biblioteca compartilhada em um dos locais padrão, veja /etc/ld.so.conf
(no Linux) e /usr/bin/crle
(no Solaris) para a lista desses locais
Você pode transmitir -R <path>
para o vinculador ao criar seu binário, o que adicionará <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 (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 executar:
$ 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 consertar isso? Adicione -R <path>
aos sinalizadores do vinculador (aqui, definindo 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 de libtest.so.0
:
$ objdump -p hello | grep NEEDED
NEEDED libtest.so.0
NEEDED libc.so.6
O binário irá procurar por 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 seja exibido no diretório atual, você pode definir o RPATH como $ORIGIN
. Isso é um pouco complicado, porque você precisa ter certeza de que o cifrão não seja interpretado por 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!
Para carregar os objetos compartilhados no mesmo diretório do seu 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 isso, e somente isso, a execução do seu programa.
Para quem ainda luta sem uma resposta, encontrei uma com a seguinte sugestão:
Você pode tentar atualizar o ld.so.cache usando: sudo ldconfig -v
Trabalhei para mim.
Para qualquer pessoa que use o CMake para sua compilação, você pode definir o CMAKE_EXE_LINKER_FLAGS
para o seguinte:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")
Isso propagará corretamente 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.