应用构建、Kconfig 与 Devicetree

本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。

Zephyr 的应用配置由源码、CMake、Kconfig、Devicetree 和板级定义共同组成。 先把命令行构建跑通,再配置 IDE,能更容易定位构建或编辑器各自的问题。

独立应用与工作区布局

实际项目通常将应用放在 Zephyr 主仓库之外(Out-of-Tree Application),避免直接修改 zephyr/samples/,以便主仓库与模块升级时保持应用目录独立:

zephyrproject/                  <-- West 工作区顶层(含 .west/)
├── zephyr/                     <-- Zephyr 官方主仓库(只读)
├── modules/                    <-- 第三方 HAL 与组件模块
└── app/                        <-- 独立应用工程目录
    ├── CMakeLists.txt          <-- 构建入口
    ├── Kconfig                 <-- (可选)应用自定义配置菜单
    ├── prj.conf                <-- 应用 Kconfig 配置文件
    ├── app.overlay             <-- (可选)设备树叠加层
    ├── include/                <-- (可选)应用私有头文件
    └── src/
        └── main.c              <-- 应用主程序入口

最小应用

在工作区顶层创建 app,最小结构仅需 CMakeLists.txt、prj.conf 和 src/main.c:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20.5)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(cn_demo)
target_sources(app PRIVATE src/main.c)

prj.conf:

CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3

src/main.c:

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(cn_demo, LOG_LEVEL_INF);

int main(void)
{
    LOG_INF("Zephyr CN application started on %s", CONFIG_BOARD);
    return 0;
}

在工作区顶层构建并运行(可使用 qemu_cortex_m3 或 64 位 qemu_cortex_a53):

west build -p always -b qemu_cortex_a53 -d build app
west build -d build -t run

find_package(Zephyr ...) 必须位于 project() 之前,由 Zephyr 接管交叉编译工具链初始化; app 是 Zephyr 提供的应用构建目标。当工程包含多个源文件与头文件目录时,可在 CMakeLists.txt 中使用 target_include_directories(app PRIVATE include) 和 target_sources(app PRIVATE src/main.c src/other.c)。

Kconfig 选择软件能力

prj.conf 配置软件功能、资源数量和参数。构建期间 Kconfig 的合并与生成链路如下:

[配置定义树: zephyr/Kconfig + app/Kconfig]
                   │
                   ▼
[按优先级合并输入源]
  ① Kconfig 默认值 (default)
  ② 板级默认配置 (<board>_defconfig)
  ③ 应用配置 (prj.conf / EXTRA_CONF_FILE)
                   │
                   ▼
[构建目录输出: build/zephyr/]
  • .config                             (最终生效的完整配置快照)
  • include/generated/zephyr/autoconf.h (自动转换为 #define CONFIG_xxx 宏)

Kconfig 符号存在依赖与选择关系,强行写 CONFIG_...=y 不能越过缺失的依赖。可通过交互界面检查依赖:

west build -d build -t menuconfig

最终生效值保存在 build/zephyr/.config 中,生成的 autoconf.h 会自动注入所有编译单元。 不要直接手工编辑 .config 或生成的头文件;menuconfig 中的临时修改需整理回 prj.conf,才能在重新配置或 -p always 干净构建后复现。

需要定义应用自己的配置项时,在应用目录添加 Kconfig,并包含 Kconfig.zephyr:

mainmenu "Custom Application Configuration"

source "Kconfig.zephyr"

config APP_SAMPLE_INTERVAL_MS
    int "Sensor sampling interval in milliseconds"
    default 1000
    range 100 60000

在 Kconfig 中定义符号时不写 CONFIG_ 前缀;在 prj.conf、CMakeLists.txt 和 C 源码中引用时统一加上 CONFIG_ 前缀(如 CONFIG_APP_SAMPLE_INTERVAL_MS)。

Devicetree 描述硬件实例

设备树描述寄存器地址、引脚、中断、总线、时钟、设备状态和板级连接;dts/bindings/*.yaml 定义节点的属性规则。应用可通过 app.overlay``(或 ``-DDTC_OVERLAY_FILE=...)在不改动官方板级源码的前提下修改或扩展目标硬件描述:

[SoC .dtsi] + [板级 <board>.dts] + [应用 app.overlay] + [dts/bindings/*.yaml]
                               │
                               ▼
[构建目录输出: build/zephyr/]
  • zephyr.dts                                      (最终合并展开的完整设备树)
  • include/generated/zephyr/devicetree_generated.h (供 DT_* 与 DEVICE_DT_GET 宏使用)

编译生成的 devicetree_generated.h 供设备树宏使用,不能通过直接修改它替代 overlay。 DT_NODELABEL() 使用 DTS 节点标签,DT_ALIAS() 使用 /aliases 中的别名(DTS 中的连字符 - 在 C 宏中需替换为下划线 _),DT_CHOSEN() 用于获取 /chosen 约定的系统角色设备。

应用取得设备的常用模式:

#include <zephyr/device.h>
#include <zephyr/devicetree.h>

const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(my_device));

my_device 是示意标签,必须替换为目标设备树中实际存在且可用的节点。 调用驱动接口前必须检查 device_is_ready(dev)。

Kconfig 与 Devicetree 的配合与排错:

  • 只有同时满足 ① 设备树中存在该节点且 status = "okay"、② Kconfig 中启用了对应驱动程序、③ 运行时驱动初始化成功,才构成可访问的设备。

  • 链接时若出现 undefined reference to `__device_dts_ord_XX' 错误,打开 build/zephyr/zephyr.dts 搜索该数字序号 XX 定位对应节点,通常是节点已在设备树中启用但 prj.conf 未开启对应的驱动 CONFIG_* 选项,或节点 status 未设为 "okay"。

开发板目标与硬件模型

Zephyr 3.7 引入的新硬件模型改变了许多板名与板级组织。 当前目标可包含板名、SoC、CPU cluster 和 variant,例如 nrf52840dk/nrf52840、nrf5340dk/nrf5340/cpuapp 或双核 SMP 模拟目标 qemu_cortex_a53/qemu_cortex_a53/smp。 旧 nrf52840dk_nrf52840 名称不能直接假定仍适用。

west boards 帮助查找板卡,完整目标与 qualifiers 应看对应板卡页面。 开发自定义板卡时按当前 Board Porting Guide 配置 board.yml、SoC 关系、DTS、 Kconfig 与 runner,避免复制旧硬件模型的目录后只改名称。

多镜像与 sysbuild

需要协调引导程序或多个镜像时,可采用 sysbuild:

west build --sysbuild -p always -b <board-target> -d build-sysbuild app

替换目标后再执行。sysbuild 自身配置使用 SB_CONFIG_*,与每个镜像的 CONFIG_* 属于不同配置域。根据镜像名和域定位最终 .config、DTS 与 ELF, 不要把单镜像的输出路径套用到所有 sysbuild 产物。

可重复构建

记录源码与模块提交、应用配置、overlay、板卡完整目标、SDK 和构建命令。 切换 Zephyr 版本、板卡或工具链后进行干净构建。 确认命令行构建输出后,再用 compile_commands.json 配置编辑器,见 使用 VS Code 开发 Zephyr。 若希望通过一个完整工程演练 Kconfig、Devicetree Overlay、日志、Shell、GPIO、多线程与 NVS 的综合协同,请继续阅读 综合应用实战(基于 qemu_cortex_a53)。

上游依据