概述:
一個 ESP-IDF 項目可以看作是多個不同組件的集合,ESP-IDF 可以顯式地指定和配置每個組件。在構建項目的時候,構建系統會前往 ESP-IDF 目錄、項目目錄和用戶自定義目錄(可選)中查找所有組件,允許用戶通過文本菜單系統配置 ESP-IDF 項目中用到的每個組件。在所有組件配置結束后,構建系統開始編譯整個項目。
概念:
項目: 特指一個目錄,其中包含了構建可執行應用程序所需的全部文件和配置,以及其他支持型文件,例如分區表、數據/文件系統分區和引導程序。
項目配置:保存在項目根目錄下名為 sdkconfig 的文件中,可以通過 idf.py menuconfig 進行修改,且一個項目只能包含一個項目配置。
應用程序:是由 ESP-IDF 構建得到的可執行文件。一個項目通常會構建兩個應用程序:項目應用程序(可執行的主文件,即用戶自定義的固件)和引導程序(啟動並初始化項目應用程序)。
組件: 是模塊化且獨立的代碼,會被編譯成靜態庫(.a 文件)並鏈接到應用程序。部分組件由 ESP-IDF 官方提供,其他組件則來源於其它開源項目。
目標: 特指運行構建后應用程序的硬件設備。ESP-IDF 當前僅支持 ESP32 這一個硬件目標。
示例項目
1 - myProject/ 2 - Makefile //設置了 PROJECT_NAME 變量,還可以定義作用於整個項目的其它 make 變量(可選)。 3 - sdkconfig //配置文件 4 - components/ //可選組件目錄 5 - component1/ 6 - component.mk //組件的makefile文件 7 - Kconfig 8 - src1.c 9 - component2/ 10 - component.mk 11 - Kconfig 12 - src1.c 13 - include/ - component2.h 14 - main/ //特殊組件,包含項目源碼。 15 - src1.c 16 - src2.c 17 - component.mk 18 - build/ //編譯輸出目錄
組件目錄中會包含組件自己的 Makefile 文件 component.mk ,里面會定義一些變量來控制該組件的構建過程,以及它與整個項目的集成。
項目 Makefiles
每個項目都有一個 Makefile ,它包含整個項目的構建設置。默認情況下,項目 Makefile 可以非常小。
PROJECT_NAME := myProject //項目名稱 include $(IDF_PATH)/make/project.mk // 頂層項目目錄,默認是包含 Makefile 文件的目錄,許多其他的項目變量都基於此變量。
以下這些可選變量都有默認值,用戶可以重寫這些變量以自定義構建行為。
- BUILD_DIR_BASE: 所有對象、庫、二進制文件的輸出目錄,默認為 $(PROJECT_PATH)/build。
- COMPONENT_DIRS: 組件的搜索目錄,默認為 $(IDF_PATH)/components,$(PROJECT_PATH)/components,$(PROJECT_PATH)/main 和 EXTRA_COMPONENT_DIRS 。
- EXTRA_COMPONENT_DIRS: 組件額外的搜索路徑,可選。
- COMPONENTS: 要構建進項目中的組件列表,默認為 COMPONENT_DIRS 指定目錄中所有的組件。
- EXCLUDE_COMPONENTS: 在構建的過程中需要剔除的組件列表,可選。請注意這只會減少構建的時間,並不會減少最終二進制文件的大小。
組件Makefiles
每個項目都包含一個或者多個組件,這些組件可以是 ESP-IDF 的一部分,也可以從其他組件目錄添加。組件是包含 component.mk 文件的任何目錄。
搜索 COMPONENT_DIRS 中指定的目錄以查找項目會使用的組件,目錄可以是組件本身(即他們包含 component.mk 文件),也可以是包含組件的上層目錄。
ESP-IDF 搜索組件時,會按照 COMPONENT_DIRS 指定的順序依次進行,這意味着在默認情況下,首先是 ESP-IDF 組件,然后是項目組件,最后是 EXTRA_COMPONENT_DIRS 中的組件。如果這些目錄中的兩個或者多個包含具有相同名字的組件,則使用搜索到的最后一個位置的組件。這就允許將組件復制到項目目錄中再修改來覆蓋 ESP-IDF 組件。
最簡單的 component.mk 文件可以是一個空文件,如果文件為空,則組件的默認構建行為會被設置為:
- makefile 所在目錄中的所有源文件(*.c,*.cpp,*.cc,*.S)將會被編譯進組件庫中。
- 子目錄 include 將被添加到其他組件的全局頭文件搜索路徑中。
- 組件庫將會被鏈接到項目的應用程序中。
空的 component.mk 文件同沒有 component.mk 文件之間存在本質差異,前者會調用默認的組件構建行為,后者不會發生默認的組件構建行為。
組件變量:
- COMPONENT_PATH: 組件的目錄,即包含 component.mk 文件的絕對路徑
- COMPONENT_NAME: 組件的名字,默認為組件目錄的名稱。
- COMPONENT_BUILD_DIR: 組件的構建目錄,即存放組件構建輸出的絕對路徑,它是 $(BUILD_DIR_BASE) 的子目錄。
- COMPONENT_LIBRARY: 組件構建后的靜態庫文件(相對於組件的構建目錄)的名字,默認為 $(COMPONENT_NAME).a。
- COMPONENT_ADD_INCLUDEDIRS: 相對於組件目錄的路徑,將被添加到項目中所有組件的頭文件搜索路徑中。
- COMPONENT_ADD_LDFLAGS: 添加鏈接參數到全局 LDFLAGS 中用以指導鏈接最終的可執行文件,默認為 -l$(COMPONENT_NAME)。
- COMPONENT_DEPENDS: 需要在當前組件之前構建的組件列表,這對於處理鏈接時的依賴不是必需的,因為所有組件的頭文件目錄始終可用。
- COMPONENT_ADD_LINKER_DEPS: 保存一些文件的路徑,當這些文件發生改變時,會觸發 ELF 文件重新鏈接。
- COMPONENT_SUBMODULES: 組件使用的 git 子模塊的路徑列表(相對於 COMPONENT_PATH)。這些路徑會在構建的過程中被檢查(並在必要的時候初始化)。
- COMPONENT_PRIV_INCLUDEDIRS: 相對於組件目錄的目錄路徑,該目錄僅會被添加到該組件源文件的頭文件搜索路徑中。
- COMPONENT_EXTRA_INCLUDES: 編譯組件的源文件時需要指定的額外的頭文件搜索路徑,這些路徑將以 -l 為前綴傳遞給編譯器。
- COMPONENT_SRCDIRS: 相對於組件目錄的目錄路徑,這些路徑用於搜索源文件(*.cpp,*.c,*.S),默認為 .,即組件目錄本身。
- COMPONENT_OBJS: 要編譯生成的目標文件,默認是 COMPONENT_SRCDIRS 中每個源文件的 .o 文件。
- COMPONENT_EXTRA_CLEAN: 相對於組件構建目錄的路徑,指向 component.mk 文件中自定義 make 規則生成的任何文件,它們也是 make clean 命令需要刪除的文件。
- COMPONENT_OWNBUILDTARGET & COMPONENT_OWNCLEANTARGET: 這些目標允許您完全覆蓋組件的默認編譯行為。
- COMPONENT_CONFIG_ONLY: 如果設置了此標志,則表示組件根本不會產生構建輸出(即不會構建得到 COMPONENT_LIBRARY),並且會忽略大多數其它組件變量。
- CFLAGS: 傳遞給 C 編譯器的標志。根據項目設置已經定義一組默認的 CFLAGS,可以通過 CFLAGS += 來為組件添加特定的標志,也可以完全重寫該變量(盡管不推薦這么做)。
- CPPFLAGS: 傳遞給 C 預處理器的標志(用於 .c,.cpp 和 .S 文件)。
- CXXFLAGS: 傳遞給 C++ 編譯器的標志。
配置組件
每個組件都可以包含一個 Kconfig 文件,和 component.mk 放在同一個目錄下。Kconfig 中包含此組件在 make menuconfig 時要展示的配置規則的設置。運行 menuconfig 時,可以在 Component Settings 菜單欄下找到這些設置。
參考:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-guides/build-system-legacy.html