Mixing libraries from different C++ compilers - c++

I am working on redhat 5.2 on a project which spans several disparate organizations. Each organization delivers libraries which have been compiled with various versions of g++. Currently, these versions include 4.1.1, 4.1.2 and 4.3.1. I am trying to link all the libraries together into an executable using 4.1.2. What, if any, problems may I expect by doing this? As an aside, is there a way to tell which ABI each compiler version builds to?

This ABI policy document details the compatibility between different ABI versions.
According to that, the libstdc++.so library should be compatible, and the last time gcc broke binary compatibility was at 3.4. You should be fine.

GCC (GNU Compiler Collection) defines version numbers and compatibility.
The G++ libraries between 4.1.1 and 4.1.2 should be compatible; link with the newest.
The G++ libraries between 4.1.x and 4.2.x are not compatible; you need to recompile something.
The G++ libraries between 3.x.y and 4.p.q are not compatible; you need to recompile something.
In your scenario, the code built with 4.3.1 is not compatible with the rest.
Either you will have to rebuild the code currently compiled with 4.3.x so it uses 4.1.x, or you need to recompile the code currently compiled with 4.1.x so it uses 4.3.x instead.

Maybe it is easier to static link the executable... makes a big binary, but runs on all platforms.

There should be no problems linking libraries built from different versions of g++ unless they've been listed on the g++ website. What is important though is that these libraries be built on the same platform which in your case is redhat 5.2. A library built for a platform other than linux/redhat (say solaris) will not link with your exe.

IIRC, there is a C++ compatibility library that is used to do just that. I think it's called libstdc++-compat.

Related

C++ build application with newer compiler without rebuilding the libraries

I have a C++ program that uses several libraries.
I build my application and the libraries with gcc version 4.
The libraries are built as static libraries and the header and libX.a files are added to the project.
Can I build my application with a newer gcc (for example gcc 7) without needing to rebuild also the libraries?
If I try building with the newer gcc and succeed, does it means I won't get any unexpected problems related to this later?
As mentioned in the comments you should recompile everything when doing such a major compiler upgrade.
Successful linking does not guarantee you will not get problems at runtime. This is due to ABI incompatibility between GCC versions. You might get lucky but it's something you can't depend on in the long run.
You might try to use GCC's code generation switches to make your compiled file compatible with your old libraries by looking up what has changed since those libraries were compiled in GCC's ABI policy but I think it's just not worth the effort.

How can I deploy a C++11 program (with dependencies) on CentOS 6, whose GCC is C++03?

