Confusão sobre a vinculação da biblioteca de reforço durante a compilação

4

Para um cliente, precisei adicionar o boost 1.54 ao sistema. Então baixei a versão mais recente (1.55) e construí-a dentro de um diretório especial: /usr/local/lib/boost1.55/. Isso funciona. Então eu tive que adaptar o Makefile dessa maneira.

LIBS = $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -LC:/deps/miniupnpc -lminiupnpc -lqrencode -lrt -LC:/deps/boost/stage/lib -Lc:/deps/db/build_unix -Lc:/deps/ssl -LC:/deps/libqrencode/.libs -lssl -lcrypto -ldb_cxx -L/usr/local/lib/boost1.55/boost_system-mgw46-mt-sd-1_54 -L/usr/local/lib/boost1.55/boost_filesystem-mgw46-mt-sd-1_54 -L/usr/local/lib/boost1.55/boost_program_options-mgw46-mt-sd-1_54 -L/usr/local/lib/boost1.55/boost_thread-mgw46-mt-sd-1_54 -lQtDBus -lQtGui -lQtCore -lpthread -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread

No Makefile não modificado, as hiperligações de impulsionamento ficaram assim:

-lboost_thread-mgw46-mt-sd-1_54

Mas isso não funcionou. Não consegui compilar porque não foi encontrado. Então eu adicionei (como você pode ver acima)

-L/usr/local/lib/boost1.55/boost_thread-mgw46-mt-sd-1_54

e

-lboost_thread

Caso contrário, também não seria compilado. Após a compilação bem sucedida, eu executei ldd no binário e me mostra:

libboost_system.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_system.so.1.53.0 (0x00007f416c169000) libboost_filesystem.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.53.0 (0x00007f416bf52000) libboost_program_options.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.53.0 (0x00007f416bce4000) libboost_thread.so.1.53.0 => /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.53.0 (0x00007f416bace000)

1.53 é a versão instalada pelo gerenciador de pacotes. Eu não entendo porque isso liga a esta versão. Se eu não tivesse instalado o 1.55, ele não seria compilado, mas agora ele não está vinculado a esta versão. Alguma explicação para isso?

Na verdade, minha meta é não usar bibliotecas vinculadas dinâmicas e ainda não descobri como fazer isso, mas ainda quero saber por que as informações acima não funcionam como esperado.

    
por Bevor 06.12.2013 / 22:50

2 respostas

6

Você não diz qual é a distribuição do Linux, mas muitas vezes há um diretório onde você pode adicionar bibliotecas dinamicamente vinculáveis. Em distribuições Redhat como o Fedora, este diretório está aqui, /etc/ld.so.conf.d/ .

LD

Você pode adicionar um arquivo a este diretório com o caminho para sua biblioteca recém-instalada da seguinte forma:

$ cat /etc/ld.so.conf.d/myboost.conf
/usr/local/lib/boost1.55

Em seguida, execute este comando:

$ ldconfig -v

Isso processará todas as bibliotecas e reconstruirá um "cache", /etc/ld.so.cache . Esse cache é usado para localizar bibliotecas quando elas são especificadas da seguinte forma: -lboost_thread-mgw46-mt-sd-1_54 .

Exemplo de saída

$ ldconfig -v
/usr/lib64/atlas:
        libclapack.so.3 -> libclapack.so.3.0
        libptcblas.so.3 -> libptcblas.so.3.0
        libf77blas.so.3 -> libf77blas.so.3.0
        libcblas.so.3 -> libcblas.so.3.0
        liblapack.so.3 -> liblapack.so.3.0
        libptf77blas.so.3 -> libptf77blas.so.3.0
        libatlas.so.3 -> libatlas.so.3.0
/usr/lib64/wxSmithContribItems:
        libwxflatnotebook.so.0 -> libwxflatnotebook.so.0.0.1
...

Ao adicionar caminhos à configuração, eu gostaria de confirmar passando por essa saída para ter certeza de que as coisas estão sendo escolhidas da maneira que eu esperava.

cache do LD

Você também pode imprimir o conteúdo do arquivo .cache usando este comando:

