5ec1cff/ddk

内核驱动开发工具包 (Kernel Driver Development Kit)

★ 5Forks 2ShellGitHub ↗Compare

Project website ↗

README

内核驱动开发工具包 (Kernel Driver Development Kit)

English | 简体中文

该工具包旨在快速开发内核模块,但不保证内核模块能够完全兼容对应版本的内核。

如果需要完全兼容性,请下载完整内核代码并自行编译,具体方法请参考相关文档。

如果不想下载 Clang,可以使用 NDK Clang 进行编译,但可能会导致编译产物的结构体偏移有所不同。

submodule 下的 prebuilts tarball 文件很大,非必要不要 clone submodules

内核模块开发模板:

Github

CNB

选择开发模式

场景 推荐模式
Linux 本机开发 Host 模式(推荐)
macOS / Windows 开发 DevContainer 模式(推荐)
CI / 自动化构建 Docker 模式

Host 模式(推荐 Linux 用户)

Note

Host 模式将内核源码和 Clang 工具链直接解压到 /opt/ddk 目录,无需 Docker 或容器环境,是 Linux 用户的首选开发方式。

前置依赖

  • git-lfs(用于拉取 submodule 中的大文件,必须在克隆前安装并初始化)
  • zstd(用于解压 .tar.zst 归档文件)
  • jq(用于 VSCode 配置脚本)

安装并启用 Git LFS:

# Debian/Ubuntu
sudo apt install git-lfs
# Arch
sudo pacman -S git-lfs

git lfs install

安装步骤

1. 克隆仓库(含 submodules)

建议方式:初次 clone 时禁用 lfs 拉取文件,后续再拉取

GIT_LFS_SKIP_SMUDGE=1
git clone --recurse-submodules https://github.com/Ylarod/ddk.git
cd ddk/prebuilts
# 无需拉取 kdir-min ,这是给 ci 使用的,其中不含可生成 compile_commands.json 的 .cmd 文件
for d in kdir clang rust src; do
 git lfs pull -I $d
done

Warning

prebuilts submodule 中包含大量通过 Git LFS 存储的预编译归档文件,体积较大,请确保已安装 git-lfs 并有足够的磁盘空间和网络带宽。

git clone --recurse-submodules https://github.com/Ylarod/ddk.git
cd ddk

如果已经克隆但未初始化 submodule:

git submodule update --init --recursive

2. 运行安装脚本

bash host/install.sh

安装脚本会将 prebuilts/ 中的内核源码(src)、编译头文件(kdir)和 Clang 工具链(clang)解压到 /opt/ddk:

/opt/ddk/
├── src/          # 各 Android 版本内核源码
│   ├── android12-5.10/
│   ├── android13-5.10/
│   └── ...
├── kdir/         # 各 Android 版本编译头文件
└── clang/        # Clang 工具链

3. 配置 VSCode clangd 代码索引

首先确保 ~/.ddk/mapping.json 存在(从仓库根目录的 mapping.json 复制):

mkdir -p ~/.ddk
cp mapping.json ~/.ddk/mapping.json

然后运行配置脚本:

bash host/vscode_clangd_configure.sh

该脚本会:

  • 读取 ~/.ddk/mapping.json 获取 Android 版本与 Clang 版本的对应关系
  • 将 host/.vscode 模板(含文件过滤规则、编辑器设置、compile_commands.json 生成脚本等)复制到每个 /opt/ddk/src/<android-version>/ 目录
  • 配置各目录下 .vscode/settings.json 中的 clangd.path,指向对应版本的 Clang

支持 --dry-run 参数预览操作:

bash host/vscode_clangd_configure.sh --dry-run

4. 在 VSCode 中打开内核源码

用 VSCode 打开对应的内核源码目录,安装 clangd 扩展 后即可获得代码补全、跳转、引用查找等功能:

code /opt/ddk/src/android16-6.12

注意:仍然需要运行命令来生成 compile_commands.json

cd /opt/ddk/src/XXX
python3 .vscode/generate_compdb.py -O /opt/ddk/kdir/$(basename $(realpath .))

DevContainer 模式(推荐 macOS / Windows 用户)

Tip

对于中国大陆用户,可以使用 docker.cnb.cool/ylarod/ddk/ddk 来代替 ghcr.io/ylarod/ddk

DevContainer 通过容器提供与平台无关的一致开发环境,适合无法直接使用 Host 模式的 macOS 或 Windows 用户。

本地 DevContainer

Warning

当你使用这个方法的时候,你必须手动 source envsetup.sh

把下面内容放置到 .devcontainer/devcontainer.json。

可以修改 features 的内容来自由组装想要的镜像,可以选择的版本参考 ddk image versions

参考:

对于 M1 Mac + OrbStack 用户,参考 ddk-module-template 中的 .devcontainer 配置可以开发,还需要提前拉取镜像:

docker run --platform linux/amd64 --rm -it docker.cnb.cool/ylarod/ddk/ddk-builder:latest

对于 x86_64 用户:

{
  "name": "ddk-module-dev",
  "image": "docker.cnb.cool/ylarod/ddk/ddk-builder:latest",
  "features": {
    "ghcr.io/ylarod/ddk/features/ddk-toolchain:latest": {
      "androidVer": "android12-5.10",
      "setDefault": true
    },
    "ghcr.io/ylarod/ddk/features/ddk-src:latest": {
      "androidVer": "android12-5.10",
      "withKdir": true,
      "setDefault": true
    }
  },
  "remoteUser": "root",
  "postCreateCommand": "echo Devcontainer ready",
  "customizations": {
    "vscode": {
      "extensions": [
        "github.copilot",
        "github.copilot-chat",
        "github.vscode-github-actions",
        "llvm-vs-code-extensions.vscode-clangd",
        "ms-azuretools.vscode-containers",
        "ms-azuretools.vscode-docker",
        "ms-ceintl.vscode-language-pack-zh-hans"
      ]
    }
  }
}

Github Codespaces 云开发

把下面内容放置到 .devcontainer/devcontainer.json。

可以修改 image 的内容来选择对应的版本开发,可以选择的版本参考 ddk image versions

{
  "name": "ddk-module-dev",
  "image": "ghcr.io/ylarod/ddk:android16-6.12",
  "remoteUser": "root",
  "postCreateCommand": "echo Devcontainer ready",
  "customizations": {
    "vscode": {
      "extensions": [
        "github.copilot",
        "github.copilot-chat",
        "github.vscode-github-actions",
        "llvm-vs-code-extensions.vscode-clangd",
        "ms-azuretools.vscode-containers",
        "ms-azuretools.vscode-docker",
        "ms-ceintl.vscode-language-pack-zh-hans"
      ]
    }
  }
}

Docker 模式(适合 CI / 自动化构建)

Note

Docker 模式通过封装好的镜像直接构建,适合 CI 流水线和自动化场景,不推荐作为日常交互式开发环境。

本地使用 Docker 镜像

推荐先安装便捷脚本 ddk(封装常用 docker 命令,强制 --platform linux/amd64 并将当前目录挂载为容器内的 /build)。

安装(macOS/Linux):

# 将 ddk 安装到 /usr/local/bin 并赋予可执行权限
sudo curl -fsSL https://raw.githubusercontent.com/Ylarod/ddk/main/scripts/ddk -o /usr/local/bin/ddk
sudo chmod +x /usr/local/bin/ddk

用法示例:

# 拉取镜像
ddk pull android12-5.10

# 进入项目目录
cd /path/to/source

# 构建
ddk build --target android12-5.10

# 传递 make 参数
ddk build --target android12-5.10 -- CFLAGS=-O2

# 清理
ddk clean --target android12-5.10

# 交互式 shell
ddk shell --target android12-5.10

如果你不想在每次命令中传入 target,可以设置环境变量 DDK_TARGET:

export DDK_TARGET=android12-5.10
ddk build   # 会使用 DDK_TARGET

Github CI

参考下面的文件构建:


致谢


附加内容

local 模式构建内核模块

使用模板创建内核模块

将 scripts/ddk 添加到你的 PATH (如 local bin)

ln -s ./scripts/ddk ~/.local/bin

进入构建环境

# 进入包含必要环境变量的 shell
ddk shell target # android16-6.12 等
# 在 ddk shell 中执行 make 即可
# 或者直接使用 ddk build ,会直接执行 make 

local 模式构建适用于多个 target 版本的内核模块

在为多个内核 target 构建模块时,我们希望输出目录分离,而树外构建默认将输出结果放到源码目录,十分不便。

内核 6.13 才正式引入树外模块的 build dir (MO),不过早期版本可以利用 src 变量来做到这一点(以 KernelSU 为例):

KDIR := $(KDIR)
MDIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
ODIR := $(MDIR)/out/$(VER)

$(info -- KDIR: $(KDIR))
$(info -- MDIR: $(MDIR))
$(info -- VER: $(VER))
$(info -- OUTPUT DIR: $(ODIR))

# 这里 M 指向输出目录 ODIR, src 指向内核模块目录 MDIR
all: check_symbol
	CONFIG_KSU=m make -C $(KDIR) M=$(ODIR) src=$(MDIR) modules -j$(shell nproc)

然而 6.10 引入的一个提交破坏了这个方法,导致 android16-6.12 内核无法使用上述方式指定 output dir 。这是由于编译源文件的自动规则将源文件的来源从 $(src) 改成了 $(obj)

因此我们需要对 Makefile 进行一些调整,你可以在 /opt/ddk/src/android16-6.12/scripts/Makefile.build 增加下面的代码,也可以在自己模块的 Makefile 增加(注意要使用 tab 缩进):

$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
	$(call if_changed_rule,cc_o_c)
	$(call cmd,force_checksrc)

这本质上是复制了 Makefile.build 的这一段规则,并把 c 源文件的来源 $(obj)/%.c 改成 $(src)/%.c :

# Built-in and composite module parts
$(obj)/%.o: $(obj)/%.c $(recordmcount_source) FORCE
	$(call if_changed_rule,cc_o_c)
	$(call cmd,force_checksrc)

这可以解决 .c 源文件无对应规则的问题,类似地, .S 等文件也可以搜索相应的规则,然后复制它,将来自 $(obj) 改成来自 $(src) 。如果你的模块只有 .c 源文件,只需要做上面的更改即可。

如此即可得到一键为所有 target 构建模块,并输出到不同目录的脚本:

#!/usr/bin/bash

ALL_VER=$(ls /opt/ddk/src)

for ver in $ALL_VER; do
    echo "building for ver $ver"
    export VER=$ver
    echo "make" | ddk shell $ver
    if [ $? -ne 0 ]; then
        echo "!!! failed to build for $ver"
        exit 1
    fi
done

echo "build all done!"

Contributors

Ylarod5ec1cfftiannfuqiuluo

Issues