GCC is great with ABI-compatibility as long as you use the same C++ standard [1].
But it strikes me that if a shared library compiled by GCC 4.3 in C++03 mode exposes, say, a std::string, this is going to be a different std::string than that understood by an executable compiled by GCC 4.8 in C++11 mode.
The reason I ask is that I am planning to deploy a program compiled by GCC 4.8 in C++11 mode on CentOS 6, whose maximum packaged GCC is 4.3... and some of the shared libraries (be they third-party C++ libraries or more system-level stuff) will presumably therefore all be C++03. But if that were the case, we'd never be able to deploy any C++11 programs on older Linux distributions, which seems unlikely.
Am I naive to think there might be a problem here? And, if there is, how can I resolve it?
There is a wonderful page on this matter: https://gcc.gnu.org/wiki/Cxx11AbiCompatibility
In short, C++11 in gcc is mostly ABI compatible with c++98, but there are a couple of mismatches. Page above lists all of those.
To alleviate the issue I can suggest following approach:
Clearly identify all your dependencies which are C++ libraries. You usually do not have too many of them - boost comes to mind first, do you have anything else?
Than you check if the symbols your app needs are in the list of broken ABI (see above). If they are not, you are in the clear.
If they are, you recompile the lib, and either distribute it as shared lib together with your app (playing with Rpath flags to make sure your app loads your version) or link statically against it.
Just in case, you might as well link statically against libstdc++.
Actually, you can distribute a program compiled with a newer g++ compiler on a vanilla CentOS 6 platform. There are several ways to do this: The easiest is to use the DevToolset 3, which will give you g++ 4.9.2 (the dev toolset 2 will give you gcc 4.8.2). Then, just compile your application with this g++. When distributing your software, you need to make sure to also ship the libstdc++.so that is being shipped with g++ 4.9. Either set the LD_LIBRARY_PATH so it gets picked up on startup, or set the RPATH to tell your executable where to look first for libraries.
Essentially, you can do this also with newer compilers, but then you first need to compile the compiler itself. If you don't want to compile a compiler first, go with a respective dev toolset and you should be fine.
Yes, you can also try to statically link libstdc++.a. Search for the option -static-libstdc++:
When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++ option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
But if you statically link, you will not get any security updates etc. Granted, you will not get the updates, if you ship libstdc++.so on your own as well, but incremental updates maybe easier.
And with respect to running your application: The rule of thumb is: Compile on the oldest platform you need to support, then your binaries (with self-shipped libstdc++ and other required libs) will likely work also on newer versions. That is, if you compile on CentoOS 6, and it works, then you can expect it to also work on CentOS 7. On a related subject, this is exactly the reason why for instance AppImage and related solutions recommend to build on an old system.
In my company we use gcc 5.1.0, compiled and used on CentOS 5.5 (with old gcc on-board).
When we deploy our application we also redistribute libstdc++.so and libgcc_s.so, compiled from gcc 5.1.0 sources.
For example:
/opt/ourapp/lib/libstdc++.so
/opt/ourapp/lib/libgcc_s.so
/opt/ourapp/bin/myapp
And for starting the binary correctly we execute:
LD_LIBRARY_PATH=/opt/ourapp/lib/ myapp.
Hope it helps.
Drawbacks:
At least you can't use native gdb on such an environment because DWARF format incompatibilities.
If you build your C++11 program with the define _GLIBCXX_USE_CXX11_ABI=0 (see this) and the option --abi-version=2 (see this) you should be compatible with any library build with GCC 4.3, including libstdc++.
The default ABI version was 2 through 4.9, it seems like a safe assumption that CentOS uses the default ABI.
The _GLIBCXX_USE_CXX11_ABI macro will affect the standard library's types, to use the same layout as the pre C++11 version. This will introduce some C++11 conformance issues (the reason why they were changed in the first place), things like the complexity of std::list<>::size().
The --abi-version= command line option affects the compiler's ABI, calling conventions, name mangling etc. The default ABI was 2 from 3.4 through 4.9.

Which version libstdc++.so is used in case of multiple GCC on the same system

I am trying to install the gcc 4.8 on a system where gcc 4.3 is installed and used currently. I did some research and knew that it is possible to keep multiple versions of gcc. And it seems for me that using --program-suffix= option is the best solution for me. But my question is, can I install new gcc 4.8 directly into the place where old gcc is installed? Can libraries from both versions be mixed in the same lib directory?
Some more details: the old gcc is installed in /usr/bin, /usr/lib64. If i install new gcc directly to the same location, new libraries will be also installed /usr/lib64. Is this a problem? Will gcc compiler know which library to use when linking?
Many thanks in advance!
I'm on Gentoo, which does support installing multiple versions of GCC at the same time. The libraries end up in /usr/lib/gcc/<target>/<version>. Ubuntu seems to install them in the same place, so I'd guess this to be a fairly common setup.
While gcc can apparently figure out the correct version to link against at compile time, the version used at runtime is configured using a file in /etc/ld.so.conf.d. So it might happen that a program gets compiled against one version of the gcc libraries, but executed with another.
If the ld.so.conf.d setting prefers newer versions over older, then this is mostly all right as long as gcc guys didn't introduce a new bug into one of these libraries, and as long as the configuration causes the libraries to be fully backwards-compatible.
In this bug we had a situation where libstdc++ broke backwards compatibility with regard to some C++11 features which were experimental and enabled using a custom configure switch. These things should be rare, but they can happen.
In a related gcc bug report I learned from Jonathan Wakely:
It is totally unsupported (and unlikely to work) to mix C++11 code built with GCC 4.x and 4.y, for any x!=y
Mixing code built with 4.8.x and 4.8.y should work, and does with the default configuration.
So while this setup works in practice on Gentoo, you are on your own if you try this yourself. Particularly since I know of no clean way to ensure that resulting binaries will link against the matching libraries at runtime.
You can try whether --program-suffix affects library names as well. If so, then the SONAME of the newer version libraries should be different from that of the older, helping to get the linking right at runtime. If the library name is unaffected, you could try examining the build system whether you can either change the SONAME of the generated libraries, or have the linker set the RPATH of all the programs it links. I have no experience with either of these approaches.
On Gentoo, /usr/bin/gcc appears to be some kind of wrapper, and the actual programs end up in /usr/<target>/gcc-bin/<version>/gcc and the likes. At least judging from the package web site, Ubuntu doesn't do this for the default version of gcc, although something similar is apparently used for cross-compilation to Android. I guess that setting is the result of a matching --bindir at configure time.

