ESP-IDF开发框架添加自定义组件 ESP32-C3

前言

因为熟悉了STM32的开发方式,同时随着项目文件越来越多,可以将自己写的代码分模块添加到工程中,下面分析如何将自己写的组件添加到工程中使其能够正常编译运行。

简介

在ESP-IDF中,构建,编译,以及下载都是通过idf.py脚本来实现的,该脚本使用

  • CMake,配置待构建的项目

  • Ninja,用于构建项目

  • esptool.py,烧录目标硬件设备

从上面可以看出管理项目架构使用的是CMake,一个 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/
  • 顶层项目 CMakeLists.txt 文件,这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。顶层项目 CMakeLists.txt 文件会导入 /tools/cmake/project.cmake 文件,由它负责实现构建系统的其余部分。该文件最后会设置项目的名称,并定义该项目。

  • “sdkconfig” 项目配置文件,执行 idf.py menuconfig 时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 sdkconfig 文件可能会也可能不会被添加到项目的源码管理系统中。

  • 可选的 “components” 目录中包含了项目的部分自定义组件,并不是每个项目都需要这种自定义组件,但它有助于构建可复用的代码或者导入第三方(不属于 ESP-IDF)的组件。或者,您也可以在顶层 CMakeLists.txt 中设置 EXTRA_COMPONENT_DIRS 变量以查找其他指定位置处的组件。

  • “main” 目录是一个特殊的组件,它包含项目本身的源代码。”main” 是默认名称,CMake 变量COMPONENT_DIRS 默认包含此组件,但您可以修改此变量。有关详细信息,请参阅 重命名 main 组件。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 “main” 中。

  • “build” 目录是存放构建输出的地方,如果没有此目录,idf.py 会自动创建。CMake 会配置项目,并在此目录下生成临时的构建文件。随后,在主构建进程的运行期间,该目录还会保存临时目标文件、库文件以及最终输出的二进制文件。此目录通常不会添加到项目的源码管理系统中,也不会随项目源码一同发布。

顶层CMakeLists.txt

可以看出,CMake文件分为顶层CMake和组件CMake,顶层CMake通过包含的方式包含组件CMake
顶层CMake为文件如下所示

# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

