TL; DR
A solução de trabalho está usando patchelf
(se você tiver que lidar com versões glibc não correspondentes: no sistema host e com as bibliotecas nix vinculadas), veja a segunda metade da minha história.
Tentando a abordagem usual
Tentando usar o LD_LIBRARY_PATH
Bem, eu configurei uma variável de ambiente para isso em ~/.bash_profile
:
NIX_LINK=/home/ivan/.nix-profile
export LD_LIBRARY_PATH="$NIX_LINK"/lib
mas isso não é tudo!
Agora existem problemas com links para versões diferentes de libc
:
$ ldd -r ../valencies
../valencies: /lib64/libc.so.6: version 'GLIBC_2.15' not found (required by ../valencies)
../valencies: /lib64/libc.so.6: version 'GLIBC_2.14' not found (required by ../valencies)
../valencies: /lib64/libc.so.6: version 'GLIBC_2.14' not found (required by /home/ivan/.nix-profile/lib/libgmp.so.10)
linux-vdso.so.1 => (0x00007fff365ff000)
/usr/local/lib/libsnoopy.so (0x00007f56c72e6000)
libgmp.so.10 => /home/ivan/.nix-profile/lib/libgmp.so.10 (0x00007f56c7063000)
libffi.so.5 => /usr/lib64/libffi.so.5 (0x00007f56c6e54000)
libm.so.6 => /lib64/libm.so.6 (0x00007f56c6bd0000)
librt.so.1 => /lib64/librt.so.1 (0x00007f56c69c7000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f56c67c3000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f56c65a6000)
libc.so.6 => /lib64/libc.so.6 (0x00007f56c6211000)
/lib64/ld-linux-x86-64.so.2 (0x00007f56c74f1000)
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference (/home/ivan/.nix-profile/lib/libgmp.so.10)
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference (../valencies)
symbol __fdelt_chk, version GLIBC_2.15 not defined in file libc.so.6 with link time reference (../valencies)
$
Classificando duas versões do glibc
O erro mais surpreendente aqui é:
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference (/home/ivan/.nix-profile/lib/libgmp.so.10)
porque nix
deve ter instalado a versão de glibc
que é usada por seu libgmp
!
E, de fato, o glibc
de nix
está lá:
$ ldd -r /home/ivan/.nix-profile/lib/libgmp.so.10
linux-vdso.so.1 => (0x00007fff0f1ff000)
/usr/local/lib/libsnoopy.so (0x00007f06e9919000)
libc.so.6 => /nix/store/93zfs0zzndi7pkjkjxawlafdj8m90kg5-glibc-2.20/lib/libc.so.6 (0x00007f06e957c000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f06e9371000)
/lib64/ld-linux-x86-64.so.2 (0x00007f06e9da7000)
symbol _dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference (/nix/store/93zfs0zzndi7pkjkjxawlafdj8m90kg5-glibc-2.20/lib/libc.so.6)
/home/ivan/.nix-profile/lib/libgmp.so.10: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$
Provavelmente, glibc
não estava disponível para o usuário, portanto, quando executei meu binário, o glibc
do sistema foi carregado primeiro. Prova:
$ ls ~/.nix-profile/lib/*libc*
ls: cannot access /home/ivan/.nix-profile/lib/*libc*: No such file or directory
$
Ok, podemos tentar tornar glibc
visível para o usuário também:
$ nix-env -i glibc
Então tudo está mal:
$ ldd -r ../valencies
/bin/bash: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$ /bin/echo ok
/bin/echo: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$
Portanto, parece não ser uma tarefa fácil se você quiser carregar bibliotecas de nix
ao executar seus próprios binários ...
Por enquanto, estou comentando
export LD_LIBRARY_PATH="$NIX_LINK"/lib
e fazendo na sessão de shell:
$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH
Precisa pensar mais. (Leia sobre __vdso_time: modo inválido para dlopen () : espera-se que outro glibc
in LD_LIBRARY_PATH
falhe, porque o seu ld-linux-x86-64.so.2
não corresponderá ao seu libc.so.6
. Ter várias versões do glibc em um único sistema é possível, mas um pouco complicado, conforme explicado nesta resposta.
A solução necessária: patchelf
Assim, o caminho para o vinculador dinâmico é codificado no binário. E o linker dinâmico usado é do sistema (do host glibc), não do nix. E como o vinculador dinâmico não corresponde ao glibc que queremos e precisamos usar, ele não funciona.
Uma solução simples e funcional é fixada .
patchelf --set-interpreter /home/ivan/.nix-profile/lib/ld-linux-x86-64.so.2 ../valencies
Depois disso, funciona. Você ainda precisa mexer com LD_LIBRARY_PATH
.
$ LD_LIBRARY_PATH=/home/ivan/.nix-profile/lib:/lib64/:/usr/lib64/ ../valencies
Se - como no meu caso imperfeito - algumas das bibliotecas são retiradas do nix, mas algumas são tiradas do sistema host (porque eu não as instalei com nix-env -i
), você tem que especifique o caminho para as bibliotecas nix e para as bibliotecas do sistema host em LD_LIBRARY_PATH
(substitui completamente o caminho de pesquisa padrão).
etapa adicional: patchelf para o caminho de pesquisa da biblioteca
(da página patchelf
)
Da mesma forma, você pode alterar o RPATH
, o caminho de pesquisa do vinculador incorporado em bibliotecas executáveis e dinâmicas:
patchelf --set-rpath /opt/my-libs/lib:/foo/lib program
Isso faz com que o vinculador dinâmico pesquise /opt/my-libs/lib
e /foo/lib
nas bibliotecas compartilhadas necessárias ao programa. É claro que você também pode definir a variável de ambiente LD_LIBRARY_PATH
, mas isso geralmente é inconveniente, pois exige um script de wrapper para configurar o ambiente.