Back
How to's

How to debug

1. Print as you go

println() works just like in Processing and is the fastest way to inspect values. You can also use Umfeld’s console("message", x), which conveniently adds a timestamp to your output.

println("frame: ", frameCount, "  x: ", x);
console("position: ", position.x, ", ", position.y);

This “print debugging” method is especially useful as a fallback for timing-based errors (like physics explosions) where pausing the app in a debugger might slow it down so much that the error never occurs.

2. Build with debug symbols

To use a debugger effectively, you first need to compile your project with debugging symbols. In Umfeld, you must configure your build by running:

cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build

3. Debugging in the terminal (GDB / LLDB)

Once built with debug symbols, you can step through your app using lldb ./build/minimal (macOS/Linux) or gdb.

For a comprehensive guide on using GDB specifically for creative coding scenarios (crashes, NaNs, freezes), check out the Everything you always wanted to know about GDB but were afraid to ask article.

GDB’s built-in TUI (Text User Interface)

You don’t need plugins to get a good terminal interface. Start GDB by typing gdb -tui ./myApp to split your terminal, showing your C++ code on top and the command line on the bottom.

Catching segmentation faults

Creative coding crashes frequently due to bad pointers (e.g., trying to draw an unloaded image). Run your app in GDB, and when it crashes, type bt (backtrace). It will output the exact lineage of function calls that led to the crash, pointing directly to the line in your code where the bad pointer is.

gdb ./build/my-sketch
(gdb) run
# ... crash ...
(gdb) bt

Conditional breakpoints

If you put a normal breakpoint inside your update() or draw() loop, GDB will freeze your app 60 times a second. Instead, use conditionals:

break application.cpp:105 if frameCount > 500
break particle.cpp:42 if position.x < 0

The first will only pause after 500 frames; the second will only pause if a particle goes off-screen.

Watchpoints for memory corruption

If a color or physics variable keeps randomly changing to garbage data, use a watchpoint like watch myColor.r. GDB runs the app at full speed and will automatically pause the exact microsecond that specific variable changes.

watch myColor.r

Catching infinite loops

If you suspect an infinite loop, let the program execute long enough to enter it. Issue the debugger’s interrupt command (e.g., Ctrl+C in GDB) to suspend the program, then do a backtrace (bt) to see exactly where it is stuck.

4. Visual debugging with IDEs

If you prefer a graphical interface, modern C++ IDEs provide excellent debugging tools:

  • VS Code (C/C++ Extension): This acts as a seamless UI for GDB or LLDB. You can click to add breakpoints, hover over your vectors and matrices to see their values, and view your call stack visually.
  • CLion: Integrates smoothly with the GDB/LLDB backend. It allows you to set breakpoints, inspect variables, and evaluate inline expressions without interrupting your current debugging session.

5. Read the first error first

When the compiler shouts, the first error is the real one; the rest are usually just fallout. Scroll up to find the root cause. If you are stuck, refer to the What to do when you face problems page for a list of common Umfeld gotchas.

6. Core debugging principles

The principle of confirmation

Fixing a buggy program is the process of confirming, one by one, that the many things you believe to be true about the code actually are true. When an assumption fails to confirm, you are surprised. Surprises are good, because they lead you to the location of the bug.

Use a top-down approach

Your main program should consist mostly of calls to functions that do substantial work. When stepping through code with a debugger and encountering a function call, choose to “step over” first. Inspect the results of the call; if the function worked correctly, you avoid the time-consuming effort of stepping through code that isn’t misbehaving.

If a syntax error is preventing compilation and the error message is unhelpful, comment out half of the code. If it compiles, the error is in the commented half. This also works in time: if a variable goes bad during the first 1,000 iterations of a loop, check its value at the 500th iteration.