ESP32工程中CMake使用及加入第三方SDK库文件

1、ESP32工程结构

        本文中使用的是乐鑫官方推出的ESP-IDF v5.1ESP32S3设备开发,并非是Arduino、Micro-python等第三方工具开发。在ESP-IDF框架中,乐鑫官方已经将CMake 和 Ninja 编译构建工具集成到了ESP-IDF中。

        ESP-IDF 即乐鑫物联网开发框架,可为在 Windows、Linux 和 macOS 系统平台上开发 ESP32-S3 应用程序提供工具链、API、组件和工作流程的支持。

ESP32的项目实例工程文件结构

- 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/

ESP32的示例工程项目 “myProject” 包含以下组成部分:

①、顶层CMakeLists.txt 文件:这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。

②、“sdkconfig” 项目配置文件:执行 idf.py menuconfig 时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 

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

④、“main” 目录:这是一个特殊的组件,它包含项目本身的源代码。”main” 是默认名称,CMake 变量 COMPONENT_DIRS 默认包含此组件,但也可以修改此变量。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 “main” 中。

⑤、“build” 目录:存放构建输出的地方,如果没有此目录,idf.py 会自动创建。CMake 会配置项目,并在此目录下生成临时的构建文件。

每个组件目录都包含一个 CMakeLists.txt 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。

每个组件还可以包含一个 Kconfig 文件,它用于定义 menuconfig 时展示的 组件配置 选项。某些组件可能还会包含 Kconfig.projbuild 和 project_include.cmake 特殊文件,它们用于 覆盖项目的部分设置。

2、CMake基础

        CMake是一个开源的、跨平台的安装(编译)工具,用于控制软件编译过程,并生成可在所选编译器环境中使用的项目文件。它使用平台无关的配置文件(通常是CMakeLists.txt文件),并可以输出各种makefile或project文件。

        因乐鑫官方的ESP-IDF高度集成CMake工具,因此需要使用ESP-IDF去开发ESP32设备,必须要掌握CMake基础,以实现对ESP32工程项目自由的扩展操作。如项目工程中添加、减少模块代码,加入第三方的SDK库等,都是通过CMake工具来实现的。        

        对于CMake的使用,在乐鑫官网的ESP32开发指南中,有较为详细的教程,但乐鑫官方的CMake教程过于繁琐,不利于初学者理解,且容易迷失方向、抓不住核心知识。因此本文对一些在ESP32开发中常用的CMake知识进行简单的整理。

构建系统 - ESP32-S3 - — ESP-IDF 编程指南 v5.1.2 文档 (espressif.com)icon-default.png?t=N7T8https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1.2/esp32s3/api-guides/build-system.html乐鑫ESP32对CMake讲解的部分文档

        在CMake管理的项目工程中,时常都能看到CMakeLists.txt这个文件的影子,这是一个用于描述 CMake 构建过程和项目配置的文件。这个文件包含了一系列 CMake 命令、变量设置和流程控制结构,用于告诉 CMake 如何生成适合特定平台和编译器的构建系统文件。

CMakeLists.txt 文件通常包含以下几个部分:

1、项目设置:这里指定了项目的名称、版本、编程语言版本等信息。

2、编译选项:配置编译类型(如 Debug 或 Release)、编译器选项、警告等级等。

3、源文件:指定项目中的源文件,可以包括多个目录和文件。

4、头文件目录:添加头文件的搜索路径。

5、库文件:链接外部库文件,包括静态库和动态库。

6、编译目标:定义编译目标,如可执行文件、静态库或动态库。

7、测试:编写和执行测试程序,以确保项目的正确性。

8、安装和打包:指定如何安装和打包项目。

CMakeLists.txt 文件的结构和命令可以根据项目的具体需求进行调整。通过编辑这个文件,可以灵活地配置项目的构建过程,以适应不同的平台和编译器。

最小的CMakeLists.txt文件示例:

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

在任意的CMakeLists.txt文件中,上面三行代码是必须存在的!

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.elf 和 myProject.bin。每个 CMakeLists 文件只能定义一个项目。

