Linking 3rd party shared libraries without soname, linker name - linux

Installing liboost-dev on Debian Squeeze gives me several libraries like /usr/lib/libboost_thread.so.1.42.0, but no libboost_thread.so. Now I can't link using the -l flag of gcc / ld because the names don't end in .so.
I notice that /usr/lib has plenty of other libraries of the form libfoo.so.N without a libfoo.so, so this isn't peculiar to Boost. I ended up adding libboost_thread.so.1 and libboost_thread.so symlinks links by hand. (The man page for ldconfig suggests it will add the links, but it didn't do anything).
Everything works fine, but it feels dirty. What should I have done?
use some more specific linker option I haven't found yet (at the cost of making my makefiles depend on a specific version number).
just add the symlinks by hand (at the risk of subverting package management).
some other Debian 'right way' to do it.

You installed the run-time package libboost-thread1.42.0 but the development package libboost-thread-dev (or even the catch-all package libboost-all-dev.
Once you have the corresponding -dev package, linking will work. That is a general feature of most Linux distribution---you almost never want to mess with the symlinks by hand.
Edit: In response to your comment:
edd#max:~$ ls -l /usr/lib/libboost_thread.*
-rw-r--r-- 1 root root 176324 2010-10-21 00:56 /usr/lib/libboost_thread.a
lrwxrwxrwx 1 root root 25 2011-05-14 10:17 /usr/lib/libboost_thread.so -> \
libboost_thread.so.1.42.0
-rw-r--r-- 1 root root 88824 2010-10-21 00:56 /usr/lib/libboost_thread.so.1.42.0
edd#max:~$ dpkg -S /usr/lib/libboost_thread.so
libboost-thread1.42-dev: /usr/lib/libboost_thread.so
edd#max:~$
Clearly the package management system created the links, and owns them.

Dirk's answer is correct about the general principle but there seems to be an extra trap for the unwary with the boost packaging.
Normally the headers and the library symlink are in the same package, so you get the library symlink without thinking about it. However with boost "libboost<version>-dev" provides the headers but "libboost-<lib><version>-dev" provides the shared library symlink. So if you only install the former you get stuff compiling but not linking.

Related

Getting CMake to understand absolute symbolic links when cross-compiling for Linux

When cross compiling with CMake, I use a toolchain file which sets up the linker to look in a local copy of the root filesystem of the embedded (Linux) target.
Things come unstuck for a few fundamental libraries like libm or librt which are usually a symbolic link to an absolute location which cannot be resolved.
For example, on the target rootfs, librt is a symbolic link at /usr/lib/arm-linux-gnueabihf/librt.so which points to /lib/arm-linux-gnueabihf/librt.so.6
I thought setting the option CMAKE_SYSROOT to the root of the root filesystem would be enough to let CMake and/or gcc work out the link, but this doesn't work.
For now I'm just manually adjusting the links to be relative and then everything links ok. I assume there must be something I'm missing about cross-compiling with CMake though?
What is the paradime for ensuring cross-compilation and linking against libraries in a root filesystem?
The root filesystem is generated with the debootstrap tool. The complications have arisen from requiring to build the project against both Wheezy and Jessie root filesystem targets.

crosstool-ng, directory structure, and sysroot

I have a working cross-compiler toolchain, thanks to crosstool-ng :) -- however, crosstool-ng is very sparsely documented, and I am brand new to cross-compiling. The specific host and target are not, I think, important in this context.
I have some basic questions about the directory structure. The toolchain was installed into a directory named after the target. Inside that are a set of directories:
arm-unknown-linux-gnueabi
bin
include
lib
libexec
share
I presume this is for the actual cross-compiler bits, since the compilers in bin/ do work for this purpose. Notice that there is an inner arm-unknown-linux-gnueabi/ directory, ie, the path in there is ../arm-unknown-linux-gnueabi/arm-unknown-linux-gnueabi. Inside that there is another tree:
bin
debug-root
include
lib
lib32
lib64
sysroot
The lib* directories are symlinks into sysroot/. The stuff in bin seems to be the same set of cross-compile tools as in the parent directory /bin:
> bin/gcc -v
Using built-in specs.
COLLECT_GCC=./gcc
Target: arm-unknown-linux-gnueabi
Configured with: /usr/x-tool/.build/src/gcc-4.7.2/configure
--build=x86_64-build_unknown-linux-gnu
--host=x86_64-build_unknown-linux-gnu
--target=arm-unknown-linux-gnueabi
So my first question is: what are these for? And what is this directory for?
My second question then is: how should sysroot/ be used? It's apparently for support libraries native to the target platform, so I presume if I were building such a library I should use that as the --prefix, although it would amount to the same thing as using the parent directory, since lib* is symlinked...this "directory in the middle" with a bin and symlinks down to sysroot is confusing. I believe (some) autotools style packages can be configured "--with-sysroot". What is the significance of that, if I see it, and how should it be used in relation to other options such as --prefix, etc?
For your first question, as toolchain installed directory:
bin/arm-unknown-linux-gnueabi-gcc
arm-unknown-linux-gnueabi/bin/gcc
They are the same, indeed hard links.
You can use arm-unknown-linux-gnueabi-gcc by CC=arm-unknown-linux-gnueabi-gcc, e.g.
export PATH=<toolchain installed dir>/bin:$PATH
CC=arm-unknown-linux-gnueabi-gcc ./configure
make
Or
export PATH=<toolchain installed dir>/arm-unknown-linux-gnueabi/bin:$PATH
./configure
make
I always used the first form, and I am not sure if the latter form works.
For your second question, in my experience, you don't need to concern about sysroot. cross-compiler will find the correct C header files in sysroot/usr/include automatically.
Except that you want to cross-compile some libraries and install them into sysroot, you can get it by
export PATH=<toolchain installed dir>/bin:$PATH
CC=arm-unknown-linux-gnueabi-gcc ./configure --prefix=<toolchain installed dir>/arm-unknown-linux-gnueabi/arm-unknown-linux-gnueabi/sysroot
make
make install
Starting at 38:39 of the talk Anatomy of Cross-Compilation Toolchains by Thomas Petazzoni, the speaker gives an in-depth walk through of the output directory structure.

