Como especificar a preferência do caminho da biblioteca?

91

Estou compilando um programa c ++ usando g++e ld. eu tenho um.so biblioteca que desejo usar durante a vinculação. No entanto, existe uma biblioteca com o mesmo nome em /usr/local/libe ldestá escolhendo essa biblioteca em vez daquela que estou especificando diretamente. Como posso consertar isso?

Para os exemplos abaixo, meu arquivo de biblioteca é /my/dir/libfoo.so.0 . Coisas que tentei que não funcionam:

  • meu comando g ++ é g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • adicionando /my/dir ao início ou fim da minha $PATHvariável en`
  • adicionar /my/dir/libfoo.so.0como argumento para g ++
Heinrich Schmetterling
fonte
1
Que outros libfoo.*arquivos existem e onde - .sow / o .0, .a, etc etc?
Alex Martelli

Respostas:

92

Adicione o caminho para onde sua nova biblioteca está LD_LIBRARY_PATH(tem um nome ligeiramente diferente no Mac ...)

Sua solução deve funcionar usando as -L/my/dir -lfooopções, em tempo de execução, use LD_LIBRARY_PATH para apontar para a localização de sua biblioteca.

Cuidado ao usar LD_LIBRARY_PATH - em resumo (do link):

..implications ..:
Security : Lembre-se de que os diretórios especificados em LD_LIBRARY_PATH são pesquisados ​​antes (!) dos locais padrão? Dessa forma, uma pessoa desagradável pode fazer seu aplicativo carregar uma versão de uma biblioteca compartilhada que contém código malicioso! Essa é uma razão pela qual os executáveis ​​setuid / setgid negligenciam essa variável!
atuação: O carregador de link deve pesquisar todos os diretórios especificados, até encontrar o diretório onde a biblioteca compartilhada reside - para TODAS as bibliotecas compartilhadas às quais o aplicativo está vinculado! Isso significa muitas chamadas de sistema para open (), que falharão com “ENOENT (nenhum arquivo ou diretório)”! Se o caminho contiver muitos diretórios, o número de chamadas com falha aumentará linearmente, e você pode dizer isso no momento de inicialização do aplicativo. Se alguns (ou todos) os diretórios estiverem em um ambiente NFS, o tempo de inicialização de seus aplicativos pode ficar muito longo - e pode tornar todo o sistema lento!
Inconsistência: Este é o problema mais comum. LD_LIBRARY_PATH força um aplicativo a carregar uma biblioteca compartilhada à qual não estava vinculado e que provavelmente não é compatível com a versão original. Isso pode ser muito óbvio, ou seja, o aplicativo trava, ou pode levar a resultados errados, se a biblioteca escolhida não fizer exatamente o que a versão original faria. Especialmente o último às vezes é difícil de depurar.

OU

Use a opção rpath via gcc para vinculador - caminho de pesquisa da biblioteca em tempo de execução, será usado em vez de procurar no diretório padrão (opção gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Isso é bom para uma solução temporária. O vinculador primeiro pesquisa o LD_LIBRARY_PATH para bibliotecas antes de procurar nos diretórios padrão.

Se você não deseja atualizar LD_LIBRARY_PATH permanentemente, pode fazê-lo instantaneamente na linha de comando:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Você pode verificar o que o vinculador de bibliotecas sabe sobre o uso (exemplo):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

E você pode verificar qual biblioteca seu aplicativo está usando:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
StefanB
fonte
21
LD_LIBRARY_PATHé pesquisado em tempo de execução, em tempo de compilação que você deseja definir LIBRARY_PATH. Consulte gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Se a sua biblioteca é completamente diferente da biblioteca do sistema, ou seja, é aquela que sempre usa, use a solução rpath. LD_LIBRARY_PATH é um hack para teste e não deve ser necessário para fazer um executável funcionar corretamente.
user2746401
1
é DYLD_LIBRARY_PATH para Mac
cbinder
Aqui está um comando de amostra completo (para C) que funciona com base nesta resposta:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

Essa é uma pergunta antiga, mas ninguém parece ter mencionado isso.

Você estava tendo sorte porque a coisa estava ligando.

Você precisava mudar

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

para isso:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Seu vinculador rastreia os símbolos que precisa resolver. Se ele ler a biblioteca primeiro, não terá nenhum símbolo necessário, então ignora os símbolos nela. Especifique as bibliotecas após as coisas que precisam ser vinculadas a elas para que seu vinculador tenha símbolos para encontrar nelas.

Além disso, -lfoofaz com que ele pesquise especificamente por um arquivo nomeado libfoo.aou libfoo.soconforme necessário. Não libfoo.so.0. Portanto, lnnomeie ou renomeie a biblioteca conforme apropriado.

Para citar a página de manual do gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Adicionar o arquivo diretamente à g++linha de comando de deve ter funcionado, a menos, é claro, que você o coloque antes de bar.cpp, fazendo com que o vinculador o ignore por falta de quaisquer símbolos necessários, porque nenhum símbolo foi necessário ainda.

Michael Speer
fonte
21

Especificar o caminho absoluto para a biblioteca deve funcionar bem:

g++ /my/dir/libfoo.so.0  ...

Você se lembrou de remover o -lfoodepois de adicionar o caminho absoluto?

R Samuel Klatchko
fonte
1
Esta solução também funcionou bem para mim - tentando fazer um link com uma versão do Qt5 diferente do pacote de desenvolvimento da distro. Obrigado.
wump
Como fazer isso funcionar para @símbolos com versão? Exemplo mínimo: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

Como alternativa, você pode usar as variáveis ​​de ambiente LIBRARY_PATHe CPLUS_INCLUDE_PATH, que indicam respectivamente onde procurar bibliotecas e onde procurar cabeçalhos ( CPATHtambém fará o trabalho), sem especificar as opções -L e -I.

Editar: CPATHinclui cabeçalho com -Ie CPLUS_INCLUDE_PATHcom -isystem.

Alexandre Hamez
fonte
Você poderia adicionar um exemplo de uso?
Hanna Khalil
export LIBRARY_PATH = /path/to/libna mesma sessão de console em que você está compilando
Alexandre Hamez
0

Se um é usado para trabalhar com DLL no Windows e gostaria de pular os números de versão .so no linux / QT, a adição CONFIG += plugineliminará os números de versão. Para usar o caminho absoluto para .so, fornecê-lo ao linker funciona bem, como o Sr. Klatchko mencionou.

Pekka Lehtikoski
fonte