Clang on Windows: how to disable the default MSVC compatibility? - windows

From Clang's documentation:
When Clang compiles C++ code for Windows, it attempts to be compatible with MSVC.
In particular, Clang defines _MSC_VER.
MSVC does not support #pragma STDC FENV_ACCESS ON:
cl t125.c /std:c11
t125.c(11): warning C4068: unknown pragma 'STDC'
Instead MSVC does support #pragma fenv_access (on). This leads to this code:
#if _MSC_VER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
Now try to compile this code using the latest Clang on Windows:
$ /cygdrive/d/SOFTWARE/LLVM/12.0.0/bin/clang t125.c -Wall -Wextra
t125.c:10:9: warning: unknown pragma ignored [-Wunknown-pragmas]
#pragma fenv_access (on)
Meaning that since #pragma fenv_access (on) is unknown pragma which is ignored, then the MSVC compatibility is underdone / unfinished? Confused.
Question: how to disable the default MSVC compatibility (so that Clang does not define _MSC_VER)?
P.S. This finally leads to this code:
#if _MSC_VER && ! __clang__ && ! __INTEL_COMPILER
#pragma fenv_access (on) /* true MSVC here?? */
#else
#pragma STDC FENV_ACCESS ON
#endif
UPD. Patch for supporting the MS spelling of the pragma: https://reviews.llvm.org/D111440.

how to disable the default MSVC compatibility (so that Clang does not define _MSC_VER)?
Adding either -fms-compatibility-version=0 or -fmsc-version=0 switch should prevent _MSC_VER from being defined. This and a few other related VC++ compatibility options are documented on the Clang command line argument reference page under Target-independent compilation options.
-fms-compatibility, -fno-ms-compatibility
Enable full Microsoft Visual C++ compatibility
-fms-compatibility-version=<arg>
Dot-separated value representing the Microsoft compiler version number to report in _MSC_VER (0 = don’t define it (default))
-fms-extensions, -fno-ms-extensions
Accept some non-standard constructs supported by the Microsoft compiler
-fms-memptr-rep=<arg>
-fms-volatile
-fmsc-version=<arg>
Microsoft compiler version number to report in _MSC_VER (0 = don’t define it (default))

Related

Pragma for not generating unneeded symbols in binary

I have a Ruby C file (a ruby gem) that prints system information. When I run rake install, it compiles the C code. My C code has pragmas like:
#if defined(__GNUC__) && !defined(__llvm__)
#pragma GCC optimize ("O3")
#pragma GCC diagnostic warning "-Wall"
#elif defined(__clang__)
#pragma clang optimize on
#pragma clang diagnostic warning "-Wall"
#endif
I would like to have a pragma that will work as an alternative to strip --strip-unneeded ~/.gem/ruby/2.7.0/gems/linux_stat-0.8.0/ext/fs_stat/fs_stat.so, because the user of this gem is say heroku, or maybe a container and I want the pragma to do that.

Cannot temporarily disable unknown-pragmas warning in GCC

I cannot make the method to temporarily disable warnings in GCC (see How to disable GCC warnings for a few lines of code) work, at least not for the "unknown-pragmas" warning.
Compiling this code ...
#pragma comment(user,"This should depend on the command line options")
#pragma GCC diagnostic warning "-Wunknown-pragmas"
#pragma comment(user,"This should cause a warning")
#pragma GCC diagnostic error "-Wunknown-pragmas"
#pragma comment(user,"This should cause an error")
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma comment(user,"This should be ignored")
... produces either no warning/error (except that the linker complais about a missing main), or when using -Wall or just -Wunknown-pragmas it produces one warning for each of the comment pragmas.
The behaviour that I would have expected is that each comment should have caused exactly what the comment says.
I think I can back my expectation with the documentation:
At the moment only warnings (normally controlled by ‘-W...’) can be controlled, and not all of them. Use -fdiagnostics-show-option to determine which diagnostics are controllable and which option controls them.
The warnings I get show as
warning: ignoring #pragma comment [-Wunknown-pragmas]
and as the part in brackets tells us,
this diagnostic is controllable
and the option -Wunknown-pragmas controls it
Hence my code should work.
So what am I doing wrong?
version info:
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
This is a long-standing missing feature in the GCC C++ front end:
C++ preprocessor ignores #pragma GCC diagnostic
Warnings generated by preprocessing cannot be controlled using programs in g++. Unlike the C front end, pragmas are processed only after the preprocessing phase in the C++ front end.

Test for C++11 in GCC 4.6

This fails to compile under GCC 4.6:
#if __cplusplus >= 201103L
#include <ratio>
#endif
__cplusplus should be set to "1" in GCC 4.6 according to this bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773
How should I test for C++11 support in GCC 4.6?
EDIT: I want to use Boost ratio when built with GCC 4.6 and std ratio with GCC 4.8 and -std=c++11. The rest of the code is ready for this, it's just this include that fails to compile.
Since even compilers which theoretically support this or that standard version can have bugs, it's better to rely on specific versions which are known to produce valid results.
In G++, you can do:
#if __GNUC__ == 4 && __GNUC_MINOR__ >= 9
// use C++11 features
#else if __GNUC__ == 5
// use C++11 features
#else
// maybe don't use some features
#endif
Just try to compile this program:
int main()
{
auto i = 0;
return 1;
}
using the command g++ -std=c++11 -c filename.cpp in your command line. auto is c++11 feature, so if that compiles with no errors, it means your compiler has support for C++11.
But in general, for gcc, before version 5.1, support for C++11 was experimental. So not until version 5.1 that gcc supported everything C++11 has to offer.

