about the flags used in compilation - c

I ran into this while studying a line of code in cmake for building a library:
-Wall -Wfloat-equal -o3 -fPIC
What do these compiler flags mean and how do they work? Why do they need to be inserted?

-Wall -Wfloat-equal -o3 -fPIC"
So
-Wall
Enables apparently not all, but an awful lot of compiler warning messages. It should be used to generate better code since you'll know if anything's wrong.
-Wfloat-equal
Warns if floating point numbers are used in equality comparisons. Comparing floats for equality is risky business because 1.0 isn't necessarily the exact value. I'm not sure why you'd want it in this context, because it seems like -Wall would display the warnings anyways.
-o3
Is probably O3, or optimization level 3. AKA optimize to the maximum level permitted (iirc).
-fPIC
Will generate position independent code. This is a bit more complicated, but was asked before, but is useful for including in a library.

Related

Best practices regarding warning outputs when compiling in gcc? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I'm learning c and am compiling all my programs using gcc in linux subsystem for windows.
I learned that I can include some flags by the gcc standards. Some include the basic -o or -lm.
I discovered the -Wall flag and it has outputted some warnings in my shell that I fix.
Right now my usual gcc compilation line usually lies along the lines of cc -Wall -lm -o file.exe file.c.
I recently learned that there are a lot of other flags that can be included, some regarding warnings; one is -w, which is supposed to show even more warnings than -Wall, so my question is -
1- Should I always specify -w? or is there any drawbacks or maybe even incorrect issued warnings?
2- Also, what are the best practices when compiling a program, i.e., what options/flags do you always turn on?
The more professional you become the more warnings you strive to enable. My current favorite set is -Wall -Wextra -pedantic which gives a good average.
If you think you receive a false warning, think again. Almost always the compiler is right. Until you become an intimate expert with the C standard you better ask, for example here on SO.
Some think that -Werror has some value, and for their development process they are probably right. Since I use some kind of build control software (namely "make") I don't need it, because GCC returns non-zero values on warnings, too.
All other flags depend on the purpose of the command. Some examples:
-o is great to define the name of the output file.
(EDIT)-O… sets the optimization level; some years ago -O3 might have some problems but today it should be fine.
-s strips the debug information from the output; good for the release version.
-g includes debug information to the output; there are variants depending on your goal.
-Wl,--wrap… is really sophisticated for special debugging and/or testing; read its documentation.
Another best practise can be considered the often use of -Wfatal-errors
GCC compiler errors can sometimes be several pages long (especially so if you ever have to compile C++ code). There are several reasons for while compiler errors can be so long; a typical example is some missing brackets at the top of the file, which causes the compiler to report errors for many lines of the remainder of the file.
Seasoned developers know to initially direct their attention on the top-most error, and fixing that often solves all the following pages of errors. To help with this working practise, you can add the -Wfatal-errors to tell gcc that you only want to see the first error, and that it should stop trying to compile the rest of the code once a compilation error is detected. Thus you never get the daunting pages of output that you have to scroll through.
Best practice is then switching to and from this -Wfatal-errors mode, or just leave it mostly on, only occasionally turning it off when you would like to see more errors for a particular problem.
Should I always specify -w?
-w removes all warning messages. You should not use -w.
If you meant -W, it's an old flag for -Wextra, has the same meaning as -Wextra.
Also, rules are not absolute. Not always, there are project specific needs and recommendations. If I write a short program, I sometimes use like gcc -ansi -xc - <<<'a;b;main() { printf("%d\n", a * b); } because I'm in a hurry. But usually, if not always, you should enable as many warnings as you can.
or is there any drawbacks or maybe even incorrect issued warnings?
The drawbacks of too many warnings are coming from too many enabled warnings - clutter in compiler output, while irrelevant warnings hide important stuff. The warnings I do not like:
unused functions -Wunused-function
unused function parameters -Wunused-parameter
Although code may be perfectly fine, ton of "unused function" warnings may be issued, while these functions may be used in like different project configuration chosen by different macro definitions.
what are the best practices when compiling a program, i.e., what options/flags do you always turn on?
I recommend for warnings: -Wall -Wextra -Wwrite-strings -Wno-unused-function -Wno-unused-parameter
I also recommend following flags to write safe code and protect against runtime mistakes: -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fsanitize=leak -fsanitize=pointer-subtract -fsanitize=pointer-compare -fno-omit-frame-pointer -fstack-protector-all -fstack-clash-protection -fcf-protection
Fun fact: -Wwrite-strings is not enabled with -Wall -Wextra and looks like a valuable warning to me.
See also redhat recommended compiler and linker flags for GCC.
With gcc10 static analyzer options are also worth a look.

gcc linking object files with warning/optimization flags

