ESP-IDF学习笔记-工程结构

学习ESP-IDF的使用,首先得要学习一个IDF工程的结构。ESP-IDF的工程是以Cmake组织的,并使用了Ninja作为构建工具,这里只简单给出如何使用这套系统。

官方文档

参考于

一,目录结构

一个IDF工程一般有以下结构的目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- myProject/
- CMakeLists.txt
- sdkconfig
- components/ - component1/ - CMakeLists.txt
- Kconfig
- src1.c
- component2/ - CMakeLists.txt
- Kconfig
- src1.c
- include/ - component2.h
- main/ - CMakeLists.txt
- src1.c
- src2.c

- build/
  • 顶层目录的CMakeList.txt:这是整个项目的CMake文件,其中引入了/tools/cmake/project.cmake用来构建其他部分。同时设置了工程名。
  • sdkconfig:项目配置文件,使用idf.py menuconfig配置在IDE中对应设置按钮出现的菜单。在菜单中的配置以宏定义的方式出现在源码中。
  • main:特殊的目录,包含项目本身的源码,被认为是mian组件。
  • build:编译结果
  • components:(可选)组件,即各种库。

项目CMakeLists

该文件配置整个项目,通常十分小。最小情况如下:

1
2
3
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(myProject)
  • cmake_minimum_required(VERSION 3.16) 必须放在 CMakeLists.txt 文件的第一行,它会告诉 CMake 构建该项目所需要的最小版本号。ESP-IDF 支持 CMake 3.16 或更高的版本。
  • include($ENV{IDF_PATH}/tools/cmake/project.cmake) 会导入 CMake 的其余功能来完成配置项目、检索组件等任务。
  • project(myProject) 会创建项目本身,并指定项目名称。该名称会作为最终输出的二进制文件的名字,即 myProject.elfmyProject.bin。每个 CMakeLists 文件只能定义一个项目。

同时该文件可以配置一些全局变量用来修改默认值自定义构建系统:

  • COMPONENT_DIRS:组件的搜索目录,默认为 IDF_PATH/componentsPROJECT_DIR/components、和 EXTRA_COMPONENT_DIRS。如果您不想在这些位置搜索组件,请覆盖此变量。
  • EXTRA_COMPONENT_DIRS:用于搜索组件的其它可选目录列表。路径可以是相对于项目目录的相对路径,也可以是绝对路径。
  • COMPONENTS:要构建进项目中的组件名称列表,默认为 COMPONENT_DIRS 目录下检索到的所有组件。使用此变量可以“精简”项目以缩短构建时间。请注意,如果一个组件通过 COMPONENT_REQUIRES 指定了它依赖的另一个组件,则会自动将其添加到 COMPONENTS 中,所以 COMPONENTS 列表可能会非常短。

使用 cmake 中的 set 命令 来设置这些变量,如 set(VARIABLE "VALUE")。请注意,set() 命令需放在include(...)之前,cmake_minimum(...) 之后。

组件CMakeList.txt

组件是 COMPONENT_DIRS 列表中的任何包含CMakeList.txt目录。IDF按以下顺序搜索组件,如果有多个同名组件,以最后一个为准

  1. 搜索 ESP-IDF 内部组件($ENV{IDF_PATH}/components
  2. 搜索 EXTRA_COMPONENT_DIRS 中的组件
  3. 搜索项目组件($ENV{PROJECT_DIR}/components

组件最小CMakeList如下:

1
2
3
4
idf_component_register(	
SRCS "foo.c" "cplus.cpp"
INCLUDE_DIRS "include"
)
  • SRCS:源文件列表
  • INCLUDE_DIRS:组件的include目录,会被添加到头文件搜索目录中

除此之外,还有一些非必须的变量:

  • REQUIRES:申明组件的共用依赖,一般就是头文件中include的其他组件

  • PRIV_REQUIRES:申明组件的私有依赖,一般是源文件中include的其他组件

  • ….

其中main也是一个组件,但其默认依赖所有组件。

二,配置菜单

IDF中将组件的配置以宏定义的形式移出代码,放进idf的meunconfig中进行配置。在项目的任意位置,都可以使用#include "sdkconfig.h“进行访问。

配置文件种类

文件名 位置 作用
Kconfig 组件(手动创建) menuconfig中的菜单中创建Component Configuration子菜单
Kconfig.projbuild 组件(手动创建) menuconfig中创建顶层菜单
sdkconfig 工程(自动生成) 保持配置
sdkconfig.h 工程编译文件(自动生成) 配置的访问接口
sdkconfig.default 工程(手动创建) 配置的默认值
sdkconfig.old 工程(自动生成) 备份
sdkconfig.ci 用于单元测试
sdkconfig.rename 用于重命名弃用的配置名,方便旧配置文件快速用于新配置,兼容

sdkconfig.default可为不同设备添加默认配置,如:sdkconfig.default.esp32s3

创建菜单

官方文档

创建菜单在Kconfig或者Kconfig.projbuild中按照特定语法进行创建。

具体语法可以参考这篇文章

这里直接给出该文章的中的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
menu "My menu"

# bool 是勾选框
config MY_TEST_BOOL
bool "bool_test"
help
This is a bool test.

# int 是输入整数
config MY_TEST_INT
int "int_test"
default 12345
help
This is an int test.

# hex 是输入16进制数
config MY_TEST_HEX
hex "hex_test"
default 0x7FFF
help
This is a hex test.

# tristate 在 ESP-IDF构建系统中会被当做 bool 处理
config MY_TEST_TRISTATE
tristate "tristate_test"
help
This is a tristate test.

# string 表示一个字符串
config MY_TEST_STRING
string "string_test"
help
This is a string test.

endmenu

生成的宏定义是:

1
2
3
4
#define CONFIG_MY_TEST_BOOL 1
#define CONFIG_MY_TEST_INT 12345
#define CONFIG_MY_TEST_HEX 0x7FFF
#define CONFIG_MY_TEST_STRING "ESP32 YYDS"

宏定义的结构是:CONFIG_+配置名

创建选项菜单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
menu "My Menu"

choice MY_TEST_CHOICE
prompt "My Test Choice"
default MY_CHOICE_OPTION1
help
This is a help.

config MY_CHOICE_OPTION1
bool "option1"
help
help for option1

config MY_CHOICE_OPTION2
bool "option2"
help
help for option2

config MY_CHOICE_OPTION3
bool "option3"
help
help for option3
endchoice
endmenu

生成的宏定义:

1
#define CONFIG_MY_CHOICE_OPTION_1