Using CMake and LLDB in Emacs
Düzenlendi · Kapsam: Modern C++ development and lldb-dap debugging in GNU Emacs 29+ with Eglot, project.el, compile and dape.
C++ development in Emacs has changed substantially through the built-in LSP client eglot, project manager project.el and Debug Adapter Protocol client dape. A modern IDE workflow can now be built with lightweight components without installing a large stack of packages such as lsp-mode, treemacs, hydra and dap-mode.
This guide configures and builds a CMake-based C++ project in Emacs, then debugs it visually using lldb-dap from LLVM 18+.
1. Why dape and lldb-dap?
Historically, debugging in Emacs had two main approaches:
- GUD (
gud-lldb/gud-gdb): the long-established terminal-oriented interface. Parsing LLDB output with regular expressions can be fragile, and does not provide the same modern object-tree, watch and complex-stack views. dap-mode: brought the VS Code debugging protocol to Emacs, but is closely tied to the largerlsp-modeecosystem.
dape — Debug Adapter Protocol for Emacs:
- Works with the built-in
eglotandproject.elin Emacs 29+ without requiring another LSP package. - Opens a GDB-MI-style multipane dashboard (
*dape-info*) with threads, stack traces, locals, watches and breakpoints. - Displays variable values directly in source buffers as inlay hints.
- Uses
repeat-modefor single-key stepping (n,s,c,o).
[!NOTE] In LLVM 18,
lldb-vscodewas renamedlldb-dapto reflect the protocol’s broader applicability.
2. Emacs configuration (init.el)
Add this configuration to ~/.emacs.d/init.el or ~/.config/emacs/init.el:
;;; init.el --- Modern C++, CMake ve LLDB Yapılandırması
(require 'use-package)
(setq use-package-always-ensure t)
;; -------------------------------------------------------------
;; 1. Dil Sunucusu (Yerleşik Eglot + Clangd)
;; -------------------------------------------------------------
(use-package eglot
:ensure nil ; Emacs 29 ile yerleşiktir
:hook
((c-mode c++-mode c-ts-mode c++-ts-mode) . eglot-ensure)
:config
(add-to-list 'eglot-server-programs
'((c-mode c++-mode c-ts-mode c++-ts-mode)
. ("clangd"
"--background-index"
"--clang-tidy"
"--completion-style=detailed"
"--header-insertion=iwyu"))))
;; -------------------------------------------------------------
;; 2. Proje ve Derleme (Yerleşik project.el & compile)
;; -------------------------------------------------------------
(use-package project
:ensure nil
:config
;; Git deposu olmasa dahi CMakeLists.txt bulunan dizini proje kökü say
(add-to-list 'project-vc-extra-root-markers "CMakeLists.txt"))
(use-package compile
:ensure nil
:custom
;; Her defasında sormadan doğrudan son derleme komutunu çalıştır
;; Komutu değiştirmek istediğinizde C-u M-x compile yapabilirsiniz
(compilation-read-command nil)
(compilation-scroll-output 'first-error)
(compilation-always-kill t)
:bind
(("C-c c" . compile)
("C-c r" . recompile)))
;; -------------------------------------------------------------
;; 3. Modern Hata Ayıklama (dape + lldb-dap)
;; -------------------------------------------------------------
(use-package dape
:preface
(setq dape-buffer-window-arrangement 'gdb)
:config
;; Adımlama sırasında tek tuş kullanımını etkinleştir (n, s, c, o)
(repeat-mode 1)
;; Kod içinde değişken değerlerini satır sonunda göster
(setq dape-inlay-hints t)
;; lldb-dap yapılandırmasını özelleştir
(with-eval-after-load 'dape
(add-to-list 'dape-configs
`(lldb-cpp
modes (c-mode c++-mode c-ts-mode c++-ts-mode)
command "lldb-dap"
:type "executable"
:request "launch"
:cwd dape-cwd-fn
:program (lambda ()
(read-file-name "İkili dosya seçin: "
(expand-file-name "build/" (dape-cwd))))
:args []
:stopOnEntry nil)))
:bind
(("C-x C-a d" . dape)
("C-x C-a b" . dape-breakpoint-toggle)
("C-x C-a c" . dape-breakpoint-expression)
("C-x C-a r" . dape-repl)
("C-x C-a i" . dape-info)))
3. Project-level CMake and Clangd configuration
Add .dir-locals.el to the project root so the Clangd language server and Emacs compilation command recognise the project:
((nil . ((compile-command . "cmake --build build -j")
(project-compilation-buffer-name-function . project-prefixed-buffer-name)))
(c++-mode . ((eglot-workspace-configuration
. (:clangd (:compilationDatabasePath "build"))))))
Enable generation of the compilation database (compile_commands.json) in CMake:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
4. Debugging workflow
The following steps demonstrate debugging a C++ program.
Step 1: Build
With a source file open, use C-c c (compile) or C-x p c (project-compile). Output appears in *compilation*. Jump to a reported error with C-x \ (next-error`).
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build -j
[!IMPORTANT] Build in Debug or RelWithDebInfo mode to make debugging symbols available.
Step 2: Set breakpoints
Move to the source line where execution should stop:
C-x C-a b(dape-breakpoint-toggle): toggles a breakpoint and displays a red marker at the start of the line.C-x C-a c(dape-breakpoint-expression): adds a conditional breakpoint, for example stopping when a loop counter satisfiesi == 100.
Step 3: Start a dape session
- Press
C-x C-a d(dape). - Choose
lldb-cppin the minibuffer. - Confirm
build/uygulamawhen asked for the binary path.
Emacs rearranges the windows into the gdb layout:
- Source at the upper left.
- Stack and threads at the upper right.
- Current local variables at the lower right.
- An interactive LLDB command line (
*dape-repl*) at the bottom.
Step 4: Inspect variables and step
When execution stops at a breakpoint:
- Inline values: current variable values appear as faint text beside the code.
- Watches: press
iin*dape-info*to watch an expression such asdizi.size(). - Single-key stepping (
repeat-mode): after the first command, continue with individual letters without repeating the prefix:n: step over / next line.s: step into a function.o: step out of a function.c: continue to the next breakpoint.r: restart the program.q: quit the debugging session.
Step 5: Use the LLDB REPL
Switch to *dape-repl* to inspect a memory address or evaluate a C++ expression:
p my_vector.size()
expr my_vector.push_back(42)
x/16xb pointer_address
Sources and verification environment
This guide was tested and verified on macOS Sonoma 14 and Ubuntu 24.04 using GNU Emacs 29.4, Clang 18 (lldb-dap), Eglot and dape 0.19.