最小组件的 CMakeLists.txt 文件:此文件存在于顶层CMakeLists.txt文件下的components或自定义的组件内。

最小组件 CMakeLists.txt 文件通过使用 idf_component_register 将组件添加到构建系统中。
idf_component_register(SRCS “car.c” “engine.c”INCLUDE_DIRS “include” REQUIRES mbedtls)
SRCS: 是源文件列表(*.c、*.cpp、*.cc、*.S),里面所有的源文件都将会编译进组件库中。
INCLUDE_DIRS: 是目录列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。
REQUIRES: 实际上并不是必需的,但通常需要它来声明该组件需要使用哪些其它组件,也就是当前组件有对其它组件存在依赖时,用于声明该依赖,防止报错。上述命令会构建生成与组件同名的库,并最终被链接到应用程序中。

3、ESP32常见的CMake函数

cmake_minimum_required( )

include( )

project( ) 

idf_component_register( )

除了之前在上面讲解的这几个CMake函数外,在ESP32中常用的CMake函数(命令)还有:

①、set、unset : 用于设置变量的值、用于清空变量的值。

set(<variable> <value>... [PARENT_SCOPE])
variable:要被赋值的变量
value:要赋给变量的值
set(data  "Hello, World!")        #设置变量data的值为"Hello World!"

unset(<variable>... [PARENT_SCOPE])
variable:要被清空的变量
unset(data)        #清空变量data的值

set 、unset的值可以为:

        一般变量(Normal Variable)
        缓存变量(Cache Variable)
        环境变量(Environment Variable)

②、message :为用户显示一条消息。

message( [STATUS | WARNING | AUTHOR_WARNING | FATAL_ERROR | SEND_ERROR] "message to display" ...)

可以用下述可选的关键字指定消息的类型:

 (无) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 但会继续执行;
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
FATAL_ERROR = CMake 错误, 终止所有处理过程;

set(AUTHOR, "牛马大师兄")

message(STATUS " Author : ${AUTHOR}.")

③、file :用于执行各种文件操作的。

file的功能十分丰富,它支持多种操作,包括但不限于读取文件、写入文件、追加到文件、计算文件的散列值等。

写入文件:file(WRITE <filename> "message to write"...)

追加到文件:file(APPEND <filename> "message to append"...)

读取文件:file(READ <filename> <variable> [LIMIT <numBytes>] [OFFSET <offset>] [HEX])

④、include_directories :用于向构建过程中添加包含目录。

include_directories([AFTER | BEFORE] [SYSTEM] [DIR1、DIR2 ...])

AFTER | BEFORE:这两个参数是可选的,并决定新添加的目录是追加到(默认)还是插入到现有的包含目录列表的开头。默认情况下,include_directories将目录添加到列表的末尾。

SYSTEM:这个可选参数用于标记目录为系统目录。

DIR1、DIR2 ...:这些是要添加的头文件搜索路径。

include_directories命令将指定的目录添加到当前CMakeLists.txt文件的INCLUDE_DIRECTORIES目录属性中,并且也添加到当前CMakeLists.txt文件中每个目标的INCLUDE_DIRECTORIES目标属性中。这意味着这些目录将被用于搜索头文件,无论是在编译源代码时,还是在链接库文件时。

include_directories(/usr/include/hello)

⑤、add_executable :用于指定一个可执行文件目标的命令。

add_executable(targetName [source1] [source2] ...)

targetName :这是想要生成的可执行文件的名称,通常是不带文件扩展名的名称。

[source1] [source2] ... :想要编译成可执行文件的源文件列表。可以指定多个源文件,它们之间用空格分隔。

add_executable 命令会创建一个构建目标,这个目标代表了最终的可执行文件。当运行构建系统(例如,通过执行 make或 ninja 命令)时,这个目标会被构建。

add_executable(my_program  main.cpp)

⑥、add_library :用于创建一个库目标的命令。

add_library 告诉 CMake 你想要从哪些源文件构建一个库,并给这个库指定一个名称。这个库可以是静态库(.a 或 .lib 文件)、共享库(.so.dylib 或 .dll 文件)或模块。

