Explicitly linking a local shared object library
Question: I'm working on setting up a `Makefile` for compiling Python wrappers for a C
library. The contents of the file are below (with library names altered for
infosec reasons). The line numbers are for reference and are not included in
the file data itself.

    
    
      1 CC = gcc                    
      2 CFLAGS = -Wall -fPIC -shared
      3 EXAMPLE_LIB = example
      4 PYTHON = /usr/include/python2.6
      5 LIBS = -L./$(EXAMPLE_LIB) -lexample
      6 INCLUDE = -I./$(EXAMPLE_LIB)/include -I$(PYTHON)
      7 DEPS = test.h
      8 OBJ = test.o
      9 SHARED = test.so
     10 
     11 .PHONY : build
     12 
     13 all: build $(SHARED)
     14 
     15 build:
     16    ./$(EXAMPLE_LIB)/config shared
     17    $(MAKE) -C $(EXAMPLE_LIB)
     18 
     19 %.o: %.c $(DEPS)
     20    $(CC) $(CFLAGS) $(INCLUDE) -c -o $@ $<
     21 
     22 $(SHARED): $(OBJ)
     23    $(CC) $(CFLAGS) $(LIBS) -o $@ $+
     24 
     25 clean:
     26    $(MAKE) clean -C $(EXAMPLE_LIB)
     27    rm $(OBJ)
     28    rm $(SHARED)
    

The `EXAMPLE_LIB` shared object file `example.so` is compiling properly and
exists at `<project-directory>/example/example.so` and the proper header files
for the 3rd party library exist at `<project-directory>/example/include`.

The problem I'm having is that a different version (with less features) of the
`example.so` shared object library is installed on the global system and is
being linked in my library (`test.so`) instead of the local (self-compiled)
copy. This causes an `undefined symbol` error when attempting to import the
library in Python.

When I check the `test.so` shared object library using `ldd` I see that
`/usr/lib64/example.so.1` is being loaded instead of `<project-
directory>/example/example.so`. Or to demonstrate:

    
    
    [mike@tester myproject]$ ldd test.so 
        linux-vdso.so.1 =>  (0x00007fff803ff000)
        example.so.1 => /usr/lib64/example.so.1 (0x00007f98700e8000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f986fd55000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f986fb50000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f986f93a000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003afda00000)
    

**Is there an option I can pass to GCC to tell it to explicitly link the local
version of the shared object library?**


Answer: The problem is that `-L` just adds a directory to the search path, and `-l`
just finds the library anywhere on the search path. So:

    
    
    LIBS = -L./$(EXAMPLE_LIB) -lexample
    

… might look for `libexample.so` (or `libexample.a`!) in `/usr/lib`,
`/usr/local/lib`, `/usr/lib64`, etc., before looking in `./example`.

See [Link Options](http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Link-
Options.html#Link-Options) and [Options for Directory
Search](http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Directory-
Options.html#Directory-Options) in the GCC docs for details.

If you want to specify a library explicitly, just pass its path to the linker:

    
    
    LIBS = ./$(EXAMPLE_LIB)/libexample.so
    

As the docs explicitly say:

> The only difference between using an -l option and specifying a file name is
> that -l surrounds library with ‘lib’ and ‘.a’ and searches several
> directories.

So, if you don't want it to search several directories, don't use `-l`.