$ ldconfig -p | head -10
2957 libs found in cache '/etc/ld.so.cache'
    lib3ds-1.so.3 (libc6,x86-64) => /usr/lib64/lib3ds-1.so.3
    libzvbi.so.0 (libc6,x86-64) => /usr/lib64/libzvbi.so.0
    libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib64/libzvbi-chains.so.0
    libzrtpcpp-1.4.so.0 (libc6,x86-64) => /usr/lib64/libzrtpcpp-1.4.so.0
    libzmq.so.1 (libc6,x86-64) => /usr/lib64/libzmq.so.1
    libzmq.so (libc6,x86-64) => /usr/lib64/libzmq.so
    libzipios.so.0 (libc6,x86-64) => /usr/lib64/libzipios.so.0
    libzipios.so (libc6,x86-64) => /usr/lib64/libzipios.so
    libzip.so.1 (libc6,x86-64) => /usr/lib64/libzip.so.1

Por que minha saída do ldd ainda está usando 1.53?

Isso porque seu binário está usando bibliotecas dinâmicas. Então, quando o binário foi compilado, foi contra as versões 1.55 das bibliotecas. No entanto, quando você interroga o binário usando ldd , ele está dentro do ambiente que está usando o conteúdo do arquivo .cache . Portanto, a biblioteca dentro do cache que está associada aos símbolos usados por esse binário corresponde àquela de 1.53, portanto você está vendo essas bibliotecas.

O seu ambiente não conhece nada das bibliotecas 1.55, apenas o seu ambiente de compilação, ou seja, o seu Makefile, está ciente disso.

Bibliotecas dinâmicas

Pense nas funções dentro delas como símbolos. Os símbolos são um nome e, portanto, esses nomes geralmente não mudam de uma versão de uma biblioteca para outra. Então, se você olhar uma biblioteca como o boost, poderá usar a ferramenta readelf para obter uma lista dos símbolos dentro de um desses arquivos .so .

Exemplo

$ readelf -Ws /usr/lib64/libboost_date_time-mt.so | head -10

Symbol table '.dynsym' contains 261 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 000000335aa096a8     0 SECTION LOCAL  DEFAULT    9 
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8bad_castD2Ev@GLIBCXX_3.4 (2)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt6locale5_ImplD1Ev@GLIBCXX_3.4 (2)
     4: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND _ZTINSt6locale5facetE@GLIBCXX_3.4 (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND wcslen@GLIBC_2.2.5 (3)
     6: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND _ZTISt11logic_error@GLIBCXX_3.4 (2)

Na saída acima, você pode ver algumas das definições de FUNC , estes são os nomes que são usados para "vincular" uma função em um executável com uma função de alguma biblioteca .so .

Estou simplificando isso, e provavelmente explicando as coisas um pouco, mas estou apenas tentando dar uma ideia geral de como funciona a mecânica de como o maquinário funciona.

Referências

por 07.12.2013 / 03:04
3

Ao compilar software que usa bibliotecas dinâmicas, a menos que você codifique um RPATH no binário compilado, quando você executar o executável (ou executa o ldd contra ele), ele procura as bibliotecas nos caminhos de busca definidos para o seu sistema operacional (geralmente configurado em /etc/ld.so.conf).

Se você compilou seu próprio software e o instalou fora dos caminhos de pesquisa da biblioteca, será necessário compilar os binários com RPATH codificado. Isso é feito passando -rpath ao seu vinculador. No entanto, na maioria das vezes, o Makefile não executa o vinculador diretamente, você precisa dizer ao gcc para passá-lo ao vinculador, geralmente adicionando -Wl,-rpath,/usr/local/whatever/lib ao CFLAGS .

Se você não quiser codificar caminhos, poderá atualizar sua variável de ambiente $LD_LIBRARY_PATH para ter uma coleção de diretórios de biblioteca delimitada por vírgulas que deseja adicionar ao caminho de pesquisa da biblioteca de tempo de execução. Definir $LD_LIBRARY_PATH é efêmero, não faz nada para o binário, então você precisa defini-lo sempre que precisar executar o executável. (Veja Módulos de Ambiente se você quiser fazer isso de maneira regular)

    
por 07.12.2013 / 02:45