ESP-IDF的vscode环境编译时出现“fatal error: nvs.h: No such file or directory”的解决方法

前言

目前刚开始在vscode IDE的ESP-IDF环境中开发ESP32的应用。由于这个环境中,编译工程用的是CMAKE工具,因此,在构建项目的源文件组织结构时,即要符合CMAKE的规范,又要满足ESP-IDF的要求。特别是很多文件的引用与依赖关系,在ESP-IDF中有对应的默认规则,并在这个规则基础上封装了一些CMAKE的函数进行设置。

这样讲可能太过理论,拿个例子来说,就是我在一个自已写的部件(在项目的components目录下的)里引用了系统的标准部nvs_flash。但是编译时却出现“fatal error: nvs.h: No such file or directory”的错译提示。

在网上找了很多文档,几乎没有一个能解决问题。根据自已的摸索,把我的解决方案也写出来,供大家参考。

在这里,我直接公布方法吧,其实上述问题的本质是依赖关系的问题。只需要在自已写的自定义组件目录里的CMakeLists.txt中的idf_component_register()语句里加入 “REQUIRES nvs_flash” 选项,就能完美解决。
在这里插入图片描述

ESP-IDF编程指南原文解读

关于ESP-IDF的组件管理模式

其实在ESP-IDF编程指南-构建系统里就有详细的说明,只是到了应用时,一时没把指南里的内容和实际对应起来。

这里把原文里的一起内容引用如下,并做相应的说明

基于 CMake 的构建系统,它是 ESP-IDF V4.0 及以上版本的默认系统。此外 ESP-IDF 还支持 基于 GNU Make 的构建系统,基于 GNU Make 的构建系统是 ESP-IDF V4.0 以下版本的默认系统。
概述
一个 ESP-IDF 项目可以看作是多个不同组件的集合,例如一个显示当前湿度的网页服务器会包含以下组件:
ESP-IDF 基础库,包括 libc、ROM bindings 等
Wi-Fi 驱动
TCP/IP 协议栈
FreeRTOS 操作系统
网页服务器
湿度传感器的驱动
负责将上述组件整合到一起的主程序

ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会前往 ESP-IDF 目录项目目录用户自定义组件目录(可选)中查找所有组件,允许用户通过文本菜单系统配置 ESP-IDF 项目中用到的每个组件。在所有组件配置结束后,构建系统开始编译整个项目。

概念
项目 特指一个目录,其中包含了构建可执行应用程序所需的全部文件和配置,以及其他支持型文件,例如分区表、数据/文件系统分区和引导程序。
项目配置 保存在项目根目录下名为 sdkconfig 的文件中,可以通过 idf.py menuconfig 进行修改,且一个项目只能包含一个项目配置。
应用程序 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(可执行的主文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序)。
组件 是模块化且独立的代码,会被编译成静态库(.a 文件)并链接到应用程序。部分组件由 ESP-IDF 官方提供,其他组件则来源于其它开源项目。
目标 特指运行构建后应用程序的硬件设备。运行 idf.py –list-targets 可以查看当前 ESP-IDF 版本中支持目标的完整列表。

说明: 以上就是ESP-IDF的相应规范。ESP-IDF是以组件的形式组织官方代码的,统一放在ESP-IDF安装目录里的components目录下,在这里插入图片描述
而用户自定义组件,则是放在VSCODE工作目录里的components目录里。在这里插入图片描述
因此这些源文件的相互关联关系和依赖就必须在编译时向CMAKE说明清楚。对于标准的CMAKE语法,有相应的依赖说明语句。而对于esp-idf则对CMAKE的这些功能进行了封装,封装成了**idf_component_register()**函数。这个函数的定义在“esp-idf/tools/cmake/project.cmake”文件中。有兴趣的小伙伴可以自行去查看,这里我们只关心如何使用。

示例项目的结构层次

在这里插入图片描述

顶层项目 CMakeLists.txt 文件,这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。顶层项目 CMakeLists.txt 文件会导入 /tools/cmake/project.cmake 文件,由它负责实现构建系统的其余部分。该文件最后会设置项目的名称,并定义该项目。
“main” 目录是一个特殊的组件,它包含项目本身的源代码。”main” 是默认名称,CMake 变量 COMPONENT_DIRS 默认包含此组件
每个组件目录都包含一个 CMakeLists.txt 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。

顶层项目CMakeLists.txt文件的解释

cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(myProject)

必要部分

每个项目都要按照上面显示的顺序添加上述三行代码:
cmake_minimum_required(VERSION 3.5) 必须放在 CMakeLists.txt 文件的第一行,它会告诉 CMake 构建该项目所需要的最小版本号。ESP-IDF 支持 CMake 3.5 或更高的版本。
include($ENV{IDF_PATH}/tools/cmake/project.cmake) 会导入 CMake 的其余功能来完成配置项目、检索组件等任务。
project(myProject) 会创建项目本身,并指定项目名称。该名称会作为最终输出的二进制文件的名字,即 myProject.elf 和 myProject.bin。每个 CMakeLists 文件只能定义一个项目。

