user warnings on msvc AND gcc? - gcc

In MSVC I have this in a header:
#define STR(x) #x
#define STR2(x) STR(x)
#define NOTE(text) message (__FILE__ "(" STR2(__LINE__) ") : -NOTE- " #text)
#define noteMacro(text) message (__FILE__ "(" STR2(__LINE__) ") : " STR2(text))
and I do
#pragma NOTE(my warning here)
GCC has:
#warning(my warning here)
However MSVC (2003) throws a fit when it sees #warning and gives "fatal error C1021: invalid preprocessor command 'warning'"
What can I do about this? Is there a way to have GCC recognize MSVC warnings or MSVC not throw an error on GCC warnings? Is there something I can do that works on both? I can have GCC warn me about unknown pragmas but that's not the most ideal solution.

The best solution I've found for this problem is to have the following in a common header:
// compiler_warning.h
#define STRINGISE_IMPL(x) #x
#define STRINGISE(x) STRINGISE_IMPL(x)
// Use: #pragma message WARN("My message")
#if _MSC_VER
# define FILE_LINE_LINK __FILE__ "(" STRINGISE(__LINE__) ") : "
# define WARN(exp) (FILE_LINE_LINK "WARNING: " exp)
#else//__GNUC__ - may need other defines for different compilers
# define WARN(exp) ("WARNING: " exp)
#endif
Then use
#pragma message WARN("your warning message here")
throughout the code instead of #warning
Under MSVC you'll get a message like this:
c:\programming\some_file.cpp(3) : WARNING: your warning message here
Under gcc you'll get:
c:\programming\some_file.cpp:25: note: #pragma message: WARNING: your warning message here
Not perfect, but a reasonable compromise.

