48

I have some code that uses some shared libraries (c code on gcc). When compiling I have to explicitly define the include and library directories using -I and -L, since they aren't in the standard places. When I try to run the code, I get the following error:

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

However, do the following, everything works just fine:

export LD_LIBRARY_PATH="/path/to/library/"
./sync_test

Now, the strange part is, this only works once. If I try and run sync_test again I get the same error unless I run the export command first. I tried adding the following to my .bashrc, but it made no difference:

LD_LIBRARY_PATH="/path/to/library/"
sigjuice
  • 28,661
  • 12
  • 68
  • 93
Paul Wicks
  • 62,960
  • 55
  • 119
  • 146
  • 1
    I think all these suggestions are bad - clearly a bug with Linux. Why wont compile time L path was not passed to runtime? –  Jan 04 '12 at 04:00
  • You can set a path with `-rpath`, but this is usually not desirably since it then imposes that path on other systems - see second comment on http://stackoverflow.com/a/695539/168175 – Flexo Jan 04 '12 at 04:24

7 Answers7

48

You should avoid setting LD_LIBRARY_PATH in your .bashrc. See "Why LD_LIBRARY_PATH is bad" for more information.

Use the linker option -rpath while linking so that the dynamic linker knows where to find libsync.so during runtime.

gcc ... -Wl,-rpath /path/to/library -L/path/to/library -lsync -o sync_test

EDIT:

Another way would be to use a wrapper like this

#!/bin/bash

LD_LIBRARY_PATH=/path/to/library sync_test "$@"

If sync_test starts any other programs, they might end up using the libs in /path/to/library which may or may not be intended.

miller
  • 1,636
  • 3
  • 26
  • 55
sigjuice
  • 28,661
  • 12
  • 68
  • 93
  • 6
    That really doesn't help if you move the application to someone else's machine and they don't want to put the library in the same /path/to that you expected at link time. While -rpath is certainly useful for sysadmins and distro providers, I believe it's presumptuous for an individual to set this. – Tom Mar 30 '09 at 03:56
  • Although, your first statement "avoid setting LD_LIBRARY_PATH in your .bashrc" I agree with 100%. A middle-ground solution that I have used is a bash script $HOME/bin/myprogram that sets the local LD_LIBRARY_PATH and then runs /path/to/real/myprogram. – Tom Mar 30 '09 at 03:58
  • You are right. One cannot assume where someone wants their libs. In case there is a fixed relation between bin/ and lib/, something like -rpath $ORIGIN/../lib might be more appropriate. There is a also a program that can change the rpath in ELF executables called chrpath. – sigjuice Mar 30 '09 at 06:32
  • 1
    I agree with the use of a wrapper shell script. I will update my answer. – sigjuice Mar 30 '09 at 06:35
  • Thanks for the tip. None of the things mentioned in the article are really issues in my case (this code is only ever going to be run on one machine by me), but I'll definitely keep them in mind if I ever run into a similar problem. – Paul Wicks Mar 31 '09 at 04:20
  • @Alcott Yes. -rpath is a GNU ld option. Other linkers might have something similar. -Wl is documented here http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html and -rpath is documented here http://sourceware.org/binutils/docs-2.22/ld/Options.html#Options – sigjuice Feb 23 '12 at 18:52
44

Use

export LD_LIBRARY_PATH="/path/to/library/"

in your .bashrc otherwise, it'll only be available to bash and not any programs you start.

Try -R/path/to/library/ flag when you're linking, it'll make the program look in that directory and you won't need to set any environment variables.

EDIT: Looks like -R is Solaris only, and you're on Linux.

An alternate way would be to add the path to /etc/ld.so.conf and run ldconfig. Note that this is a global change that will apply to all dynamically linked binaries.

user
  • 5,335
  • 7
  • 47
  • 63
brian-brazil
  • 31,678
  • 6
  • 93
  • 86
  • 8
    Use `-Wl,-rpath` (if passing to `cc`) or `-rpath` (if passing to `ld`) as more portable than `-R`. – ephemient Mar 30 '09 at 17:35
  • 1
    `-rpath` can be problematic, see http://wiki.debian.org/RpathIssue for a discussion – Flexo Jan 04 '12 at 04:27
  • 1
    For compatibility, -R is also supported by GNU ld, though as mentioned in the comment by @awoodland, such is undesired. ("Top 10 commercial software mistakes" even, I'd say) – jørgensen Jan 04 '12 at 05:21
11

You can just put this all on one line:

LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/path/to/library" ./sync_test

Should make things a little easier, even if it doesn't change anything fundamental

  • This syntax is wonderful... especially if some of your program behavior is based on transient environment variables, such as TMP or TMPDIR – Tom Mar 30 '09 at 00:12
10

Did you 'export' in your .bashrc?

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"/path/to/library"
bedwyr
  • 5,774
  • 4
  • 31
  • 49
6

Instead of overriding the library search path at runtime with LD_LIBRARY_PATH, you could instead bake it into the binary itself with rpath. If you link with GCC adding -Wl,-rpath,<libdir> should do the trick, if you link with ld it's just -rpath <libdir>.

fgp
  • 8,126
  • 1
  • 17
  • 18
2

What you also can do, if it's something you installed on your system, is to add the directory that contains the shared libraries to your /etc/ld.so.conf file, or make a new file in /etc/ld.so.conf.d/

(I've both checked RHEL5 and Ubuntu distribution so I think it's generic for linux)

The ldconfig program will make sure they are system-wide included.

See the following link for more information: www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/dlls.html

Roalt
  • 8,330
  • 7
  • 41
  • 53
1

You could add in your code a call system with the new definition:

sprintf(newdef,"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s:%s",ld1,ld2);
system(newdef);

But, I don't know it that is the rigth solution but it works.

Regards

Rick Smith
  • 9,031
  • 15
  • 81
  • 85