可选的项目变量

以下这些变量都有默认值,用户可以覆盖这些变量值以自定义构建行为。更多实现细节,请参阅 /tools/cmake/project.cmake 文件。

COMPONENT_DIRS:组件的搜索目录,默认为 IDF_PATH/components、 PROJECT_DIR/components、和 EXTRA_COMPONENT_DIRS。如果您不想在这些位置搜索组件,请覆盖此变量。

EXTRA_COMPONENT_DIRS:用于搜索组件的其它可选目录列表。路径可以是相对于项目目录的相对路径,也可以是绝对路径。

COMPONENTS:要构建进项目中的组件名称列表,默认为 COMPONENT_DIRS 目录下检索到的所有组件。使用此变量可以“精简”项目以缩短构建时间。请注意,如果一个组件通过 COMPONENT_REQUIRES 指定了它依赖的另一个组件,则会自动将其添加到 COMPONENTS 中,所以 COMPONENTS 列表可能会非常短。

以上变量中的路径可以是绝对路径,或者是相对于项目目录的相对路径。

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

说明:以上这几个变量相当关键,一般情况下,如果用了MENUCONFIG功能以后,IDE会设置好这些编译变量。我们无须太关心,但是如果涉及到自定义的组件时,如果自定义组件有依赖到官方的一些标准组件,而又没有在MENUCONFIG功能里配置时,则需要添加以上变量,特别是COMPONENTS。这样也能避免出现本文前言里出现的找不到头文件的错误。

组件 CMakeLists 文件的解读

每个项目都包含一个或多个组件,这些组件可以是 ESP-IDF 的一部分,可以是项目自身组件目录的一部分,也可以从自定义组件目录添加(见上文)。
组件是 COMPONENT_DIRS 列表中包含 CMakeLists.txt 文件的任何目录。

最小组件 CMakeLists 文件

最小组件 CMakeLists.txt 文件通过使用 idf_component_register 将组件添加到构建系统中。

在这里插入图片描述

SRCS 是源文件列表(.c、.cpp、.cc、.S),里面所有的源文件都将会编译进组件库中。
INCLUDE_DIRS 是目录列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。
REQUIRES 实际上并不是必需的,但通常需要它来声明该组件需要使用哪些其它组件,请参考 组件依赖。

main 组件比较特别,因为它在构建过程中自动依赖所有其他组件。所以不需要向这个组件传递 REQUIRES 或 PRIV_REQUIRES。

在构建中导入组件
默认情况下,每个组件都会包含在构建系统中。
如果将 COMPONENTS 变量设置为项目直接使用的最小组件列表,那么构建系统会扩展到包含所有组件。完整的组件列表为:
COMPONENTS 中明确提及的组件。
这些组件的依赖项(以及递归运算后的组件)。
每个组件都依赖的通用组件。
将 COMPONENTS 设置为所需组件的最小列表,可以显著减少项目的构建时间。

说明: 这里就是关键所在了,如上举例说明,如果在自定义组件的头文件(公共接口)里有包含nvs_flash这个组件里的头文件nvs.h,那么就需要在上图中的命令语句里加上REQUIRES nvs_flash 选项。。。如果是在自已组件里的某个.C文件里(私有依赖关系)的包含nvs_flash组件的头文件件nvs.h,那么只需要使用PRIV_REQUIRES nvs_flash选项即可。这个结论在下面这个例子中有明确的阐述。

组件依赖示例

假设现在有一个 car 组件,它需要使用 engine 组件,而 engine 组件需要使用 spark_plug 组件:
在这里插入图片描述

Car 组件
car.h 头文件是 car 组件的公共接口。该头文件直接包含了 engine.h,这是因为它需要使用 engine.h 中的一些声明。同时 car.c 也包含了 car.h
在这里插入图片描述

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

在这里插入图片描述

总结

以上就是关于“fatal error: nvs.h: No such file or directory”错误所引出的一连串ESP-IDF构建编译过程所涉及的规范。看起来内容很多,里面的概念似乎也不少,主要是因为涉及到ESP-IDF本身的概念,如,项目,组件,系统组件,自定义组件,目录组织结构。也有关于CMAKE的内容,但由于ESP-IDF对CMAKE的封装,使得我们在使用是并不是用的标准CMAKE语句。而只是简单地使用了一个顶层CMakeLists.txt 的语句规范。一个是组件里的CMakeLists.txt的语句规范。以及COMPONENTS变量等几个内容。所以ESP-IDF的封装其实是简化了整个构建系统的使用。

  • 16
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑牛唱剧本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值