What Are Your GCC Flags?
blog.httrack.com
blog.httrack.com
-Wall -Wextra -Wformat=2 -Wno-format-nonliteral -Wshadow \
-Wpointer-arith -Wcast-qual -Wmissing-prototypes -Wno-missing-braces \
-std=gnu89 -D_GNU_SOURCE -O2
Note that -Wall and -Wextra do not enable all warnings. To keep backwards compatibility, -Wall is basically, "All warnings as of 1990." -Wextra covers a lot of the newer warnings, but still misses a few.I also use scan-build[2] for static analysis and clang-format[3] to ensure a consistent style. It was frustrating when I first enabled all these options, but the warnings helped me discover bugs that had been lurking for years.
1. https://github.com/ggreer/the_silver_searcher
-Wstrict-aliasing=1/-Wsuggest-attribute= can give good suggestions during development.
Probably not useful for Ag: But I do a lot of numeric stuff so -Wfloat-equal is handy for me. For code using float this should be mandatory: -Wdouble-promotion.
I thought there was a better tool, but can't find the name, hmm.
-Werror
is fine on your dev machine, but is a very bad idea in the official build system, notably if you do it for a library that you want people to use.As soon as you want to compile with various compilers, systems, use cross-compilation and other funny things that makes it portable, you're going to have a bad time.
New compilers will make new warnings, old compilers will make new warnings, clang and gcc have different warnings. Different distributions with gcc compiled with different flags will make different warnings too!
And of course, I don't mention libraries (or Mingw) that will always warn because of warnings inside their headers (I'm looking at you Fribidi).
What you build with in-house for development/test-farms is not what you should ship as default to users of your project.
If it's on every line and not kept in one place in $(CFLAGS), you have bigger problems.
Kinda off-topic, but have you considered translating HTTrack comments and variable names to English ?
Especially when you have ASM code or complex arithmetic, and when you allow to compile for different versions of Windows...
It's a good idea to have it on your build-farm, to track bugs, but it is not OK on your shipping build.
[0]: http://atp.fm
Not being an autotools guru this was incredibly frustrating. I had no idea why the damn thing wasn't working until I noticed "warnings are treated as errors".
Please don't use -Werror in any context if your project is open source.
-fno-exceptions
I don’t like C++ exceptions. And we don’t use them where I work
And none of your code uses the STL nor third party libraries that might throw exceptions either, right [1][1] "Doing without" http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_excepti...
clang++ -Qunused-arguments -Qunused-arguments -Wall -Wpointer-arith -Woverloaded-virtual
-Werror=return-type -Werror=int-to-pointer-cast -Wtype-limits -Wempty-body
-Wsign-compare -Wno-invalid-offsetof -Wno-c++0x-extensions -Wno-extended-offsetof
-Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-mismatched-tags
-Wno-error=uninitialized -Wno-error=deprecated-declarations -isysroot /Developer/
SDKs/MacOSX10.6.sdk -fno-exceptions -fno-strict-aliasing -fno-rtti -ffunction-sections
-fdata-sections -fno-exceptions -fno-math-errno -std=gnu++0x -pthread -DNO_X11 -pipe
-DNDEBUG -DTRIMMED -g -O3 -fno-omit-frame-pointer -Qunused-arguments -Os
I really don't like the stack protector. It adds a lot of space to executables, so I turn it off: -fno-stack-protector
Arthur told me about: -fno-asynchronous-unwind-tables
which seems to save a lot of space. I don't know exactly what it does, but the documentation suggests it does something with debugging, however `-s` doesn't remove it so I have this here.I often work without glibc (don't need it) but I like gcc's builtins so I have:
-Dabort=__builtin_trap -Dmemcpy=__builtin_memcpy -Dmemset=__builtin_memset -minline-all-stringops -msse2 -ffreestanding -nostdlib -fno-builtin
which seems to do the trick. I don't think all of these are necessary on all versions of GCC but I keep running into versions that complain about something so this line keeps getting longer. On x86 I additionally use: -mregparm=3
since it saves a lot of space and helps benchmarks.g++ -std=c++11 -O3 -fomit-frame-pointer -fwrapv
fwrapv turns off some "bad" optimizations around signed integer overflow (too likely to cause harm, too unlikely to make a significant performance difference in most cases.)
I also use a lot of asserts to verify the behaviors too costly to not rely on for what I do (low-level CPU simulation and such): linear A-Z, 8-bit char, twos-complement math, arithmetic shift right on signed types, int > 16-bits, etc.
I'm sure my views won't be popular, and I'm not encouraging anyone to follow what I do, just stating my preferences.
I have a love-hate relationship with warnings. My problem is that you end up with false positives that amount more to "how the compiler authors think you should style your code" instead of reporting legitimate issues. When combined with -Werror, it's a show-stopper for no reason.
Clang is much more naggy than GCC. For instance, I frequently switch on boolean variables. Clang doesn't even have a "-Wno-" intrinsic I can push to temporarily disable this.
But there's nothing at all illegal about switching on a boolean value. It annoys me that I need to go back and add unnecessary explicit casting in 100 places in my project to keep Clang quiet, or face real warnings being lost in a sea of false warnings every single time I build my project. I know you can do if(var) { ... } else { ... } ... I don't care. I want to use switch, and I legally am allowed to. Don't bug me about it, Clang.
It also really hates empty statements, eg while(do_something()); warns that there's nothing inside the while loop. I know, the important part is do_something() and its return value. Same for if's, for's, etc. It wants me to put the ; on its own line. Uh, no. That's not my style at all.
And at the same time ... Clang caught a few bugs that GCC overlooked.
So, my current strategy is to build WIPs with GCC at default warnings and Clang with the sledgehammer of -w; and then before any releases, build with maximum warnings on both compilers and analyze each one for legitimate issues. I also run with valgrind to catch many other types of issues, like using uninitialized variables and memory leaks.
I don't know how responsive they are, but you might try filing a bug.
// switch(bool_expr) {...} is often a programmer error, e.g.
// switch(n && mask) { ... } // Doh - should be "n & mask".
// One can always use an if statement instead of switch(bool_expr).
I agree that clang should not warn on this without asking for warnings and even then it should be possible to disable it. Maybe it would be a good idea to file a bug report.That being said, I can't imagine why you would ever choose to switch on a bool, and even go to the trouble to add a cast instead of just writing an if statement.
Also, my clang and g++ with "-Wall -Wextra" does not warn on an empty while statement.
> I can't imagine why you would ever choose to switch on a bool
In my case, it's for opcode execution. They consist of various bit fields that control the behavior, some are only 1-bit wide, some are 2-bits to 5-bits wide. The implementation is a series of switch statements, one after the other, that have cases for all possible values. So by using switch() in all cases, the code looks consistent.
So this is kind of what I dislike about style choice warnings. It's easy to presume there's no valid use case, until you actually find one later on. I get that people can make mistakes, but when I know for certain that I haven't made a mistake, I don't like having to change my code anyway.
Could I force the boolean values to unsigned types even though they're only 1-bit? Yes. Could I just do if/else anyway here? Yes. But I don't want to. I'm happy with my code, and received no warnings at all when I wrote it with GCC several years ago. It's only a "problem" now that I need Clang to target OS X.
> Also, my clang and g++ with "-Wall -Wextra" does not warn on an empty while statement
Hmm, good to hear. If I get to my dev PC before the post is buried, I'll post the output I was getting.
Either way, very cool! Thanks for the heads up! I can't use it now obviously, but I can add a diagnostic disable line that'll work in the future.
2. "too likely to cause harm, too unlikely to make a significant performance difference in most cases."
Please define "most cases". Without this, GCC will have significant trouble being able to derive the bounds of most loops, and in turn, will not be able to vectorize, unroll, peel, split, etc.
Saying "unlikely to make a significant performance different in most cases" is probably very very wrong for most people. The last benchmarks I saw across a wide variety of apps showed the perf difference was 10% in most cases, and a lot more in others.
2. I always get bitten when I try and generalize. I tested this in all of my software, and was not able to detect any performance difference with or without -fwrapv (that is to say, < 1% difference, too small of a difference to make any conclusions.)
I know you can create extreme edge cases where there's a huge difference, just as you can probably make up one that's slower without -fwrapv if you really wanted to.
But yeah, maybe I just don't write code that lends itself to benefiting heavily from these types of assumptions. I also tend to not really rely on signed integer overflow following twos-complement. But all the same, I will take well-defined behavior over the crazy stuff GCC can produce any day, even at the cost of a bit of performance. Of course, going all the way to -O0 is way too extreme. So a case where I see no perceptible performance impact and gain defined behavior? Win-win.
Fun fact btw: GCC and LLVM are the only compilers I know of to assume loops can overflow at all when optimizations are on.
Compilers like XLC will actually even assume unsigned loop induction variables will not ovefrlow at O3, unless you give them special flags.
:)
That's not exactly fair. The C standard guarantees that unsigned variables will overflow by wrapping, so if the compiler assumes such a loop won't terminate, it is not conformant.
Let us all now bow our heads to the almighty SPEC gods ...
Otherwise, given as something as simple as
for (unsigned i = 0; i < N; i+=2)
You can't say it iterates N/2 times
The results: http://ideone.com/7vidIs
Generated code http://tinyurl.com/le72k4o
On a 32-bit machine an unsigned array index means one object using more than half the address space. It's sensible to use unsigned 64-bit for file sizes, but I think it's quite odd that C programers would use it for a loop or array index. Wrong, but defined, behavior is worse than undefined behavior, you know.
On a 64-bit machine, well, it shouldn't be a problem to use signed long long.
Think of n == UNSIGNED_MAX. n+1 will overflow.
You said "I can change <= n to != n + 1". You cannot. for n == UNSIGNED_MAX, the former loop will iterate infinitely, the latter loop will never iterate.
Both are well defined to occur. You cannot change the loop behavior and say you have the same loop :)
EDIT: Ignore me. I see your explanation below.
I definitely also have a debug-mode that builds with -g and without -s -O3 -fomit-frame-pointer.
On the other hand, some platforms don't need a frame pointer for debugging; if you emit correct unwind tables that's enough for the debugger to construct a backtrace. I haven't looked lately but am pretty sure amd64 ELF is one of them.
Also, modern gcc generates okay debug info for optimized programs such that it's much more likely you can read variables out of a crash in gdb.
Working with unwind tables is more complicated and many useful debugging tools don't do so.
For tuning GCC flags for a particular application, see http://opentuner.org/
Optimally is kind of a non-sensical term for this. There is no optimality to be found here in any mathematical sense. Even COLE does not generate optimal, it finds something mildly reasonable.
However, the main problem with things like COLE, is that they mostly discover phase ordering issues or latent optimization bugs. Those are bugs and problems that should be fixed.
Most of phase ordering is decided by design and architecture, ie "we want it to work a certain way for certain reasons". To the degree it doesn't work best that way, it's usually a problem to be fixed, not a fundamental issue that COLE has discovered.
Personally I consider "-Werror" stupid. Warnings are designed to help and be reviewed, but aiming at "100% warning free" code should not be an "aim". For instance, I'd rather have "unitialized warnings" than use "i = i", which you know, might actually be correct code if "i" was available in scope and you want an additional copy that you can modify (nester for loops come to mind).
I sometimes leave warnings when silencing them "uglifies" the code.
"-fvisibility=hidden" is not so easy to leave on all the time when building software build by others. What I use is mostly "-fvisibility-inlines-hidden" in C++ code, even when building OSS projects, for which I never had a problem so far (in c++ inlines _are_ expected to have hidden visibility).
I also use "-march=native -flto=jobserver" and "-fwhole-program" (when linking) when I'm targetting my own hardware.
I also noticed that gcc now supports "-Og" to build optimized programs without impact on debugging, for which I had a very long command line before. "-Og -g3" gives pretty decent performance and optimal debugging, which is ideal for beta-testing programs.
gcc supports a pretty infinite list of command line switches. Actually, if you know what you are doing, you can optimize a program so well it's pretty much impossible to beat even by hand-crafting assembly. I know I tried several times, before realizing I could move a function to a separate object and supply a different set of optimization flags tuned just for that function.
For instance, "-Ofast" is actually safe most of the time for system utilities (and most other OSS software), and gives quite a boost for programs working with floats (most image-resizing loops and the like). Very few programs actually rely on exact IEEE arithmetic. Though I never use it, since finding issues might be _very_ hard.
so now we have a flag that disables a hack in code that is used to disable a warning caused by another flag. This is about as ridiculous to my (untrained in C) mind as it is to have -Wall not in-fact turn on all warnings.
Take assignment/evaluation in a condition:
if(a = [expr])
was not so frowned upon before, because it was sort of implicit that "a" was also needed in the nested block that followed. Now it's a warning without a double parenthesis, because it's also common the typo of using = instead of ==.The list goes on and on. In fact, the level of diagnostics that you get in C is pretty bit, and probably one of the best in class compared to any other language thanks to the maturity of the toolchain.
In my mind it's way better to just build your software with -Wall/others and implicitly review all warnings before pushing changed files to a common repository (which is kind of obvious, since when you are developing you also are looking the build logs).
For instance, -Wunused-args is helpful, but for a provisional API that's going to stay in the repository for a couple of weeks the warning is useless. Some people would go on and add useless code to silence the warning, though I will just commit the code.
I never had in my career large projects with more than a handful of warnings anyway. The kind of person that would use -Werror, in reality would go perfectly fine without.
Eliminating warnings can often be a hassle for no short-term benefit, and there's a decent number of people who agree that zero warnings is useful but don't actually get around to sticking to that if the compiler doesn't force them to.
The bigger benefit is when working with people that will just ignore warnings completely if you let them.
As for the optimization, I just tested on my machine:
int main(int argc, char** argv)
{
int x = 0;
switch (argc)
{
case 0:
x = 1;
break;
case 1:
x = 5;
break;
case 2:
x = 7;
break;
default:
x = 9;
break;
}
return x;
}
gcc -O3 -o opt-assign opt-assign.c
(gdb) disassemble main
Showed that x is never assigned zero. gcc -c -Wall -Werror -std=c99 -pedantic -O3
I use -std=c99 because I use these two features of C:1. Mixed declarations and code, e.g.
double x = 4.8 * 5.3;
printf("x = %.15g\n", x);
double y = 8.7 * x;
printf("y = %.15g\n", y);
2. Flexible array members, e.g. for my safe string operations: struct str
{
long len;
char data[];
};
If I were to use -ansi (same as -std=c89), instead of -std=c99, then -pedantic would give me these errors: error: ISO C90 forbids mixed declarations and code [-Werror=edantic]
error: ISO C90 does not support flexible array members [-Werror=edantic]
(By the way, I have no idea why the error message omits the "p" from pedantic there. That doesn't smell right. I hope the gcc people fix that.)I use -O3 for optimization, and I chose level 3 because that enables -finline-functions. I typically avoid macros, even for simple one-liners like this:
/* Increment the reference count. */
void hold(value f)
{
f->N++;
}
With -finline-functions enabled (via -O3), I can see that function being expanded inline, by examining the assembly output of gcc -S -O3.I did a quick experiment, compiling one C file with -O2 -finline-functions and another with -O3, using the -S flag so I could see the assembler output.
The only difference I saw was this:
.comm free_list,8,8
Versus this: .comm free_list,8,16
Who knows. I guess I'm really using -O3 because "3 is more than 2" -- in other words, "Ours goes to 11!" :)It is basically CSE "around loops". You can generalize it to subsume loop store motion and strength reduction, but most compilers (including GCC) don't bother.
For example, it transforms
for (int i = 0; i < 50; i++)
a[i+2] = a[i] + a[i+1]
into p0 = a[0]
p1 = a[1]
for (int i = 0; i < 50; i++) {
a[i+2]=p2=p0+p1;
p0=p1;
p1=p2;
}
Eliminating a whole ton of loads and stores.It's been a while since i looked at GCC's implementation, but it did pretty well in the past (whether you can do commoning depends on your ability to identify and group sequences, etc)
-ftree-vectorize does the obvious thing (turn on vectorization). How effective it is depends on a lot of factors.
- The GNU Compiler Collection can compile Java, as well as other languages with "bytecode".
- GCC actually has a native intermediate language, it's just not very well advertised.
-g -g3 -ggdb -gdwarf-4
Being able to debug C-macros has improved my life! (gdb) info macro Py_TYPE
Defined at Include/object.h:117
included at Include/pytime.h:6
included at Include/Python.h:65
included at Parser/myreadline.c:12
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -Wl,-O1 Did you know that you also have an optimization flag for the linker ? Now you know!
Ages ago the linker on SUN used to compile templates. What is GCC doing/using this flag for? If level is a numeric values greater than zero ld optimizes the output. This might take significantly longer and therefore probably should only be enabled for the final binary. At the moment this option only affects ELF shared library generation. -Weverything -Werror
That's how I roll. -Wall -Wextra -Werror-Waggregate-return - everything returns an aggregate in C++, and that's not necessarily a bad thing.
-Wlong-long - We use long longs.
-Wmissing-declarations - We don't need to declare every internal function before we use it.
-Wmissing-include-dirs - Sadly necessary; gcc seems to include some on its own.
-Wpadded - Everything's padded.
-Wsystem-headers - I only wish I was in a position where this could be useful :)
As K&R would say, let the machine do the dirty work. If a warning check exists, there's probably a good reason for it.
[1] https://github.com/rescrv/HyperDex/blob/master/m4/anal_warni...
Because it makes things a lot easier when writing cross platform code besides when using MSC, as that is the ugly sister.
-Wall -Wextra -pedantic-errors -funroll-loops.info -Weffc++ -Wunreachable-code -fno-exceptions -03 -WerrorMostly because it forces you upfront to make sure you're considering every case, and it looks like those warnings ought to give me the same kind of nagging with C and enums.
-pipe
-std=c++11
-gfull # generate correct debugging symbols for dead code stripping
-stdlib=libc++
-Ofast # fast, aggressive optimizations (clang-specific)
-fvectorize # enable loop autovectorizer
-fdiagnostics-show-template-tree (clang: print C++ template error as a tree instead of on a single line)
-Weverything # clang specific: enable every single warning
-Werror
-Wfatal-errors # die after the first error encountered
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
-Wno-global-constructors
-Wno-exit-time-destructors
-ffast-math # enable some floating point optimizations that break IEEE754 compliance but usually work
-funroll-loops # enable loop unrolling
-fstrict-aliasing # make more aggressive assumptions about whether pointers can point to the same objects
-fatal_warnings # treat linker warnings as fatal
-flto # enable link-time optimization
-dead_strip # enable dead code stripping
-Wno-error=deprecated # like being able to put __attribute((deprecated)) in code as a note to self
-Wno-error=#warnings # same thing goes for #warnings
-Wno-parentheses
because that one really rubs me the wrong way.Also, speaking of flags, I'm personally in love with -MMD. It makes dependency generation pretty painless.
-Larry -Wall
Saw that in the perl6 build long ago :-) -Os
Then if any functions are a bottleneck, compile them with function-specific O2 or O3.-u -r -s -t -u -p -i -d