I'm currently using gcc 4.8.2 with no std option to compile my c/c++ code.
Now I would like to use some of the new C/C++ features that are provided by the newer language versions of c/c++.
(Un?)Fortunately gcc understands many flavors of C/C++:
c90, c99, c11, gnu90, gnu99, gnu11
c++98, c++03, c++11, gnu++98, gnu++03, gnu++11
Currently I'm asking myself:
Do I need for every c/c++ version a separate library or is it possible to use one library for multiple C/C++ versions?
Especially can I link a libary compiled with a specific c/c++ version, when I use the corresponding c/c++-version with the gnu extensions?
Clarification (based on the comments)
Please note, that I'm using just one compiler. Not two gcc's that only differ in the revision number.
I'm only asking for ABI incompatibilities between the different std-options, when using only one gcc compiler.
In general:
No you can't combine different language versions in the same program, this will cause "One Definition Rule" violations in many library headers.
You may find in limited cases that a few classes actually don't change with the language version. However this is rare, rvalue references are required by the C++11 Standard, and not available in C++03 mode at all.
As for versions with and without support for GNU extensions, you're likely to have more success, but you will still need to run each header through the preprocessor and verify that the exact same sequence of tokens is seen by the compiler using both options.
And that's completely apart from ABI changes, that could cause memory layout or name mangling to differ between compiler variants.
You can also avoid one-definition rule violations on your own public APIs by avoiding using any version and language-specific features. Essentially, this means a flat C API.
Related
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
My understanding is that the function std::isnan is only available from C++11 onwards. Further, g++ uses -std=gnu++98 unless specifically told not to.
So why does this compile?
>> cat test.cpp
#include <cmath>
int main(int argc, char** argv)
{
return std::isnan(0);
}
>> g++ test.cpp
Is there a flag to take the function out of <cmath>?
Compiler developers are lazy about exactly removing every feature that should only be available in the next version of the standard, especially when related libraries (C99) have it at the same time.
The utility (of validing your code actually obeys a specific standard) is not high enough for compiler writers to work extremely hard at making their compiler provide that service.
Instead, what usually happens is new features are implemented under specific standard flags. Sometimes they are accidentally backported. When the standard finalizes, the partial implementation exists for a while until it gets good enough.
Then work starts on the next version of the standard. The next version flag gives you a less stable development environment, as new features are tried out and discarded and changed.
Some effort it put into not backporting stuff, but it isn't a showstopper.
This is a long-standing issue, documented in the FAQ but in a way that you wouldn't necessarily be able to make sense of.
4.3. _XOPEN_SOURCE and _GNU_SOURCE are always defined?
On Solaris, g++ (but not gcc) always defines the preprocessor macro _XOPEN_SOURCE. On GNU/Linux, the same happens with _GNU_SOURCE. (This is not an exhaustive list; other macros and other platforms are also affected.)
These macros are typically used in C library headers, guarding new versions of functions from their older versions. The C++98 standard library includes the C standard library, but it requires the C90 version, which for backwards-compatibility reasons is often not the default for many vendors.
More to the point, the C++ standard requires behavior which is only available on certain platforms after certain symbols are defined. Usually the issue involves I/O-related typedefs. In order to ensure correctness, the compiler simply predefines those symbols.
Note that it's not enough to #define them only when the library is being built (during installation). Since we don't have an 'export' keyword, much of the library exists as headers, which means that the symbols must also be defined as your programs are parsed and compiled.
To see which symbols are defined, look for CPLUSPLUS_CPP_SPEC in the gcc config headers for your target (and try changing them to see what happens when building complicated code). You can also run g++ -E -dM - < /dev/null" [sic] to display a list of predefined macros for any particular installation.
This has been discussed on the mailing lists quite a bit.
This method is something of a wart. We'd like to find a cleaner solution, but nobody yet has contributed the time.
To explain:
glibc is what provides the standard C library. It supports several modes.
It supports various strict C modes and strict POSIX modes. In these modes, when only standard headers are included, only standard functions are available. In C90 mode, this does not include isnan.
It supports various extension modes. In these modes, non-standard functions are also available. In C90 + extensions mode, this includes isnan. The _GNU_SOURCE preprocessor macro is the one that enables all extensions.
libstdc++ is what provides the standard C++ library. It requires more from glibc than what strict C90 mode offers. Therefore, there are only two options: either libstdc++ does not offer those standard C++ features it cannot provide, or libstdc++ forcibly enables glibc's extensions even in strict ANSI mode. Both mean a failure to conform to the C++ standard, but the former restricts features, while the latter provides them. The latter is seen as the lesser evil.
The only reasonable way to fix this is for glibc to provide some non-standard way to access its extensions even in strict ANSI mode. No such way exists yet, and until such a way is created, non-standard names will be available even in meant-to-be-standard C++ compilation modes.
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.
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.
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.