No type named 'unique_ptr' in namespace 'std' when compiling under LLVM/Clang

I'm catching a compile error when attempting to use unique_ptr on Apple platforms with -std=c++11:
$ make
c++ -std=c++11 -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c 3way.cpp
In file included ...
./smartptr.h:23:27: error: no type named 'unique_ptr' in namespace 'std'
using auto_ptr = std::unique_ptr<T>;
~~~~~^
./smartptr.h:23:37: error: expected ';' after alias declaration
using auto_ptr = std::unique_ptr<T>;
According to Marshall Clow, who I consider an expert on the C++ Standard Library with Clang and Apple:
Technical Report #1 (TR1) was a set of library additions to the C++03
standard. Representing the fact that they were not part of the
"official" standard, they were placed in the namespace std::tr1.
In c++11, they are officially part of the standard, and live in the
namespace std, just like vector and string. The include files no
longer live in the "tr1" folder, either.
Take aways:
Apple and C++03 = use TR1 namespace
Apple and C++11 = use STD namespace
Use LIBCPP_VERSION to detect libc++
Now, here's what I have in smartptr.h:
#include <memory>
// Manage auto_ptr warnings and deprecation in C++11
// Microsoft added template aliases to VS2015
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif // C++11
I think the last thing to check is the __APPLE__ define, and here it is:
$ c++ -x c++ -dM -E - < /dev/null | grep -i apple
#define __APPLE_CC__ 6000
#define __APPLE__ 1
#define __VERSION__ "4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)"
#define __apple_build_version__ 5030040
Why am I receiving a error: no type named 'unique_ptr' in namespace 'std' when using -std=c++11?
I think these are the four test cases. It attempts to exercise the four configurations from the cross product of: {C++03,C++11} x {libc++,libstdc++}.
c++ -c test-clapple.cxx
OK
c++ -stdlib=libc++ -c test-clapple.cxx
OK
c++ -std=c++11 -c test-clapple.cxx
FAIL
c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
OK
Here is the test driver. Be sure to test it on OS X so you get the full effects of the TR1 namespace in 2015.
$ cat test-clapple.cxx
// c++ -c test-clapple.cxx
// c++ -stdlib=libc++ -c test-clapple.cxx
// c++ -std=c++11 -c test-clapple.cxx
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
#include <memory>
// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif // C++11
int main(int argc, char* argv[])
{
return argc;
}
And the CFE Devs specifically told me to use that code;
No they didn't. They told you to do something similar if you want to use shared_ptr, because for C++03 <tr1/memory> defines std::tr1::shared_ptr and for C++11 <memory> defines std::shared_ptr.
But you're not using shared_ptr. If you want to use auto_ptr then it's just std::auto_ptr, everywhere, which is always defined in <memory>.
I think you've misunderstood Marshall's comment and you're overcomplicating things. What you quoted ('In c++11, they are officially part of the standard, and live in the namespace std, just like vector and string. The include files no longer live in the "tr1" folder, either.') is not Apple-specific or Clang-specific, it applies to all compilers. But since auto_ptr was never part of TR1 and never in <tr1/memory> it's irrelevant that the contents of TR1 are now in namespace std, because what you're trying to use was never included in TR1.
You should not be using TR1 at all here.
# include <memory>
// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif // C++11
This should be correct for modern compilers, but won't work on the stupid configuration that comes with XCode, which is a modern version of Clang that supports C++11 and the libstdc++ from GCC 4.2 which is nearly ten years old and doesn't support unique_ptr.
To cope with the default OS X toolchain this works:
#include <memory>
#if __cplusplus >= 201103L
# ifdef __clang__
# if __has_include(<forward_list>)
// either using libc++ or a libstdc++ that's new enough to have unique_ptr
# define HAVE_UNIQUE_PTR 1
# endif
# else // not clang, assume unique_ptr available
# define HAVE_UNIQUE_PTR 1
# endif
#endif
#ifdef HAVE_UNIQUE_PTR
template<typename T> using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif
This works by using the presence of <forward_list> as an indicator of whether the standard library clang is using supports std::unique_ptr.
If clang is using libc++ as its standard library then all versions support unique_ptr and also provide <forward_list>, so the test passes.
If clang is using libstdc++ then whether unique_ptr is supported depends on the libstdc++ version. unique_ptr was added to libstdc++ in GCC 4.3, which is the same version that added <forward_list>, so if that header is available then unique_ptr will be too. If you are using clang with the ancient libstdc++ that ships with the Apple toolchains (from GCC 4.2) then unique_ptr is not supported, but neither is <forward_list>, so the test fails and you use auto_ptr instead.
That should work for any GCC/libstdc++, Clang/libc++ or Clang/libstdc++ combination found in the wild. I don't know what is needed for VC++/Dinkumware and Clang/Dinkumware, from your answer it looks like maybe you would just change the first condition to:
#if __cplusplus >= 201103L || _MSC_VER >= 1600

pragma ignored in g++ and clang

I would like to disable specific known warnings in C++ code coming from a library header when compiling my own code. There are clang and gcc specific methods for disabling the warnings. The way this is done is almost identical.
For clang:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#include <library.h>
#pragma clang diagnostic pop
For gcc:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <library.h>
#pragma GCC diagnostic pop
Is there a clean way to suppress these warnings that is portable across clang and GCC?

Resources