dev-guides

VSCode Workflow

Note: Before following this guide, make sure to follow the SSH guide.

If you’re a fan of Visual Studio Code (VSCode), you can work on your VM directly from a VSCode window on your host machine using SSH, allowing you to take advantage of all of VSCode’s features in a local-quality development experience.

SSH Extension

Once you’ve installed VSCode on your local machine, all you have to do is install the VSCode SSH Extension.

From now on, you can SSH into your VM by opening your Command Palette (Ctrl-Shift-P) and looking for Remote-SSH: Connect to Host. Alternatively, you can click the double triangle icon at the bottom left corner of the window. This will give you a variety of SSH-related options. Selecting Connect to Host or Connect Current Window to Host will give you a list of remote machines from your SSH config file. Choose your OS VM - if you’ve properly configured your SSH keys, it should log in automatically and start setting up a remote VSCode server.

See the SSH extension documentation for more features and tricks.

Getting Started

When you open VSCode, the Welcome screen will recommend a few tutorials. We highly recommend going through these - they cover several essential VSCode features and various tips and tricks.

As a bare minimum, you should know the following:

The VSCode documentation has many, many more tips.

Themes

One of the benefits of VSCode is that in addition to being highly configurable, it’s very visually appealing. You can change the default theme to one of VSCode’s built-in themes by going to the Command Palette and searching for Preferences: Color Themes. Use your arrow keys to switch themes and preview the selected theme. Once you’ve settled on a theme, click on it to select it.

You can also install additional themes using VSCode’s Extensions functionality. Go to the Extensions tab (the four squares on the left sidebar), and search for @category:"themes". This will give you both color themes and file icon themes, which can be set in Preferences as well.

You can also customize existing color themes or create your own, if you’re so inclined. See the documentation for more information.

Kernel Configuration

First, you should install the C/C++ Extension Pack. This will enable several useful features for C development.

VSCode allows you to specify different configurations when editing C or C++ files. For our use case, we specify two configurations: one for kernel development, and one for kernel module development. In each assignment’s top-level directory, create a .vscode directory, and paste the following into .vscode/c_cpp_properties.json, depending on your machine type.

For arm64 users:

