一个 ESP-IDF 项目可以看作是多个不同组件的集合,ESP-IDF可以显式地指定和配置每个组件。在构建项目的时候,构建系统会前往** ESP-IDF 目录、项目目录和用户自定义组件目录(可选)**中查找所有组件,允许用户通过文本菜单系统配置 ESP-IDF 项目中用到的每个组件。在所有组件配置结束后,构建系统开始编译整个项目。
项目
: 特指一个目录,其中包含了构建可执行应用程序所需的全部文件和配置,以及其他支持型文件,例如分区表、数据/文件系统分区和引导程序。项目配置
: 保存在项目根目录下名为 sdkconfig 的文件中,可以通过idf.py menuconfig
进行修改,且一个项目只能包含一个项目配置。应用程序
: 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(可执行的主文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序)。组件
: 是模块化且独立的代码,会被编译成静态库(.a 文件)并链接到应用程序。部分组件由 ESP-IDF 官方提供,其他组件则来源于其它开源项目。目标
: 特指运行构建后应用程序的硬件设备。运行 idf.py –list-targets
可以查看当前 ESP-IDF 版本中支持目标的完整列表。- 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
该示例项目 “myProject” 包含以下组成部分:
idf.py menuconfig
时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 sdkconfig 文件可能会也可能不会被添加到项目的源码管理系统中。每个组件目录都包含一个 CMakeLists.txt 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。更多详细信息请参阅 组件 CMakeLists 文件.
每个组件还可以包含一个 Kconfig 文件,它用于定义 menuconfig 时展示的 组件配置 选项。某些组件可能还会包含 Kconfig.projbuild 和 project_include.cmake 特殊文件,它们用于 覆盖项目的部分设置
每个项目都有一个顶层 CMakeLists.txt 文件,包含整个项目的构建设置。默认情况下,项目 CMakeLists 文件会非常小。
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp-wroom-32)
每个项目都要按照上面显示的顺序添加上述三行代码:
以下这些变量都有默认值,用户可以覆盖这些变量值以自定义构建行为。
构建系统会对 main 组件进行特殊处理。假如 main 组件位于预期的位置(即 ${PROJECT_PATH}/main),那么它会被自动添加到构建系统中。其他组件也会作为其依赖项被添加到构建系统中,这使用户免于处理依赖关系,并提供即时可用的构建功能。重命名 main 组件会减轻上述这些幕后工作量,但要求用户指定重命名后的组件位置,并手动为其添加依赖项。重命名 main 组件的步骤如下:
每个项目都包含一个或多个组件,这些组件可以是 ESP-IDF 的一部分,可以是项目自身组件目录的一部分,也可以从自定义组件目录添加。组件是 COMPONENT_DIRS 列表中包含 CMakeLists.txt 文件的任何目录。
搜索 COMPONENT_DIRS 中的目录列表以查找项目的组件,此列表中的目录可以是组件自身(即包含 CMakeLists.txt 文件的目录),也可以是子目录为组件的顶级目录。当 CMake 运行项目配置时,它会记录本次构建包含的组件列表,它可用于调试某些组件的添加/排除。
ESP-IDF 在搜索所有待构建的组件时,会按照 COMPONENT_DIRS 指定的顺序依次进行,这意味着在默认情况下,首先搜索 ESP-IDF 内部组件(IDF_PATH/components),然后是 EXTRA_COMPONENT_DIRS 中的组件,最后是项目组件(PROJECT_DIR/components)。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改以覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。
最小组件 CMakeLists.txt 文件通过使用 idf_component_register 将组件添加到构建系统中。
set(SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
idf_component_register(
SRCS ${SRC_LISTS}
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
REQUIRES freertos esp_common
)
以下专用于组件的变量可以在组件 CMakeLists 中使用,但不建议修改:
每个组件都可以包含一个 Kconfig 文件,和 CMakeLists.txt 放在同一目录下。Kconfig 文件中包含要添加到该组件配置菜单中的一些配置设置信息。运行 menuconfig 时,可以在 Component Settings 菜单栏下找到这些设置。创建一个组件的 Kconfig 文件,最简单的方法就是使用 ESP-IDF 中现有的 Kconfig 文件作为模板,在这基础上进行修改。
├── CMakeLists.txt
├── README.md
├── build.sh
├── core
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── main.h
├── docs
└── sdkconfig
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17)
# search for components in these places
set(EXTRA_COMPONENT_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/core
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp-wroom-32)
set(SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
idf_component_register(
SRCS ${SRC_LISTS}
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
REQUIRES freertos esp_common
)
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
class Main final
{
public:
[[nodiscard]] esp_err_t setup(void);
void loop(void);
};
#include "main.h"
#define LOG_LEVEL_LOCAL ESP_LOG_VERBOSE
#include "esp_log.h"
#define LOG_TAG "MAIN"
static Main my_main;
[[nodiscard]] esp_err_t Main::setup(void)
{
auto status{ESP_OK};
ESP_LOGI(LOG_TAG, "app main setup done");
return status;
}
void Main::loop(void)
{
ESP_LOGI(LOG_TAG, "Hello world!");
vTaskDelay(pdMS_TO_TICKS(1000));
}
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(my_main.setup());
while (true) {
my_main.loop();
}
}