add_library(targetName [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
targetName:库的逻辑名称,不带文件扩展名。

[STATIC | SHARED | MODULE]:这个可选参数用于指定库的类型。

               STATIC    ---创建静态库

               SHARED ---创建共享库

               MODULE ---创建可以被动态加载的库

默认为 STATIC   

[EXCLUDE_FROM_ALL]: 可选参数,如果指定了,那么这个库就不会被默认构建。

source1 [source2 ...]:想要编译成库的源文件列表,可以指定多个源文件,它们之间用空格分隔

add_library(mylib  STATIC  mylib.cpp)

add_library(mylib SHARED mylib.cpp)

对于静态库,CMake 会自动添加 .a(在 Unix 上)或 .lib(在 Windows 上)扩展名;对于共享库,CMake 会自动添加适当的平台相关扩展名。

⑦、target_link_libraries:用于指定目标(比如可执行文件或库)应该链接哪些库。

target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> lib1 [lib2 ...])

target:这是你想要链接库的目标,可以是一个可执行文件或库。

PRIVATE|PUBLIC|INTERFACE:这些关键字用于指定库链接的范围和传递性。

   PRIVATE:库仅对目标私有,不会传递给其他目标。

         PUBLIC:库对目标是公共的,并且还会传递给依赖该目标的其他目标。

   INTERFACE:库仅对其他目标可见,但对当前目标不可见。

lib1 [lib2 ...:这是你想要链接的库列表。

add_executable(my_program  main.cpp)

add_library(my_library  my_library.cpp)

target_link_libraries(my_program  my_library)

在这个例子中,my_program 可执行文件会被链接到 my_library 库。

对于外部SDK库,需要提供库的完整路径(如果库不在标准库路径中)

target_link_libraries(my_program  /path/to/external/libfoo.a)

4、ESP32链接第三方SDK库

        在项目开发中,大多情况为团队内部合作或者跨公司进行合作,为了保证代码的安全及项目的正常进展,往往会将负责的部分代码编译成一个SDK库文件,可以是静态库或动态库文件,以库和开发手册的方式交付程序代码。因此ESP32开发中,非常有必要掌握链接第三方SDK库到项目工程中。

        在顶层的CMakeLists.txt文件中加入以下代码,引入链接第三方库。

#全路径引入库
#link_libraries 表示将具体的库文件引入到当前工程中,所填入的路径必须是全路径。
方法一:直接填入全部的路径,可移植性较差,移动文件位置或修改文件夹名字后,需要重新修改
#link_libraries("/home/tony/Desktop/gm_algorithm/lib/gm/libsm_esp32c3.a")
方法二:使用Cmake变量获取当前文件所在路径,填充到文件中
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/lib/gm/libsm_esp32c3.a)
不能使用相对路径
#link_libraries(./lib/gm/libsm_esp32c3.a) #错误示例
使用message打印CMAKE_CURRENT_SOURCE_DIR所指的路径值message(STATUS "The CMAKE_CURRENT_SOURCE_DIR is: ${CMAKE_CURRENT_SOURCE_DIR}")

链接SDK库测试工程的顶层CMakeLists.txt文件源码

cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
message(STATUS "The CMAKE_CURRENT_SOURCE_DIR is: ${CMAKE_CURRENT_SOURCE_DIR}")
#包含第三方SDK库头文件所在的路径
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/gm)
#链接第三方SDK静态库文件
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/lib/gm/libsm_esp32c3.a)
project(gm)

提醒:link_libraries( ) 函数中填入的库路径必须是绝对路径,采用相对路径会报错。

①、手动填入绝对路径

        采用这种方法移植性较差,一但更改了文件路径或工程文件名,编译必定会报错,需要手动去修改CMakeLists.txt文件中的链接库文件路径,因此不推荐采用此方法,但可以学习了解一下。

②、自动获取补全库的绝对路径

        建议使用CMake设置的宏变量去实现路径的填写,这样可移植性较好,可以减少开发过程的工作量。

③、第三方的SDK包、链接库成功,编译顺利通过

④、相对路径报错,SDK包链接不通过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/689627.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java前端技术栈】Promise

