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.
Related
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.
Reading the fine print of the -I switch in GCC, I'm rather shocked to find that using it on the command line overrides system includes. From the preprocessor docs
"You can use -I to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories."
They don't seem to be lying. On two different Ubuntu systems with GCC 7, if I create a file endian.h:
#error "This endian.h shouldn't be included"
...and then in the same directory create a main.cpp (or main.c, same difference):
#include <stdlib.h>
int main() {}
Then compiling with g++ main.cpp -I. -o main (or clang, same difference) gives me:
In file included from /usr/include/x86_64-linux-gnu/sys/types.h:194:0,
from /usr/include/stdlib.h:394,
from /usr/include/c++/7/cstdlib:75,
from /usr/include/c++/7/stdlib.h:36,
from main.cpp:1:
./endian.h:1:2: error: #error "This endian.h shouldn't be included"
So stdlib.h includes this types.h file, which on line 194 just says #include <endian.h>. My apparent misconception (and perhaps that of others) was that the angle brackets would have prevented this, but -I is stronger than I'd thought.
Though not strong enough, because you can't even fix it by sticking /usr/include in on the command line first, because:
"If a standard system include directory, or a directory specified with -isystem, is also specified with -I, the -I option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain."
Indeed, the verbose output for g++ -v main.cpp -I/usr/include -I. -o main leaves /usr/include at the bottom of the list:
#include "..." search starts here:
#include <...> search starts here:
.
/usr/include/c++/7
/usr/include/x86_64-linux-gnu/c++/7
/usr/include/c++/7/backward
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
Color me surprised. I guess to make this a question:
What legitimate reason is there for most projects to use -I considering this extremely serious issue? You can override arbitrary headers on systems based on incidental name collisions. Shouldn't pretty much everyone be using -iquote instead?
What legitimate reasons are there for -I over -iquote? -I is standardized (at least by POSIX) while -iquote isn't. (Practically, I'm using -I because tinycc (one of the compilers I want my project to compile with) doesn't support -iquote.)
How do projects manage with -I given the dangers? You'd have the includes wrapped in a directory and use -I to add the directory containing that directory.
filesystem: includes/mylib/endian.h
command line: -Iincludes
C/C++ file: #include "mylib/endian.h" //or <mylib/endian.h>
With that, as long as you don't clash on the mylib name, you don't clash (at least as far header names are concerned).
Looking back at the GCC manuals it looks like -iquote and other options were only added in GCC 4: https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options
So the use of "-I" is probably some combination of: habit, lazyness, backwards compatibility, ignorance of the new options, compatibility with other compilers.
The solution is to "namespace" your header files by putting them in sub directories. For example put your endian header in "include/mylib/endian.h" then add "-Iinclude" to the command line and you can #include "mylib/endian.h" which shouldn't conflict with other libraries or system libraries.
I this your premise that it's -I that's dangerous is false. The language leaves the search for header files with either form of #include sufficiently implementation-defined that it's unsafe to use header files that conflict with the names of the standard header files at all. Simply refrain from doing this.
An obvious case is cross-compilation. GCC suffers a bit from a historical UNIX assumption that you're always compiling for your local system, or at least something that's very close. That's why the compiler's header files are in the system root. The clean interface is missing.
In comparison, Windows assumes no compiler, and Windows compilers do not assume you're targeting the local system. That's why you can have a set of compilers and a set of SDK's installed.
Now in cross-compilation, GCC behaves much more like a compiler for Windows. It no longer assumes that you intend to use the local system headers, but lets you specify exactly which headers you want. And obviously, the same then goes for the libraries you link in.
Now note that when you do this, the set of replacement headers is designed to go on top of the base system. You can leave out headers in the replacement set if their implementation would be identical. E.g. chances are that <complex.h> is the same. There's not that much variation in complex number implementations. However, you can't randomly replace internal implementation bits like <endian.h>.
TL,DR : this option if for people who know what they're doing. "Being unsafe" is not an argument for the target audience.
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.
I had to customize some projects which have been written for some other purpose but some core functionality is same for my project and works as it is. But There are lots of variables, macros,functions etc.. which are not useful for my current context and they are just making the code very uneasy to read and unnecessarily big.
So I started removing the variables macros functions etc.. by using "Find References" and "Show Call Graph" in Netbeans. I'm using netbeans remote development tools for c/c++.
But its cumbersome. So Is there any tool to do this clean up??
From what I know there is currently no tool that does all the things you have mentioned, however there is one that helps in cleaning up the unused include headers: include-what-you-use
"Include what you use" means this: for every symbol (type, function
variable, or macro) that you use in foo.cc, either foo.cc or foo.h
should #include a .h file that exports the declaration of that symbol.
The include-what-you-use tool is a program that can be built with the
clang libraries in order to analyze #includes of source files to find
include-what-you-use violations, and suggest fixes for them.
The main goal of include-what-you-use is to remove superfluous #includes. It does this both by figuring out what #includes are not actually needed for this file (for both .cc and .h files), and
replacing #includes with forward-declares when possible.
One might expect that the Clang static analyzer would do this, but from what I see the availalbe checks do not offer such things.
This might be a good time for someone to suggest a feature request to the analyzer or create a separate tool using LibTooling on a similar par with the tools described at Clang Tools
In the meantime, I'd suggest you enable -Wall and -Wextra compiler flags, which will trigger the following warnings (among others)(see the GCC docs below):
-Wunused-function
-Wunused-label
-Wunused-value
-Wunused-variable
-Wunused-parameter
-Wunused-but-set-parameter
If for some reason you don't want to do that, you could just add -Wunused which will enable only the above -Wunused options combined, without the other flags that -Wall or -Wextra adds.
But in order to get a warning about an unused function parameter, you
must either specify -Wextra -Wunused (note that -Wall implies
-Wunused), or separately specify -Wunused-parameter.
Of course, this means that you have to do the cleanup manually
If you want to be extra pedantic you might as well convert all the warnings into errors by adding the -pedantic-errors flag
For more details read the GCC Warnings Options documentation.
I've sometimes used the method of marking a big block of code as "not used" by adding
#if 0
... lots of code
#endif
You can then compile the code and see what goes wrong. Analyze the "undeclared varibale X" errors you get and reinstate the bits necessary for that. You can do this by either "cutting up" the #if 0 block (adding an #endif, then a new #if 0 a bit further down), or by moving the pieces you need out of the current block.
For example, if you have a block of global variables or macros, just put #if 0 around all of them, and see which ones are actually used. [Although macros can be a little more tricky if they are used in #ifdef and such].
I'd be surprised if there isn't a tool out there, but at the same time, you still have to do the cutting job, and once you have a large chunk of code in #if 0 ... #endif, it's pretty easy to cut it out.
Many static code analysis tools provide the information you want. Wikipedia has a list.
We have successfully used such a tool (with some custom changes) to remove includes and speed up compile time.
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.