{
    "configurations": [
        {
            "name": "Linux Kernel Module",
            "includePath": [
                "/usr/src/linux-headers-5.10.0-20-common/include",
                "/usr/src/linux-headers-5.10.0-20-common/arch/arm64/include",
                "/usr/src/linux-headers-5.10.0-20-arm64/include/**",
                "/usr/src/linux-headers-5.10.0-20-arm64/arch/arm64/include/**",
                "/usr/lib/gcc/aarch64-linux-gnu/10/include",
                "${workspaceFolder}/**"
            ],
            "defines": [
                "__GNUC__",
                "__KERNEL__",
                "MODULE"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu89",
            "intelliSenseMode": "linux-gcc-arm64"
        },
        {
            "name": "Linux Kernel",
            "includePath": [
                "/usr/src/linux-headers-5.10.0-20-common/include",
                "/usr/src/linux-headers-5.10.0-20-common/arch/arm64/include",
                "/usr/src/linux-headers-5.10.0-20-arm64/include/**",
                "/usr/src/linux-headers-5.10.0-20-arm64/arch/arm64/include/**",
                "/usr/lib/gcc/aarch64-linux-gnu/10/include",
                "${workspaceFolder}/**"
            ],
            "forcedInclude": [
                "${workspaceFolder}/linux/include/generated/autoconf.h"
            ],
            "defines": [
                "__GNUC__",
                "__KERNEL__"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu89",
            "intelliSenseMode": "linux-gcc-arm64"
        }
    ],
    "version": 4
}

For x86 users:

{
    "configurations": [
        {
            "name": "Linux Kernel Module",
            "includePath": [
                "/usr/src/linux-headers-5.10.0-20-common/include",
                "/usr/src/linux-headers-5.10.0-20-common/arch/x86/include",
                "/usr/src/linux-headers-5.10.0-20-amd64/include/**",
                "/usr/src/linux-headers-5.10.0-20-amd64/arch/x86/include/**",
                "/usr/lib/gcc/x86_64-linux-gnu/10/include",
                "${workspaceFolder}/**"
            ],
            "defines": [
                "__GNUC__",
                "__KERNEL__",
                "MODULE"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu89",
            "intelliSenseMode": "gcc-x64"
        },
        {
            "name": "Linux Kernel",
            "includePath": [
                "/usr/src/linux-headers-5.10.0-20-common/include",
                "/usr/src/linux-headers-5.10.0-20-common/arch/x86/include",
                "/usr/src/linux-headers-5.10.0-20-amd64/include/**",
                "/usr/src/linux-headers-5.10.0-20-amd64/arch/x86/include/**",
                "/usr/lib/gcc/x86_64-linux-gnu/10/include",
                "${workspaceFolder}/**"
            ],
            "forcedInclude": [
                "${workspaceFolder}/linux/include/generated/autoconf.h"
            ],
            "defines": [
                "__GNUC__",
                "__KERNEL__"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu89",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

These files set various paths which VSCode will use to search for header files, along with setting the C standard used by the kernel (gnu89). You may need to update the paths specified in includePath depending on your Debian version, based on what directories are present in /usr/src.

These configurations also do the following:

Make sure to use the correct configuration for each assignment. When working on kernel modules, you’ll want to use the “Linux Kernel Module” configuration, and use “Linux Kernel” when working on a full kernel tree.

Once you’ve set these configurations, it may take a while for VSCode to parse all of the files in your workspace in order for the full functionality to work. You can switch between the configurations on the bottom right.

VSCode may also assume that the .c and .h files that you use are C++ files, rather than C files. You can change this on the bottom left as well, along with changing the default file association behavior.

Note that you may still run into VSCode errors (“red squiggly lines”) even with this configuration, for various reasons. While this guide won’t be able to resolve every issue you run into, it should at least make it easier for you to do kernel development in VSCode.

Clangd

When working inside the kernel, we recommend using the clangd over VSCode’s native C/C++ extension pack. clangd is a language server that allows for a host of functionalities, such as semantic auto-complete and GoTo. We have found clangd to be faster and more accurate than VSCode’s IntelliSense when working inside the Linux kernel.

Note that using clangd means that C/C++ language features won’t work in projects that don’t have a compile-commands.json file, such as when working on kernel modules or userspace code. If you prefer a general-case solution, using the configuration files provided above with IntelliSense should work reasonably well, although you may still see some warnings.

First, install clangd to your VM:

sudo apt install clangd

Then, install the clangd extension from the VSCode marketplace. Then, to enable it over VSCode’s default IntelliSense engine, set the C_Cpp: Intelli Sense Engine setting to disabled.

To function properly, clangd requires a compile_commands.json file, which specifies the simulated compilation flags clangd should use when analyzing your code. The Linux kernel provides a script to generate this file automatically like so:

$ cd <path-to-homework-assignment>
$ make # Only need to do this if you haven't built the kernel yet
$ scripts/clang-tools/gen_compile_commands.py

If you would like to use clangd with projects other than the Linux kernel, see bear and compiledb.

Since we are compiling the kernel with gcc rather than clang, clangd will report some compatibility errors with gcc-specific compilation flags. To mitigate these errors, create a file at ~/.config/clangd/config.yaml with the following:

CompileFlags:
  Remove: [ -mpreferred-stack-boundary=*, -mindirect-branch*, 
            -fno-allow-store-data-races, -fconserve-stack, -mrecord-mcount,
            -mfunction-return=*, -mskip-rax-setup, -mno-fp-ret-in-387,
            -mno-var-tracking-assignments, -femit-struct-debug-baseonly,
            -mabi=lp64 ]

This file tells clangd to automatically remove the listed gcc-specific flags. Feel free to add to this list of flags if other errors appear.

After this, clangd will index the Linux kernel code for you automatically. All functionality that was previously provided by IntelliSense, such as GoTo, will now work as expected.

Formatting

The Linux kernel provides a .clang-format file, which specifies how to format the source code using clang-format. First, install clang-format:

# apt install clang-format

By default, VSCode will search for a .clang-format file for formatting C code. You can format your code using Alt-Shift-F. You can also configure VSCode to format on save, which can save you some time fixing checkpatch errors. This can be set in the VSCode settings if you search for “Editor: Format on Save”.

If you would like this formatting functionality when working on kernel modules, just copy the .clang-format file from the linux folder to the user folder of your homework assignment like so:

$ cd <path/to/homework/assignment>
$ cp linux/.clang-format user

Miscellaneous