Build, Debug, and Test

Build, Debug, and Test

Compile with warnings, debug with symbols, and use sanitizers to catch bugs early.

Build, Debug, and Test

Compiler flags

For local work, start with strong warnings.

-std=c++23 -Wall -Wextra -Wpedantic

These warnings catch suspicious code early. Treat a new warning as a bug report until you can justify ignoring it.

Debugging

Add debug symbols and disable heavy optimization while diagnosing problems.

-g -O0

Use low optimization while diagnosing logic bugs so stepping and variable inspection stay trustworthy.

Sanitizers

-fsanitize=address,undefined

These catch memory and undefined-behavior bugs that might otherwise look random.

For concurrent code, create a separate ThreadSanitizer build instead of trying to combine every sanitizer in one binary.

A practical command-line workflow

g++ -std=c++23 -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined src/main.cpp -o build/app
./build/app

This is enough for small projects before you introduce CMake or a larger build layout.

Testing advice

When you can reproduce a bug with one small test, debugging becomes faster and future regressions become cheaper to catch.

A practical CMake loop

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build
ctest --test-dir build --output-on-failure

This is the default workflow many modern C++ projects settle on, even when the codebase grows.

Debugging loop that scales

  1. Reproduce the bug reliably.
  2. Build with debug info and relevant sanitizers.
  3. Reduce the failing case until it is small enough to reason about.
  4. Fix the code.
  5. Keep the reproducer as a test when possible.

Sanitizer strategy

Run them in dedicated builds instead of combining every tool in one configuration.

Example CMake presets worth having

Even if you do not use CMake presets literally, thinking in named configurations keeps workflow decisions consistent.

Better bug reports

When you find a bug, record the failing input, compiler, build flags, and exact observed output. That information turns debugging from guessing into engineering.

Small but important habits

Example in practice

g++ -std=c++23 -Wall -Wextra -Wpedantic -g src/main.cpp -o build/app-debug

Try this variation

Add a second build configuration with sanitizers enabled. Use it for debugging sessions and keep a faster release build for routine runs.

g++ -std=c++23 -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined src/main.cpp -o build/app-asan