Link to home
Start Free TrialLog in
Avatar of tomatoyohe
tomatoyohe

asked on

How do I prevent hard coded library path dependencies in my executables created with gcc ?

My make file links the executable with shared libraries.  I have set the library search path with the "-L..\lib\x86_64".  The resultant executable then has hard coded dependency to ..\lib\x86_64 which I do not want.  When program loads, I want LD_LIBRARY_PATH to determine which shared library to link with - I do not want it hard coded.

Below is my make file for tgoctest executable.  Along with a "strings" output which proves that the executable is hard wired to a specific path.

PROJ = tgoctest
CC = gcc
LINK = gcc
SHELL=/bin/sh

#default configuation - this should be speciifed when using this makefile
CONFIG=DEBUG
#default platform - this should be specified when using this makefile
TGPLATFORM:=$(shell arch)

OBJDIR=./$(TGPLATFORM)
LIBS_EXT = -lpthread -lncurses
CFLAGSDEBUG = -g  -D "_DEBUG" -D "UNIX" -D "LINUX" -I ../include
LFLAGSDEBUG = -g -L../lib/$(TGPLATFORM) -ltgoc -ltgjpeg
CFLAGSRELEASE = -O -D "UNIX" -D "LINUX" -I ../include
LFLAGSRELEASE = -L../lib/$(TGPLATFORM) -ltgoc -ltgjpeg

TGOCTEST_DEP = ../include/tgocosdp.h \
        ../include/tgocache.h

all:    checkconfig $(OBJDIR)/$(PROJ)


checkconfig:
        @if [[ ! -d $(OBJDIR) ]]; then \
                mkdir $(OBJDIR); \
        fi

copy:
"tgoctestlinux.mak" 50L, 1116C                      


tyohe@suse64:/yam/tg/source/tgoctest> strings x86_64/tgoctest | grep lib
/lib64/ld-linux-x86-64.so.2
../lib/x86_64/libtgoc.a
../lib/x86_64/libtgjpeg.a
libpthread.so.0
libncurses.so.5
libc.so.6
__libc_start_main
Zlib Compile Flags =0x%x
Set Zlib compression level
tyohe@suse64:/yam/tg/source/tgoctest>
Avatar of Alf666
Alf666

strings is not the right way of testing.

Use ldd.

Using -L does not hardcode library paths. -R has to be used for this. So, it's not a problem of where your libs are at compile time. If they are somewhere in the LD_LIBRARY_PATH at exec time, they will be used.

Avatar of tomatoyohe

ASKER

Thanks for your insight, however it is not quite on target.  ldd shows where the libraries will be loaded from if you were to execute the program and it uses LD_LIBRARY_PATH to help determine this.  When I try to load the executable, it fails even if LD_LIBRARY_PATH is set to a directory where the shared libraries reside.  The strings command shows that the shared libraries must reside in ..\lib\x8_64 relative to the current directory.

The following illustrates this.

tyohe@suse64:~/test> set | grep LD_LIBRARY_PATH
LD_LIBRARY_PATH=/home/tyohe/test/junk
tyohe@suse64:~/test> ls -l junk
total 404
-rwxr-xr-x  1 tyohe users 176803 2004-04-22 14:36 libtgjpeg.a
-rwxr-xr-x  1 tyohe users 230689 2004-04-22 14:36 libtgoc.a
tyohe@suse64:~/test> ls -l
total 200
drwxr-xr-x  2 tyohe users    112 2004-04-22 14:37 junk
-rwxr-xr-x  1 tyohe users 203259 2004-04-22 14:36 tgoctest
tyohe@suse64:~/test> ./tgoctest
./tgoctest: error while loading shared libraries: ../lib/x86_64/libtgoc.a: cannot open shared object file: No such file or directory
tyohe@suse64:~/test> pwd
/home/tyohe/test
tyohe@suse64:~/test>

Previous investigation led me to this article
http://sources.redhat.com/ml/binutils/2003-08/msg00345.html 
 which indicates that ldd does not show hardcoded references - only what would be chosen by dynamic linker.
Oh no !!!

