could not load library cannot open shared object file

Instalações de executáveis binários pré-compilados ou bibliotecas dinâmicas podem não ter as dependências bem resolvidas e quando executados ou carregadas, respectivamente, podem retornar o erro could not load library cannot open shared object file. Em alguns casos links simbólicos podem ser uma solução de contorno.

Não vou entrar em detalhes sobre shared library, LD_LIBRARY_PATH, ld.so e outras coisas, pois alguém com muita propriedade no assunto já escreveu sobre isto. O que vou explicar aqui é como eu costumo depurar este erro e uma das soluções de contorno que uso.

NOTA: não me responsabilizo por qualquer coisa estou comentando aqui, vocês conhecem os seus sistemas e os seus ambientes, inspirem-se e usem as informações aqui para o bem. Qualquer mau uso destas informações e dos utilitários sugeridos é por sua conta e risco.

O processo é simples, eu uso os utilitários ldd ou objdump, sendo que este último é mais recomendado, visto que o ldd executa o programa passado como argumento, logo pode ser perigoso utilizá-los com binários não-confiáveis.

Como estudo de caso vou usar um exemplo de uma extensão do PostgreSQL, que é uma shared library que depende de bibliotecas do Oracle instaladas.

Ao criar a extensão no PostgreSQL ele tenta carregar a biblioteca, e logo eu vejo o erro:

guedes=# create extension oracle_fdw ;
ERROR:  could not load library "/usr/lib/postgresql/10/lib/oracle_fdw.so": libclntsh.so.18.1: cannot open shared object file: Arquivo ou diretório não encontrado

Todas as dependências estavam instaladas, conforme:

➤ ls -la /usr/lib/oracle/12.2/client64/lib/
total 219708
drwxr-xr-x 2 root root      4096 abr 14 16:23 ./
drwxr-xr-x 4 root root      4096 abr  2  2018 ../
-rw-rwxr-- 1 root root       342 jan 26  2017 glogin.sql*
lrwxrwxrwx 1 root root        21 abr  2  2018 libclntshcore.so -> libclntshcore.so.12.1*
-rw-rwxr-- 1 root root   8033199 jan 26  2017 libclntshcore.so.12.1*
lrwxrwxrwx 1 root root        17 abr  2  2018 libclntsh.so -> libclntsh.so.12.1*
-rw-rwxr-- 1 root root  71638263 jan 26  2017 libclntsh.so.12.1*
-rw-rwxr-- 1 root root   2981501 jan 26  2017 libipc1.so*
-rw-rwxr-- 1 root root    539065 jan 26  2017 libmql1.so*
-rw-rwxr-- 1 root root   6568149 jan 26  2017 libnnz12.so*
lrwxrwxrwx 1 root root        15 abr  2  2018 libocci.so -> libocci.so.12.1*
-rw-rwxr-- 1 root root   2218687 jan 26  2017 libocci.so.12.1*
-rw-rwxr-- 1 root root 124771800 jan 26  2017 libociei.so*
-rw-rwxr-- 1 root root    158543 jan 26  2017 libocijdbc12.so*
-rw-rwxr-- 1 root root    380996 jan 26  2017 libons.so*
-rw-rwxr-- 1 root root    116563 jan 26  2017 liboramysql12.so*
-rw-rwxr-- 1 root root   1641005 jan 26  2017 libsqlplusic.so*
-rw-rwxr-- 1 root root   1559466 jan 26  2017 libsqlplus.so*
-rw-r--r-- 1 root root   3984814 jan 26  2017 ojdbc8.jar
-rw-rwxr-- 1 root root    312974 jan 26  2017 ottclasses.zip*
-rw-r--r-- 1 root root     37494 jan 26  2017 xstreams.jar

Porém a falta era da libclntsh.so.18.1 o que pode ser visto inspecionando a lib da extensão que eu estou tentando carregar:

➤ ldd /usr/lib/postgresql/10/lib/oracle_fdw.so
		linux-vdso.so.1 (0x00007fff8855d000)
		libclntsh.so.18.1 => not found
		libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcc9b58e000)
		/lib64/ld-linux-x86-64.so.2 (0x00007fcc9bb50000)

