How can I find the full file path given a library name like libfoo.so.1?
Without implementing a linker or using ldd , how can I find the full path to a library? Is there a standard library available for that on Linux? (POSIX maybe?) Using ldd and grep on a file that is knowingly using libGL.so.1 , it looks like:
$ ldd /usr/bin/glxinfo | grep libGL libGL.so.1 => /usr/lib/libGL.so.1 (0x00007f34ff796000)
Given a library name like libGL.so.1 , how can I find the full path /usr/lib/libGL.so.1 ?. Preferably accepting an option for finding 32-bit and 64-bit libraries. If no library does that, does a program exist to do this? Something like find-library-path libGL.so.1 . The locate libGL.so.1 command does not count. I don’t want to actually load the library using dlopen or something if it executes code from that library.
5 Answers 5
Use ldconfig which is the tool that manages link space.
The -p flag lets you browse all available linkable libraries.
Thanks for your answer ,but -p prints cached entries from a file, not the current state (directories in $LD_LIBRARY_PATH are not respected for example)
@Lekensteyn If you want to find the library in any location and not rely on any mechanic that is actually used to manage libraries, find or the locate DB might be your only options. As your questions is stated, looking at the source for the loader might also be an option.
Expanding on Honky Tonk’s answer, the command echo «$(ldconfig -p | grep libGL.so.1 | tr ‘ ‘ ‘\n’ | grep /)» will give you the path alone.
If you don’t mind actually loading the library and using some nonstandard but widely-available functions, calling dladdr on any symbol from the library will return information containing the full pathname that was loaded.
I’ll have a look at the manpage, I also added another requirement to the question: the library should not execute code of the library that is being checked. EDIT: It looks like that dladdr is not going to help me as it needs dlopen first.
Well you can’t (portably) avoid executing global constructors in the library that’s loaded. There might be some non-portable hacks to get back control before the constructors run, using library dependencies and the implementation-specific order in which constructors run to call _exit (doing all of this from a forked child process) from another library’s constructor beforehand, but I think that’s getting into far-fetched hack territory. Ideally dlopen would have a RTLD_NOEXEC flag to prevent any code execution in the library, useful for tasks like yours.
Yeah, that is wishful thinking. There is a RTLD_NOLOAD, but that just returns NULL when the library is not loaded before. I don’t think there is even a solution available that takes 32-bit/64-bit into account (without building a 32-bit and 64-bit program designed to check this, that is).
Well there’s another ugly hack — you could fork a child process and ptrace it, and terminate it on the first mmap system call made. The prior open call should give you the pathname. 🙂 By the way, why do you need to know the pathname? I suspect there’s a better way to do what you’re trying to achieve.
primus intercepts GL calls and splits rendering from accelerating. These libraries do not have to sit in $LD_LIBRARY_PATH , hence I cannot pass libGL.so.1 to the dlopen function in that program and therefore I have to pass the absolute path to the libraries. In a second program, I want to lookup the libraries as stated in the question so I can pass it to the the primus program.
For systems with GNU libc and Python the following is the closest I found. It uses LD_DEBUG (described in the man page of ld.so(8) ).
LD_DEBUG=libs python3 -c "import ctypes; ctypes.CDLL('libssl.so.1.0.0')" 2>&1 | \ grep -A 1000 "initialize program: python" | grep -A 3 "find library"
The output (for libssl.so.1.0.0 ) is the following:
15370: find library=libssl.so.1.0.0 [0]; searching 15370: search cache=/etc/ld.so.cache 15370: trying file=/lib/x86_64-linux-gnu/libssl.so.1.0.0 15370: 15370: find library=libcrypto.so.1.0.0 [0]; searching 15370: search cache=/etc/ld.so.cache 15370: trying file=/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 15370:
I implemented such a script here:
#!/usr/bin/env python3 """ Like `type` but for libs. """ import sys import os from argparse import ArgumentParser from glob import glob def parse_ld_conf_file(fn): paths = [] for l in open(fn).read().splitlines(): l = l.strip() if not l: continue if l.startswith("#"): continue if l.startswith("include "): for sub_fn in glob(l[len("include "):]): paths.extend(parse_ld_conf_file(sub_fn)) continue paths.append(l) return paths def get_ld_paths(): # To be very correct, see man-page of ld.so. # And here: http://unix.stackexchange.com/questions/354295/what-is-the-default-value-of-ld-library-path/354296 # Short version, not specific to an executable, in this order: # - LD_LIBRARY_PATH # - /etc/ld.so.cache (instead we will parse /etc/ld.so.conf) # - /lib, /usr/lib (or maybe /lib64, /usr/lib64) paths = [] if "LD_LIBRARY_PATH" in os.environ: paths.extend(os.environ["LD_LIBRARY_PATH"].split(":")) paths.extend(parse_ld_conf_file("/etc/ld.so.conf")) paths.extend(["/lib", "/usr/lib", "/lib64", "/usr/lib64"]) return paths def main(): arg_parser = ArgumentParser() arg_parser.add_argument("lib") args = arg_parser.parse_args() paths = get_ld_paths() for p in paths: fn = "%s/%s" % (p, args.lib) if os.path.exists(fn): print(fn) return print("Did not found %r in %r." % (args.lib, paths), file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()
How do you specify the location of libraries to a binary? (linux)
For this question I’ll be using a specific example, but really this generalizes to pretty much any binary on linux that can’t seem to find its’ dependent libraries. So, I have a program that won’t run because of missing libraries:
./cart5: error while loading shared libraries: libcorona-1.0.2.so: cannot open shared object file: No such file or directory
linux-vdso.so.1 => (0x00007fff18b01000) libcorona-1.0.2.so => not found libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/libstdc++.so.6 (0x00007f0975830000) libm.so.6 => /lib/libm.so.6 (0x00007f09755af000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f0975399000) libc.so.6 => /lib/libc.so.6 (0x00007f0975040000) libz.so.1 => /lib/libz.so.1 (0x00007f0974e2b000) /lib64/ld-linux-x86-64.so.2 (0x00007f0975b36000)
oliver@human$ find / -name libcorona-1.0.2.so 2> /dev/null /usr/local/lib64/libcorona-1.0.2.so /home/oliver/installed/corona-1.0.2/src/.libs/libcorona-1.0.2.so
3 Answers 3
For a once-off, set the variable LD_LIBRARY_PATH to a colon-separated list of directories to search. This is analogous to PATH for executables, except that the standard system directories are additionally searched after the ones specified through the environment.
LD_LIBRARY_PATH=/usr/local/lib64 ./cart5
If you have a program that keeps libraries in a non-standard location and isn’t able to find them on its own, you can write a wrapper script:
#!/bin/sh if [ -n "$LD_LIBRARY_PATH" ]; then LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64 else LD_LIBRARY_PATH=/usr/local/lib64 fi export LD_LIBRARY_PATH exec /path/to/cart5 "$@"
The list of standard system directories is kept in /etc/ld.so.conf . Recent systems allow this file to include other files; if yours contains something like include /etc/ld.so.conf.d/*.conf , create a new file called /etc/ld.so.conf.d/mala.conf containing the directories you want to add. After you change /etc/ld.so.conf or an included file, run /sbin/ldconfig for your changes to take effect (this updates a cache).
( LD_LIBRARY_PATH also applies to many other unices, including FreeBSD, NetBSD, OpenBSD, Solaris and Tru64. HP-UX has SHLIB_PATH and Mac OS X has DYLD_LIBRARY_PATH . /etc/ld.so.conf has analogs on most unices but the location and syntax differs more widely.)
Where do library C header files go on Linux
Embarrassingly basic question. sudo apt-get install libmemcached6 — where do the .h’s and .o’s or .so’s live in a typical install on a Linux machine (Ubuntu)? And, how do I make sure g++ can pick them up?
g++ can pick them up if they are properly installed because they should be in the PATH. Otherwise, you could compile the library yourself statically and place the output somewhere in a folder of your choice.
3 Answers 3
They go to /usr/include and /usr/lib. If you use the -l option (for the libraries) it should find them from these standard places. If you include using it should also get it from the right place.
Found the so in /usr/lib. No header in /usr/include. Is this likely something not included in an apt-get install and I’ll just need to acquire the source myself?
mostprobably your library has a -dev version that installs the header and this one just installs the runtime requirements (aka the .so) try doing apt-cache search libmemcached6 and see if there’s a libmemcached6-dev package for development files. that will add the header file
Linking with -lmemcached seems like it compiles but fails to link the C functions in, not sure how to tell where to find them (or where they are.)
@djechlin, try running objdump -T /usr/lib/libmemcached.so.6 and checking to make sure the names match what you have in your code.
On Ubuntu (and other Debian variants) you can use the dpkg command to find out. For example:
$ dpkg -L libxml2 /. /usr /usr/share /usr/share/doc /usr/share/doc/libxml2 /usr/share/doc/libxml2/AUTHORS /usr/share/doc/libxml2/NEWS.gz /usr/share/doc/libxml2/TODO.gz /usr/share/doc/libxml2/copyright /usr/share/doc/libxml2/README /usr/share/doc/libxml2/changelog.Debian.gz /usr/share/doc/libxml2/README.Debian /usr/lib /usr/lib/libxml2.so.2.7.8 /usr/lib/libxml2.so.2
As you can see, Debian packages don’t typically include the .h files; those are normally in corresponding -dev packages. So you can find the header files here:
$ dpkg -L libxml2-dev /. /usr /usr/share /usr/share/doc /usr/share/doc/libxml2-dev /usr/share/doc/libxml2-dev/AUTHORS /usr/share/doc/libxml2-dev/NEWS.gz /usr/share/doc/libxml2-dev/TODO.gz /usr/share/doc/libxml2-dev/copyright /usr/share/doc/libxml2-dev/README /usr/share/doc/libxml2-dev/changelog.Debian.gz /usr/share/aclocal /usr/share/aclocal/libxml2.m4 /usr/share/man /usr/share/man/man3 /usr/share/man/man3/libxml.3.gz /usr/share/man/man1 /usr/share/man/man1/xml2-config.1.gz /usr/include /usr/include/libxml2 /usr/include/libxml2/libxml /usr/include/libxml2/libxml/HTMLtree.h /usr/include/libxml2/libxml/tree.h /usr/include/libxml2/libxml/xmlreader.h /usr/include/libxml2/libxml/xmlschemastypes.h .
As for gcc , the manual explains how it searches for header files. Note that this is different and separate from using -l to instruct the linker to link with a certain library.