1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 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.
|