J'ai un exécutable qui doit être lié à libtest.so
dynamiquement, donc 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.so
qui se trouve déjà dans le même répertoire que l'exécutable lui-même?
Le chargeur ne vérifie jamais le répertoire courant pour les objets partagés à moins qu'il ne soit explicitement dirigé vers via $LD_LIBRARY_PATH
. Consultez la page de manuel ld.so(8)
pour plus de détails.
Bien que vous puissiez définir LD_LIBRARY_PATH pour que l'éditeur de liens dynamique sache où chercher, il existe de meilleures options. Vous pouvez placer votre bibliothèque partagée dans l'un des emplacements standard, voir /etc/ld.so.conf
(sous Linux) et /usr/bin/crle
(sur Solaris) pour la liste de ces lieux
Tu peux passer -R <path>
à l'éditeur de liens lors de la construction de votre binaire, ce qui 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 (des 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
Lançons-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, en définissant 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 recherchera 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 binaire regarde dans le répertoire courant, 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 procéder:
$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$Origin'"
$ objdump -p hello | grep RPATH
RPATH $Origin
$ ./hello
Hello world, I'm a library!
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 cela, et seulement cela, l'exécution de votre programme.
Pour tous ceux qui luttent encore sans réponse, j'en ai trouvé un moi-même avec la suggestion suivante:
Vous pouvez essayer de mettre à jour le ld.so.cache en utilisant: Sudo ldconfig -v
A travaillé pour moi.
Pour toute personne utilisant CMake pour sa construction, vous pouvez définir le CMAKE_EXE_LINKER_FLAGS
aux éléments suivants:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$Origin'")
Cela propage correctement les indicateurs de l'éditeur de liens pour tous les types de build (par exemple, Debug, Release, etc ...) pour rechercher d'abord les fichiers .so dans le répertoire de travail actuel.
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 manière identique pour des raisons de compatibilité.].
Pour citer des extraits de Wikipedia:
L'éditeur de liens dynamique de la bibliothèque GNU C recherche les bibliothèques partagées aux emplacements suivants:
- Les chemins (séparés par deux-points) dans le
DT_RPATH
attribut de section dynamique du binaire s'il est présent et leDT_RUNPATH
l'attribut n'existe pas.- Les chemins (séparés par deux points) dans la variable d'environnement
LD_LIBRARY_PATH
, sauf si l'exécutable est un binairesetuid
/setgid
, auquel cas il est ignoré.LD_LIBRARY_PATH
peut être substitué en appelant l'éditeur de liens dynamique avec l'option --library-path (par exemple /lib/ld-linux.so.2 --library-path $ HOME/mylibs myprogram).- Les chemins (séparés par deux-points) dans le
DT_RUNPATH
attribut de section dynamique du binaire s'il est présent.- Recherche basée sur le fichier de cache ldconfig (souvent situé à
/etc/ld.so.cache
) qui contient une liste compilée des bibliothèques candidates précédemment trouvées dans le chemin de la bibliothèque augmentée (définie par/etc/ld.so.conf
). Si, cependant, le binaire était lié au-z nodefaultlib
option de l'éditeur de liens, les bibliothèques dans les chemins de bibliothèque par défaut sont ignorées.- Dans le chemin d'accès par défaut approuvé
/lib
, et alors/usr/lib
. Si le binaire a été lié avec l'option de l'éditeur de liens -z nodefaultlib, cette étape est ignorée.