0

内核模块是用 Makefile 作为编译系统的,而 vscode 并不能自动从 Makefile 里读取出需要的信息,所以需要我们手动在 .vscode 目录下写一些配置文件,才能愉快的用 vsc 工作。

用 vscode 打开一个包含内核模块源码的目录,我们会看到

检测到 #include 错误。请更新 includePath。已为此翻译单元(/home/rapiz/Source/linux-dev/hello-world-module/hello.c)禁用波形曲线。C/C++(1696)

无法打开 源 文件 “linux/init.h”C/C++(1696)

同时自动补全也基本不可用。

这是因为没有配置正确的 includePath,vscode 找不到头文件,自然也没法补全相应的定义。

1

为了正常开发内核模块,我们至少需要 include 两个东西:

  1. Linux 源码中的一般头文件 内核源码根目录/include/linux
  2. Linux 源码中的与架构相关的头文件 内核源码根目录/arch/架构名/include

注意,这里的源码根目录不一定就是编译时使用的源码目录。编译内核模块时我们仍然是在终端里使用 Makefile 手动编译,内核源码目录是我们任意指定的。这里 vscode 配置的内核源码目录仅仅是提供给 vscode 进行扫描来自动补全和代码检查的,所以和编译时用的源码不一样问题不大。

为什么要说这个呢,因为源里会有内核的源码包,安装之后是固定位置的,只要版本和我们期望编译的版本差距不大,我们可以一直用这个固定位置的源码,比较方便。

比如 Arch Linux 安装 linux-header 后,源码跟目录就是 /usr/src/linux

下文就以 x86 64 位 Arch 从源里安装内核源码的情景为例

  1. Linux 源码中的一般头文件 /usr/src/linux/include
  2. Linux 源码中的与架构相关的头文件 /usr/src/linux/arch/x86/include

虽然是 64 位的 Arch Linux,但用的路径名字是 x86,并且我也找不到 x86_64 这个目录。不太清楚具体命名规则,反正能用。

2

但是,这样配置了 includePath 之后,我们还会报错。

检测到 #include 错误。请更新 includePath。已为此翻译单元(/home/rapiz/Source/linux-dev/task05/hello.c)禁用波形曲线。C/C++(1696)

无法打开 源 文件 “asm/rwonce.h” (dependency of “linux/init.h”)C/C++(1696)

所以我就去找了下 rwonce.h 在哪,结果是 /usr/src/linux/arch/x86/include/generatedasm 目录下。所以我们还需要 include /usr/src/linux/arch/x86/include/generated

此时我们需要 include 的有三样:臭豆腐,腐乳,韭菜花

  1. /usr/src/linux/include
  2. /usr/src/linux/arch/x86/include
  3. /usr/src/linux/arch/x86/include/generated

3

知道了需要包含的路径,接下来我们就来具体配置 vscode。

vscode 中Ctrl + Shift + P 调出命令面板,输入 edit 应该就能搜到 C/C++: 编辑配置,这里选择 UI 或者 JSON 方式都行。UI 模式下找到包含路径选项,添加刚刚给出的三个包含路径。JSON 模式可以参考在文末给出的我的配置。

4

然而,竟然还有问题。MODULE_AUTHOR MODULE_LICENSE MODULE_DESCRIPTION 这种宏会被标红,提示 KBUILD_MODNAME 未定义之类的问题。

搜索了一下,KBUILD_MODNAME 是在编译时 Makefile 自动定义的宏。还好 vscode 可以在检查错误时预定义宏。在刚刚的设置页面,我们随便起个名字,定义一下 KBUILD_MODNAME="mod_hello"。这样就好了。注意,这里的配置也是只影响 vscode 的分析引擎,对编译过程没有影响。

搜了一下还需要定义 __KERNEL__MODULE,没有去实验有什么影响,反正我加上了。

5

这样就可以愉快的在补全和错误提示下进行内核开发了。

我的 vscode 配置(.vscode/c_cpp_properites.json),只需要看 includePathdefines

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/src/linux/include",
                "/usr/src/linux/arch/x86/include",
                "/usr/src/linux/arch/x86/include/generated"
            ],
            "defines": [
                "__KERNEL__=1",
                "KBUILD_MODNAME=\"mod_hello\"",
                "MODULE=1"
            ]
        }
    ],
    "version": 4
}