C/C++: cannot open shared object file

As bibliotecas compartilhadas são carregadas no início da execução de um programa. No Linux, o dynamic loader procura pelas bibliotecas em /lib e /usr/lib. Caso a biblioteca não esteja presente neste caminho, recebemos uma mensagem de erro parecida com a mensagem a seguir:

error while loading shared libraries: libfoo.so:
  cannot open shared object file: No such file or directory

Imagine um ambiente de desenvolvimento, onde estamos codificando uma biblioteca. Não queremos instalar esta biblioteca no sistema só para testá-la. Uma alternativa é configurar a variável de ambiente LD_LIBRARY_PATH, apontando para o diretório onde se encontra o binário da biblioteca. Assim o dynamic loader vai procurar pela biblioteca também neste diretório.

$ export LD_LIBRARY_PATH=/home/user/libfoo/

Uma segunda opção seria no momento em que seu programa é “linkado”, passar o caminho da biblioteca para a opção -rpath do linker. Isto coloca o caminho de busca pela biblioteca dentro da estrutura do executável (ELF). A opção -Wl do gcc serve para passar parâmetros para o linker (usando “,” no lugar de espaço) que é chamado automaticamente após a compilação.

$ gcc -shared -Wall -o libfoo.so foo.c
$ gcc -Wall -o test test.c -L/home/user/libfoo/ -lfoo
$ ./test # Erro! Não acha a biblioteca libfoo.so
$ gcc -Wall -Wl,-rpath,/home/user/libfoo/ -o test test.c \
  -L/home/user/libfoo/ -lfoo
$ ./test # Funciona!
This entry was posted in C, CPP, Linux and tagged , , , , , , , . Bookmark the permalink.

7 Responses to C/C++: cannot open shared object file

  1. Olá!

    Não somente configurar a variável LD_LIBRARY_PATH para o diretório onde está explicitamente a biblioteca como também para o diretório corrente!

    export LD_LIBRARY_PATH=”.”

    ou

    export LD_LIBRARY_PATH=”.:${LD_LIBRARY_PATH}”

    []s

  2. Cássio says:

    Faz tempo que não faço isso, mas acho que
    $ LD_PRELOAD= ./test
    funcionaria.

  3. Cássio says:

    ops. O sanitize comeu parte do meu comentário. seria
    $ LD_PRELOAD=<caminho para o .so> ./test

  4. Cássio, acho que não!

    Para esquema do uso da LD_PRELOAD e preciso que seu objeto tenha declarações explicitas do tipo “constructor”, exemplo abaixo!

    ## wrap.c:
    #define _GNU_SOURCE
    #include
    #include

    static void wrap_init(void) __attribute__((constructor));
    static FILE *(*s_fopen)(const char *, const char *);

    FILE *fopen(const char *path, const char *mode)
    {
    printf(“Olá, wrapper para fopen: %p\n”, s_fopen);
    if(!s_fopen) {
    printf(“Ops, endereço NULL\n”);
    return NULL;
    }
    return s_fopen(path, mode);
    }

    static void wrap_init(void)
    {
    s_fopen = dlsym(RTLD_NEXT, “fopen”);
    printf(“Init: %p\n”, s_fopen);
    }
    ## End wrap.c

    ## lib.c
    #include
    static void lib_init(void) __attribute__((constructor));
    static void lib_init(void) {
    fopen(“foo.txt”, “r”);
    }
    ## End lib.c

    # Compila ele como shared
    # gcc -shared -o libninja-wrapper.so wrapper.c lib.c

    Dai o seu programa que por exemplo venha a chamar a função fopen() e por sua vez utiliza o LD_PRELOAD, dai será possível fazer um “catch” da função!

    # LD_PRELOAD=./libninja-wrapper.so ./seu-programa-que-dentr-chama-fopen

    Abraços!
    []s

  5. andreyevbr says:

    Ops, a lista de libs compartilhadas também pode ser mantida no arquivo /etc/ld.so.conf, não?

  6. @Andre: Sim, desde que o cache esteja atualizado atraves do comando ldconfig

  7. bogado says:

    Só uma coisa que sempre atrapalha, lembre-se que se o seu programa tem que rodar com suid o LD_LIBRARY_PATH e outras variaveis de ambiente LD_* são ignoradas, por medidas de segurança. Por isso a unica solução neste caso é usar o run_path.

Leave a Reply

Your email address will not be published. Required fields are marked *