Nicolas Noben

Configure Visual Studio Code with clangd, clang for builds, to use gdb for debugging and makefile

vscode, clangd, gdb, debugging

2022-09-01

Introduction

Running C/C++ on macOS with VSCode, clang and gdb, can be quite interesting (challenging) to set up.

I’m no expert, but this is how I did it and it might help you. I certainly document it for my own benefit as well.

VSCode + clangd

Once VSCode is installed, install clangd as a plugin. This is the language server used in the backend of VSCode which will give you auto completion and “click through” navigation between header files and code.

It requires two additional files to work properly. You can check them in your repo.

compile_flags.txt

Without this file, your build might work properly via make, however VSCode will be full of squiggly lines.

# -Iheader_path -Llibrary_path -llibrary_name

-Ilib
-llib
-Llib

.clang-format

Contains the formatting config of your choice, the default certainly sucks. Here is mine.

IndentWidth: 4
ColumnLimit: 0
SpacesBeforeTrailingComments: 2
PointerAlignment: Left

makefile

Here is mine as a reference.

COMPILER = clang
SOURCE_LIBS = -Ilib/ -Llib/
OSX_OPT = -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL lib/libraylib.a
WARNINGS = -Wall
OSX_OUT = -o "bin/build"
DEBUG_BUILD = -ggdb
CFILES = **.c

build_osx:
	$(COMPILER) $(CFILES) $(SOURCE_LIBS) $(OSX_OUT) $(OSX_OPT) $(WARNINGS) $(DEBUG_BUILD)

Pretty straight forward, it runs clang and a bunch of parameters.

Note the -ggdb flag that is necessary for debugging with gdb in VSCode. Remove that flag for production build, in fact, make a prod build other than build_osx

Installing gdb on macOS Monterey

This is the guide I followed to the letter. I highly recommend it. Pay close attention though as it is quite tricky to not miss a step.

VSCode launch.json

Here is the magic sauce that will launch the binary and invoke gdb. Once gdb is installed on your system, breakpoints should stop the runtime and let you inspect things.

Find launch.json in your project .vscode/ subdirectory. You can also search for it using the navigate input menu. Often, VSCode will prompt for you to edit this file when you attempt to run something, so you might already have a local copy.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "MIMode": "gdb",
            "program": "${workspaceFolder}/bin/build",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
        }
    ]
}

C/C++ properties files for VSCode

Finally, we need to let VSCode know how to build C/C++ via the c_cpp_properties.json

Find or create c_cpp_properties.json along side launch.json in the .vscode/ folder of your project.

{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [],
            "macFrameworkPath": ["/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c99",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "macos-clang-x64",
            "configurationProvider": "ms-vscode.makefile-tools"
        }
    ],
    "version": 4
}

VSCode builds via makefile

Nearly there. Last piece of the puzzle is invoking the makefile build from VSCode. That’s rather straight forward, just add a shortcut to Makefile: build the current target

E.g. mine is F6

Conclusion

So there you have it. Builds via makefile within VSCode. Debugging via gdb, supporting breakpoints and “launch” via launch.json.

I have my launch set to F5 and build set to F6. I use F9 to set breakpoints and F10 to step over. It’s been pretty smooth once it’s all working, and very efficient to stop and debug, set watchers etc.

HTH.