﻿---
title: Setting Up a C/C++ Debug Environment in VSCode
date: 2024-01-15
tags:
  - VSCode
  - C
  - Cpp
  - Windows
  - Linux
excerpt: How to set up a C/C++ debug environment in VSCode, with a walkthrough of `task.json` and `launch.json` and sample configurations.
updated: 2026-07-08 21:17:39
lang: en
i18n:
  cn: /debug_ccpp
  translation: 2
---

Today I read [Configure launch.json for C/C++ debugging in Visual Studio Code](https://code.visualstudio.com/docs/cpp/launch-json-reference) and got a basic VSCode C/C++ debug setup working. This post records how I configured the C/C++ debug environment in VSCode on Windows/WSL, as a reference for other beginners. Before starting, you need VSCode installed, a working WSL environment, and gcc on your PATH.

The article explains the meaning of some of the attributes in `launch.json` and `tasks.json`, and includes my own configurations for reference.

## Steps

### launch.json

To set up debugging, first configure `launch.json`. `launch.json` configures VSCode's debug environment. It contains a list of debug configurations; each one is an object with a set of fields that define how to start and run the debugger. In VSCode, you can enter debug mode with `F5` or by clicking the debug button in the sidebar. VSCode then looks for a `launch.json` file in the current working directory. If it can't find one, VSCode prompts you to create it; if it finds one, VSCode loads the configurations from `launch.json` and starts the debugger accordingly.

> A `launch.json` file is used to configure the [debugger](https://code.visualstudio.com/docs/editor/debugging) in Visual Studio Code.
>
> Visual Studio Code generates a `launch.json` (under a `.vscode` folder in your project) with almost all of the required information. To get started with debugging you need to fill in the `program` field with the path to the executable you plan to debug. This must be specified for both the launch and attach (if you plan to attach to a running instance at any point) configurations.

#### Launch.json Code

**Here is my configuration, for reference only**

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "c/c++ gdb",
      "type": "lldb",
      "request": "launch",
      "args": [],
      "cwd": "${fileDirname}",
      "console": "integratedTerminal",
      "windows": {
        "program": "${fileDirname}/${fileBasenameNoExtension}.exe",
        "preLaunchTask": "compile c file(Windows)"
      },
      "linux": {
        "program": "${fileDirname}/${fileBasenameNoExtension}.out",
        "preLaunchTask": "compile c file(Linux)"
      }
    }
  ]
}
```

#### Attributes

- **version**: version of this file format
  No need to change this

- **configurations**: List of configurations.
  An array of configurations holding your debug setups. Each debug configuration is an object with a set of fields that define how to start and run the debugger

- **type**: Type of configuration
  Specifies which debugger to use. The available values depend on the debugger extensions you have installed. Common values for the type field include `node, java, lldb (mainly for debugging c/cpp and other LLVM-supported languages), chrome (JavaScript, TypeScript)`, and so on

- **name**: Name of configuration; appears in the launch configuration dropdown menu.
  Exactly what it says; here `c/c++ gdb` is the `name` in `launch.json`

<center>
<img src="https://assets.vluv.space/Dev/debug_ccpp/debug_c1.webp" alt="configure name" style="width:50%;" />
</center>

- **preLaunchTask**: Task to run before debug session starts.
  A task executed before debugging starts, such as compiling your code to produce an executable (.exe, .out e.g.). If the task fails, the debug session won't start. Since we're setting up a c/cpp debug environment here, set preLaunchTask to build active file (any name works), as long as it matches the label attribute of the task object in `tasks.json`

- **program**: Path to the program to debug.
  Specify the debug program's path. Taking Windows as an example, if we wrote hello.c, the program to debug is `filePath/hello.exe`. We can simplify program with the following pre-defined variables

  > **Common pre-defined variables provided by VSCode for configuration files:**
  >
  > - `${workspaceFolder}`: The path of the folder opened in VS Code.
  > - `${workspaceRootFolderName}`: The name of the folder opened in VS Code without any slashes (/).
  > - `${file}`: The current opened file.
  > - `${fileWorkspaceFolder}`: The current opened file's workspace folder.
  > - `${relativeFile}`: The current opened file relative to workspaceFolder.
  > - `${relativeFileDirname}`: The current opened file's dirname relative to workspaceFolder.
  > - `${fileBasename}`: The current opened file's basename.
  > - `${fileBasenameNoExtension}`: The current opened file's basename with no file extension.
  > - `${fileDirname}`: The current opened file's dirname.
  > - `${fileExtname}`: The current opened file's extension.
  > - `${lineNumber}`: The current selected line number in the active file.
  > - `${selectedText}`: The current selected text in the active file.
  > - `${execPath}`: The location of the VS Code executable.
  > - `${defaultBuildTask}`: The name of the default build task.

- **request**: Indicates whether the configuration section is intended to `launch` the program or `attach` to an already running instance.
  Usually pick launch; attach may come up in frontend debugging

- **console**: Terminal type to use.
  A matter of personal preference. The options are

  - **internalConsole**: the TERMINAL in the VSCode Panel

  - **integratedTerminal**: the DEBUG CONSOLE in the VSCode Panel

  - **externalTerminal**: an external integrated terminal

- **cwd**: Program working directory.
  The `cwd` field sets the Current Working Directory. When you start the debugger, this directory is used as the program's working directory; it's usually set to `"cwd": "${fileDirname}"`
- **window/linux/osx**: specific launch configuration attributes
  Attributes set separately for the Windows, Linux/WSL, and MacOS platforms

### tasks.json

For the debugger to work, your code has to be compiled into an executable first (.exe, .out e.g.), so in `preLaunch` we defined two tasks to compile the c file.

[Using tasks.json](http://vluv.space/ToolChain/tasks.json%E7%9A%84%E4%BD%BF%E7%94%A8/)

#### Tasks.json Code

```json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "compile c file(Windows)",
      "command": "gcc",
      "args": [
        "-g",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe"
      ]
    },
    {
      "type": "shell",
      "label": "compile c file(Linux)",
      "command": "gcc",
      "args": [
        "-g",
        "${file}",
        "-o",
        "${fileDirname}/${fileBasenameNoExtension}.out"
      ]
    }
  ]
}
```

#### Attribute

- **tasks**: The task configurations. Usually these are enrichments of task already defined in the external task runner.
  For example, the two `task`s defined earlier in `launch.json`

  ```json
  "windows": {
      "program": "${fileDirname}/${fileBasenameNoExtension}.exe",
      "preLaunchTask": "build active file(Windows)"
  },
  "linux": {
      "program": "${fileDirname}/${fileBasenameNoExtension}.out",
      "preLaunchTask": "build active file(Linux)"
  }
  ```

- **type**: Defines whether the task is run as a process or as a command inside a shell.
  The options are shell and process. The gcc command runs in a shell, so pick shell here
- **label**: The task's user interface label
  The task's name; `launch.json` uses the label to specify which tasks to run

- **command**: The command to be executed. Can be an external program or a shell command.
  gcc works here; you can also pick clang or another c/cpp compiler

- **args**: Arguments passed to the command when this task is invoked.
  The command's arguments, such as -o, -g, and so on

## Outro

​ Tested with the classic `hello.c`, and debugging works fine. I hope this post helps you 🕊️

![demo](https://assets.vluv.space/Dev/debug_ccpp/debug_c2.webp)
