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.
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.
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:
After opening a remote folder, use Ctrl-P to quickly open any file in your workspace.
Use Ctrl-J to open an integrated terminal to run commands on your VM. You can use the same shortcut to hide the terminal.
Whenever you open a new VSCode window, the Welcome Tab has a “Recent” section that allows you to quickly open files from past sessions. This becomes extremely useful when you have to restart your VM after installing your kernel.
The VSCode documentation has many, many more tips.
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.
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:
forcedInclude
automatically includes linux/include/generated/autoconf.h
in
each file. This file contains #define
statements corresponding to your
.config
file, to let VSCode know which configuration variables we want to
use. In order to generate this file, you need to configure your kernel and
then run make prepare
. Note that this is only relevant if you’re working
on a full kernel assignment. For kernel module assignments, you don’t need to
do this.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.
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.
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
You can add rulers in VSCode marking various columns. This makes keeping track
of line length much easier. We recommend adding rulers at columns 80 and 100,
the traditional Linux max line length and the new max line length. To do so,
insert the following in your VSCode settings.json
:
"editor.rulers": [
80, 100
]
The VSCode search (and replace) feature is incredibly fast and powerful. We highly recommend using it as a supplement to Bootlin.
VSCode provides a Makefile extension which seems to provide advanced functionality. However, it doesn’t really work that well with our assignment setup, but the developers claim that it works well with Linux kernel development in general. While it may not be that useful for our class, it may prove useful to you in the future.