As you have now discovered, #warning is not a standard feature, so you cannot use it with compilers that don't suppport it. If you want your code to work across platforms, you won't use #warning at all - or, at the least, not in code that MSVC is intended to process (it could be preprocessed out by #ifdef or equivalent). Hence:
#ifdef __GNUC__
#warning(warning message)
#else
#pragma NOTE(warning message)
#endif
But that repeats the message and I'm sure you had in mind not doing that - and it is bulky ; you'd only use it very seldom. You might also need to deal with other compilers than GCC (and I'm not familiar enough with MSVC to know how to identify it reliably).
It would be nice if #warning were standardized; it is not standardized in C99.
(There was, once upon a long time ago, an SO question about such features that could be added to C and #warning came up there.)
See also: Portability of #warning preprocessor directive

Guard them with #if statements. Look for a symbol that's defined by one compiler but not the other.
#ifdef _MSC_VER
#pragma NOTE(my warning here)
#else
#warning(my warning here)
#endif
Kind of ugly, but I don't see another way.

It is possible have code that works everywhere, and emits custom
warnings on many compilers, including most compilers people are likely
to use (GCC, clang, MSVC, Intel, ...).
First, we should distinguish between warnings and informational
messages. I think the only thing that makes sense is that, if you
compile with fatal warnings (e.g., -Werror on GCC), warnings
should cause compilation to fail, whereas informational messages
shouldn't.
As the original question mentions, MSVC 9.0+ supports
#pragma message("Hello")
Despite the (IMHO unfortunate) name, MSVC will emit a warinng here,
not an informational message. AFAICT there is no way to emit an
informational message.
GCC 4.8+ and Intel support warning message pragmas, which means we can
use the preprocessor to generate them:
#pragma GCC warning "Hello"
Note that, as of version 18, PGI does not support such warnings, even
though pgc++ masquerades as a version of GCC that should (i.e., it
sets __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__ to values which
indicate GCC >= 4.8). They are
aware
of the issue. To get around this while still allowing some future
version of PGI which does support those to work properly, you can do
something like:
#if defined(__PGI)
# pragma diag_suppress 1675
#endif
Unfortunately I don't think there is a way to push/pop the warning
stack for PGI, so if you do this all subsequent unknown pragmas will
be silently ignored. Also, keep in mind that #pragma message is
silently ignored by PGI (it will not even generate a warning about the
pragma being unknown).
Clang also supports #pragma GCC warning (as well as #pragma clang
...), but as of 6.0 such warnings are actually informational (I've
filed a bug). I'm not sure when support was added, but clang's version
numbers are pretty useless anyways (thanks to Apple setting them to
something completely different in their clang
distribution). Unfortunately there is no __has_pragma feature test
macro, but we can temporarily disable the unknown pragma warnings so
that if the compiler doesn't support the pragma it will be silently
ignored instead of emitting an unwanted warning:
#if defined(__has_warning)
# if __has_warning("-Wunknown-pragmas")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-pragmas"
# pragma message "Hello"
# pragma clang warning "Hello"
# pragma clang diagnostic pop
# endif
#endif
Sure, it's ugly, but at least we can hide it behind a macro.
Cray 5.0+ also has a pragma for messages:
#pragma _CRI message "Hello"
I don't actually have access to Cray's compiler, so I can't be sure
about whether it is informational or a warning. If someone knows the
anwser, please comment!
Putting it all together, I recently added some macros to
Hedley to handle this, the current
version looks like this:
#if HEDLEY_HAS_WARNING("-Wunknown-pragmas")
# define HEDLEY_MESSAGE(msg) \
HEDLEY_DIAGNOSTIC_PUSH \
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
HEDLEY_PRAGMA(message msg) \
HEDLEY_DIAGNOSTIC_POP
#elif \
HEDLEY_GNUC_VERSION_CHECK(4,4,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0)
# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg)
#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0)
# DEFINE HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg)
#else
# define HEDLEY_MESSAGE(msg)
#endif
#if HEDLEY_HAS_WARNING("-Wunknown-pragmas")
# define HEDLEY_WARNING(msg) \
HEDLEY_DIAGNOSTIC_PUSH \
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
HEDLEY_PRAGMA(clang warning msg) \
HEDLEY_DIAGNOSTIC_POP
#elif \
(HEDLEY_GNUC_VERSION_CHECK(4,8,0) && !defined(__PGI)) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0)
# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg)
#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)
# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg))
#else
# define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg)
#endif
If you don't want to use Hedley (it's a single public domain / CC0 header for just this sort of thing) you can replace the internal macros without too much effort. If you do that, I'd suggest basing your port on the Hedley repo instead of this answer as I'm much more likely to keep it up to date.

