1、ESP32工程結(jié)構(gòu)
? ? ? ? 本文中使用的是樂(lè)鑫官方推出的ESP-IDF v5.1對(duì)ESP32S3設(shè)備開(kāi)發(fā),并非是Arduino、Micro-python等第三方工具開(kāi)發(fā)。在ESP-IDF框架中,樂(lè)鑫官方已經(jīng)將CMake 和 Ninja 編譯構(gòu)建工具集成到了ESP-IDF中。
????????ESP-IDF 即樂(lè)鑫物聯(lián)網(wǎng)開(kāi)發(fā)框架,可為在 Windows、Linux 和 macOS 系統(tǒng)平臺(tái)上開(kāi)發(fā) ESP32-S3 應(yīng)用程序提供工具鏈、API、組件和工作流程的支持。
ESP32的項(xiàng)目實(shí)例工程文件結(jié)構(gòu)
- 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的示例工程項(xiàng)目 “myProject” 包含以下組成部分:
①、頂層CMakeLists.txt 文件:這是 CMake 用于學(xué)習(xí)如何構(gòu)建項(xiàng)目的主要文件,可以在這個(gè)文件中設(shè)置項(xiàng)目全局的 CMake 變量。
②、“sdkconfig” 項(xiàng)目配置文件:執(zhí)行?idf.py?menuconfig?時(shí)會(huì)創(chuàng)建或更新此文件,文件中保存了項(xiàng)目中所有組件(包括 ESP-IDF 本身)的配置信息。?
③、可選的 “components” 目錄:包含了項(xiàng)目的部分自定義組件,并不是每個(gè)項(xiàng)目都需要這種自定義組件,但它有助于構(gòu)建可復(fù)用的代碼或者導(dǎo)入第三方(不屬于 ESP-IDF)的組件。也可以在頂層 CMakeLists.txt 中設(shè)置?EXTRA_COMPONENT_DIRS?變量以查找其他指定位置處的組件。
④、“main” 目錄:這是一個(gè)特殊的組件,它包含項(xiàng)目本身的源代碼?!眒ain” 是默認(rèn)名稱,CMake 變量?COMPONENT_DIRS?默認(rèn)包含此組件,但也可以修改此變量。如果項(xiàng)目中源文件較多,建議將其歸于組件中,而不是全部放在 “main” 中。
⑤、“build” 目錄:存放構(gòu)建輸出的地方,如果沒(méi)有此目錄,idf.py?會(huì)自動(dòng)創(chuàng)建。CMake 會(huì)配置項(xiàng)目,并在此目錄下生成臨時(shí)的構(gòu)建文件。
每個(gè)組件目錄都包含一個(gè)?CMakeLists.txt?文件,里面會(huì)定義一些變量以控制該組件的構(gòu)建過(guò)程,以及其與整個(gè)項(xiàng)目的集成。
每個(gè)組件還可以包含一個(gè)?Kconfig?文件,它用于定義?menuconfig?時(shí)展示的?組件配置?選項(xiàng)。某些組件可能還會(huì)包含?Kconfig.projbuild?和?project_include.cmake?特殊文件,它們用于?覆蓋項(xiàng)目的部分設(shè)置。
2、CMake基礎(chǔ)
????????CMake是一個(gè)開(kāi)源的、跨平臺(tái)的安裝(編譯)工具,用于控制軟件編譯過(guò)程,并生成可在所選編譯器環(huán)境中使用的項(xiàng)目文件。它使用平臺(tái)無(wú)關(guān)的配置文件(通常是CMakeLists.txt文件),并可以輸出各種makefile或project文件。
????????因樂(lè)鑫官方的ESP-IDF高度集成CMake工具,因此需要使用ESP-IDF去開(kāi)發(fā)ESP32設(shè)備,必須要掌握CMake基礎(chǔ),以實(shí)現(xiàn)對(duì)ESP32工程項(xiàng)目自由的擴(kuò)展操作。如項(xiàng)目工程中添加、減少模塊代碼,加入第三方的SDK庫(kù)等,都是通過(guò)CMake工具來(lái)實(shí)現(xiàn)的。? ? ? ??
????????對(duì)于CMake的使用,在樂(lè)鑫官網(wǎng)的ESP32開(kāi)發(fā)指南中,有較為詳細(xì)的教程,但樂(lè)鑫官方的CMake教程過(guò)于繁瑣,不利于初學(xué)者理解,且容易迷失方向、抓不住核心知識(shí)。因此本文對(duì)一些在ESP32開(kāi)發(fā)中常用的CMake知識(shí)進(jìn)行簡(jiǎn)單的整理。
構(gòu)建系統(tǒng) - ESP32-S3 - — ESP-IDF 編程指南 v5.1.2 文檔 (espressif.com)https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1.2/esp32s3/api-guides/build-system.html樂(lè)鑫ESP32對(duì)CMake講解的部分文檔
????????在CMake管理的項(xiàng)目工程中,時(shí)常都能看到CMakeLists.txt這個(gè)文件的影子,這是一個(gè)用于描述 CMake 構(gòu)建過(guò)程和項(xiàng)目配置的文件。這個(gè)文件包含了一系列 CMake 命令、變量設(shè)置和流程控制結(jié)構(gòu),用于告訴 CMake 如何生成適合特定平臺(tái)和編譯器的構(gòu)建系統(tǒng)文件。
CMakeLists.txt 文件通常包含以下幾個(gè)部分:
1、項(xiàng)目設(shè)置:這里指定了項(xiàng)目的名稱、版本、編程語(yǔ)言版本等信息。
2、編譯選項(xiàng):配置編譯類(lèi)型(如 Debug 或 Release)、編譯器選項(xiàng)、警告等級(jí)等。
3、源文件:指定項(xiàng)目中的源文件,可以包括多個(gè)目錄和文件。
4、頭文件目錄:添加頭文件的搜索路徑。
5、庫(kù)文件:鏈接外部庫(kù)文件,包括靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)。
6、編譯目標(biāo):定義編譯目標(biāo),如可執(zhí)行文件、靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)。
7、測(cè)試:編寫(xiě)和執(zhí)行測(cè)試程序,以確保項(xiàng)目的正確性。
8、安裝和打包:指定如何安裝和打包項(xiàng)目。
CMakeLists.txt 文件的結(jié)構(gòu)和命令可以根據(jù)項(xiàng)目的具體需求進(jìn)行調(diào)整。通過(guò)編輯這個(gè)文件,可以靈活地配置項(xiàng)目的構(gòu)建過(guò)程,以適應(yīng)不同的平臺(tái)和編譯器。
最小的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 文件的第一行,它會(huì)告訴 CMake 構(gòu)建該項(xiàng)目所需要的最小版本號(hào)。ESP-IDF 支持 CMake 3.16 或更高的版本。
include($ENV{IDF_PATH}/tools/cmake/project.cmake):會(huì)導(dǎo)入 CMake 的其余功能來(lái)完成配置項(xiàng)目、檢索組件等任務(wù)。
project(myProject):會(huì)創(chuàng)建項(xiàng)目本身,并指定項(xiàng)目名稱。該名稱會(huì)作為最終輸出的二進(jìn)制文件的名字,即?myProject.elf?和?myProject.bin。每個(gè) CMakeLists 文件只能定義一個(gè)項(xiàng)目。
最小組件的 CMakeLists.txt 文件:此文件存在于頂層CMakeLists.txt文件下的components或自定義的組件內(nèi)。
最小組件 CMakeLists.txt 文件通過(guò)使用 idf_component_register 將組件添加到構(gòu)建系統(tǒng)中。
idf_component_register(SRCS “car.c” “engine.c”
INCLUDE_DIRS “include” REQUIRES mbedtls)
SRCS: 是源文件列表(*.c、*.cpp、*.cc、*.S),里面所有的源文件都將會(huì)編譯進(jìn)組件庫(kù)中。
INCLUDE_DIRS: 是目錄列表,里面的路徑會(huì)被添加到所有需要該組件的組件(包括 main 組件)全局 include 搜索路徑中。
REQUIRES: 實(shí)際上并不是必需的,但通常需要它來(lái)聲明該組件需要使用哪些其它組件,也就是當(dāng)前組件有對(duì)其它組件存在依賴時(shí),用于聲明該依賴,防止報(bào)錯(cuò)。
上述命令會(huì)構(gòu)建生成與組件同名的庫(kù),并最終被鏈接到應(yīng)用程序中。
3、ESP32常見(jiàn)的CMake函數(shù)
cmake_minimum_required( )
include( )
project( )?
idf_component_register( )
除了之前在上面講解的這幾個(gè)CMake函數(shù)外,在ESP32中常用的CMake函數(shù)(命令)還有:
①、set、unset :?用于設(shè)置變量的值、用于清空變量的值。
set(<variable> <value>... [PARENT_SCOPE])
variable:要被賦值的變量
value:要賦給變量的值
set(data? "Hello, World!")? ? ? ? #設(shè)置變量data的值為"Hello World!"unset(<variable>... [PARENT_SCOPE])
variable:要被清空的變量
unset(data)? ? ? ? #清空變量data的值set 、unset的值可以為:
????????一般變量(Normal Variable)
????????緩存變量(Cache Variable)
????????環(huán)境變量(Environment Variable)
②、message :為用戶顯示一條消息。
message( [STATUS | WARNING | AUTHOR_WARNING | FATAL_ERROR | SEND_ERROR] "message to display" ...)
可以用下述可選的關(guān)鍵字指定消息的類(lèi)型:
?(無(wú)) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 但會(huì)繼續(xù)執(zhí)行;
AUTHOR_WARNING = CMake 警告 (dev), 會(huì)繼續(xù)執(zhí)行;
SEND_ERROR = CMake 錯(cuò)誤, 繼續(xù)執(zhí)行,但是會(huì)跳過(guò)生成的步驟;
FATAL_ERROR = CMake 錯(cuò)誤, 終止所有處理過(guò)程;set(AUTHOR, "牛馬大師兄")
message(STATUS " Author :?${AUTHOR}.")
③、file :用于執(zhí)行各種文件操作的。
file的功能十分豐富,它支持多種操作,包括但不限于讀取文件、寫(xiě)入文件、追加到文件、計(jì)算文件的散列值等。
寫(xiě)入文件:file(WRITE <filename> "message to write"...)
追加到文件:file(APPEND <filename> "message to append"...)
讀取文件:file(READ <filename> <variable> [LIMIT <numBytes>] [OFFSET <offset>] [HEX])
④、include_directories :用于向構(gòu)建過(guò)程中添加包含目錄。
include_directories([AFTER | BEFORE] [SYSTEM] [DIR1、DIR2?...])
AFTER | BEFORE:這兩個(gè)參數(shù)是可選的,并決定新添加的目錄是追加到(默認(rèn))還是插入到現(xiàn)有的包含目錄列表的開(kāi)頭。默認(rèn)情況下,
include_directories
將目錄添加到列表的末尾。SYSTEM:這個(gè)可選參數(shù)用于標(biāo)記目錄為系統(tǒng)目錄。
DIR1、DIR2?...:這些是要添加的頭文件搜索路徑。
include_directories命令將指定的目錄添加到當(dāng)前
CMakeLists.txt
文件的INCLUDE_DIRECTORIES
目錄屬性中,并且也添加到當(dāng)前CMakeLists.txt
文件中每個(gè)目標(biāo)的INCLUDE_DIRECTORIES
目標(biāo)屬性中。這意味著這些目錄將被用于搜索頭文件,無(wú)論是在編譯源代碼時(shí),還是在鏈接庫(kù)文件時(shí)。include_directories(/usr/include/hello)
⑤、add_executable :用于指定一個(gè)可執(zhí)行文件目標(biāo)的命令。
add_executable(targetName [source1] [source2] ...)
targetName :這是想要生成的可執(zhí)行文件的名稱,通常是不帶文件擴(kuò)展名的名稱。
[source1] [source2] ... :想要編譯成可執(zhí)行文件的源文件列表。可以指定多個(gè)源文件,它們之間用空格分隔。
add_executable 命令會(huì)創(chuàng)建一個(gè)構(gòu)建目標(biāo),這個(gè)目標(biāo)代表了最終的可執(zhí)行文件。當(dāng)運(yùn)行構(gòu)建系統(tǒng)(例如,通過(guò)執(zhí)行?
make
或?ninja
?命令)時(shí),這個(gè)目標(biāo)會(huì)被構(gòu)建。add_executable(my_program? main.cpp)
⑥、add_library :用于創(chuàng)建一個(gè)庫(kù)目標(biāo)的命令。
add_library 告訴 CMake 你想要從哪些源文件構(gòu)建一個(gè)庫(kù),并給這個(gè)庫(kù)指定一個(gè)名稱。這個(gè)庫(kù)可以是靜態(tài)庫(kù)(.a
?或?.lib
?文件)、共享庫(kù)(.so
、.dylib
?或?.dll
?文件)或模塊。
add_library(targetName [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
targetName:庫(kù)的邏輯名稱,不帶文件擴(kuò)展名。[STATIC | SHARED | MODULE]:這個(gè)可選參數(shù)用于指定庫(kù)的類(lèi)型。
? ? ? ? ? ? ? ?STATIC? ? ---創(chuàng)建靜態(tài)庫(kù)
? ? ? ? ? ? ? ?SHARED ---創(chuàng)建共享庫(kù)
? ? ? ? ? ? ? ?MODULE ---創(chuàng)建可以被動(dòng)態(tài)加載的庫(kù)
默認(rèn)為?STATIC? ?
[EXCLUDE_FROM_ALL]:?可選參數(shù),如果指定了,那么這個(gè)庫(kù)就不會(huì)被默認(rèn)構(gòu)建。
source1 [source2 ...]:想要編譯成庫(kù)的源文件列表,可以指定多個(gè)源文件,它們之間用空格分隔
add_library(mylib? STATIC? mylib.cpp)
add_library(mylib SHARED mylib.cpp)
對(duì)于靜態(tài)庫(kù),CMake 會(huì)自動(dòng)添加?.a
(在 Unix 上)或?.lib
(在 Windows 上)擴(kuò)展名;對(duì)于共享庫(kù),CMake 會(huì)自動(dòng)添加適當(dāng)?shù)钠脚_(tái)相關(guān)擴(kuò)展名。
⑦、target_link_libraries:用于指定目標(biāo)(比如可執(zhí)行文件或庫(kù))應(yīng)該鏈接哪些庫(kù)。
target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> lib1 [lib2 ...])
target
:這是你想要鏈接庫(kù)的目標(biāo),可以是一個(gè)可執(zhí)行文件或庫(kù)。
PRIVATE|PUBLIC|INTERFACE
:這些關(guān)鍵字用于指定庫(kù)鏈接的范圍和傳遞性。
? ?PRIVATE
:庫(kù)僅對(duì)目標(biāo)私有,不會(huì)傳遞給其他目標(biāo)。? ? ? ? ?
PUBLIC
:庫(kù)對(duì)目標(biāo)是公共的,并且還會(huì)傳遞給依賴該目標(biāo)的其他目標(biāo)。
? ?INTERFACE
:庫(kù)僅對(duì)其他目標(biāo)可見(jiàn),但對(duì)當(dāng)前目標(biāo)不可見(jiàn)。
lib1 [lib2 ...
:這是你想要鏈接的庫(kù)列表。add_executable(my_program? main.cpp)
add_library(my_library? my_library.cpp)
target_link_libraries(my_program? my_library)
在這個(gè)例子中,
my_program
?可執(zhí)行文件會(huì)被鏈接到?my_library
?庫(kù)。對(duì)于外部SDK庫(kù),需要提供庫(kù)的完整路徑(如果庫(kù)不在標(biāo)準(zhǔn)庫(kù)路徑中)
target_link_libraries(my_program? /path/to/external/libfoo.a)
4、ESP32鏈接第三方SDK庫(kù)
????????在項(xiàng)目開(kāi)發(fā)中,大多情況為團(tuán)隊(duì)內(nèi)部合作或者跨公司進(jìn)行合作,為了保證代碼的安全及項(xiàng)目的正常進(jìn)展,往往會(huì)將負(fù)責(zé)的部分代碼編譯成一個(gè)SDK庫(kù)文件,可以是靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)文件,以庫(kù)和開(kāi)發(fā)手冊(cè)的方式交付程序代碼。因此ESP32開(kāi)發(fā)中,非常有必要掌握鏈接第三方SDK庫(kù)到項(xiàng)目工程中。
????????在頂層的CMakeLists.txt文件中加入以下代碼,引入鏈接第三方庫(kù)。
#全路徑引入庫(kù)
#link_libraries 表示將具體的庫(kù)文件引入到當(dāng)前工程中,所填入的路徑必須是全路徑。
方法一:直接填入全部的路徑,可移植性較差,移動(dòng)文件位置或修改文件夾名字后,需要重新修改
#link_libraries("/home/tony/Desktop/gm_algorithm/lib/gm/libsm_esp32c3.a")
方法二:使用Cmake變量獲取當(dāng)前文件所在路徑,填充到文件中
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/lib/gm/libsm_esp32c3.a)
不能使用相對(duì)路徑
#link_libraries(./lib/gm/libsm_esp32c3.a) #錯(cuò)誤示例
使用message打印CMAKE_CURRENT_SOURCE_DIR所指的路徑值
message(STATUS "The CMAKE_CURRENT_SOURCE_DIR is: ${CMAKE_CURRENT_SOURCE_DIR}")
鏈接SDK庫(kù)測(cè)試工程的頂層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庫(kù)頭文件所在的路徑
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/gm)
#鏈接第三方SDK靜態(tài)庫(kù)文件
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/lib/gm/libsm_esp32c3.a)
project(gm)
提醒:link_libraries( ) 函數(shù)中填入的庫(kù)路徑必須是絕對(duì)路徑,采用相對(duì)路徑會(huì)報(bào)錯(cuò)。
①、手動(dòng)填入絕對(duì)路徑
????????采用這種方法移植性較差,一但更改了文件路徑或工程文件名,編譯必定會(huì)報(bào)錯(cuò),需要手動(dòng)去修改CMakeLists.txt文件中的鏈接庫(kù)文件路徑,因此不推薦采用此方法,但可以學(xué)習(xí)了解一下。
②、自動(dòng)獲取補(bǔ)全庫(kù)的絕對(duì)路徑
? ? ? ? 建議使用CMake設(shè)置的宏變量去實(shí)現(xiàn)路徑的填寫(xiě),這樣可移植性較好,可以減少開(kāi)發(fā)過(guò)程的工作量。
③、第三方的SDK包、鏈接庫(kù)成功,編譯順利通過(guò)
④、相對(duì)路徑報(bào)錯(cuò),SDK包鏈接不通過(guò)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-828310.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-828310.html
到了這里,關(guān)于ESP32工程中CMake使用及加入第三方SDK庫(kù)文件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!