Compiling and linking with a different versions of gcc on linux

I am planning to compile a static library (mylib.a) with gcc 4.7.1. I want to take the advantages of C++11, so -std=c++11 is used. The platform, where I compile this lib is x86_64 SLES 11 with glibc-2.8.
Then I want to link this static library on a legacy platform with a legacy code, therefore I must use gcc 4.1.2 for linking and compiling the legacy code. So in my library headers I will not use any C++11 specific code. Also I will link libstdc++.a from gcc.4.7.1. The platform, where I want to link mylib.a, libstdc++.a(gcc4.7.1) and the legacy object files is x86_64 SLES 10 with glibc-2.4.
I tried all of this mess with some dummy C++11 code (std::async()) in mylib.a and it worked. I think this is possible only becuase of the ELF requiriements. Am I thinking correctly, or ELF has nothing to do with it? What kind of errors should I expect if mylib.a will contain some truly complex logic?
Linux has a C++ Application Binary Interface (ABI), which has been around for a while. This means that the calling conventions and name mangling across compilers on Linux is fixed. Therefore, as long as the libraries are compatible, you should be able to compiler with different compilers (or different versions of the same compiler) and have code which correctly and reliably links together.
Not entirely the ELF requirements per se...
GCC guarantees binary compatibility all the way back to some ancient version of 3. As long as the libstdc++ you're linking to has the new library features, there's no reason you can't use them. You will just have to stay away from the new language and library features in code compiled with GCC 4.1.2.

g++ and libstdc++

I have the following setup.
A redhat 4 machine with libstdc++ (old) installed under /usr/lib and an older version of gcc installed to the default location.
We also have a newer version of gcc 4.4.5 installed in a different directory with a newer version of libstdc++.
When I build a program with 4.4.5 and try to run I get errors indicating that I am using an older version of libstdc++.
Is there a way I can make the new compiler link against the system libstdc++ installed at /usr/lib instead of the one it comes with.
Thanks in advance
(I know it's an old question, this is for fellow googlers)
It seems that gcc is closely tied to its standard includes and standard lib. Their pathes are even hardcoded in gcc executables so gcc vX should automatically pick its corresponding files (includes + standard lib) that were built alongst itself (option --prefix in the ./configure command before the build) unless overriden.
The gcc standard C++ lib is shipped with gcc and built with the same command.
So it is not possible/recommanded to use non matching standard lib and compiler versions, unless with luck if the changes are minor.
Why do you want the new compiler to link against the old libstdc++? The problem sounds like its the new compiler using the old library already because it doesn't know where its is. Specify the path in LD_LIBRARY_PATH.
export LD_LIBRARY_PATH="/path/to/my/new/lib:${LD_LIBRARY_PATH}"