C++11 compatibility with existing libraries/frameworks - c++

I am wondering something for which I have not found a convincing answer yet.
Situation:
A system with some libraries (e.g. gtkmm) compiled without c++11 enabled.
An application compiled with C++11 enabled.
Both are compiled and linked with the same GCC version/environment.
The application has some function calls to the library which use std::string and std::vector.
both std::string and std::vector support move semantics which most likely mean they are not binary compatible with wth non C++11 variants. However both the application and library are build with the same compiler and standard libraries, so it would not be so strange if the lib would recognize this and support it.
Is the above situation safe, or would it be really required to compile everything with the C++11 flag, even if the same build environment is used ?

This page is dedicated to g++ abi breaks with c++11 up to version 4.7.
The first sentence there is:
The C++98 language is ABI-compatible with the C++11 language, but several places in the library break compatibility. This makes it dangerous to link C++98 objects with C++11 objects.
Though there are examples, where enabling c++11 won't brake ABI compatibility: one example is Qt where you can freely mix c++11 enabled builds with c++03 builds.

You can consider each translation of C++ by a different compiler (even if the compiler is the same, but has a different (minor) version) incompatible. C++ has no common application binary interface (ABI).
In addition, a change of the dialect supported by the compiler is a change of the ABI, hence the resulting libraries are incompatible. An obvious example is a release build vs. debug build, where the debug data structures introduce additional members.
And moving structures (C++11) or not moving structures ( < C++11) is a radical change of the ABI.

Related

Please explain the C++ ABI

The common explanation for not fixing some issues with C++ is that it would break the ABI and require recompilation, but on the other hand I encounter statements like this:
Honestly, this is true for pretty much all C++ non-POD types, not just exceptions. It is possible to use C++ objects across library boundaries but generally only so long as all of the code is compiled and linked using the same tools and standard libraries. This is why, for example, there are boost binaries for all of the major versions of MSVC.
(from this SO answer)
So does C++ have a stable ABI or not?
If it does, can I mix and match executables and libraries compiled with different toolsets on the same platform (for example VC++ and GCC on Windows)? And if it does not, is there any way to do that?
And more importantly, if there is no stable ABI in C++, why are people so concerned about breaking it?
Although the C++ Standard doesn't prescribe any ABI, some actual implementations try hard to preserve ABI compatibility between versions of the toolchain. E.g. with GCC 4.x, it was possible to use a library linked against an older version of libstdc++, from a program that's compiled by a newer toolchain with a newer libstdc++. The older versions of the symbols expected by the library are provided by the newer libstdc++.so, and layouts of the classes defined in the C++ Standard Library are the same.
But when C++11 introduced the new requirements to std::string and std::list, these couldn't be implemented in libstdc++ without changing the layout of these classes. This means that, if you don't use the _GLIBCXX_USE_CXX11_ABI=0 kludge with GCC 5 and higher, you can't pass e.g. std::string objects between a GCC4-compiled library and a GCC5-compiled program. So the ABI was broken.
Some C++ implementations don't try that hard to have compatible ABI: e.g. MSVC++ doesn't provide such compatibility between major compiler releases (see this question), so one has to provide different versions of library to use with different versions of MSVC++.
So, in general, you can't mix and match libraries and executables compiled with different versions even of the same toolchain.
C++ does not have an ABI standard as of yet. They are attempts to have it in the standard; You can read following it explains it in details:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2028r0.pdf

Can I give the C++ header file using Pimpl or do I have to flatten with C built-in types? [duplicate]

