Vous ne trouvez pas .so dans le même répertoire que l'exécutable?

45

J'ai un exécutable qui doit être lié libtest.sodynamiquement, alors je les mets dans le même répertoire, puis:

cd path_to_dir
./binary

Mais j'ai ceci:

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

Comment peut-il être incapable de trouver libtest.soce qui se trouve déjà dans le même répertoire que l'exécutable lui-même?

linuxer
la source

Réponses:

25

Le chargeur ne vérifie jamais les objets partagés dans le répertoire en cours, sauf s'il est explicitement dirigé vers via $LD_LIBRARY_PATH. Voir la ld.so(8)page de manuel pour plus de détails.

Ignacio Vazquez-Abrams
la source
echo $LD_LIBRARY_PATHest vide sur ma machine :(
linuxer
C'est habituellement.
Ignacio Vazquez-Abrams le
2
Il spécifie des répertoires supplémentaires dans lesquels le chargeur doit rechercher des bibliothèques.
Ignacio Vazquez-Abrams
1
Les chemins dans * nix sont séparés par un signe deux-points ( :), pas un point-virgule.
Ignacio Vazquez-Abrams Le
3
LD_LIBRARY_PATH est généralement un mauvais choix en production. C'est utile pour les hacks rapides et pour aider des binaires désinstallés à trouver leurs bibliothèques partagées lors de l'exécution de tests unitaires (think ./configure; make; make check). Lors de la construction de votre binaire, vous pouvez soit placer votre bibliothèque dans un emplacement standard (répertorié dans /etc/ld.so.conf), soit transmettre l'indicateur -R à l'éditeur de liens pour indiquer au binaire où chercher.
automatthias
57

Bien que vous puissiez définir LD_LIBRARY_PATH pour laisser l’éditeur de liens dynamique savoir où regarder, de meilleures options existent. Vous pouvez placer votre bibliothèque partagée à l’un des emplacements standard, voir /etc/ld.so.conf(sous Linux) et /usr/bin/crle(sous Solaris) pour obtenir la liste de ces emplacements.

Vous pouvez passer -R <path>à l'éditeur de liens lors de la construction de votre binaire, ce qui s'ajoutera <path>à la liste des répertoires analysés pour votre bibliothèque partagée. Voici un exemple. Tout d'abord, montrant le problème:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

Bonjour c:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile (les onglets doivent être utilisés):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

Courons le:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

Comment le réparer? Ajouter -R <path>aux drapeaux de l'éditeur de liens (ici, par paramètre LDFLAGS).

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

En regardant le binaire, vous pouvez voir qu'il a besoin de libtest.so.0:

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

Le binaire cherchera ses bibliothèques, en dehors des emplacements standard, dans le répertoire spécifié:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

Si vous voulez que le fichier binaire regarde dans le répertoire en cours, vous pouvez définir le RPATH sur $ORIGIN. C'est un peu délicat, car vous devez vous assurer que le signe dollar n'est pas interprété par make. Voici une façon de le faire:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!
automatismes
la source
1
Si vous ne l'utilisez pas make, par exemple lors d'un appel manuel g++, essayez -Wl,-rpath='$ORIGIN'(notez les guillemets simples) d'empêcher le $ORIGINdéveloppement d'une chaîne vide.
Morpork
14

Pour charger les objets partagés à partir du même répertoire que votre exécutable, exécutez simplement:

$ LD_LIBRARY_PATH=. ./binary

Remarque: Cela ne modifiera pas la variable LD_LIBRARY_PATH de votre système. Le changement n'affecte que ceci et seulement cela l'exécution de votre programme.

Cygnes
la source
4

Pour ceux qui se battent encore sans réponse, j'en ai trouvé une moi-même avec la suggestion suivante:

Vous pouvez essayer de mettre à jour le fichier ld.so.cache en utilisant: sudo ldconfig -v

Travaillé pour moi

Ian Frisbie
la source
Travaillé pour moi aussi.
Joel
3

Pour toute personne utilisant CMake pour sa construction, vous pouvez définir les paramètres CMAKE_EXE_LINKER_FLAGSsuivants:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

Cela propagera correctement les indicateurs de l'éditeur de liens pour tous les types de construction (par exemple, Debug, Release, etc.) afin de rechercher d'abord les fichiers .so dans le répertoire de travail en cours.

Michael Goldshteyn
la source
0

L'éditeur de liens dynamique décidera où chercher les bibliothèques. Dans le cas de Linux, l'éditeur de liens dynamique est généralement GNU ld.so(ou une alternative qui se comportera généralement de la même manière pour des raisons de compatibilité).

Pour citer des citations sur Wikipedia:

L'éditeur de liens dynamique de la bibliothèque GNU C recherche les bibliothèques partagées aux emplacements suivants:

  1. Les chemins (séparés par des points) dans l' DT_RPATHattribut de section dynamique du binaire s'il est présent et que l' DT_RUNPATHattribut n'existe pas.
  2. Les chemins (séparés par des points) dans la variable d'environnement LD_LIBRARY_PATH, à moins que l'exécutable soit un setuid/ setgidbinary, auquel cas il est ignoré. LD_LIBRARY_PATHpeut être remplacé en appelant l'éditeur de liens dynamique avec l'option --library-path (par exemple, /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram).
  3. Les chemins (séparés par des points) dans l' DT_RUNPATHattribut de section dynamique du binaire s'il est présent.
  4. Recherche basée sur le fichier cache ldconfig (souvent situé sur /etc/ld.so.cache) qui contient une liste compilée de bibliothèques candidates précédemment trouvées dans le chemin de bibliothèque augmenté (défini par /etc/ld.so.conf). Si, toutefois, le fichier binaire était lié à l' -z nodefaultliboption de l' éditeur de liens, les bibliothèques des chemins de bibliothèque par défaut sont ignorées.
  5. Dans le chemin par défaut approuvé /lib, puis /usr/lib. Si le fichier binaire était lié à l'option de lieur -z nodefaultlib, cette étape est ignorée.

Source: https://en.wikipedia.org/wiki/Rpath

Mecki
la source