2、模块目录结构:Zephyr模块的标准目录布局、关键文件详解

好,咱们接着聊模块。上一章我讲了什么是模块,以及为什么需要它。这一章,咱们直接动手——看看一个标准的Zephyr模块,它的目录到底长什么样。

说白了,模块就是一个有规矩的文件夹。你随便扔一堆代码进去,Zephyr不认识。但如果你按照它的“规矩”来摆,它就能自动找到你的代码、编译进去、还能在menuconfig里配置。这个“规矩”,就是我今天要讲的目录结构和三个关键文件。

2.1 标准目录布局:一个模块的“骨架”

我在项目中见过很多新手,上来就写代码,结果模块怎么都加载不进去。后来一看,目录结构不对。嗯,这里要注意,Zephyr对目录结构是有要求的,虽然不是强制,但大家都遵循这个约定。

一个典型的Zephyr模块,长这样:

my_driver_module/
├── CMakeLists.txt          # 告诉构建系统:怎么编译我
├── Kconfig                 # 告诉配置系统:我有哪些开关
├── zephyr/
│   └── module.yml          # 告诉Zephyr:我是谁,我在哪
├── drivers/
│   ├── CMakeLists.txt
│   └── my_driver/
│       ├── CMakeLists.txt
│       └── my_driver.c
├── include/
│   └── my_driver.h
├── dts/
│   └── bindings/
│       └── my-device.yaml
├── samples/
│   └── hello_my_driver/
│       ├── CMakeLists.txt
│       ├── prj.conf
│       └── src/
│           └── main.c
└── tests/
    └── my_driver_test/
        ├── CMakeLists.txt
        ├── prj.conf
        └── src/
            └── main.c

你可能会问:“这么多文件夹,每个都要吗?”
我的回答是:不是。但上面这几个,是“最佳实践”。

咱们拆开来看:

  • CMakeLists.txt:根目录的构建文件。它告诉Zephyr,我这个模块有哪些源文件、依赖哪些库。
  • Kconfig:配置菜单。你可以在menuconfig里看到它定义的选项。
  • zephyr/module.yml:模块的“身份证”。Zephyr通过它来发现你这个模块。
  • drivers/:放驱动代码。如果你写的是驱动,就放这里。
  • include/:头文件。对外暴露的API放这里。
  • dts/bindings/:设备树绑定。如果你的驱动需要设备树支持,这里放yaml文件。
  • samples/:示例代码。方便别人快速上手。
  • tests/:测试代码。我建议每个模块都写测试,别偷懒。
我的习惯: 我一般会在根目录再加一个 README.md,写清楚这个模块是干什么的、怎么用。别小看这个文件,半年后你自己回来看代码,都得靠它回忆。

2.2 关键文件一:CMakeLists.txt —— 构建的“指挥中心”

这个文件,说白了就是告诉CMake:“嘿,我的源文件在这,帮我编译一下。” 但Zephyr的CMakeLists.txt,比普通的要复杂一点点。

一个最简的模块级CMakeLists.txt,长这样:

# 根目录的 CMakeLists.txt
cmake_minimum_required(VERSION 3.20)

# 添加子目录,让CMake去drivers里找
add_subdirectory(drivers)

# 如果你有额外的库,可以这样加
# zephyr_library()
# zephyr_library_sources(src/my_lib.c)

而drivers目录下的CMakeLists.txt,通常是:

# drivers/CMakeLists.txt
zephyr_library()
zephyr_library_sources(
    my_driver/my_driver.c
)
zephyr_library_include_directories(../include)

这里有几个关键点:

  • zephyr_library():这是Zephyr提供的宏,用来创建一个Zephyr风格的库。它会自动处理链接和依赖。
  • zephyr_library_sources():把源文件加进去。
  • zephyr_library_include_directories():指定头文件路径。
我曾经踩过的坑: 有一次我忘了加 zephyr_library_include_directories(),结果头文件死活找不到。编译报错“file not found”,我查了半天,最后发现是路径没加进去。所以,头文件路径一定要显式声明,别指望CMake自动帮你找。

2.3 关键文件二:Kconfig —— 配置的“开关面板”

Kconfig文件,就是你在menuconfig里看到的那些选项。它定义了你的模块有哪些配置开关。

一个典型的Kconfig文件:

# Kconfig
menuconfig MY_DRIVER
    bool "My Driver Support"
    default n
    help
      Enable support for my custom driver.

if MY_DRIVER

config MY_DRIVER_SPEED
    int "Driver speed in Hz"
    default 1000000
    range 1000 10000000
    help
      Set the operating speed of the driver.

config MY_DRIVER_DEBUG
    bool "Enable debug output"
    default n
    help
      Enable verbose debug messages.

endif # MY_DRIVER

这里要注意几个语法:

  • menuconfig:创建一个可展开的菜单项。用户选中它,才能看到里面的子选项。
  • bool:布尔类型,要么y要么n。
  • int:整数类型,可以设范围。
  • default n:默认关闭。我建议所有模块默认都关掉,用户需要时再开。
  • help:帮助信息。写清楚这个选项是干什么的。
重要原则: Kconfig的命名要遵循 模块名_功能名 的格式。比如 MY_DRIVER_SPEED,这样在menuconfig里搜索时,一眼就能看出来是哪个模块的。

2.4 关键文件三:zephyr/module.yml —— 模块的“身份证”

这个文件,是Zephyr 2.6之后引入的。它的作用,就是告诉Zephyr构建系统:“我是一个模块,我的代码在这里,我的Kconfig在那里。”

一个标准的module.yml:

# zephyr/module.yml
name: my_driver
build:
  cmake: .
  kconfig: Kconfig

字段解释:

  • name:模块的名字。要唯一,不要跟其他模块重名。
  • build.cmake:CMakeLists.txt所在的目录。点号表示当前目录。
  • build.kconfig:Kconfig文件的路径。相对于模块根目录。

你可能会问:“就这么简单?”
对,就这么简单。但别小看它,没有这个文件,Zephyr根本不会理你的模块。

我的建议: 如果你有多个Kconfig文件,可以这样写:
kconfig: Kconfig 指向主文件,然后在主文件里用 source "subdir/Kconfig" 引入子文件。这样结构更清晰。

2.5 实战:如何让Zephyr找到你的模块

好,文件都写好了。怎么让Zephyr知道你的模块存在呢?

有两种方式:

  1. 环境变量方式:设置 ZEPHYR_EXTRA_MODULES 环境变量,指向你的模块路径。
  2. West方式:在west.yml里添加你的模块。

我个人推荐第二种,因为更规范。west.yml里这样写:

manifest:
  projects:
    - name: my_driver
      path: modules/my_driver
      url: https://github.com/yourname/my_driver.git
      revision: main

然后运行 west update,Zephyr就会自动拉取并识别你的模块。

注意: 如果你用环境变量方式,记得每次打开新终端都要重新设置。我见过有人因为这个折腾了半天,最后发现是环境变量没生效。

2.6 总结:一个模块的“最小可行”结构

如果你现在就想动手试试,最少需要哪些文件?

文件 是否必须 作用
zephyr/module.yml 告诉Zephyr:我是模块
CMakeLists.txt 告诉构建系统:怎么编译
Kconfig 推荐 提供配置选项
源文件 你的代码
头文件 推荐 对外接口

嗯,这一章的内容就到这里。下一章,我会带你手把手创建一个完整的模块,从零开始,一步步跑起来。到时候你就知道,这些文件到底是怎么配合工作的。

记住:目录结构是骨架,三个关键文件是灵魂。骨架歪了,灵魂再强也跑不起来。