We are compiling a piece of software using generics where files are first made into object files, they are built like so:
arm-unknown-linux-gnu-gcc -c -O2 -Wstrict-prototypes -Wdeclaration-after-statement -fsigned-char -I/opt/tm-sdk/include -mlittle-endian -Wno-trigraphs -fno-strict-aliasing -fno-omit-frame-pointer -march=armv4 -mtune=arm9tdmi -Wall -Wextra -o src/flex.o src/flex.c
...
arm-unknown-linux-gnu-gcc -c -O2 -Wstrict-prototypes -Wdeclaration-after-statement -fsigned-char -I/opt/tm-sdk/include -mlittle-endian -Wno-trigraphs -fno-strict-aliasing -fno-omit-frame-pointer -march=armv4 -mtune=arm9tdmi -Wall -Wextra -o src/flexdb.o src/flexdb.c
Then they are linked with:
arm-unknown-linux-gnu-gcc -o flex src/flex.o src/flexdb.o src/flexio.o src/flexprotocol.o src/flexsettings.o src/flexstate.o -L/opt/tm-sdk/lib -ltag -lrt -ltmreader -lsqlite3 -lsha1
My questions is:
Do we need to include optimization and warning flags during linking? Would it do anything if -Wall, -Wextra, and -O2 were included when creating the flex binary from the object files?
Edit: Clarifying meaning based on feedback.
Do we need to include optimization and warning flags during this final stage of compilation?
Of course you don't need to include them for the link stage. You already know that, because you don't include them. But I think what you really want to know is ...
Would it do anything if -Wall, -Wextra, and -O2 were included when building the flex binary from object files.
All or almost all warnings are generated during the compilation stage. I don't off-hand know any exceptions, but it's conceivable that there are some. Thus, it's possible that passing warning-related flags during linking would trigger warnings that otherwise you would not receive. But that shouldn't affect the compiled binary in any way.
Optimization is different. There are optimizations that can be performed at link time, but that might not be performed at the default optimization level. Omitting optimization flags from the link command should not break your build, but including them may result in a binary that is faster and / or smaller.
Overall, I see no good reason to avoid passing the same warning and optimization flags during the link step that you do during the compilation steps. If you wish, it's not harmful to pass preprocessor-specific flags (e.g. -D) as well, as they'll just be ignored during linking. I presume that all this is managed by make, so it's not like you actually need to type out the options every time.
NO You're just calling the linker with the final call to gcc and -W and -O flags are for the compiler.
-Wall is primarily a preprocessor option, but there is also a reference for the libraries. See here
-Wextra appears to be strictly a c++ preprocessor option. See here
-O2 is a compiler optimization level setting. See here
So to answer your precise question, only -Wall would possibly help during your link step. The other two would not. You could test this by building with and without these options, seeing if any additional output is created in the case of warnings and if the code size or execution time differed between builds.

Curious result from the gcc linker behaviour around -ffast-math

I've noticed an interesting phenomenon around flags to the compiler linker affecting the running code in ways I cannot understand.
I have a library that presents different implementations of the same algorithm in order to test the run speed of those different implementations.
Initially, I tested the situation with a pair of identical implementation to check the correct thing happened (both ran at roughly the same speed). I begun by compiling the objects (one per implementation) with the following compiler flags:
-g -funroll-loops -flto -Ofast -Werror
and then during linking passed gcc the following flags:
-Ofast -flto=4 -fuse-linker-plugin
This gave a library that ran blazingly fast, but curiously was reliably and repeatably ~7% faster for the first object that was included in the arguments during linking (so either implementation was faster if it was linked first).
so with:
gcc -o libfoo.so -O3 -ffast-math -flto=4 -fuse-linker-plugin -shared support_obj.os obj1.os obj2.os -lm
vs
gcc -o libfoo.so -O3 -ffast-math -flto=4 -fuse-linker-plugin -shared support_obj.os obj2.os obj1.os -lm
the first case had the implementation in obj1 running faster than the implementation in obj2. In the second case, the converse was true. To be clear, the code is identical in both cases except for the function entry name.
Now I removed this strange link-argument-order difference (and actually sped it up a bit) by removing the -Ofast flag during linking.
I can replicate mostly the same situation by changing -Ofast to -O3 -ffast-math, but in that case I need to supply -ffast-math during linking, which leads again to the strange ordering speed difference. I'm not sure why the speed-up is maintained for -Ofast but not for -ffast-math when -ffast-math is not passed during linking, but I can accept it might be down to the link time optimisation passing the relevant info in one case but not the other. This doesn't explain the speed disparity though.
Removing -ffast-math means it runs ~8 times slower.
Is anybody able to shed some light on what might be happening to cause this effect? I'm really keen to know what might be going on to cause this funny behaviour so I can not accidentally trigger it down the line.
The run speed test is performed in python using a wrapper around the library and timeit, and I'm fairly sure this is doing the right thing (I can twiddle orders and things to show the python side effects are negligible).
I also tested the library for correctness of output, so I can be reasonably confident of that too.
too long for a comment so posted as an answer:
Due to the risk of obtaining incorrect results in math operations, I would suggest not using it.
using -ffast_math and/or -Ofast can lead to incorrect results, as expressed in these excerpts from the gcc manual:
option:-ffast-math Sets the options:
-fno-math-errno,
-funsafe-math-optimizations,
-ffinite-math-only,
-fno-rounding-math,
-fno-signaling-nans and
-fcx-limited-range.
This option causes the preprocessor macro __FAST_MATH__ to be defined.
This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications. "
option: -Ofast
Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on -ffast-math and the Fortran-specific -fno-protect-parens and -fstack-arrays.

