title: Telling ld where to look for dependent shared libraries during compilation
body: <p>I'm trying to crosscompile some libraries for an ARM processor, specifically:</p>
  
  <p>DirectFB, which depends on libpng, which depends on zlib.</p>
  
  <p>Libpng is linked against zlib, but since the paths on the build system don't match the paths on the target system, ld can't find the zlib that libpng is linked against during the compilation of DirectFB.</p>
  
  <p>I've reduced the issue to the following example:
  testb depends on libb, which depends on liba.</p>
  
  <p>Build liba:</p>
  
  <pre><code>gcc -Wall -fPIC -c a.c
  gcc -shared -Wl,-soname,liba.so.1 -o liba.so.1.0 a.o
  
  ln -fs liba.so.1.0 liba.so.1
  ln -fs liba.so.1 liba.so
  </code></pre>
  
  <p>Built testa:</p>
  
  <pre><code>gcc -Wall -I. -L. testa.c -la -o testa
  LD_LIBRARY_PATH=. ./testa
  a: 0
  </code></pre>
  
  <p>Build libb:</p>
  
  <pre><code>gcc -Wall -fPIC -I. -L. -c b.c -la
  gcc -shared -Wl,-soname,libb.so.1 -o libb.so.1.0 b.o
  
  ln -fs libb.so.1.0 libb.so.1
  ln -fs libb.so.1 libb.so
  </code></pre>
  
  <p>So far, so good. However, building testb fails:</p>
  
  <pre><code>gcc -Wall -I. -L. testb.c -lb -o testb
  </code></pre>
  
  <p>Results in:</p>
  
  <pre><code>./libb.so: undefined reference to `a'
  collect2: ld returned 1 exit status
  make: *** [testb] Error 1
  </code></pre>
  
  <p>So ld can't find the definition of a in liba, even though libb is linked against liba, and both are in the current directory, which is being passed with "-L."</p>
  
  <p>Running gcc with -v results in:</p>
  
  <pre><code>gcc -v -Wall -I. -L. testb.c -lb -o testb
  Using built-in specs.
  Target: i486-linux-gnu
  Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
  Thread model: posix
  gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) 
  COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
   /usr/lib/gcc/i486-linux-gnu/4.4.3/cc1 -quiet -v -I. testb.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase testb.c -mtune=generic -march=i486 -auxbase testb -Wall -version -fstack-protector -o /tmp/ccqAkMFb.s
  GNU C (Ubuntu 4.4.3-4ubuntu5.1) version 4.4.3 (i486-linux-gnu)
      compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1.
  GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128244
  ignoring nonexistent directory "/usr/local/include/i486-linux-gnu"
  ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../i486-linux-gnu/include"
  ignoring nonexistent directory "/usr/include/i486-linux-gnu"
  #include "..." search starts here:
  #include &lt;...&gt; search starts here:
   .
   /usr/local/include
   /usr/lib/gcc/i486-linux-gnu/4.4.3/include
   /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed
   /usr/include
  End of search list.
  GNU C (Ubuntu 4.4.3-4ubuntu5.1) version 4.4.3 (i486-linux-gnu)
      compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1.
  GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128244
  Compiler executable checksum: 2349e080d2b2f3f970047e63bbe98cb2
  COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
   as -V -Qy -o /tmp/ccc6ux7S.o /tmp/ccqAkMFb.s
  GNU assembler version 2.20.1 (i486-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.20.1-system.20100303
  COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/
  LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../:/lib/:/usr/lib/:/usr/lib/i486-linux-gnu/
  COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
   /usr/lib/gcc/i486-linux-gnu/4.4.3/collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o testb -z relro /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L. -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu /tmp/ccc6ux7S.o -lb -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o
  ./libb.so: undefined reference to `a'
  collect2: ld returned 1 exit status
  make: *** [testb] Error 1
  </code></pre>
  
  <p>Setting LD_LIBRARY_PATH and/or LIBRARY_PATH to the current directory doesn't resolve the problem.</p>
  
  <p>Compiling with -la works, but it shouldn't be necessary, since libb is linked against liba. For example, when linking against libpng in a native build environment (correct paths, library paths in ld.so.conf) doesn't require -lz.</p>
  
  <p>Also, setting additional libs to link against is a pain, because I would have to patch the Makefiles for every compilation that depends on a lib that depends on another lib.</p>
  
  <p>In summary, how do I tell ld where to look for dependent shared libraries during compilation?</p>
  
  <p>My problem is similar to these two:
  <a href="https://stackoverflow.com/questions/9621179/cross-linking-for-arm-qnx-fails-with-indirect-transitive-dependencies">Cross-linking for ARM/QNX fails with indirect/transitive dependencies</a>
  <a href="https://stackoverflow.com/questions/1926716/how-to-resolve-shared-library-linking-during-compilation-gcc">How to resolve shared library linking during compilation( GCC )?</a></p>
  
  <p>Neither suggests a solution which doesn't require the addition of -la, which in my opinion shouldn't be necessary.</p>
  
  <hr>
  
  <p><strong>Files used:</strong></p>
  
  <p>a.c:</p>
  
  <pre><code>int a() {
      return 0;
  }
  </code></pre>
  
  <p>liba.h:</p>
  
  <pre><code>#ifndef LIBA_H
  #define LIBA_H
  
      int a();
  
  #endif 
  </code></pre>
  
  <p>testa.c:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;liba.h&gt;
  
  int main() {
      printf("a: %d\r\n", a());
      return 0;
  } 
  </code></pre>
  
  <p>b.c:</p>
  
  <pre><code>#include &lt;liba.h&gt;
  
  int b() {
      return a();
  }
  </code></pre>
  
  <p>libb.h:</p>
  
  <pre><code>#ifndef LIBB_H
  #define LIBB_H
  
      int b();
  
  #endif 
  </code></pre>
  
  <p>testb.c:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;libb.h&gt;
  
  int main() {
      printf("b: %d\r\n", b());
      return 0;
  }
  </code></pre>
  
  <p>Makefile:</p>
  
  <pre><code># Makefile for shared library test
  
  all:
  
  liba:
      gcc -Wall -fPIC -c a.c
      gcc -shared -Wl,-soname,liba.so.1 -o liba.so.1.0 a.o
  
      ln -fs liba.so.1.0 liba.so.1
      ln -fs liba.so.1 liba.so
  
  testa: liba
      gcc -Wall -I. -L. testa.c -la -o testa
  
  runtesta: testa
      LD_LIBRARY_PATH=. ./testa
  
  libb: liba
      gcc -Wall -fPIC -I. -L. -c b.c -la
      gcc -shared -Wl,-soname,libb.so.1 -o libb.so.1.0 b.o
  
      ln -fs libb.so.1.0 libb.so.1
      ln -fs libb.so.1 libb.so
  
  testb: libb
      gcc -v -Wall -I. -L. testb.c -lb -o testb
  
  runtestb: testb
      LD_LIBRARY_PATH=. ./testb
  
  clean:
      # clean up
      rm -rf *.o
      rm -rf liba.s*
      rm -rf libb.s*
      rm -rf testa testb
  </code></pre>