In order to make use of C++11 and c++14 features I have an application compiled using a newer version of gcc (4.9.1) and thus an newer version of libstdc++. The application consists of many small programs so I am linking with libstdc++ as a shared library rather than a static one (i.e. I don't wish to use -static-libstdc++)
I wish to ship the new version of libstdc++ with the application under /opt//lib64 (note: that this is specifically allowed under an exception to the GPL)
The new version of libstdc++.so differs with the version on the target platform only by minor version. libstdc++ is designed to be forward compatible so that existing programs can use the new version of the library. However, I have observed subtle differences in behaviour (i.e. bugs) when some programs use the new version rather than the older one. I wish to prevent this.
I also find that ld
will try to link my application with the system version of libstdc++ unless
I put /opt//lib64 earlier on the LD_LIBRARY_PATH.
Supposedly you can force linking against a specific version using -l:<library>.<version>
, however, this doesn't seem to work. I suspect that it would for a user created library but not for
a language runtime library like libstd++ because gcc itself generates the linker script.
Also on one of my target platforms (RHEL5) it is not even understood by gcc/ld.
I presume this is possible via using -nostdlib and linking in everything required (e.g. -lgcc) in my build system
rather than leaving it to gcc which I would prefer. So far I haven't tried this.
A simple way workaround for this is to ensure LD_LIBRARY_PATH contains /opt//lib64 when I run my application and not otherwise or equally I could use LD_PRELOAD with the correct library version. The problem with this if someone decides ignore my advice and runs
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/<vendor>/lib64
it could lead to subtle and hard to diagnose problems. So I have been looking for a better way.
I wondered if there was some way I could rename libstdc++ as lib_stdc++ and link against that soname instead. Renaming libstdc++ is not enough as you need to alter the soname in the file as given by readelf. i.e
0x000000000000000e (SONAME) Library soname: [libstdc++.so.6]
If you do this on a normal program linked by gcc
even using -l:stdc++.so.6.0.20
say you will notice this
gives the major version and not the specific minor version.
i.e.
readelf -d <myapp>
0x0000000e (SONAME) Library soname: [libstdc++.so.6]
rather than:
0x0000000e (SONAME) Library soname: [libstdc++.so.6.0.20]
So I have instead created a dummy shared library with the soname I want to depend on in order to add a dependency as follows:
gcc dummy.o -Wl,-soname,lib<vendor>_stdc++.so.6.0.20 -nostdlib -shared -o lib<vender>_dummycpp.so
(where dummy.o is an empty object file made from an empty source file to stop -nostdlib leading to complaints)
then:
gcc <myapp> -l<vendor>_dummycpp
as desired I now get:
readelf -d <myapp>
0x0000000000000001 (NEEDED) Shared library: [lib<vendor>_stdc++.so.6.0.20]
instead of
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
The dummycpp library contains all the symbols in libstdc++ because it is libstd++ so there is no need for gcc to link with the soname libstdc++ at all. I appear to have solved the issue completely.
It strikes me as a slightly hacky solution so the questions I want to ask here are:
Is this a good idea?
If not why not?
Is there a better/more correct way?
Note: that if you package the libstdc++ with a different name (e.g. lib_stdc++.so.6.0.20) in an RPM you will get a missing dependency on it and need to install using --nodeps. This is because RPM scans for link time dependencies. The workaround for this is to install the dummy library as well. RPM will then pick up the soname from the dummy library and not claim it is missing.
-rpath
(linker option) to specify a nonstandard location to search in first? ie:-Wl,-rpath=/opt/lib64
– Chaunce