Is it possible to enforce a C or C++ language standard for just part of a source file? I want to ensure that my source file is C90 compliant, but it depends on some headers that require C99. The compliance of those headers isn't important to me right now (I can compile with C99 for the time being), but I want to minimize effort required to port my code to a more restrictive platform in the future.
In short, I want a language standard to apply to the entire file except for the included headers. Given how header inclusion works in C and C++, I figure that the general problem is to apply a language standard to an arbitrary portion of a given source file.
I'm working with GCC in particular, but I'm also curious if this is possible with other compilers (msvc, clang).
If you want to make sure your code is C90 compatible while still relying on headers that use C99, you can enable the GCC warning flag -Wc90-c99-compat. This allows you to use C99 features, but emits a warning wherever you use features not available in C90. To avoid generating these warnings in your header files (which are presumably correct), enable the warning using a pragma, after you include the files.
This will basically achieve what you want. The warnings will only be emitted for the code you specify.
#include "myheader.h"
#pragma GCC diagnostic warning "-Wc90-c99-compat"
void func(void) { ... }
A stricter version would be to use:
#pragma GCC diagnostic error "-Wc90-c99-compat"
As far as I know, Clang is mostly compatible, but MSVC doesn't really support C99 that well to begin with so you're on your own.
No. You cannot build a file (compilation unit) as partly one language standard and partly another.
What you can do however is split the file into two files and compile each of them using different language standards (just be sure that it is then still well defined to link both object files afterwards).
A better solution would be to ensure that all the code complies with the newer or older language standard and then just use that.
Related
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 would like to use thread_local keyword in my project. However, not all the compiler that supports -std=c++11 supports thread_local. Can I know whether there's a way to determine whether thread_local is supported on compile time? I tried googling it but didn't find the answer.
However, not all the compiler that supports -std=c++11 supports thread_local.
According to this reference they need to, to be c++11 standard compliant.
So your question basically boils down to determine if parts of your code are compiled with the -std=c++11 option or not, which is already well answered here.
If you see differences with particular OS environments/C++ Compiler implementations, I'd recommend to run a pre-compilation script, that probes for particular compiler capabilities, and generate a config.h header for you.
Including this header can be used to determine, if particular features are available and you can place appropriate
#if defined(FEATURE)
// feature specific code
#else
// plain code
#endif
in your header and source files.
To support the latter option I have introduced, there are the GNU automake tools, which support to generate such probing script. It's available to support a broad variety of target platforms.
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.
I'm working on a utility that needs to be able to compile on both standard C++ compilers and pre-standard compilers. The code can and will be thrown at just about any C++ compiler in existence.
I am looking for a means to robustly and portably determine whether the target compiler supports header files with or without an .h extension. I will also need to detect whether namespaces are supported. Both of these needs may or may not be possible.
A little background: The utility is the Inline::CPP language extension for Perl. The extension automatically includes <iostream>, and tries to make a good guess whether a '.h' is required or not (and of course whether or not the compiler supports namespaces). But it's far from perfect in that regard, and this issue is diminishing the breadth of the utility's usefulness.
So to reiterate the question: How do I portably detect whether a compiler supports standard headers such as <iostream>, or pre-standard headers such as <iostream.h>?
Not in the code, but in the build/configure system. For example in CMake, you could use try_compile and provide it a sample file.
...
try_compile(PRE_STANDARD_HEADERS tmp_builds pre_standard_headers_test.cpp)
if ( ${PRE_STANDARD_HEADERS} )
add_definitions( -D PRE_STANDARD_HEADERS )
endif()
You'd need to make that pre_standard_headers_test.cpp .. just a simple compilable exe that #include <iostream.h> for example.
Then in your normal code just an
#ifdef PRE_STANDARD_HEADERS
would do the trick.
The standard approach for Linux and other Unix-friendly platforms is to use a configure script. The script will generate as its output a Makefile and a config.h header file that turns on or off any compiler features that your code could rely on when available.
For Windows it is kind of expected that you will provide solution and project files for Visual Studio, with a pre-generated config.h header file.
Are header files standard or different in gcc vs other compilers?
Its not really clear what you are asking, but the "standard" header files are only standard in the sense that they (should) meet the C/C++ standard (as specified by the governing body, e.g. ANSI, etc.)
Different compilers often meet these standards through different implementations, at least when the standard allows them to do so.
In other words, you should only rely on the behavior that is specified in the standard, as specific implementations may vary slightly.
Standard header files are called so, because they are defined as a part of ANSI C/C++ standard, an so, they will be the same for all compilers, that are ANSI-compliant.
I hope I understand your question but here's my go.
Header files (.h) that go along with a .cpp file to create a class are how you do things in C++.
For most cases, a SomeClass.h will prototype the class, and the SomeClass.cpp will contain the code necessary for the class to work.
If for some reason GCC does something very different for compilation, then I have no idea. I assume it's the same idea for any compiler.
The concept of header files, outside of the standard ones required for the standard library, is not specified by the standard. But using #include to specify files to import is. So that is standard, as well as the general order the compiler searches for those files. And the #ifndef BLAH method for avoiding multiple inclusion is also mandated by the standard, insofar as the behavior of the preprocessor is well defined (although as I said, the standard is silent on whether or not you use them at all). #pragma once is not standard, though, so use it at your own risk.
You may find minor variations between different compiler suites. But more significantly, you will find a variety of libraries and header files across different platforms. For instance, GCC is often found on POSIX systems, so it's quite common to find, say, <pthread.h>, whenever __GNUC__ is pre-defined. This leads to assumptive code like the following:
#ifdef __GNUC__
#include <pthread.h>
#else
#include <windows.h>
#endif
If in doubt, favor the C++ Standard Library when using C++ and the C Standard Library when using C. (But continue to expect a few niggling inconsistencies caused mostly by different compiler versions.)
Also, test that your code builds and runs on different systems. If it works using Visual Studio under Windows and GCC under Linux, you can be somewhat assured that porting your code to other systems will be straight-forward.