include($ENV{
    
    IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "./conponets/conponent1" | "./conponets/conponent2")
project(myProject)

一个CMake文件应该首先指定所需的CMake的最小版本,然后包含了$IDF_PATH/tools/cmake/project.cmake这个配置文件,最后project(project name)指定了构建项目的名称。

在这个文件中就出现了EXTRA_COMPONENTS_DIRS,其实从其名字里不难看出EXTRA(外部)、COMPONENTS(组件)、DIRS(文件夹)它是用来保存外部组件文件夹的一个CMake变量

因此可以通过set(EXTRA_CONPONENTS)的方式导入外部组件,但是这条命令只能使用一次,多次使用时后面的会覆盖前面的,可以通过set(EXTRA_COMPONENT_DIRS “./user_components_1” | “./user_components_2”)的方式或者使用CMake的函数list(APPEND EXTRA_COMPONENT_DIRS “子目录”)这两种方法实现包含多个组件。

组件CMakeLists.txt

每个组件都包含一个CMakeLists.txt用于包含组件所包含的文件,便于顶层CMake索引。
最小组件 CMakeLists.txt 文件通过使用 idf_component_register 将组件添加到构建系统中。

idf_component_register(SRCS “src1.c”
						INCLUDE_DIRS “include” 
						REQUIRES demo1
						PRI_REQUIRES demo2)
  • SRCS 是组件包含的源文件列表(.c、.cpp、.cc、.S),里面所有的源文件都将会编译进组件库中。

  • INCLUDE_DIRS 是组件的头文件列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。

  • REQUIRES 实际上并不是必需的,但通常需要它来声明该组件需要使用哪些其它组件,举个例子,当自己写的组件的头文件需要依赖其他组件的时候需要在REQUIRES后跟所需的组件名称

  • PRI_REQUIRES与REQUIRES的作用类似,都是包含所需的组件,但是PRI_REQUIRES的意思是私有依赖,即源文件中需要包含组件的头文件时可以使用PRI_REQUIRES来包含组件,而REQUIRES是头文件包含其他组件的头文件时用的。

在 CMake 中,REQUIRES 和 PRIV_REQUIRES 是 CMake 函数 target_link_libraries(… PUBLIC …) 和 target_link_libraries(… PRIVATE …) 的近似包装。

下面是一个官方的示例:

组件依赖示例

假设现在有一个 car 组件,它需要使用 engine 组件,而 engine 组件需要使用 spark_plug 组件:

- autoProject/
             - CMakeLists.txt
             - components/ - car/ - CMakeLists.txt
                                     - car.c
                                     - car.h
                           - engine/ - CMakeLists.txt
                                     - engine.c
                                     - include/ - engine.h
                           - spark_plug/  - CMakeLists.txt
                                          - spark_plug.c
                                          - spark_plug.h
                    

Car 组件

car.h 头文件是 car 组件的公共接口。该头文件直接包含了 engine.h,这是因为它需要使用 engine.h 中的一些声明:

/* car.h */
#include "engine.h"

#ifdef ENGINE_IS_HYBRID
#define CAR_MODEL "Hybrid"
#endif

同时 car.c 也包含了 car.h:

/* car.c */
#include "car.h"

这代表文件 car/CMakeLists.txt 需要声明 car 需要 engine:

idf_component_register(SRCS "car.c"
                  INCLUDE_DIRS "."
                  REQUIRES engine)
  • SRCS 提供 car 组件中源文件列表。

  • INCLUDE_DIRS 提供该组件公共头文件目录列表,由于 car.h 是公共接口,所以这里列出了所有包含了 car.h 的目录。

  • REQUIRES 给出该组件的公共接口所需的组件列表。由于 car.h 是一个公共头文件并且包含了来自 engine 的头文件,所以我们这里包含 engine。这样可以确保任何包含 car.h 的其他组件也能递归地包含所需的 engine.h。

Engine 组件

engine 组件也有一个公共头文件 include/engine.h,但这个头文件更为简单:

/* engine.h */
#define ENGINE_IS_HYBRID

void engine_start(void);

engine.c :

/* engine.c */
#include "engine.h"
#include "spark_plug.h"

...

在该组件中,engine 依赖于 spark_plug,但这是私有依赖关系。编译 engine.c 需要 spark_plug.h 但不需要包含 engine.h。

这代表文件 engine/CMakeLists.txt 可以使用 PRIV_REQUIRES

idf_component_register(SRCS "engine.c"
                  INCLUDE_DIRS "include"
                  PRIV_REQUIRES spark_plug)

因此,car 组件中的源文件不需要在编译器搜索路径中添加 spark_plug include 目录。这可以加快编译速度,避免编译器命令行过于的冗长。

Spark Plug 组件

spark_plug 组件没有依赖项,它有一个公共头文件 spark_plug.h,但不包含其他组件的头文件。

这代表 spark_plug/CMakeLists.txt 文件不需要任何 REQUIRES 或 PRIV_REQUIRES:

idf_component_register(SRCS "spark_plug.c"
                  INCLUDE_DIRS ".")
                  

源文件 Include 目录

每个组件的源文件都是用这些 Include 路径目录编译的,这些路径在传递给 idf_component_register 的参数中指定:

idf_component_register(..
                       INCLUDE_DIRS "include"
                       PRIV_INCLUDE_DIRS "other")

当前组件的 INCLUDE_DIRS 和 PRIV_INCLUDE_DIRS。

REQUIRES 和 PRIV_REQUIRES 参数指定的所有其他组件(即当前组件的所有公共和私有依赖项)所设置的 INCLUDE_DIRS。

递归列出所有组件 REQUIRES 列表中 INCLUDE_DIRS 目录(如递归展开这个组件的所有公共依赖项)。

顶层CMakeLists.txt

參考上面列出來的頂層CMake,需要使用set(EXTRA_COMPONENT_DIRS "./user_components_1" | "./user_components_2")

# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

include($ENV{
    
    IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS "./car")
project(smartconfig)

总结:

如果要添加一个组件,我们需要修改顶层CMakeLists.txt以及新添加的组件的CMakeLists.txt,具体内容参考上面示例

参考:

猜你喜欢

转载自blog.csdn.net/weixin_51954217/article/details/130463971