I'm working with a recent version of gcc, writing C++ code (but I would like an answer which would work for C as well). I have various extra warning flags enabled.
In my code, I am including a header from some popular library, #include <mylib.h>. Now, mylib.h triggers some of these compiler warnings; but I need to include it as-is, I can't alter it.
I want to suppress all compiler warnings when including mylib.h. I know I can suppress individual warnings with:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwarning-name-here"
#pragma GCC diagnostic ignored "-Wanother-warning-name-here"
// my code goes here
#pragma GCC diagnostic pop
but I want to suppress all of the warnings. Can I do that? Note that I'm willing to tweak the compiler command-line if that helps.
Note: This related question indicates that, in 2015, one could not do this using pragmas.
From GCC manual:
2.7 System Headers
The header files declaring interfaces to the operating system and
runtime libraries often cannot be written in strictly conforming C.
Therefore, GCC gives code found in system headers special treatment.
All warnings, other than those generated by `#warning' (see
Diagnostics), are suppressed while GCC is processing a system header.
Macros defined in a system header are immune to a few warnings
wherever they are expanded. This immunity is granted on an ad-hoc
basis, when we find that a warning generates lots of false positives
because of code in macros defined in system headers.
Normally, only the headers found in specific directories are
considered system headers. These directories are determined when GCC
is compiled. There are, however, two ways to make normal headers into
system headers.
The -isystem command line option adds its argument to the list of
directories to search for headers, just like -I. Any headers found in
that directory will be considered system headers.
All directories named by -isystem are searched after all directories
named by -I, no matter what their order was on the command line. If
the same directory is named by both -I and -isystem, the -I option is
ignored. GCC provides an informative message when this occurs if -v is
used.
There is also a directive, #pragma GCC system_header, which tells GCC
to consider the rest of the current include file a system header, no
matter where it was found. Code that comes before the `#pragma' in the
file will not be affected. #pragma GCC system_header has no effect in
the primary source file.
how to make this happen in CMake?
From CMake manual:
include_directories
Add include directories to the build.
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
...
If the SYSTEM option is given, the compiler will be told the directories are meant as system include directories on some platforms. Signalling this setting might achieve effects such as the compiler skipping warnings, or these fixed-install system files not being considered in dependency calculations - see compiler docs.
Related
I'm trying to introduce -Werror flag to rather big legacy project. As expected, it breaks the compilation completely. Therefore I've decided to introduce it gradually, and for the new code first of all. My original approach was to compile new features as separate static targets and link them to the project, which works kind of good both in terms of project structure and readability. The problem which persist are pre-existing tangled includes. Basically, even after fixing all warnings in new code I'm left with chain of includes introducing new warnings. Is there any way to limit warning flags usage to given source files strictly?
I do understand that include means basically copy/pasting headers into cpps, so it does not seem possible with just cmake settings. Then pragmas, perhaps?
You can use the set_source_files_properties command to set the COMPILE_OPTIONS property on the files you need.
Something like this:
set_source_files_properties(bad.cpp PROPERTIES COMPILE_OPTIONS -Werror)
I don't know about any compiler flags that allow you to apply flags to only some of the files included, so cmake cannot do better for you. Therefore pragmas are the way to go.
Basically what you effectively want in your cpp files is something like this:
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wall"
#include "updated_lib/header1.hpp"
#include "updated_lib/header2.hpp"
...
#pragma GCC diagnostic pop
#include "non_updated_lib/header1.hpp"
#include "non_updated_lib/header2.hpp"
Note that this would require this logic to be repeated in multiple translation units which you may want to avoid, if you're updating the headers gradually over time.
As an alternative you could duplicate the header file subdirectories, and make the non-updated versions available via one path and updated headers via another, e.g. for a header foo/bar/baz.hpp either make the header available via path old/foo/bar/baz.hpp or new/foo/bar/baz.hpp and create a new header available via foo/bar/baz.hpp that looks like this:
#if __has_include("new/foo/bar/baz.hpp")
# pragma GCC diagnostic push
# pragma GCC diagnostic error "-Wall"
# include "new/foo/bar/baz.hpp"
# pragma GCC diagnostic pop
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic warning "-Wall"
# include "old/foo/bar/baz.hpp"
# pragma GCC diagnostic pop
#endif
Note that you'll probably need to write these kind of headers for you. You could even generate the actual includes via cmake during the generation of the project which which would shorten the headers to 3 pragmas plus one include; this would have the additional benefit of working with compiler versions not supporting __has_include.
function(my_generate_include OUT_LIST DESTINATION_DIR FIRST_HEADER)
set(GENERATED_HEADERS ${${OUT_LIST}})
foreach(HEADER IN ITEMS ${FIRST_HEADER} ${ARGN})
if (HEADER MATCHES "^old/(.*)$")
configure_file(old_include.hpp.in "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
list(APPEND GENERATED_HEADERS "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
elseif (HEADER MATCHES "^new/(.*)$")
configure_file(new_include.hpp.in "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
list(APPEND GENERATED_HEADERS "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "Header '${HEADER}' doesn't start with 'new/' or 'old/'")
endif()
endforeach()
set(${OUT_LIST} ${GENERATED_HEADERS} PARENT_SCOPE)
endfunction()
...
set(HEADERS)
my_generate_include(HEADERS ${CMAKE_CURRENT_BINARY_DIR}/generated_includes
old/a/b/c.hpp
new/d/e/f.hpp
)
I have a big project that uses many, many libraries. Some of them are HDF5, PugiXML, Boost.ASIO, Qt, MuParser, and many others. Some of these libraries are included by header, and some are pre-compiled, and some of them I compiled myself. I'd like to use the gcc option -Weffc++ to ensure the quality of my code.
The problem is that I got over 2000 warnings when I enabled that option, and when I went quickly through the list, there was like 1 of them related to my project, and almost everything else was from the headers I included! It's very not practical to go through the whole list. Is there a way to tell gcc to either analyze files from given directories, or exclude directies in some way (regex maybe?).
The comments in the documentation are not good news:
When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use ‘grep -v’ to filter out those warnings.
You can disable the warning temporarily with pragmas:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <header1>
#include <header2>
#pragma GCC diagnostic push
You might also be able to use -isystem to specify include paths, which suppresses certain warnings from files included through those paths.
Recommendation
Just don't use -Weffc++. It gives garbage even in your own project. For example, it will ask you to define virtual destructors for all base classes, regardless of whether that makes even a small amount of sense. It will warn if you don't initialize every member in aggregate initialization. After throwing my hands in the air and saying, "That warning is just stupid!" for the hundredth time, I turned -Weffc++ off and moved on with my life.
There are much better tools out there for code quality and enforcing style. Clang tools like clang-tidy, clang-modernize, and clang-format come to minde.
You can specify directories with -isystem to avoid the -Weffc++ processing on those directories. This works even when they have been specified earlier with -I.
We're using clang with -fmodule and -fcxx-module to enable module support as documented at http://clang.llvm.org/docs/Modules.html. We're already seeing a significant improvement in build times by defining module maps for our core libraries.
However, we have some library headers that use pragmas to disable warnings for certain lines, for example:
template <typename TFloat>
static bool exactlyEqual(TFloat lhs, TFloat rhs)
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
return lhs == rhs;
#pragma clang diagnostic pop
}
When this header is pulled in as a precompiled module, it seems clang's internal representation does not preserve the pragma information and the warning is still emitted. Since we treat warnings as errors this causes compilation to fail. Some might argue to just disable float-equal entirely, but we have a bunch of other cases with different warnings which we don't want to globally disable.
We're already using -Wno-system-headers and -isystem so that clients of libraries generally don't see warnings like this anyway (even without the pragma), but this doesn't seem to work when the header is imported as a module. In addition we still hit these warnings for code internal to the library which includes the header as a non-system header (i.e. without using -isystem / using double quotes), since module precompilation and importing also occurs here.
I've tried using _Pragma(...) instead of #pragma which didn't have any effect.
Is there some other way to conditionally ignore warnings in headers that come from precompiled clang modules?
UPDATE: I've put a sample project up on https://github.com/MikeWeller/ClangModuleWarnings which reproduces the problem
UPDATE: Seems the [system] module attribute will suppress all warnings. However this suppresses even warnings we want to see when building the library itself, and we don't want to make all our modules system modules. If we find a way to not use the library's module map when building the library itself this may be acceptable but we'd still like to pragma out certain warnings for non-system modules..
Is it possible to restict the -pedantic switch for certain files? For example I compile stuff using alsa-lib, which I refer with standard
#include <alsa/asoundlib.h>
however -pedantic panics on this file. I am willing and interested in correcting warning and oddities in my own code, but not in alsa and other unrelated third parties.
Is there a way to scope the -pedantic usage?
Normally, GCC suppresses warnings in system headers, unless you explicitly specify -Wsystem-headers. And normally, files included with <> from /usr/include are treated as system headers. Your question suggests you specifically added something that makes GCC not treat it as a system header. You haven't specified which compiler options you're using, but are you adding any pointless -I* options that might make /usr/include get treated as a non-system header directory?
If all else fails, you can use the -isystem to actually add directories as system header directories, but you shouldn't need that here.
Edit: after re-reading the question, if you installed alsa-lib in a non-standard path, then my remark that you should not need the -isystem option may be wrong: it may be exactly what you need.
You can scope any compilation key to one compilation unit.
Apperently, if you has multiple compilation units you can use deferent keys to compile them:
g++ -pedantic file_that_does_not_use_ugly_alsa.cpp
g++ file_that_uses_ugly_alsa.cpp
But you you can not scope keys inside compilation unit: code get prepropcessed before compiling, all headers are inlined and actually after macros substitution you may find out that your code uses some things, that make compiler panic.
I have a project that uses log4cxx, boost, etc. libraries whose headers generate lots of (repetitive) warnings. Is there a way to suppress warnings from library includes (i.e. #include <some-header.h>) or includes from certain paths? I'd like to use -Wall and/or -Wextra as usual on project code without relevant info being obscured. I currently use grep on make output but I'd like something better.
You may try to include library headers using -isystem instead of -I. This will make them "system headers" and GCC won't report warnings for them.
For those using CMake, you can modify your include_directories directives to include the symbol SYSTEM which suppresses warnings against such headers.
include_directories(SYSTEM "${LIB_DIR}/Include")
^^^^^^
You can use pragmas. For example:
// save diagnostic state
#pragma GCC diagnostic push
// turn off the specific warning. Can also use "-Wall"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
// turn the warnings back on
#pragma GCC diagnostic pop
I found the trick. For library includes, instead of -Idir use -isystem dir in the makefile. GCC then treats boost etc. as system includes and ignores any warnings from them.
#pragma are instructions to the compiler. you can set something before the #include and disable it after.
You can also do it at the command line.
Another GCC page specifically on disabling warnings.
I would go for the option of using #pragma's within the source code, and then providing a
sound reason (as a comment) of why you are disabling the warnings. This would mean reasoning about the headers files.
GCC approaches this by classifying the warning types. You can classify them to be warnings or to be ignored. The previously linked articles will show you which warnings are may be disabled.
Note: you can also massage the source code to prevent certain warnings by using attributes; however, this bind you quite closely to GCC.
Note2: GCC also uses the pop/push interface as used in microsoft's compiler -- Microsoft disables warnings through this interface. I suggest you investigate this further , as I do not know if it is even possible.
Putting the following
#pragma GCC system_header
will turn off GCC warnings for all following code in this file.
You can try using precompiled headers. Warnings won't go away but at least the won't show up in your main compilation.
If you need to explicitly override a system header then you're restricted to pragmas. You can verify which includes you're using via make depend output.
Also see diagnostic push-pop for gcc >= 4.6
Another way to do it is, in the makefile, to tell the compiler to ignore warnings for the specific folder:
$(BUILD_DIR)/libs/%.c.o: CFLAGS += -w
There must be reasons for those warnings. These will either be caused by errors in your code that uses the library, or by errors in the library code itself. In the first case, fix your code. In the second case, either stop using the library or if it is FOSS code, fix it.