一、Promise 基本介绍 1. 传统的 Ajax 异步调用在需要多个操作的时候&#xff0c;会导致多个回调函数嵌套&#xff0c;导致代码不够直观&#xff0c;就是常说的Callback Hell 2. 为了解决上述的问题&#xff0c;Promise对象应运而生&#xff0c;在 EMCAScript 2015当中已经成…

车道拓扑、目标布局、天气条件全都要!Text2Street:犀利的街景生成神器!

文本到图像生成在扩散模型的出现下取得了显著进展。然而&#xff0c;基于文本生成街景图像仍然是一项困难的任务&#xff0c;主要是因为街景的道路拓扑复杂&#xff0c;交通状况多样&#xff0c;天气情况各异&#xff0c;这使得传统的文本到图像模型难以处理。为了解决这些挑战…

每日一题——LeetCode1460.通过翻转子数组使两个数组相等

方法一 哈希Map 用两个Map集合分别统计target和arr里出现的元素和出现的次数&#xff0c;在比较两个Map集合看是否出现的元素和次数都相同 var canBeEqual function(target, arr) {let map1 new Map();let map2 new Map();for (let item of target) {map1.set(item, (map1…

039-安全开发-JavaEE应用SpringBoot框架Actuator监控泄漏Swagger自动化

039-安全开发-JavaEE应用&SpringBoot框架&Actuator监控泄漏&Swagger自动化 #知识点&#xff1a; 1、JavaEE-SpringBoot-监控系统-Actuator 2、JavaEE-SpringBoot-接口系统-Swagger 3、JavaEE-SpringBoot-监控&接口&安全问题 演示案例&#xff1a; ➢Spring…

机器人初识 —— 电机传动系统

一、背景 波士顿动力公司开发的机器人&#xff0c;其电机传动系统是其高性能和动态运动能力的核心部分。电机传动系统通常包括以下几个关键组件&#xff1a; 1. **电动马达**&#xff1a;波士顿动力的机器人采用了先进的电动马达作为主要的动力源&#xff0c;如伺服电机或步进…

【数据分享】2014-2024年全国监测站点的逐时空气质量数据(15个指标\Excel\Shp格式)

空气质量的好坏反映了空气的污染程度&#xff0c;在各项涉及城市环境的研究中&#xff0c;空气质量都是一个十分重要的指标。空气质量是依据空气中污染物浓度的高低来判断的。 我们发现学者王晓磊在自己的主页里面分享了2014年5月以来的全国范围的到站点的逐时的空气质量数据&…

OpenCV运行gstreamer管道获取相机数据,处理以后,再交给gstreamer显示(QT实现)

前言 无意中发现&#xff0c;OpenCV也可以运行gstreamer的命令管道&#xff0c;然后使用appsink来与OpenCV连接起来进行处理&#xff0c;在不断测试之下&#xff0c;先后实现了以下功能&#xff1a; 1. OpenCV运行gstreamer命令&#xff0c;通过appsink传递给OpenCV显示 2. Ope…

Java入门及环境变量

文章目录 1.1 Java简介1.2 JDK的下载和安装1.3 第一个程序1.4 常见问题1.5 常用DOS命令1.6 Path环境变量 1.1 Java简介 下面我们正式进入Java的学习&#xff0c;在这里&#xff0c;大家第一个关心的问题&#xff0c;应该就是 Java 是什么&#xff0c;我们一起来看一下&#xf…

ktutil编写生成keytab文件的脚本、通过keytab文件认证用户

文章目录 1. 生成keytab文件脚本2. 通过keytab文件认证3. 查看认证的用户4. 失效认证的用户 1. 生成keytab文件脚本 生成keytab文件的脚本 vim generate_kb.sh #!/usr/bin/bash ktutil <<EOF add_entry -password -p $1 -k 1 -e arcfour-hmac $2 write_kt $3 EOF示例&am…

C语言系列-带有副作用的宏参数#和##命名约定宏替换的规则

&#x1f308;个人主页: 会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 目录 带有副作用的宏参数 宏替换的规则 宏函数的对比 #和## #运算符 ##运算符 命名约定 #undef 带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候&#xff0c;如果…

