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

news/2024/11/22 10:06:55/

文章目录

    • 前言
    • 简介
      • 顶层CMakeLists.txt
      • 组件CMakeLists.txt
      • 组件依赖示例
        • Car 组件
        • Engine 组件
        • Spark Plug 组件
        • 源文件 Include 目录
        • 顶层CMakeLists.txt
    • 总结:
    • 参考:

前言

因为熟悉了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 demo1PRI_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_HYBRIDvoid 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,具体内容参考上面示例

参考:

  • 乐鑫官方构建系统

  • https://blog.csdn.net/lum250/article/details/123382392

  • https://blog.csdn.net/RuiyaoNi/article/details/124804251

  • https://blog.csdn.net/DINGDING_GO/article/details/112724707


http://www.ppmy.cn/news/61057.html

相关文章

Linux 挂载磁盘教程,Linux系统分区及磁盘挂载

Linux 挂载磁盘教程,Linux系统分区及磁盘挂载 说明:以下教程是以未安装任何程序及无数据的数据盘基础上编写 如已安装程序或数据盘含有数据切勿使用此教程 本文中的磁盘/dev/sdb为笔者测试服务器上的命名,在您的服务器中可能是/dev/xdb、/dev…

C++:类和对象

文章目录 1、类的定义1.1、类的组成1.2、this 指针1.3、访问控制访问说明符友元 1.4、类作用域 2、对象的创建与销毁2.1、构造函数初始化列表默认构造函数委托构造函数隐式类型转换 2.2、析构函数 3、拷贝控制3.1、拷贝构造函数浅拷贝 & 深拷贝 3.2、拷贝赋值运算符3.3、移…

华为OD机试题,用 Java 解【最远足迹】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不要…

星火认知大模型发布,科大讯飞入场科技巨头AI大战?

自从ChatGPT横空出世,一个更美好的世界开始向我们招手。为了推开新时代的大门,几乎所有人工智能厂商都投入了最大的热情逐浪AIGC。 5月6日,科大讯飞召开了“讯飞星火认知大模型”成果发布会。发布会现场,科大讯飞董事长刘庆峰展示…

CSS布局基础(传统布局小结)

传统布局小结 传统布局方式标准流浮动流定位伪类元素CSS应用对象应用到自身应用到其他元素 传统布局方式 传统布局采用 标准流 浮动流 定位的方式实现布局效果,也就是通常所说的 DIV CSS 布局。 标准流 标准流中的元素在 页面默认的 维度,块级元素…

一、spring Cloud Alibaba概述

spring Cloud Alibaba学习,第一篇spring Cloud Alibaba概述篇。 微服务是一种架构思想,spring Cloud Alibaba是微服务的系列化实现方式之一。 一、架构演变过程 架构粒度更加精细,拆分成不同的服务,每个服务直接互不影响&#…

GPT 告诉你请求到达 Tomcat 是怎么处理的

tomcat如何监听请求到达 没有SpringMVC,tomcat 如何处理请求 Tomcat 线程池的作用是什么 如何配置tomcat 线程池 tomcat 线程池的主要任务是处理连接请求 tomcat线程池是怎么实现的 到这里可以看出来,tomcat线程池的实现方式也是通过ThreadPoolExecutor 实现 如何根…

深入源码理解redis数据结构(一)

文章目录 一. 动态字符串SDS二. IntSet三. Dict 一. 动态字符串SDS 我们都知道Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。不过Redis没有直接使用C语言的字符串,因为C语言字符串存在着很多…