Shared Libs in Benutzerverzeichnissen

Als root kann man natürlich die shared lib einfach dort installieren, wo der Linker sucht: In eines der Systemverzeichnisse /lib, /usr/lib o.ä.

Man könnte auch LD_LIBRARY_PATH setzen, damit der Linker weiss wo er suchen soll. Das müsste man aber vor jedem Aufruf des Programms tun, daher sind elegantere Lösungen gefragt.

Besser ist es, dem Linker mit dem Flag " -R <pfad> bereits beim compilieren und linken, wo die shared lib zu suchen ist. Das wird dann im ELF binary mit abgespeichert.

Ein kleiner Test zur Demonstration des Ganzen:

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

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

Makefile
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

Ok, lassen wir es laufen:

$ 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

Wie korrigiert man den Fehler? Füge "-R <path>" zu den Linkerflags hinzu (hier indem wir LDFLAGS setzen).

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

Wenn wir nun das ELF binary analysieren, sehen wir dass es libtest.so.0 braucht:

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

Das binary (oder genauer, der Lader) sucht nach den Libraries, ausser in den Standardpfaden, auch im angegebenen Verzeichnis in RPATH:

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

Wenn in RPATH das aktuelle Verzeichnis als Suchverzeichnis angegeben werden soll, kann man RPATH auf "$ORIGIN" setzen. Das ist etwas tricky, weil man verhindern muss, dass das Dollarzeichen bereits von make ausgewertet wird. Hier ist eine Möglichkeit, dies zu erreichen:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'" $ objdump -p hello | grep RPATH RPATH $ORIGIN $ ./hello Hello world, I'm a library!