If you wish, you can add to the above solutions a little thing (#pragma warning) before
your #pragma message:
#pragma warning()
#pragma message(" SOME USER WARNING - FILE LINE etc... ")
This little add-in generates real warning, and does not look bad in the window of VC.
For example:
1>e:\proj\file.h(19) : warning C4615: #pragma warning : unknown user warning type
1> SOME USER WARNING - FILE LINE etc...
1>proj - 0 error(s), 1 warning(s)
Usually I use this method to warnings were not too quiet, as in the case code without the #pragma warning().
For example, the form of warnings too quiet (for me of course).
1> SOME USER WARNING - FILE LINE etc..
1>proj - 0 error(s), 0 warning(s)
However, only a small cosmetics.

Related

User-defined errors with nagfor preprocessor

I'm trying to abort compilation if an unsupported fortran compiler is used. The nagfor preprocessor defines the macro NAGFOR, so I wrote the following test program:
program foo
implicit none
#ifdef NAGFOR
PRINT *, "Hello from nagfor"
#else
#error "Compiler not supported"
#endif
end program foo
When I compile with gfortran or ifort, I get the expected error message
$ gfortran foo.F90
foo.F90:8:2: error: #error "Compiler not supported"
$ ifort foo.F90
foo.F90(8): #error: "Compiler not supported"
but nagfor gives a different error
$ nagfor foo.F90
NAG Fortran Compiler Release 5.3.1(907)
"foo.F90", line 8: error: unknown fpp directive.
I can't find any mention of how to create an error in the nagfor fpp documentation so maybe #error doesn't exist. In which case, is there an alternative approach to get the same effect?
I work on the NAG Compiler. fpp is intended to be pretty lightweight in terms of operation (and functionality). It originates from Sun; we are using a version based on the netlib one from http://netlib.org/fortran/fdfpp.tgz.
The fpp manual (http://www.nag.co.uk/nagware/np/r60_doc/fpp.html) does not document #error as being supported, which you have discovered.
As francescalus suggests, the best way to acheive what you want would be with something along the lines of
program foo
implicit none
#ifdef NAGFOR
PRINT *, "Hello from nagfor"
#else
error "Compiler not supported"
#endif
end program foo

gcc macro expansion of #error

I have some preprocessor code like this:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#if GCC_VERSION < 40503
#error Your compiler is outdated.
#error You need at least gcc 4.5.3 for this library.
#error You have: GCC_VERSION
#error You have: STR(GCC_VERSION)
#endif
However both ways I tried to output the current compiler version fail. According to the documentation this is because
Neither ‘#error’ nor ‘#warning’ macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.
How can I output the compiler version with the error message anyway? Is there any preprocessor magic that allows me to achieve this?
The classic "solution" to this problem is to manage to generate an error which includes the desired message. For example:
#define S(x) #x
#define STR(x) S(x)
#if GCC_VERSION < 40503
#error Outdated compiler: you need at least gcc 4.5.3 for this library.
#define above_message_indicates_installed_gcc_version STR(Installed GCC version: GCC_VERSION)
#include above_message_indicates_installed_gcc_version
#endif
While that does provide some information, it is still subject to misinterpretation; personally, I think letting the developer know the minimum version required is sufficient.
Note: The above snippet assumes that GCC_VERSION has already been defined, which I assume must have been done before the snippet in the OP. But beware: since the preprocessor does text substitution, not arithmetic evaluation (except in #if directives), you need to assemble GCC_VERSION in a different form for the error message If you want to try this, you could use the following:
#define GCC_VERSION (__GNUC_PATCHLEVEL__ + 100 * (__GNUC_MINOR__ + 100 * __GNUC__))
#define S_(x) #x
#define STR(x) S_(x)
#if GCC_VERSION < 40503
#undef GCC_VERSION
#define GCC_VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
#error Outdated compiler: you need at least gcc 4.5.3 for this library.
#define above_message_indicates_installed_gcc_version STR(Installed GCC version: GCC_VERSION)
#include above_message_indicates_installed_gcc_version
#endif
See it on gcc.godbolt
If #error does not expand its arguments, I would just take a pragmatic approach:
#if GCC_VERSION < 40503
#error Outdated compiler < 4.5.3, run 'gcc --version' to get version.
#endif
The only other possibility I can think of is to preprocess the file with your own preprocessor, to replace all occurences of (for example) xyzzy_GCC_VERSION_plugh with something extracted from gcc --version.
That's going to be a lot of effort and maintenance load to do what probably isn't necessary anyway.
But, if you really want to do it, you could use something like:
actual=$(echo "GCC_VERSION" | gcc -E - | tail -1)
sed "s/xyzzy_GCC_VERSION_plugh/$actual/g" file1.c >file1_morphed.c
gcc -c -o file1.o file1_morphed.c
and your file1.c would contain at the top somewhere:
#if GCC_VERSION < 40503
#error Outdated compiler xyzzy_GCC_VERSION_plugh < 4.5.3
#endif
But, as i said, that's a fair bit of work for not much benefit. My advice is just to tell the person using your library how to get the compiler version themselves. They are developers after all, I'd expect them to be able to handle an instruction like that.
Combining the proposal of paxdiablo and ideas for static compile time assertions I settled for the following solution.
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#define ERROR_MESSAGE(major, minor, patchlevel) compiler_version__GCC_ ## major ## _ ## minor ## _ ## patchlevel ## __ ;
#define OUTDATED_COMPILER_ERROR(major, minor, patchlevel) ERROR_MESSAGE(major, minor, patchlevel)
#if GCC_VERSION < 40503
#error Outdated compiler version < 4.5.3
#error Absolute minimum recommended version is avr-gcc 4.5.3.
#error Use 'avr-gcc --version' from the command line to verify your compiler version.
#error Arduino 1.0.0 - 1.0.6 ship with outdated compilers.
#error Arduino 1.5.8 (avr-gcc 4.8.1) and above are recommended.
OUTDATED_COMPILER_ERROR(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#endif

Detect whether clang is compiling using c++11 or legacy libstdc++ standard library

I've got an Xcode project that I'm migrating to use with clang's option -stdlib libc++, to enable C++11 support. Some of my source files need to know which library is being used, for instance so that I do things like this:
#ifdef HAVE_CPP11_LIB_SUPPORT
#include <memory>
#else
#include <tr1/memory>
#endif
#ifdef HAVE_CPP11_LIB_SUPPORT
vector.emplace_back(newValue);
#else
vector.push_back(newValue);
#endif
I'm having trouble though finding the preprocessor macros (if indeed there are any) that are set for this option. I've tried dumping the outputs of clang with:
clang -x c++ -std=c++11 -stdlib=libc++ -dM -E - < /dev/null
to compare with:
clang -x c++ -std=c++11 -stdlib=libstdc++ -dM -E - < /dev/null
but this gives the same results. Note that I don't want to switch on whether we're using the c++11 language setting, but whether we're using the c++11 library. Is there any reliable way of detecting this in the code?
I don't know of any sure way that is guaranteed to be portable, but this is what I use for now:
// libc++ detected: _LIBCPP_VERSION
// libstdc++ detected: __GLIBCXX__
#if defined(__clang__)
# if __has_include(<__config>) // defines _LIBCPP_VERSION
# include <__config>
# elif __has_include(<bits/c++config.h>) // defines __GLIBCXX__
# include <bits/c++config.h>
# else
# include <ios>
# endif
#elif defined(__GNUC__) // gcc does not have __has_include
# include <ios> // ios should include the c++config.h which defines __GLIBCXX__
#endif
It's not great, but works for me for now.
libc++ defines _LIBCPP_VERSION and stdc++ defines __GLIBCXX__ which is nice, but unfortunately these macros are not defined by the compiler. Instead, they're defined in a non-standard header file, and you cannot test their definition unless that header has been included.
Note: Apparently stdc++ defined __GLIBCPP__ in older versions instead. Since you require c++11, this isn't going to be a problem.
Clang (Edit: Standard since C++17) has a nice feature __has_include which can be used to test for these but if neither header is found, the macro falls back to just including a standard header which hopefully uses the internal header under the hood. I have <ios> here, but the choice of standard header to include is up to you. You can look for headers that include the internal header with something like (this is for gcc on linux):
grep -Rl '#include <bits/c++config.h>' /usr/include/c++
Pick any header that you're likely to use in the project anyway.
Since this isn't guaranteed to work for any given past or future compiler/standard library version, I wouldn't rely on these defines for anything but optional features like:
#ifdef __GLIBCXX__
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
#ifdef __has_include
# if __has_include(<ciso646>)
# include <ciso646>
# if defined(_LIBCPP_VERSION)
# define USING_LIBCPP 1
# endif
# endif
#endif
#if !USING_LIBCPP
# define USING_LIBSTDCXX 1
#endif
If you're writing these kinds of checks I suggest you choose a compiler/library version and require that or newer. It makes no sense to half-use C++11 library features. On Mac OS X, just require compilation with clang++ -stdlib=libc++.
I use next code:
#include <cstddef> // for __GLIBCXX__
#ifdef __GLIBCXX__
# include <tr1/memory>
#else
# include <memory>
#endif
source

Xcode & preprocessor ##

In Xcode can I use ## in a macro?
In MSVC I can write:
#define FOO(_var) int foo##_var## = 1
FOO(bar);
foobar++;
On the Mac (edit: compiling with GCC) the same code gives me the error "Pasting "foobar" and "=" does not give a valid preprocessing token. Is ## not supported in xcode?
Concatenation is supported in GCC and Clang. Xcode isn't a compiler; if you're posting errors like this, check what version of GCC, LLVM-GCC or Clang ("LLVM compiler") you're using because their behavior can differ.
You're trying to make = part of an identifier (i.e., create a variable called foobar=) which I don't think is what you want.
Try #define FOO(_var) int foo##_var = 1 instead.
Incidentally, Clang gives a somewhat better error message:
foo.c:4:5: error: pasting formed 'foobar=', an invalid preprocessing token
FOO(bar);
^
foo.c:1:32: note: instantiated from:
#define FOO(_var) int foo##_var## = 1
^

How do you suppress GCC linker warnings?

I've been on a crusade lately to eliminate warnings from our code and have become more familiar with GCC warning flags (such as -Wall, -Wno-<warning to disable>, -fdiagnostics-show-option, etc.). However I haven't been able to figure out how to disable (or even control) linker warnings. The most common linker warning that I was getting is of the following form:
ld: warning: <some symbol> has different visibility (default) in
<path/to/library.a> and (hidden) in <path/to/my/class.o>
The reason I was getting this was because the library I was using was built using the default visibility while my application is built with hidden visibility. I've fixed this by rebuilding the library with hidden visibility.
My question though is: how would I suppress that warning if I wanted to? It's not something that I need to do now that I've figured out how to fix it but I'm still curious as to how you'd suppress that particular warning — or any linker warnings in general?
Using the -fdiagnostics-show-option for any of the C/C++/linker flags doesn't say where that warning comes from like with other compiler warnings.
Actually, you can't disable a GCC linker warning, as it's stored in a specific section of the binary library you're linking with. (The section is called .gnu.warning.symbol)
You can however mute it, like this (this is extracted from libc-symbols.h):
Without it:
#include <sys/stat.h>
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
Gives:
$ gcc a.c
/tmp/cc0TGjC8.o: in function « main »:
a.c:(.text+0xf): WARNING: lchmod is not implemented and will always fail
With disabling:
#include <sys/stat.h>
/* We want the .gnu.warning.SYMBOL section to be unallocated. */
#define __make_section_unallocated(section_string) \
__asm__ (".section " section_string "\n\t.previous");
/* When a reference to SYMBOL is encountered, the linker will emit a
warning message MSG. */
#define silent_warning(symbol) \
__make_section_unallocated (".gnu.warning." #symbol)
silent_warning(lchmod)
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
gives:
$ gcc a.c
/tmp/cc195eKj.o: in function « main »:
a.c:(.text+0xf): WARNING:
With hiding:
#include <sys/stat.h>
#define __hide_section_warning(section_string) \
__asm__ (".section " section_string "\n.string \"\rHello world! \"\n\t.previous");
/* If you want to hide the linker's output */
#define hide_warning(symbol) \
__hide_section_warning (".gnu.warning." #symbol)
hide_warning(lchmod)
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
gives:
$ gcc a.c
/tmp/cc195eKj.o: in function « main »:
Hello world!
Obviously, in that case, replace Hello world! either by multiple space or some advertisement for your wonderful project.
Unfortunately ld does not appear to have any intrinsic way of suppressing specific options. One thing that I found useful was limiting the number of duplicate warnings by passing -Wl,--warn-once to g++ (or you can pass --warn-once directly to ld).

Resources