Offer必备算法07_递归_五道力扣题详解(由易到难)

目录 递归算法原理 ①力扣面试题 08.06. 汉诺塔问题 解析代码 ②力扣21. 合并两个有序链表 解析代码 ③力扣206. 反转链表 解析代码 ④力扣24. 两两交换链表中的节点 解析代码 ⑤力扣50. Pow(x, n) 解析代码 本篇完。 递归算法原理 递归算法个人经验&#xff1a;给…

PHP支持的伪协议

php.ini参数设置 在php.ini里有两个重要的参数allow_url_fopen、allow_url_include。 allow_url_fopen:默认值是ON。允许url里的封装协议访问文件&#xff1b; allow_url_include:默认值是OFF。不允许包含url里的封装协议包含文件&#xff1b; 各协议的利用条件和方法 php:/…

数据结构OJ题——top-k问题:最小的K个数(Java实现)

题目链接&#xff1a;top-k问题&#xff1a;最小的K个数 top-k问题&#xff1a;最小的K个数假 1.方法一2.方法二时间复杂度 3.方法三时间复杂度 1.方法一 各种排序算法&#xff08;由于本文主要讲有关堆的使用&#xff0c;这里不做有关排序算法解决本题的介绍。对于Top-K问题…

linux(阿里云)安装pytorch

目录 环境 安装步骤 1 检查python3和pip3是否已经安装 2 安装pytorch 3 安装完毕&#xff0c;检查pytorch版本 环境 阿里云 ubuntu 22.04 UEFI版 64位 安装步骤 1 检查python3和pip3是否已经安装 输入下面两条指令&#xff1a; python3 --version pip --version 检…

1Panel使用GMSSL+Openresty实现国密/RSA单向自适应

本文 首发于 Anyeの小站&#xff0c;转载请取得作者同意。 前言 国密算法是国家商用密码算法的简称。自2012年以来&#xff0c;国家密码管理局以《中华人民共和国密码行业标准》的方式&#xff0c;陆续公布了SM2/SM3/SM4等密码算法标准及其应用规范。其中“SM”代表“商密”&a…

ChatGPT对软件测试的影响!

ChatGPT 是一个经过预训练的 AI 语言模型&#xff0c;可以通过聊天的方式回答问题&#xff0c;或者与人闲聊。它能处理的是文本类的信息&#xff0c;输出也只能是文字。它从我们输入的信息中获取上下文&#xff0c;结合它被训练的大模型&#xff0c;进行分析总结&#xff0c;给…

【C++杂货铺】string详解

目录 1. 基本概念&#xff1a; 1.1 本质&#xff1a; 1.2 string和char*区别&#xff1a; 1.3 特点&#xff1a; 2. 构造函数(初始化) 3. 赋值操作 4. 字符串拼接 5 查找 和 替换 6. 字符串比较 7. 字符存取 8. 插入和删除 ​9. 子串获取 &#x1f308;前言&#x…

Rocky Linux网卡静态配置

一、开源系统 Rocky Linux 下载安装 1、安装教程 Rocky Linux 下载安装 二、远程工具 MobaXterm下载安装 1、安装教程 MobaXterm 下载安装 三、Rocky Linux 网卡配置 1、使用ip addr确认网卡名称&#xff08;此处可得知网卡为ens160&#xff09; [rootlocalhost ~]# ip a 1:…

23款奔驰GLE350升级小柏林音响 安装效果分享

小柏林之声音响是13个喇叭1个功放&#xff0c;功率是590W&#xff0c;对应普通音响来说&#xff0c;已经是上等了。像著名的哈曼卡顿音响&#xff0c;还是丹拿音响&#xff0c;或者是BOSE音响&#xff0c;论地位&#xff0c;论音质柏林之声也是名列前茅。星骏汇小许Xjh15863 升…

2.C语言——输入输出

1.字符输入输出函数 1.输入:getchar() 字面意思&#xff0c;接收单个字符&#xff0c;使用方法 char a; a getchar();实际上效果等同于char a; scanf("%c",&a);2.输出:putchar() 2.格式化输入输出函数 1.输入:scanf() 格式&#xff1a; scanf(“格式控制…