How are shared library dependency paths determined on Linux?

When I run ldd against a shared library such as libphp5.so I see that it has a dependency on libmysqlclient.so.16:
$ ldd ./libphp5.so
libmysqlclient.so.16 => /usr/lib/mysql/libmysqlclient.so.16
[other dependencies snipped out]
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary? Or is this path determined by some other means such as via /etc/ld.so.conf.d/mysql-i386.conf, which incidentally contains:
/usr/lib/mysql/
One other thing is puzzling me:
There is a shared library I have that I compile from source. This has a dependency on libmysqlclient_r. The gcc compiler switches to produce this this library look like:
gcc -shared -L/usr/lib/mysql -lmysqlclient_r [+various other switches]
When I do ldd mylib.so I see:
libmysqlclient_r.so.16 => /usr/lib/mysql/libmysqlclient_r.so.16 (0x0055c000)
However in the /usr/lib/mysql directory I see:
-rwxr-xr-x. libmysqlclient_r.so -> libmysqlclient_r.so.16.0.0
lrwxrwxrwx. libmysqlclient_r.so.16 -> libmysqlclient_r.so.16.0.0
-rwxr-xr-x. libmysqlclient_r.so.16.0.0
lrwxrwxrwx. libmysqlclient.so -> libmysqlclient.so.16.0.0
lrwxrwxrwx. libmysqlclient.so.16 -> libmysqlclient.so.16.0.0
-rwxr-xr-x. libmysqlclient.so.16.0.0
libmysqlclient_r.so is a symbolic link to libmysqlclient_r.so.16.0.0, so why does ldd show the dependency as libmysqlclient_r.so.16. Is there some magic I'm missing here?
Having been a Windows dev for many years I'm a bit new to gcc and development on Linux.
My Linux distribution is CentOS 6.0 x86-32bit.
You can see which paths are coming from where by running
LD_DEBUG=libs ldd ./libphp5.so
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary?
The filename almost certainly is. The path usually isn't. You can see what is baked into the binary with
readelf -d ./libphp5.so
Look for (NEEDED) and (RPATH) entries.
Also give man ld.so a read. There are many factors that affect how dynamic loader searches for shared libraries: ld.so.conf, LD_LIBRARY_PATH, whether the executable is suid or not, how glibc was configured, which -rpath settings were given at link time, etc. etc.
Are these dependency filenames and paths (/usr/lib/mysql/libmysqlclient.so.16) baked into the shared library binary?
Yes, they can be and often are. The keyword here is -rpath. However, ld.conf also has its say. The whole system is quite complex, unfortunately.

How do applications resolve to different versions of shared libraries at run time?

