Debugging C/C++ in VS Code on Apple Silicon with clang++ and LLDB
For small single-file C/C++ programs on an Apple Silicon Mac, I want one keystroke to compile the file I’m looking at and drop me into a debugger. The setup below does exactly that: a build task compiles the active file with /usr/bin/clang++, and a launch configuration starts it under LLDB using the Microsoft C/C++ extension’s cppdbg debugger.
Only two files are involved, both in the project’s .vscode/ folder:
.vscode/
├── tasks.json # build the active file with clang++
└── launch.json # build, then debug with LLDB
Prerequisites
- The C/C++ extension (
ms-vscode.cpptools). It provides both thecppbuildtask type and thecppdbgdebug type. - The Xcode Command Line Tools (
xcode-select --install) or full Xcode. This gives you/usr/bin/clang++, plus theLLDB.frameworkthat the extension’s bundledlldb-mineeds to talk to LLDB.
tasks.json: build the active file
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang++ build active file",
"command": "/usr/bin/clang++",
"args": ["-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}"],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}
This is essentially the task the C/C++ extension generates (hence the detail string). The fields that matter:
-
labelis the name the debug configuration uses to find this task, so it has to matchpreLaunchTaskinlaunch.jsonexactly. -
commandcalls the systemclang++with these arguments:-
-fdiagnostics-color=alwayskeeps compiler errors and warnings colored in the terminal. -
-gemits debug info. Without it, LLDB can’t map the binary back to source lines, so breakpoints won’t bind. -
${file}is the file open in the active editor. -
-o ${fileDirname}/${fileBasenameNoExtension}writes the executable next to the source, named after it without the extension (foo.cppbuilds tofoo).
-
-
options.cwdruns the compiler from the source file’s directory. - The
$gccproblem matcher parses clang’s GCC-style diagnostics into the Problems panel. -
groupwith"isDefault": truemakes this the default build task.
Because this calls clang++, .c files are compiled as C++. For plain C, point command at /usr/bin/clang instead.
launch.json: debug with LLDB
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "C/C++: clang++ build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": true,
"MIMode": "lldb",
"preLaunchTask": "C/C++: clang++ build active file"
}
]
}
-
"type": "cppdbg"with"MIMode": "lldb"selects the C/C++ extension’s GDB/LLDB debug adapter and has it drive LLDB throughlldb-mi. GDB doesn’t support Apple Silicon, so LLDB is the only option here. -
programis the same path the build task writes to with-o. -
cwdis the source file’s directory.argsandenvironmentare empty, so no command-line arguments or extra environment variables are passed. -
"stopAtEntry": falseruns straight to your first breakpoint. Set it totrueto stop atmain. -
"externalConsole": trueruns the program in a separate Terminal window. On macOS,lldb-mican’t use VS Code’s integrated terminal. Withfalse, output only shows up in the Debug Console, so you’d have no way to type intostdin. -
preLaunchTasknames the build task’slabel. That’s what makes F5 rebuild before every debug session.
My original config also set "targetArchitecture": "arm64". The C/C++ extension added native Apple M1 debugger support in version 1.9.7 (March 2022), and the docs now mark targetArchitecture as deprecated because the architecture is detected automatically, so I’ve dropped it.
The C/C++ extension isn’t the only way to use LLDB in VS Code: CodeLLDB ("type": "lldb") and LLVM’s LLDB DAP extension ("type": "lldb-dap") talk to LLDB without going through lldb-mi, though each uses its own launch.json schema.
What about settings.json?
You don’t need any workspace settings for this. My original .vscode/settings.json had built up a long files.associations list mapping extensionless headers like vector and iostream, inconsistently, to either c or cpp. Older versions of the C/C++ extension added those entries automatically whenever you navigated into a system header (the C_Cpp.autoAddFileAssociations setting). Since version 1.29.2 (December 2025), that setting is off by default and the extension associates the standard extensionless headers with C++ on its own, so you can delete entries like these.
Usage
- Copy
tasks.jsonandlaunch.jsoninto.vscode/at the root of your project. - Open a C/C++ source file and set some breakpoints.
- In the Run and Debug view, select C/C++: clang++ build and debug active file and press F5. VS Code runs the build task first. LLDB then launches the freshly built binary in an external Terminal window.
- To build without debugging, use Terminal > Run Build Task (⇧⌘B). This task is the default, so it runs without asking.
On macOS Catalina and later, the external Terminal window may open but ignore your input until VS Code has permission to control Terminal. The VS Code docs describe a workaround: run a one-off task that opens Terminal via osascript, and accept the permission prompt.
This setup compiles only the active file (${file}), so it suits exercises and small programs. Multi-file projects need different compiler arguments in tasks.json, or a real build system.
Enjoy Reading This Article?
Here are some more articles you might like to read next: