Quick and dirty debugging in JUCE


#1

Hi all

One of the things that’s been slowing me down as I learn JUCE is that I don’t know how to debug properly. If I get runtime errors in my code I usually have to come up with custom ways to test it, which can take me hours, but I’m sure that a more experienced eye could find the problem in minutes. When I was starting out in C++ and writing console applications, it was easy enough to add a single std::cout line of code to query some variable, but now that I’m working with a JUCE application, I don’t even know how to print simple messages. So,

  1. What are the easiest ways of printing simple test messages in a JUCE application? Ideally I would like to be able to insert a single line of code and have a message pop up somewhere (in a console, in a new window, or anywhere). I’ve seen people use the DBG() function before, but I’m not sure how it works, nor if it’s the right tool.
  2. Does anyone have any general advice for debugging JUCE application code? I’m trying to invest time into learning how to use the CodeBlocks built-in debugger, but I find it confusing in larger applications with multiple dependencies and no console. Is learning how to use the debugger a must, or is it just a matter of style?

Any help would be appreciated. I hope these questions are useful to others also.


#2
DBG( "message" );

messages only show up in the output window in your IDE in debug builds, not release builds.
If you want to know how it works, right click on it, “Go to definition” and look at the source code. it’s just a macro.

use breakpoints. Xcode and Visual Studio have great support for breakpoints and debugging.


#3

When I try DBG("message") in CodeBlocks (Ubuntu) I don’t see any output messages anywhere. I’m looking in the “Build Log” and “Debugger” windows at the bottom. Am I missing something? The IDE is definitely set to compile on debug.


#4

I don’t know about CodeBlocks, but it will most certainly show up, when you start your executable in a terminal.

Since you mention “quick and dirty”, it is ok to do it like that. But be aware, that printing to anything like file logging, std::cout and DBG etc. are all blocking calls, and must be removed from your audio thread, once you found what you were looking for. These calls can easily create buffer underruns and result in distorted (chopped) audio.


#5

I’d say that learning to use a debugger is worth the time; it will save you time when trying to pinpoint errors, as you can set breakpoints, step through code and inspect variable values to get an idea of what’s going on. Printing log messages is fine too, I use both methods, but the debugger is usually a more efficient way seeing whats going especially as you can set/remove breakpoints as the code is running without restarting or recompiling.


#6

Thanks for the tips. I’m trying to migrate to Visual Studio right now, as the debugging in CodeBlocks is pretty buggy.

Part of the problem is that the tutorials etc. which teach you have to use a debugger always show very simple and contrived example code. This leaves me with an understanding of the basic principles of debugging, but not an intuition of how and when to use it. When I come to try it out in a real program, I’m not exactly sure how to proceed and I get confused with the amount of new information that it presents. But Visual Studio does seem to be better, so hopefully I can develop the right intuitions.


#7

Text logging is also a completely valid way to investigate the behavior of the code and IMHO can in some cases be much more convenient than setting up breakpoints, stepping in the code etc with the debugger…I have also used variable/data visualizers that work by drawing in the GUI which can also be quite informative to understand the behavior of the running software. However, these are mostly useful for cases when you have code that actually manages to run, just with incorrect/unexpected results.

When you hit actual crashes and/or JUCE or other assertions, using the debugger is obviously the way to go to deal with those issues. Adding your own JUCE asserts (jassert) into your own code is also a good way to do basic sanity checking for out of bounds variables, null pointers and so on. But to get good use of those, you need to be able to use the debugger.


#8

Good logging hygiene is an under-appreciated discipline!

I always try to think carefully about this and ship products with some way to toggle logging on in the field – there will always be bugs that only happen on one customer’s machine, and it’s often the case that having them email the log file will provide enough of a clue to fix an otherwise intractable bug.

Check the JUCE Logger and FileLogger classes in the docs.