ldd
lista as bibliotecas compartilhadas que seu argumento requer. Com a opção -v
, lista todas as informações disponíveis, incluindo símbolos de versão.
Linhas do formulário
linux-vdso.so.1 => (0x00007fffa3dff000)
librt.so.1 => /lib64/librt.so.1 (0x00007fea7a7b2000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fea7a4ab000)
liste as bibliotecas exigidas por libAtlasUtilsPB.so
e como elas são resolvidas; no seu caso, todas as bibliotecas necessárias são encontradas. linux-vdso.so.1
é especial, é uma uma biblioteca virtual fornecida pelo kernel.
Linhas do formulário
libgcc_s.so.1 (GCC_3.0) => /lib64/libgcc_s.so.1
libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6
libpthread.so.0 (GLIBC_2.2.5) => /lib64/libpthread.so.0
liste os símbolos de versão exigidos por libAtlasUtilsPB.so
e, novamente, como eles são resolvidos. É aqui que ldd
não consegue resolver os itens, o que indica ambos indicando "não encontrado" aqui e imprimindo mensagens de erro no início de sua saída.
GLIBC_...
, GLIBCXX_...
etc. são símbolos de versão, que são usados em algumas bibliotecas (incluindo a biblioteca GNU C e as bibliotecas do GCC) para identificar as versões necessárias e gerenciar a compatibilidade com versões anteriores. Um binário (executável ou biblioteca) geralmente acabará exigindo várias versões, com base nos símbolos que ele realmente usa da biblioteca de destino. Para satisfazer os requisitos de um dado binário, você precisa fornecer uma biblioteca que suporte todas as versões necessárias - ou seja, uma biblioteca que corresponda pelo menos ao símbolo da versão mais alta na lista de requisitos.
O motivo pelo qual várias versões podem acabar sendo necessárias é que cada objeto importado (função etc.) pode ter uma versão e um determinado binário pode vincular-se a várias versões em todas as funções que ele usa. Por exemplo, escolhendo um exemplo com duas versões no meu sistema, /lib/x86_64-linux-gnu/libgcc_s.so.1
, ldd -v
mostra
/lib/x86_64-linux-gnu/libgcc_s.so.1:
libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
libgcc_s.so.1
precisa de dois símbolos de versão de libc.so.6
. Para descobrir o porquê, precisamos examinar os símbolos indefinidos que contém - estes são os símbolos que ele precisa importar:
$ objdump -T /lib/x86_64-linux-gnu/libgcc_s.so.1|grep -F '*UND*'
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 dl_iterate_phdr
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 free
0000000000000000 w D *UND* 0000000000000000 __pthread_key_create
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 abort
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strlen
0000000000000000 w D *UND* 0000000000000000 pthread_getspecific
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 memset
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 calloc
0000000000000000 w D *UND* 0000000000000000 pthread_key_create
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
0000000000000000 w D *UND* 0000000000000000 pthread_once
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 pthread_mutex_unlock
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 malloc
0000000000000000 w D *UND* 0000000000000000 pthread_setspecific
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realloc
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 pthread_mutex_lock
Isso lista vários símbolos com versão (aqueles com GLIBC_2.2.5
ou GLIBC_2.14
na segunda e última coluna), e podemos ver aqui que as versões correspondem àquelas que vimos com ldd
. Por que acabamos com vários símbolos de versões? É aqui que entra a compatibilidade com versões anteriores. A versão 2.2.5 é a linha de base para o versionamento de símbolos na biblioteca GNU C; qualquer função que estava presente na versão 2.2.5 carrega essa versão. Na versão 2.13 da biblioteca GNU C, o comportamento de memcpy
foi alterado; isso quebrou vários programas, portanto, na versão 2.14, uma versão compatível com versões anteriores foi implementada com a tag opcional GLIBC_2.2.5
version e uma nova versão adicionada com a tag GLIBC_2.14
version. Portanto, binários antigos construídos com versões anteriores da biblioteca C usam a versão antiga de memcpy
e binários criados com a versão 2.14 e posterior usam a nova versão de memcpy
.
A mesma história se aplica a libstdc++.so.6
, mas com muitas outras alterações com números de versão atualizados; o manual libstdc++
fornece detalhes .
No seu caso, você precisa de libstdc++.so.6
matching GLIBCXX_3.4.18
, ou seja, a versão fornecida pelo GCC 4.8.0 ou posterior, e a versão 2.14 da biblioteca GNU C.
Você não pode criar facilmente binários no RHEL 7 e executá-los no RHEL 6 (é por isso que a versão principal é diferente). Seria melhor reconstruir seu programa no RHEL 6 ...