Kahibaro
Discord Login Register

Debug builds

What is a Debug Build?

A debug build is a version of your program compiled specifically to make finding and fixing bugs easier, not to run as fast as possible. In HPC, you typically:

Debug builds trade performance for:

Typical Characteristics of Debug Builds

While details vary by compiler, most debug builds have these properties:

Common Compiler Flags for Debug Builds

Exact flags depend on the compiler family. Here are the typical patterns in HPC compilers.

GCC (gcc, g++, gfortran)

Core debug flags:

Example debug compile commands:

Optional but very useful:

Intel oneAPI (icx/icpx/ifx, classic icc/ifort)

Core debug flags:

Example:

Some Intel-specific helpful flags (availability may vary between classic and oneAPI):

LLVM/Clang and Flang

Core debug flags are similar to GCC:

Examples:

Build-Type Separation: Debug vs Release

In HPC projects, you almost never want to manually toggle flags every time. Instead, you define two (or more) build types:

Key ideas:

Debug Builds in Make-based Workflows

A typical pattern in a Makefile is to define variables for flags and build types.

Example:

CC      = gcc
CFLAGS_DEBUG   = -g -O0 -Wall -Wextra
CFLAGS_RELEASE = -O3 -march=native -DNDEBUG
# Default build type
CFLAGS = $(CFLAGS_DEBUG)
all: myprog
myprog: main.o solver.o
	$(CC) $(CFLAGS) -o $@ $^
main.o: main.c
	$(CC) $(CFLAGS) -c $<
solver.o: solver.c
	$(CC) $(CFLAGS) -c $<
debug: clean
	$(MAKE) CFLAGS="$(CFLAGS_DEBUG)"
release: clean
	$(MAKE) CFLAGS="$(CFLAGS_RELEASE)"
clean:
	rm -f myprog *.o

Usage:

This simple pattern keeps debug and release configurations defined in one place and easy to switch.

Debug Builds in CMake-based Workflows

CMake has first-class support for build types. For single-config generators (e.g. Makefiles, Ninja):

cmake -B build-debug -DCMAKE_BUILD_TYPE=Debug

cmake -B build-release -DCMAKE_BUILD_TYPE=Release

Then:

CMake sets default flags for each build type using variables like:

Typical defaults (simplified):

You can append your own flags in CMakeLists.txt:

set(CMAKE_C_FLAGS_DEBUG   "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra")

Or use target_compile_options scoped to specific targets and configurations:

target_compile_options(myprog PRIVATE
  $<$<CONFIG:Debug>:-Wall -Wextra>
  $<$<CONFIG:Release>:-DNDEBUG>
)

For multi-config generators (e.g. Visual Studio, some Ninja setups), you choose the configuration at build time:

Using Debug Builds with HPC Debuggers

The value of a debug build in HPC is largely about how well you can inspect the running program.

With -g and low optimization, you can:

For MPI/OpenMP/OpenACC programs, HPC debuggers (such as gdb for simple cases, or cluster tools like DDT, TotalView, etc.) rely heavily on debug symbols. Without a debug build, they often show:

On clusters, you usually:

  1. Compile your code with debug flags on a login node.
  2. Run the parallel program under the debugger on compute nodes (often via a job script or an interactive allocation).
  3. Use the debugger’s GUI or CLI to attach to multiple processes/threads.

Debug Builds and Runtime Checks

Debug builds are a good place to turn on extra runtime checking. Examples (compiler-, language-, and library-dependent):

In HPC contexts, you may want to run smaller test problems when using heavy checks, to avoid long runtimes and resource waste.

Trade-offs of Debug Builds in HPC

Key trade-offs relative to optimized builds:

Because of this, a common pattern is:

  1. Debug logic and correctness on a workstation or single node with debug builds.
  2. Spot-check on the cluster with small parallel runs, still debug builds.
  3. Switch to an optimized build for scaling tests and production jobs.

Practical Workflow Recommendations

To use debug builds effectively in an HPC environment:

Summary

Debug builds in HPC:

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!