117

I'm compiling a c++ program using g++ and ld. I have a .so library I want to be used during linking. However, a library of the same name exists in /usr/local/lib, and ld is choosing that library over the one I'm directly specifying. How can I fix this?

For the examples below, my library file is /my/dir/libfoo.so.0. Things I've tried that don't work:

  • my g++ command is g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • adding /my/dir to the beginning or end of my $PATH en` variable
  • adding /my/dir/libfoo.so.0 as an argument to g++
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Heinrich Schmetterling
  • 6,614
  • 11
  • 40
  • 56

5 Answers5

110

Add the path to where your new library is to LD_LIBRARY_PATH (it has slightly different name on Mac ...)

Your solution should work with using the -L/my/dir -lfoo options, at runtime use LD_LIBRARY_PATH to point to the location of your library.

Careful with using LD_LIBRARY_PATH - in short (from link):

..implications..:
Security: Remember that the directories specified in LD_LIBRARY_PATH get searched before(!) the standard locations? In that way, a nasty person could get your application to load a version of a shared library that contains malicious code! That’s one reason why setuid/setgid executables do neglect that variable!
Performance: The link loader has to search all the directories specified, until it finds the directory where the shared library resides – for ALL shared libraries the application is linked against! This means a lot of system calls to open(), that will fail with “ENOENT (No such file or directory)”! If the path contains many directories, the number of failed calls will increase linearly, and you can tell that from the start-up time of the application. If some (or all) of the directories are in an NFS environment, the start-up time of your applications can really get long – and it can slow down the whole system!
Inconsistency: This is the most common problem. LD_LIBRARY_PATH forces an application to load a shared library it wasn’t linked against, and that is quite likely not compatible with the original version. This can either be very obvious, i.e. the application crashes, or it can lead to wrong results, if the picked up library not quite does what the original version would have done. Especially the latter is sometimes hard to debug.

OR

Use the rpath option via gcc to linker - runtime library search path, will be used instead of looking in standard dir (gcc option):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

This is good for a temporary solution. Linker first searches the LD_LIBRARY_PATH for libraries before looking into standard directories.

If you don't want to permanently update LD_LIBRARY_PATH you can do it on the fly on command line:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

You can check what libraries linker knows about using (example):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

And you can check which library your application is using:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
slashmais
  • 7,069
  • 9
  • 54
  • 80
stefanB
  • 77,323
  • 27
  • 116
  • 141
  • 29
    `LD_LIBRARY_PATH` is searched at runtime, at compile time you want to set `LIBRARY_PATH`. See https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html – Bjoern Dahlgren Oct 18 '14 at 16:49
  • 1
    If you're library is completely different from the system library, i.e. is the one to always use, please use the rpath solution. LD_LIBRARY_PATH is a hack for testing and should not be required to make an executable work correctly. – user2746401 Mar 20 '15 at 14:20
  • 1
    its DYLD_LIBRARY_PATH for Mac – cbinder Nov 27 '15 at 06:33
  • Here is a full sample command (for C) that works based on this answer: `gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary` – Jet Blue May 04 '19 at 00:43
  • Shouldn't the executable know where to look for the library at run time with `-L/my/dir -lfoo`, why do we need to tell again where to look for the library with `-Wl,-rpath (LD_LIBRARY_PATH)`? – Ramses Aldama Feb 26 '21 at 05:22
38

This is an old question, but no one seems to have mentioned this.

You were getting lucky that the thing was linking at all.

You needed to change

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

to this:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Your linker keeps track of symbols it needs to resolve. If it reads the library first, it doesn't have any needed symbols, so it ignores the symbols in it. Specify the libraries after the things that need to link to them so that your linker has symbols to find in them.

Also, -lfoo makes it search specifically for a file named libfoo.a or libfoo.so as needed. Not libfoo.so.0. So either ln the name or rename the library as appopriate.

To quote the gcc man page:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Adding the file directly to g++'s command line should have worked, unless of course, you put it prior to bar.cpp, causing the linker to ignore it for lacking any needed symbols, because no symbols were needed yet.

Michael Speer
  • 4,656
  • 2
  • 19
  • 10
  • 1
    Thank you! After many days of dead-ends, this was the solution for me. I confirmed the -l position in fact mattered a lot. :) – Kenny Cason Dec 01 '22 at 22:51
25

Specifying the absolute path to the library should work fine:

g++ /my/dir/libfoo.so.0  ...

Did you remember to remove the -lfoo once you added the absolute path?

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • 1
    This solution also worked fine for me - trying to link against a version of Qt5 other than the distro development package. Thanks. – wump May 03 '16 at 10:39
  • How to make this work for `@` versioned symbols? Minimal example: https://github.com/cirosantilli/cpp-cheat/blob/0b4b1bdeed693d16129b282ce0c8145499bf34f6/shared-library/symbol-version/Makefile#L13 – Ciro Santilli OurBigBook.com Mar 26 '17 at 11:11
13

As an alternative, you can use the environment variables LIBRARY_PATH and CPLUS_INCLUDE_PATH, which respectively indicate where to look for libraries and where to look for headers (CPATH will also do the job), without specifying the -L and -I options.

Edit: CPATH includes header with -I and CPLUS_INCLUDE_PATH with -isystem.

Alexandre Hamez
  • 7,725
  • 2
  • 28
  • 39
0

If one is used to work with DLL in Windows and would like to skip .so version numbers in linux/QT, adding CONFIG += plugin will take version numbers out. To use absolute path to .so, giving it to linker works fine, as Mr. Klatchko mentioned.

Delimitry
  • 2,987
  • 4
  • 30
  • 39