Suppose we have a shared library which accepts or returns some kind of std class:
//lib.h
#include <vector>
std::vector<int> returnSomeInts();
//lib.cpp
#include "lib.cpp"
std::vector<int> returnSomeInts() {
return {1, 3, 5};
}
So, obviously, when compiling the shared library lib.so, this code had to be compiled against a particular version of the standard library, for instance with -std=c++11.
Now imagine we have an application which will be using our shared library, but it will be compiled against a newer std library, for example -std=c++2a
//app.cpp
#include <lib.h>
int main()
auto v = returnSomeInts();
//Process v
}
As the standard library defines inline classes, if the layout of the class members changes, ABI compatibility gets broken, so the code above would not work properly.
My questions are: Is there any guarantee for ABI stability with the common implementations of the the std library when compiling against the same header using different c++ standards? And when compiling against different header versions (libstdc++-8 and libstdc++-9 for example)?
PD: The code above is just an example, I am not referring specifically to std::vector
ABIs in practice are not linked to the standard, for example consider this following code compiled with gcc 4.9.4 and gcc 5.1
using the same flags:
-std=c++11 -O2
#include <string>
int main(){
return sizeof (std::string);
}
gcc 4.9.4 returns 8 from main, gcc 5.1 returns 32.
As for guarantees: it is complicated:
Nothing is guaranteed by the standard.
Practically MSVC used to break ABI compatability, they stopped (v140,v141,v142 use the same ABI), clang/gcc have a stable ABI for a long time.
For those interested in learning more:
For a broad discussion of ABI/C++ standard that is not directly related to this question you an look at this blog post.
Your example with std::vector is not a problem. As other answer points out compilers maintain compatibility and std::vector is quite old.
Problem can be new library features of newer C++ standard is used.
For example I have some product which uses C++17 languages features. My product supports MacOS 10.13. I can build my project using C++17 (language features), but I can't use for example std::optional since some methods are throwing std::bad_optional_access which is part dynamic library and this is not supported/present in MacOS 10.13. Clang warns me about that (reports an error).
Same applies on other system (clang nicely controls that). So when you use some library features you need make sure that libraries on deployed system supports that (on Linux package managers handle that nicely if system doesn't have access to required package version installation will fail). On Windows 10 AFAIK Windows update keeps newest version of msvc redistributable, older versions of Windows need manual updates.
Note that many templates are becoming part of your executable and do not have dependencies to shared standard library. Those will not create problems.
These are the kinds of question that the standard doesn't answer, it is down to individual implementers how long they keep compatibility for and which (if any) compiler flags affect compatibility.
In practice libstdc++ on Linux has tried very hard to keep a stable ABI for quite a long time now. The soversion has remained at 6 for around 15 years now.
However there have been some changes, most notable were those introduced with g++-5.1 related to std::list and std::string. New requirements in c++11 meant that to be compliant libstdc++ needed to make breaking changes to the ABI of those classes.
g++'s solution was to define two versions of those classes. To allow both types to coexist in the same shared library they are defined with different names, so the old std::list is defined as std::list while the new std::list is defined as std::__cxx11::list and then aliased as std::list. Which definition is used in a given source file is controlled by a preprocessor macro.
Note that the setting of said preprocessor macro is independent of the -std= setting, you can use the compiler in c++11 mode with the old string/list implementation (in which case it won't be fully compliant with the standard) or you can use the compiler in c++03 mode with the new string/list implementations.
The default value of the macro (if not set explicitly by the user) depends on compiler version and can also be overridden by distribution maintainers.
The trouble is while this solves the problem for libstdc++ it doesn't solve it for all the other libraries. If a program was built with the new implementations while a library was built with the old ones or vice-versa and the library used std::string or std::list in it's API, then the likely outcome was a link failure (it was also possible but less-likely for the linking to succeed but the program to be silently broken). In Debian at least this lead to a massive set of library transitions (it would not surprise me if it was the largest in the project's entire history).

Can I use a library developed in c++11 in c++17 code?

I'm working on a c++ project and I use c++17 as c++ standard. I've some library dependencies which has been developed using c++11. Are there any obstacles in using this library? Do I need to recompile it using c++17 in order to make sure I can use it in my project? I'm using Clang as compiler in my code and the library has been compiled using g++ .
Edit: If I use g++ in both library and my code is there any obstacle in terms of different c++ standards (std11 vs std17)?
Many Thanks,
In general, you should be able to use a C++11 library in C++17 code.
But, you need to remember that C++ does not have a standardized ABI. So the source may be compatible, but any pre-compiled artifacts are likely not.
You have source compatibility, not binary compatibility. This means that - as a rule - you must compile all parts of your project with the exact same compiler. You cannot (as a rule) re-use a library compiled with a different or older compiler with code you compile with a different (or newer) one.
But you should be able to compile that C++11 code with your C++17 compiler (in most cases - there are exceptions).

How do I make a C++ (shared) library compatible with clang and GCC?

I've written a fairly substantial C++11 library, and I'm planning to allow download of pre-compiled versions from my website.
So I've set up an automated build which compiles the library with clang and make it available for download, but this has exposed a problem: if I try to use the clang-compiled library with GCC I get undefined references (mainly related to std::string). I think this is related to the GCC dual-ABI changes in GCC 5.1 but I'm not sure how to fix it.
My question is, what flags should I set, or practices should I follow to make a C++ library compatible with both clang and GCC?
Or should I give up and compile two separate libraries?
As already mentioned in several places (eg. here) libc++ is not fully binary compatible with libstdc++.
There are several options, but some of them are somewhat not-so-straightforward.
Compile two separate libraries - always working solution.
Remove incompatible containers from your interface (eg. std::string) - but this might be lot of work and sometimes not a good idea.
Instruct your library GCC users that you link with libc++ and that they need to do the same, basic steps here. But I guess most GCC users do not want to do this.
Use clang with libstdc++ using -stdlib=libstdc++ flag to be compatible with libstdc++ (as suggested in other answer). This solution might be harder to setup on some platforms though.
I would suggest as already mentioned in comments to go with option 1.
There are several options:
Don't distribute it in binary form. Instead, make it easy to build everywhere (e.g. by using CMake, or autotools or ...)
Make it header only. This is by far the simplest solution but might not be what you want. It only really makes sense for templated code, and incurs a heavy impact on compile-time performance of your library.
Tell people to link with libstdc++ when using Clang and your library. Suboptimal solution (I for one like to check my code against libc++ as well as libstdc++), but (virtually) every Linux user has libstdc++ installed anyway. Make sure to pick a slightly older version (the one shipped in the latest Debian Stable distro is a good choice), because newer versions might introduce new symbols olders versions are missing. New versions should be ABI compatible anyway.
Note the situation for Visual Studio users is even worse, where every single compiler release mandates a new binary because they guarantee absolutely nothing with respect to the C++ libraries' or compiler's ABI.
Another option is for your shared library to not expose any C++ standard library types in its interface. And have a header file supplied with your shared library that converts std::string to types consumed by your library, such as struct my_string_span { char const *begin, *end; }; and other standard containers as necessary.

Interoperability between Boost and C++11

What is the extent of interoperability between C++11 and a recent version of Boost (say 1.55) built with a C++11 compiler.
Does the behavior of any library feature change depending on whether I built the libraries with c++11 flags enabled or not?
How do language features like lambda functions cooperate with Boost's lambdas?
You cannot use objects built with gcc with and without -std=c++11 together. You will get link errors or even runtime crashes. I cannot vouch for other C++ implementations. So at least with gcc, you do need to build a separate version of Boost with c++11 mode enabled.
They are pretty much independent. They don't cooperate and don't interfere with each other.
EDIT I see people are still reading (and upvoting!) this answer. Point 1 is no longer true (or perhaps never was true). Versions of gcc from I think 5.1 upwards use an ABI compatible with -std=<anything> by default.
No behaviours change: at the code level Boost is compatible with both C++03 and C++11.
However, at the object level you won't be able to mix and match: if your program is compiled as C++11, and you're using some non-header Boost libraries, you will have to build those Boost libraries as C++11 as well. This is because the respective C++ runtimes of your toolchain for each version of the language cannot be guaranteed to have ABI compatibility.