What is a good way of checking for the presence of specific C++11 features of the standard library.
For compiler features I just went by the way of checking the compiler version for the (IMHO) major compilers (VC++, gcc, clang at the moment, maybe Intel) Although this is not the best and most flexible approach, I don't know of anything better yet, except for clang which has the really nice __has_feature macros.
But it's even worse for library features, which are not coupled that rigidly to the compiler. At the moment I want to use the same approach of checking the compiler version for VC++ (where it's pretty easy, assuming it uses its own library). For clang I can at least use __has_include for large-scale header-based queries. Other than that I guess checking __GLIBCXX__'s value if defined might be a good idea, but then again I cannot find any information of what specific libstdc++ versions introduced which features, other than what the current version supports.
The methods should be kept to preprocessor checks and the like, since I want to use it in a header-only library without any sophisiticated configure procedure and without using any third-party libraries (and yes, boost is third-party).
So what are my possibilities of checking for specific C++11 library features under those (pretty narrow) conditions. Maybe even on the scale of particular functions or types being declared?
If checking for the compiler or library version is still the best approach, where can I find detailed information about the particular C++11 features supported by a specific version of libstdc++ (and maybe other important ones, libc++ perhaps)?
FWIW at the moment I'm interrested in <cstdint>, C++11 <cmath> functions and std::hash, but this may change and is probably not of importance for the general approach.
There is really nothing nice you can do here besides knowing which compiler in which version implements what and have the proper defines in place.
gcc has a special table for library functionality. The main problem of __has_include are of course additions to the standard that live in old includes. libstdc++ also has the necessary includes, but that doesn't mean the necessary define to enable the content of those files. It also wont tell you anything about the actual amount of available implementation (which sometimes is incomplete).
As you have a header-only library this doesn't apply to you, but is still important: binary incompatibility between C++11 and C++03 can come back and bite you.
I seriously wouldn't approach any of that on my own and rather use Boost.Config. Originally it only described language features but has now expanded to standard library headers.
You could write autoconf macros to check, and if you do, submit them to http://www.gnu.org/software/autoconf-archive/
The only relevant one so far checks for complete coverage, not for individual features: http://www.gnu.org/software/autoconf-archive/ax_cxx_header_stdcxx_0x.html#ax_cxx_header_stdcxx_0x
But that fails the requirement for no complicated configure checks.
Other than that I guess checking __GLIBCXX__'s value if defined might be a good idea,
Looking at the value of __GLIBCXX__ is not useful, it contains the date the version was released which tells you almost nothing about the version (e.g. 4.6.3 is released after 4.7.0 so has a later date in __GLIBCXX__ but has fewer C++11 features.) When using libstdc++ with GCC you want to use the general GCC version numbers in __GLIBC__ and __GLIBC_MINOR__ for checking versions (in general you can only use a given version of libstdc++ with the GCC release it came with.)
Edit: Starting with GCC 7 there is a new macro defined by the libstdc++ headers, _GLIBCXX_RELEASE, which is defined to the same value as GCC's __GNUC__, but is still usable even when using the libstdc++ headers with non-GCC compilers.
but then again I cannot find any information of what specific libstdc++ versions introduced which features, other than what the current version supports.
The libstdc++ C++11 status tables for previous releases are available online where all GCC docs live: http://gcc.gnu.org/onlinedocs/
For 4.7 it's at http://gcc.gnu.org/onlinedocs/gcc-4.7.1/libstdc++/manual/manual/status.html#status.iso.2011 and for 4.6 it's at http://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/manual/manual/status.html#status.iso.200x and for previous releases is included with the source (but the coverage in pre-4.6 releases is pretty patchy anyway.)
Some added features are listed in the release notes for each version, e.g. http://gcc.gnu.org/gcc-4.7/changes.html (in the libstdc++ section)
Edit: For C++17 library support we now list which version first added the feature, so you only need to look at the latest docs: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.201z
FWIW at the moment I'm interrested in <cstdint>, C++11 <cmath> functions and std::hash
They should be present in all versions of libstdc++ that have any C++0x/C++11 support.
Related
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).
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.
When I am compiling my code with C++11 support (using the -std=c++11 flag) and use non-header-only Boost libraries, then I need to have Boost compiled with -std=c++11. This is because Boost has some interface differences in header files when C++11 is enabled, and some function signatures are different for the different C++ standards.
My question is whether the same is true with C++14 (using g++ 4.9, with the `-std=c++1y flag), or is it safe to use Boost compiled with C++11 for a program compiled with C++14?
This is a very broad question that is difficult to answer definitively, because
Boost is a federation of libraries, many of which are over decade old
there are quite a lot of backward compatibilities that could in principle happen, some detected by the compiler, and some only by unit tests
many Boost libraries are actually C++98 implementations of C++11/14 features (both library and compiler functionality), so that you would not need to use this in a C++11/14 project.
Boost itself is very much debating at which pace the library should be updated to C++11/14, whether V2 versions of libraries should be written that fully take advantage of C++11/14, and even whether new C++11/14 libraries should offer backward C++98 compatibility
You might want to closely read your compiler errors (if any) and compare them to the list of breaking changes listed below. Furthermore, I would recommend following the Boost test harness for finding suspect compiler/library combinations that apply to your system.
Some relevant Q&A's here:
What breaking changes are introduced in C++11?
What changes introduced in C++14 can potentially break a program written in C++11?
Relevant boost features vs C++11
How well does boost use 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.
How do I check for presence of individual C++0x/C++11 language features? I know Clang has a nice system for this. What about GCC, Visual Studio or Boost? I guess one way to do it is to detect the compiler version and relate that to the features introduced in that version. But that is cumbersome. Has someone already done that?
boost config comes with a script to check for some but not all C++11 features.
It generates a config-file with macros for each feature.
Your build-tool may be able to help with this.
CMake has the try_compile command which allows you to test whether a code sample will compile and set a variable based on the result of compilation.
At the moment I've just been using the more commonly supported features such as auto typing.
You can often use Boost to replace the missing library features, and this may be the best option for a few year while compilers and libraries are updated and bugs fixed.
The C++11 feature compatibility list for GCC is here: http://gcc.gnu.org/projects/cxx0x.html
Note the warning:
Important: GCC's support for C++11 is still experimental. Some features were implemented based on early proposals, and no attempt will be made to maintain backward compatibility when they are updated to match the final C++11 standard.