thecodingidiot.com

Building CCompiler Flags Worth Using

Compiler Flags Worth Using

The compile command on the previous page was gcc sort.c -o sort. That works, but it leaves several useful checks turned off and the binary harder to debug than it has to be. From here on out we will use four flags every time we compile.

gcc -Wall -Wextra -g sort.c -o sort

-Wall and -Wextra

You met these in f04/01. They turn on the warnings the compiler can produce. -Wall enables most of the common ones; -Wextra adds a few more that catch real mistakes (assigning a value you never use, comparing signed and unsigned types, leaving variables uninitialised in some code paths). Together they catch a lot at compile time, for free.

Treat warnings as errors during development. If the compiler is telling you something looks wrong, it usually does. Recompile sort with these flags now:

gcc -Wall -Wextra sort.c -o sort

If it compiles silently, good. The bugs we are about to hunt are not the kind warnings can catch — they manifest at runtime, not compile time.

-g

-g tells gcc to include debug symbols in the binary. Debug symbols are a table mapping every machine instruction in the executable back to the source file and line number it came from. With them, gdb can show you the actual line of sort.c your program is running, set breakpoints by function name, and print the values of named variables. Without them, the debugger only sees raw memory addresses and assembly.

Every binary we build for the rest of this chapter will use -g. If you forget, the next three pages will not work — gdb will show you addresses instead of code, valgrind will report a leak without a line number, and the sanitiser stack traces will be unintelligible.

gcc -Wall -Wextra -g sort.c -o sort

The binary gets larger by a few kilobytes, but that does not matter during development. You strip debug symbols later, only for the release build.

-std=c99

By default gcc compiles in its own extended dialect — typically something newer than C99, with GCC-specific extras mixed in. -std=c99 tells it to enforce the 1999 C standard exactly and reject anything beyond it. Code that compiles under -std=c99 will compile the same way on any conforming toolchain, including the cross-compilers we use in the r-tier.

We will add it to CFLAGS in the Makefile on page 06. The sanitiser rebuilds from page 05 onward also carry it.

Optimisation: -O0, -O2, -O3, -Og

gcc can rearrange and rewrite your code to make the binary faster, at the cost of making it harder to debug — variables disappear into registers, lines get reordered, branches get predicted. The flag is -O followed by a level:

  • -O0 is the default if you do not say. No optimisation. Slowest binary, easiest to debug.
  • -O2 is what most release builds use. Aggressive optimisation that does not bloat the binary unnecessarily.
  • -O3 is more aggressive still. Sometimes faster, sometimes not.
  • -Og is "optimise for debugging" — a middle ground that does some safe optimisations while keeping the binary debuggable.

During development we use -O0 (implicit, no flag) so debugger output lines up exactly with source. Release builds use -O2. We will not need release builds in this chapter.

-I, -L, -l

These three are about external code. You will not need them yet — sort only uses the standard library, which gcc finds without help — but they show up the moment a project pulls in a third-party library, so they are worth meeting now.

  • -I path adds path to the list of directories gcc searches for header files. If you #include "foo.h" and foo.h lives in ~/code/include/, you compile with -I ~/code/include.
  • -L path does the same for library files (the compiled artefacts the linker pulls in).
  • -l name tells the linker to link against lib<name>.so (or lib<name>.a). For example -lm links the math library.

If you ever see a build error like cannot find -lfoo or no such file: bar.h, one of these three flags is missing.

Recompiling sort

With everything together:

gcc -Wall -Wextra -g sort.c -o sort
./sort test.txt

You should still see the same sorted output, with no warnings. The program looks correct. It is not.

The next three pages turn each of gdb, valgrind, and the sanitisers loose on it. One bug per tool.