Como eu tenho a libclntsh.so.12.1, levantei a hipotese de criar um link simbólico para ver se funcionava:

➤ cd /usr/lib/oracle/12.2/client64/lib/
➤ sudo ln -s libclntsh.so.12.1 libclntsh.so.18.1

Mesmo assim não funcionou:

➤ ldd /usr/lib/postgresql/10/lib/oracle_fdw.so
		linux-vdso.so.1 (0x00007fff8855d000)
		libclntsh.so.18.1 => not found
		libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcc9b58e000)
		/lib64/ld-linux-x86-64.so.2 (0x00007fcc9bb50000)

Mesmo conferindo o ld.so.conf pela milésima vez, parecia tudo certo:

➤ cat /etc/ld.so.conf.d/oracle.conf
/usr/lib/oracle/12.2/client64/lib/

Pensei em ver as variáveis de ambiente do usuário em que o Postgres estava executando e o truque aqui foi pegar o PID do processo principal e usar o /proc para ver se tinha alguma LD_LIBRARY_PATH específica.

➤ ps -ef | grep postgres
postgres 21571     1  0 abr12 ?        00:00:01 /usr/lib/postgresql/10/bin/postgres -D /var/lib/postgresql/10/pgml -c config_file=/etc/postgresql/10/pgml/postgresql.conf
postgres 21573 21571  0 abr12 ?        00:00:00 postgres: 10/pgml: checkpointer process
postgres 21574 21571  0 abr12 ?        00:00:00 postgres: 10/pgml: writer process
postgres 21575 21571  0 abr12 ?        00:00:00 postgres: 10/pgml: wal writer process
postgres 21576 21571  0 abr12 ?        00:00:00 postgres: 10/pgml: autovacuum launcher process
postgres 21577 21571  0 abr12 ?        00:00:00 postgres: 10/pgml: stats collector process

O número mágico aqui é 21571.

➤ sudo cat /proc/21571/environ | xargs -n 1 -0 echo
PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
PG_GRANDPARENT_PID=21565
PGLOCALEDIR=/usr/share/locale
PGSYSCONFDIR=/etc/postgresql-common
LANG=pt_BR.UTF-8
PWD=/
PGDATA=/var/lib/postgresql/10/pgml

Nada. Postgres utilizando o padrão. Sendo assim pensei e criar um link simbólico lá no /usr/lib:

➤ cd /usr/lib
➤ sudo ln -s /usr/lib/oracle/12.2/client64/lib/libclntsh.so.18.1

E dai sim funcionou:

➤ ldd /usr/lib/postgresql/10/lib/oracle_fdw.so
		linux-vdso.so.1 (0x00007ffcb8fdd000)
		libclntsh.so.18.1 => /usr/lib/libclntsh.so.18.1 (0x00007f555dbd8000)
		libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f555d839000)
		libmql1.so => /usr/lib/oracle/12.2/client64/lib/libmql1.so (0x00007f555d5c2000)
		libipc1.so => /usr/lib/oracle/12.2/client64/lib/libipc1.so (0x00007f555d18f000)
		libnnz12.so => /usr/lib/oracle/12.2/client64/lib/libnnz12.so (0x00007f555ca46000)
		libons.so => /usr/lib/oracle/12.2/client64/lib/libons.so (0x00007f555c7f8000)
		libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f555c5f4000)
		libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f555c2f0000)
		libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f555c0d3000)
		libnsl.so.1 => /lib/x86_64-linux-gnu/libnsl.so.1 (0x00007f555bebb000)
		librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f555bcb3000)
		libaio.so.1 => /lib/x86_64-linux-gnu/libaio.so.1 (0x00007f555bab1000)
		libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f555b89a000)
		/lib64/ld-linux-x86-64.so.2 (0x00007f55618a0000)
		libclntshcore.so.12.1 => /usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1 (0x00007f555b2cc000)
		libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f555b0b5000)

E a extensão criou normalmente:

guedes=# create extension oracle_fdw ;
CREATE EXTENSION
guedes=#

Bom, foi isto. “:)

comments powered by Disqus