How to optimize the executable generated by a C compilation in Linux terminal

Is there any way to reduce the memory used by an executable generated with a command like gcc source_file.c -o result? I browsed the Internet and also looked in the man page for "gcc" and I think that I should use something related to -c or -S. So is gcc -c -S source_file.c -o result working? (This seems to reduce the space used...is there any other way to reduce even more?)
Thanks,
Polb
The standard compiler option on POSIX-like systems to instruct the compiler to optimize is -O (capital letter O for optimize). Many compilers allow you to optionally specify an optimization level after -O. Common optimization levels include:
-O0 no optimization at all
-O1 basic optimization for speed
-O2 all of -O1 plus some advanced optimizations
-O3 all of -O2 plus expensive optimizations that aren't usually needed
-Os optimize for size instead of speed (gcc, clang)
-Oz optimize even more for size (clang)
-Og all of -O2 except for optimizations that hinder debugging (gcc)
-Ofast all of -O3 and some numeric optimizations not in conformance with standard C. Use with caution. (gcc)
option -S generate assembler output.
Better option is using llvm and generating asembler for multi architecture. Similar http://kripken.github.io/llvm.js/demo.html
llc
here is example https://idea.popcount.org/2013-07-24-ir-is-better-than-assembly/

Which gcc optimization flags should I use?

If I want to minimize the time my c programs run, what optimization flags should I use (I want to keep it standard too)
Currently I'm using:
-Wall -Wextra -pedantic -ansi -O3
Should I also use
-std=c99
for example?
And is there I specific order I should put those flags on my makefile? Does it make any difference?
And also, is there any reason not to use all the optimization flags I can find? do they ever counter eachother or something like that?
I'd recommend compiling new code with -std=gnu11, or -std=c11 if needed. Silencing all -Wall warnings is usually a good idea, IIRC. -Wextra warns for some things you might not want to change.
A good way to check how something compiles is to look at the compiler asm output. http://gcc.godbolt.org/ formats the asm output nicely (stripping out the noise). Putting some key functions up there and looking at what different compiler versions do is useful if you understand asm at all.
Use a new compiler version. gcc and clang have both improved significantly in newer versions. gcc 5.3 and clang 3.8 are the current releases. gcc5 makes noticeably better code than gcc 4.9.3 in some cases.
If you only need the binary to run on your own machine, you should use -O3 -march=native.
If you need the binary to run on other machines, choose the baseline for instruction-set extensions with stuff like -mssse3 -mpopcnt. You can use -mtune=haswell to optimize for Haswell even while making code that still runs on older CPUs (as determined by -march).
If your program doesn't depend on strict FP rounding behaviour, use -ffast-math. If it does, you can usually still use -fno-math-errno and stuff like that, without enabling -funsafe-math-optimizations. Some FP code can get big speedups from fast-math, like auto-vectorization.
If you can usefully do a test-run of your program that exercises most of the code paths that need to be optimized for a real run, then use profile-directed optimization:
gcc -fprofile-generate -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
./my_program -option1 < test_input1
./my_program -option2 < test_input2
gcc -fprofile-use -Wall -Wextra -std=gnu11 -O3 -ffast-math -march=native -fwhole-program *.c -o my_program
-fprofile-use enables -funroll-loops, since it has enough information to decide when to actually unroll. Unrolling loops all over the place can make things worse. However, it's worth trying -funroll-loops to see if it helps.
If your test runs don't cover all the code paths, then some important ones will be marked as "cold" and optimized less.
-O3 enables auto-vectorization, which -O2 doesn't. This can give big speedups
-fwhole-program allows cross-file inlining, but only works when you put all the source files on one gcc command-line. -flto is another way to get the same effect. (Link-Time Optimization). clang supports -flto but not -fwhole-program.
-fomit-frame-pointer has been the default for a while now for x86-64, and more recently for x86 (32bit).
As well as gcc, try compiling your program with clang. Clang sometimes makes better code than gcc, sometimes worse. Try both and benchmark.
The flag -std=c99 does not change the optimization levels. It only changes what target language standard you want the compiler to confirm to.
You use -std=c99 when you want your program to be treated as a C99 program by the compiler.
The only flag that has to do with optimization among those you specified is -O3. Others serve for other purposes.
You may want to add -funroll-loops and -fomit-frame-pointer, but they should be already included in -O3.

Resources