I'm a noob to how shared libraries work on linux. I am trying to understand how do applications resolve different revisions of the same shared library at run-time on linux.
As far as I understand, a shared library has three "names", for example,
libmy.so.1.2 (real-name i.e. the actual obj file)
libmy.so.1 (SONAME, which is embedded in the actual obj file)
libmy.so (linker name, provided to the linker at link time and embedded in executable)
When you install the library via LDCONFIG, it will create the following symbolic links
(2) => (1)
(3) => (2)
Now lets say I compile another version of the same library with the following real-name,
libmy.so.2.0. The SONAME by guidelines would be libmy.so.2.0
At application link time what is the linker name that I would provide with the "-l" flag. Following the guidelines I read (http://www.dwheeler.com/program-library/Program-Library-HOWTO/x36.html), wouldn't it have to be libmy.so and if so, how will both versions of the obj file be distinguished ?
Versioning of shared objects works as follows:
When you create a shared object, you give it both a real name and an soname. These are used to install the shared object (which creates both the object and a link to it).
So you can end up with the situation:
pax> ls -al xyz*
-rw-r--r-- 1 pax paxgroup 12345 Nov 18 2009 xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so.1 -> xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so -> xyz.so.1
with xyz.so.1.5 possessing the SONAME of xyz.so.1.
When the linker links in xyz.so, it follows the links all the way to xyz.so.1.5 and uses its SONAME of xyz.so.1 to store in the executable. Then, when you run the executable, it tries to load xyz.so.1 which will point to a specific xyz.so.1.N (not necessarily version 1.5).
So you could install xyz.so.1.6 and update the xyz.so.1 link to point to it instead and already-linked executables would use that instead.
One advantage of this multi-layer method is that you can have multiple potentially incompatible libraries of the same name (xyz.so.1.*, xyz.so.2.*) but, within each major version, you can freely upgrade them since they're supposed to be compatible.
When you link new executables:
Those linking with xyz.so will get the latest minor version of the latest major version.
Others linking with xyz.so.1 will get the latest minor version of a specific major version.
Still others linking with xyz.so.1.2 will get a specific minor version of a specific major version.
Now keep that last paragraph in mind as we examine your comment:
Now lets say I compile another version of the same library with the following real-name, libmy.so.2.0. The SONAME by guidelines would be libmy.so.2.0.
No, I don't believe so. The soname would be more likely to be libmy.so.2 so that you can make minor updates to the 2.x stream and get the latest behaviour.
At application link time, if you specify -lmy, the linker will search for a file named libmy.so. It will find this file, and link you executable with it. If this file is a symbolic link, then your application will be linked with the target of the symlink.
Application link time is the place to specify which version of the dynamic library you want to use with your application.
A complement to #paxdiablo's answer bullet one:
ldconfig doesn't set up the linker names; typically this is done during library installation, and the linker name is simply created as a symbolic link to the ``latest'' soname or the latest real name.
it means xxx.so will link to a latest minor version of the latest major version dynamic library file.
I think this explains why:
Those linking with xyz.so will get the latest minor version of the latest major version.
But I don't know how installation setup linker name and which tool make it(apt-get?)
Libs have different versions in the name.
Packages with name "lib" have only libs and have different versions in the name.
System will compile only with the latest library,
unless you define a different one.
The application uses only those libraries that it needs.
Check ldd , readelf.
Apps contain a link .so and .pc file, check rpm system for what.
https://fedoraproject.org/wiki/Packaging:Guidelines?rd=Packaging#Devel_Packages

why after setting LD-LIBRARY_PATH and ld.so.cache properly, there are still library-finding problems?

I have a certain shared object library in a special directory which I
make sure special directory is in $LD_LIBRARY_PATH
make sure this directory has read and execute permisions for all
make sure appropriate library directory is in ld.so.conf and that root has done a ldconfig
(verify by checking for library using ldconfig -p as normaluser.
make sure it is has no soname problems (i.e. create a few symlinks if necessary)
Now, say I compile a program that needs that special library, a program packaged in a typical Open Source manner which ./configure && make, etc) and it says -lspecialibrary cannot be found, an error which a lack of any of the above checks would also probably throw.
A workaround I have done is to symlink the library to /usr/local/lib64 and suddenly the library has ben found. Also when compiling a relatively simple package, I manually add -L/path/to/spec/lib and that also has worked. But I regard those two methods as hacks, so I was looking for any clues as to why my list of checks aren't good enough to find a library.
(I particularly find the $LD_LIBRARY_PATH of shallow use. In fact I can exclude certain libraries from it, and they will still be found in a compilation process).
$LD_LIBRARY_PATH and ldconfig are only used to locate libraries when running programs that need libraries, i.e. they are used by the loader not the compiler. Your program depends on libspeciallibrary.so. When running your program $LD_LIBRARY_PATH and ldconfig are consulted to find libspeciallibary.so.
These methods are not used by your compiler to find libraries. For your compiler, the -L option is the right way to go. Since your package uses the autotools, you should set the $LDFLAGS environment variable:
LDFLAGS=-L/path/to/lib ./configure && make
This is also documented in the configure help:
./configure --help

Resources