From 9d938534054a6cb7582cf0b8625a230bfa4f1460 Mon Sep 17 00:00:00 2001 From: Taylor Sasser Date: Tue, 29 Jul 2025 10:41:56 -0400 Subject: [PATCH] Help: Add documentation for debugging with GDB --- Help/dev/README.rst | 2 + Help/dev/debug.rst | 197 +++++++++++++++++++++++++++++++++ Utilities/gdb/gdbinit-template | 5 + 3 files changed, 204 insertions(+) create mode 100644 Help/dev/debug.rst create mode 100644 Utilities/gdb/gdbinit-template diff --git a/Help/dev/README.rst b/Help/dev/README.rst index 2a2d32d9d9..84766a67d6 100644 --- a/Help/dev/README.rst +++ b/Help/dev/README.rst @@ -40,11 +40,13 @@ CMake developer documentation is provided by the following documents: * The `CMake Documentation Guide`_. * The `CMake Testing Guide`_. * The `CMake Experimental Features Guide`_. +* The `CMake Debugging Guide`_. .. _`CMake Source Code Guide`: source.rst .. _`CMake Documentation Guide`: documentation.rst .. _`CMake Testing Guide`: testing.rst .. _`CMake Experimental Features Guide`: experimental.rst +.. _`CMake Debugging Guide`: debug.rst Maintainer Documentation ======================== diff --git a/Help/dev/debug.rst b/Help/dev/debug.rst new file mode 100644 index 0000000000..ded270f618 --- /dev/null +++ b/Help/dev/debug.rst @@ -0,0 +1,197 @@ +CMake Debugging Guide +********************* + +This guide explains how to attach a debugger to CMake's unit testing framework. +We'll focus on using **GDB** on Linux for both command-line and IDE debugging. +See documentation on `CMake Development`_ for more information. + +.. _`CMake Development`: README.rst + +Linux: Using GDB +================ + +On Linux, the GNU Debugger (**GDB**) is the standard tool for debugging the +CMake test suite. The core process involves launching the ``cmake`` executable +from within GDB with a specific set of arguments that configure and run the +desired test. + +GDB Configuration +----------------- + +For effective debugging, GDB must be configured to handle child processes +correctly, which CMake tests often create. A good practice is to use a local +``.gdbinit`` file in your build directory. This keeps CMake-specific settings +separate from your global configuration. + +**1. Enable Local .gdbinit Files (One-Time Setup)** + +To allow GDB to automatically load configuration from your build directory, +add the following line to your global GDB initialization file at +``$HOME/.gdbinit``. This is a one-time setup that makes future projects easier +to manage. + +.. code-block:: text + + set auto-load local-gdbinit on + +**2. Create a Project-Specific .gdbinit** + +Next, create a ``.gdbinit`` file inside your CMake **build directory**. +This file will contain settings specific to debugging CMake. +To make this easier, you can symlink the template file provided in the CMake +source tree: + +.. code-block:: bash + + # Navigate to your build directory + cd /path/to/your/cmake/build + + # Create a symlink to the template + ln -s $cmake_srcdir/Utilities/gdb/gdbinit-template .gdbinit + +The template contains the essential settings for debugging CMake tests: + +.. code-block:: gdb + + # Allows GDB to follow child processes + set follow-fork-mode child + + # Allows the parent process continue in parallel + set non-stop on + +Debugging from the Command Line +------------------------------- + +To start debugging, first cd to the build directory. Then, launch the +``cmake`` executable using ``gdb --args``, which passes the necessary test +configuration arguments directly to CMake. + +.. note:: + + To get the launch command, run ``ctest -R "RunCMake.$TESTNAME" -VV -N`` + + +The following example runs the ``InstallPackageInfo`` test. + +.. code-block:: bash + + # Define paths to your CMake source and build directories + CMAKE_SOURCE_DIR="$HOME/cmake" + CMAKE_BUILD_DIR="$CMAKE_SOURCE_DIR/build" + + # Define the specific test to run + TEST_NAME="InstallPackageInfo" + + # Navigate to the build directory + cd "$CMAKE_BUILD_DIR" + + # Launch GDB with the appropriate arguments for the test + gdb --args ./bin/cmake \ + "-DCMAKE_MODULE_PATH=$CMAKE_SOURCE_DIR/Tests/RunCMake" \ + "-DRunCMake_GENERATOR=Ninja" \ + "-DRunCMake_SOURCE_DIR=$CMAKE_SOURCE_DIR/Tests/RunCMake/$TEST_NAME" \ + "-DRunCMake_BINARY_DIR=$CMAKE_BUILD_DIR/Tests/RunCMake/$TEST_NAME" \ + "-P" "$CMAKE_SOURCE_DIR/Tests/RunCMake/RunCMakeTest.cmake" + +Once GDB loads, you may set breakpoints (e.g., ``b cmInstallCommand``) and +then start the test by typing ``run``. + +Filtering Tests +--------------- + +Some test suites contain multiple sub-tests. To run only a specific one, +you can use the ``RunCMake_TEST_FILTER`` environment variable. + +For example, to run only the "Metadata" test within the ``InstallPackageInfo`` +suite, you can set the variable before launching GDB: + +.. code-block:: bash + + RunCMake_TEST_FILTER="Metadata" gdb --args ... + +Alternatively, you can set the environment variable from within the +GDB session before running the test: + +.. code-block:: gdb-prompt + + (gdb) set environment RunCMake_TEST_FILTER Metadata + (gdb) run + + +IDE Integration +--------------- + +You can also debug CMake tests directly from your IDE. + +CLion +===== + +If you have configured GDB to auto-load local ``.gdbinit`` files as described +above, CLion will automatically pick up the necessary settings. + +A simple way to debug a test is to modify its ``CTest`` run configuration: + +#. **Select the Test**: In the "Run/Debug Configurations" dialog, find the + ``CTest`` entry for your test (e.g., ``RunCMake.InstallPackageInfo``). +#. **Add CTest Arguments**: In the "CTest arguments" field, add + ``--extra-verbose``. This is helpful for debugging because it prints the + exact command ``CTest`` uses to run the test. +#. **Set Working Directory**: Ensure the "Working Directory" field is set to + ``$CMakeCurrentLocalGenerationDir$``. + +You can now set breakpoints in your code and debug this configuration. + +Visual Studio Code +================== + +Create a ``launch.json`` file in the ``.vscode`` directory of your +CMake **source folder** with the following configuration. This configuration +hardcodes the necessary GDB settings, so it does not depend on an external +``.gdbinit`` file. + +.. code-block:: json + + { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug CMake Test", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/bin/cmake", + "args": [ + "-DCMAKE_MODULE_PATH=${workspaceFolder}/Tests/RunCMake", + "-DRunCMake_GENERATOR=Ninja", + "-DRunCMake_SOURCE_DIR=${workspaceFolder}/Tests/RunCMake/InstallPackageInfo", + "-DRunCMake_BINARY_DIR=${workspaceFolder}/build/Tests/RunCMake/InstallPackageInfo", + "-P", + "${workspaceFolder}/Tests/RunCMake/RunCMakeTest.cmake" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build", + "environment": [], + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Follow child processes", + "text": "set follow-fork-mode child", + "ignoreFailures": true + }, + { + "description": "Don't stop the parent process", + "text": "set non-stop on", + "ignoreFailures": true + } + ] + } + ] + } + +.. note:: + + Remember to change the test name (``InstallPackageInfo``) in the ``"args"`` section to the specific test you want to debug. diff --git a/Utilities/gdb/gdbinit-template b/Utilities/gdb/gdbinit-template new file mode 100644 index 0000000000..0e4a26774d --- /dev/null +++ b/Utilities/gdb/gdbinit-template @@ -0,0 +1,5 @@ +# Allows GDB to follow child processes +set follow-fork-mode child + +# Allows the parent process continue in parallel +set non-stop on