This is totally normal. The libraries you have here are "static libraries". I did not notice it in the first place.

in fact, a ".a" file is an archive file that contains ".o" files.

If you want to link with shared libraries, you have to use the following :

gcc -shared -Xlinker -x -o mylib.so myobj1.o myobj1.o

Then, link against these.

And, I'm sorry, but ldd is completely on topic. It will show you what will actually be used by the dynamic loader. So, it allows you to see that the libraries are correctly loaded.

A short example :

serval:/tmp # cat test.c
doit() {
  printf("test\n") ;
}

serval:/tmp # cat test2.c
extern doit() ;

main() {

  doit() ;

}

serval:/tmp # gcc -c test.c
serval:/tmp # gcc -shared -Xlinker -x -o libtest.so test.o
serval:/tmp # gcc test2.c -o test2 -L/tmp -ltest

serval:/tmp # ls -al test*
-rw-r--r--    1 root     root           32 Apr 22 21:15 test.c
-rw-r--r--    1 root     root          760 Apr 22 21:22 test.o
-rwxr-xr-x    1 root     root         8466 Apr 22 21:22 test2
-rw-r--r--    1 root     root           41 Apr 22 21:16 test2.c

serval:/tmp # mkdir foo
serval:/tmp # cd foo/
serval:/tmp/foo # ldd ../test2
        libtest.so => not found
        libc.so.6 => /lib/i686/libc.so.6 (0x40032000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

serval:/tmp/foo # export LD_LIBRARY_PATH=/tmp
serval:/tmp/foo # ldd ../test2
        libtest.so => /tmp/libtest.so (0x4001a000)
        libc.so.6 => /lib/i686/libc.so.6 (0x40034000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

serval:/tmp/foo # ../test2
test


See ?
Oh. And, yes. ldd only shows what's used.
But you don't care about static references if your dynamic linker is able to find the libraries where you want them to be.
Sorry. One more.

Works on Linux, but not on all systems.

serval:/tmp # unset LD_LIBRARY_PATH
serval:/tmp # gcc test2.c -o test2 -Wl,-rpath,/tmp -L/tmp -ltest
serval:/tmp # cd foo/
serval:/tmp/foo # ldd ../test2
        libtest.so => /tmp/libtest.so (0x4001a000)
        libc.so.6 => /lib/i686/libc.so.6 (0x40034000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Some systems (like Solaris) use the '-R' option to the compiler.

These differences is the reason why most big projects make use of libtool. libtool standardizes the calls to the compiler/linker and adapt to the actual system's options.
As far as I know, libtgoc.a is not a static library but a shared library.  When I built it, I thought I specified it to be shared.  Here is pertinent part of the make file:

PROJ = libtgoc.a

CC = gcc
LINK = gcc
SHELL=/bin/sh

#default configuation - this should be speciifed when using this makefile
CONFIG=RELEASE
#default platform - this should be specified when using this makefile
TGPLATFORM:=$(shell arch)

OBJDIR=./$(TGPLATFORM)


CFLAGSDEBUG = -g -fPIC -D "_DEBUG" -D "UNIX" -D "LINUX" -I ../include
LFLAGSDEBUG = -shared -fPIC -Wl,-Bsymbolic -ldl

CFLAGSRELEASE = -fPIC -O3 -D "UNIX" -D "LINUX" -I ../include
LFLAGSRELEASE = -shared -fPIC -Wl,-Bsymbolic -ldl

LIBS_EXT =  -l m -l c -l pthread
Furthermore, objdump utility indicates that the library is dynamic (not static).

tyohe@suse64:~/test/junk> objdump -f libtgoc.a

libtgoc.a:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000007470
ASKER CERTIFIED SOLUTION
Avatar of Alf666
Alf666

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well after simply renaming the ".a" files to ".so" files the hard coded paths are now removed from the executable!  Thank you.

tyohe@suse64:/yam/tg/source/tgoctest> strings x86_64/tgoctest | grep lib
/lib64/ld-linux-x86-64.so.2
libtgoc.so
libtgjpeg.so
libpthread.so.0
libncurses.so.5
libc.so.6
__libc_start_main
../lib/x86_64