Search code examples
cautomakelibtool

built library dirs not added to LD_LIBRARY_PATH in libtool wrapper script


I cannot easily test my program after build:

$ ./src/rap/rap -h
/home/il/workspace/rap/src/rap/.libs/lt-rap: error while loading shared libraries: libpmclient.so: cannot open shared object file: No such file or directory

libpmclient.so is in ./src/nsreclient/x86_64-unknown-linux-gnu/ and a proper -L flag was used during link

Automake builds my binary with libtool. It creates a wrapper script src/rap/rap.

My expectation was: while generating the script, libtool would ignore the current value of LD_LIBRARY_PATH. When running the script, it would append the needed directories in the build tree to existing value of LD_LIBRARY_PATH. e.g, executing:

LD_LIBRARY_PATH=/foo ./src/rap/rap

would result:

LD_LIBRARY_PATH=/foo:/home/il/workspace/rap/src/nsreclient/x86_64-unknown-linux-gnu ./src/rap/.libs/lt-rap

But libtool does the opposite: it hardcodes the current value of LD_LIBRARY_PATH into the generated script:

LD_LIBRARY_PATH=/opt/oracle/product/11.2.0/client_64/lib:/lib:/usr/lib:/usr/local/lib; export LD_LIBRARY_PATH;

It makes no sense. Why doesn't it add there the build tree directories?

Here's pretty formated output of make command:

/bin/sh ../../libtool  --tag=CC   --mode=link gcc  -Werror-implicit-function-declaration -O2 \
    -pthread   -o rap rap.o \
    librap.a \
    ../liclib/liblic.a \
    ../fget-1.3.3/lib/libfget.a \
    ../lib_mt/libppb.la \
    ../sgplib/libsgp.la \
    ../../variations/asn1lib/ebuf_lib_mt/libasn1cebuf.la \
    -L../../src/nsreclient/x86_64-unknown-linux-gnu -lpmclient \
    -L/opt/oracle/product/11.2.0/client_64/lib -lclntsh \
    -L/usr/lib -lexpat \
    -lssl \
    -lcrypto  \
    -lm


libtool: link: gcc -Werror-implicit-function-declaration -O2 -pthread -o .libs/rap rap.o  librap.a ../liclib/liblic.a ../fget-1.3.3/lib/libfget.a \
    ../lib_mt/.libs/libppb.so \
    ../sgplib/.libs/libsgp.so \
    ../../variations/asn1lib/ebuf_lib_mt/.libs/libasn1cebuf.so \
    -L../../src/nsreclient/x86_64-unknown-linux-gnu -lpmclient \
    -L/opt/oracle/product/11.2.0/client_64/lib -lclntsh \
    -L/usr/lib /usr/lib/libexpat.so \
    -lssl -lcrypto -lm -pthread -Wl,-rpath -Wl,/usr/local/lib

Solution

  • The wrapper script does not set LD_LIBRARY_PATH at all. It assumes that subdirs containing the needed libraries were added to RPATH of the real binary.

    When -lfoo flag passed to libtool, it first tries to open the corresponding file libfoo.la. If that file does not exist, libtool falls back to passing the flag to gcc unchanged.

    If the .la file exists and points to a shared library, libtool tells the linker to add the directory containing the library to RPATH of output binary.

    Many packages install their .la files to /usr/lib/. That means newer libtool will be able parse files created by previous versions. It must be totally safe to manually write .la files for precompiled .so files instead of generating them every time.

    I created the file ./src/nsreclient/x86_64-unknown-linux-gnu/libpmclient.la :

    # libpmclient.la - a libtool library file
    # Generated by ltmain.sh - GNU libtool 1.5.22 (1.1220.2.365 2005/12/18 22:14:06)
    #
    # Please DO NOT delete this file!
    # It is necessary for linking the library.
    
    # The name that we can dlopen(3).
    dlname='libpmclient.so'
    
    # Names of this library.
    library_names='libpmclient.so'
    
    # The name of the static archive.
    old_library='libpmclient.a'
    
    # Linker flags that cannot go in dependency_libs.
    inherited_linker_flags=' -pthread'
    
    # Libraries that this one depends upon.
    dependency_libs=''
    
    # Names of additional weak libraries provided by this library
    weak_library_names=''
    
    # Version information for libpmclient.
    current=0
    age=0
    revision=0
    
    # Is this an already installed library?
    installed=no
    
    # Should we warn about portability when linking against -modules?
    shouldnotlink=no
    
    # Files to dlopen/dlpreopen
    dlopen=''
    dlpreopen=''
    
    # Directory that this library needs to be installed in:
    libdir='/usr/local/lib'
    

    After rebuild, my wrapper script no longer complains.