ESP32构建系统 (传统 GNU Make)
概述:
一个 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