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 the cppbuild task type and the cppdbg debug type.
  • The Xcode Command Line Tools (xcode-select --install) or full Xcode. This gives you /usr/bin/clang++, plus the LLDB.framework that the extension’s bundled lldb-mi needs 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:

  • label is the name the debug configuration uses to find this task, so it has to match preLaunchTask in launch.json exactly.
  • command calls the system clang++ with these arguments:
    • -fdiagnostics-color=always keeps compiler errors and warnings colored in the terminal.
    • -g emits 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.cpp builds to foo).
  • options.cwd runs the compiler from the source file’s directory.
  • The $gcc problem matcher parses clang’s GCC-style diagnostics into the Problems panel.
  • group with "isDefault": true makes 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 through lldb-mi. GDB doesn’t support Apple Silicon, so LLDB is the only option here.
  • program is the same path the build task writes to with -o.
  • cwd is the source file’s directory. args and environment are empty, so no command-line arguments or extra environment variables are passed.
  • "stopAtEntry": false runs straight to your first breakpoint. Set it to true to stop at main.
  • "externalConsole": true runs the program in a separate Terminal window. On macOS, lldb-mi can’t use VS Code’s integrated terminal. With false, output only shows up in the Debug Console, so you’d have no way to type into stdin.
  • preLaunchTask names the build task’s label. 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

  1. Copy tasks.json and launch.json into .vscode/ at the root of your project.
  2. Open a C/C++ source file and set some breakpoints.
  3. 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.
  4. 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:

  • Debugging Nextcloud LDAP with occ
  • Complete Guide to Intel i3-12100 iGPU SR-IOV on Proxmox VE 9
  • NFS over RDMA Configuration Guide
  • InfiniBand Quick Command Reference
  • Exposing an Internal SSH Port with FRP and Docker Compose