ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RIOT 操作系统 Kconfig 编译期配置系统完全指南:从 menuconfig 到构建系统集成

RIOT 操作系统 Kconfig 编译期配置系统完全指南:从 menuconfig 到构建系统集成 RIOT 操作系统 Kconfig 编译期配置系统完全指南从 menuconfig 到构建系统集成【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOTRIOT 是面向物联网IoT的开源实时操作系统其内核与驱动均以 C 模块化组织。为了让用户在编译期以统一、可校验的方式配置这些软件模块RIOT 引入了 Linux 内核同源的 Kconfig 配置系统。本文以官方文档 doc/guides/build-system/kconfig.md 为主线结合 makefiles/kconfig.mk、根 Kconfig 以及sys/net/sock/Kconfig、tests/build_system/kconfig等仓库源码系统讲解 Kconfig 的设计目标、四种配置手段、构建期五步集成流程以及 CPU / Board 的 Kconfig 建模规范。读完本文你将能够在自己的 RIOT 应用中熟练使用 menuconfig、.config文件与环境变量完成编译期配置并理解autoconf.h生成与符号合并的底层机制。上图是 RIOT 应用目录下运行make menuconfig后出现的典型界面顶部为RIOT Kernel Configuration可通过(Top) → System Modules → Networking逐级导航勾选如[*] Configure Gcoap这样的模块级开关后再展开其子选项进行细化配置。一、Kconfig 在 RIOT 中的定位与设计目标RIOT 引入 Kconfig 的核心目标是在编译期配置软件模块并为此提供一套标准化的流程覆盖以下四个方面暴露Exposure模块通过各自的 Kconfig 文件对外暴露可配置参数分配Assignment应用与用户把自定义配置值写入.config文件或通过 menuconfig 等界面赋值验证Verification系统校验参数取值是否合法、参数之间的依赖关系是否成立应用Application构建系统把最终选定的配置生成到autoconf.h头文件中供编译使用。1. 暴露Kconfig 文件即参数数据库模块通过 Kconfig 文件描述其可配置参数。Kconfig 文件采用 Kconfig 语言Linux 内核定义编写可以表达参数的类型、提示文本、默认值、取值范围以及依赖关系。Kconfig 文件在仓库中的目录结构与模块分布一一对应随着迁移推进所有模块最终都将提供自己的 Kconfig 文件。例如文档中提到的sock_util模块在当前的仓库中对应 sys/net/sock/Kconfig其内容为menu SOCK utility functions depends on USEMODULE_SOCK_UTIL config SOCK_SCHEME_MAXLEN int Maximum length of the scheme part default 16 help This value is used in sock_urlsplit(). config SOCK_HOSTPORT_MAXLEN int Maximum length of host:port part default 64 help This value is used in sock_urlsplit(). config SOCK_URLPATH_MAXLEN int Maximum path length default 64 help This value is used in sock_urlsplit(). endmenu # SOCK utility functions这段源码清晰地示范了 Kconfig 文件的三个关键要素menu ... endmenu把相关参数组织成一个菜单分组depends on USEMODULE_SOCK_UTIL声明依赖——只有构建中确实使用了sock_util模块即USEMODULE中包含它这一组配置项才对用户可见详见附录 Aint类型 default默认值 help说明共同构成参数的完整定义。2. 分配.config文件与用户配置用户可以通过手写.config文件或使用 menuconfig 界面为暴露出的参数赋值。没有赋值的参数将采用 Kconfig 中声明的默认值。.config文件与 Kconfig 文件的本质区别参见附录 B。3. 验证与应用生成autoconf.h构建系统根据.config文件与 Kconfig 文件对参数值进行校验包括取值范围与依赖关系检查随后生成autoconf.h头文件。该头文件以CONFIG_前缀宏的形式承载全部最终配置例如CONFIG_SOCK_SCHEME_MAXLEN。此后所有源码中的CONFIG_*引用都会由该头文件提供定义。二、用户配置实战四种配置途径1. 使用 menuconfig 图形界面在应用目录下执行make menuconfigmenuconfig 会基于当前应用实际使用的模块列出该平台全部可配置参数。默认情况下某个模块的 Kconfig 配置是未启用的需要在菜单中选中对应的模块级开关如[*] Configure Gcoap才会展开并允许配置其内部选项。完成配置后选择Save保存到默认路径并退出。之后执行make all编译时该配置即被应用。如果希望配置在make clean之后依然保留可在 menuconfig 的Save选项中将当前配置另存到应用目录下的user.config文件。这样无论应用目录如何清理user.config都会作为持久化的用户配置被重新合并。2. 手写.config文件第二种方式是不进入图形界面直接在应用目录下手写.config文件。构建系统在生成最终头文件时会合并两个固定来源的配置app.config放置于应用目录用于设定该应用自身的默认配置值user.config放置于应用目录用于覆盖app.config中的值。此外还可以通过 Makefile 变量KCONFIG_ADD_CONFIG追加更多的.config文件。这些追加文件会在默认 CPU/板级配置、app.config、user.config之后被合并因此拥有最高优先级。文档给出的user.config示例配置sock_util模块的 scheme 部分最大长度# activate configuration of sock_util using Kconfig CONFIG_KCONFIG_MODULE_SOCK_UTILy # change scheme part length CONFIG_SOCK_UTIL_SCHEME_MAXLEN24注意上述符号名取自文档编写时的模块命名。在当前仓库中该参数已演变为 sys/net/sock/Kconfig 中的CONFIG_KCONFIG_MODULE_SOCK_UTIL模块级开关与CONFIG_SOCK_SCHEME_MAXLEN默认值 16。配置同一功能的现代写法为CONFIG_KCONFIG_MODULE_SOCK_UTILy CONFIG_SOCK_SCHEME_MAXLEN24使用这种方式无需运行 menuconfig直接在应用目录执行make all即可完成配置的读取与应用。若出现依赖问题例如某个模块的 Kconfig 配置开关未打开构建系统会输出警告信息。3. 应用级 Kconfig暴露应用自己的配置应用同样可以在自己的目录下放置Kconfig文件以暴露应用专属的配置项。仓库中的 tests/build_system/kconfig/Kconfig 是一个完整示例menu Application menuconfig KCONFIG_APP_MSG_1 bool Configure message 1 default y help This will enable configuring the first message via Kconfig if KCONFIG_APP_MSG_1 config APP_MSG_1_TEXT string Message 1 text default Message 1 defined in Kconfig file endif # KCONFIG_APP_MSG_1 config APP_MSG_2 bool Message 2 help Activate printing the second message endmenu # Application对应的 app.config 演示了应用默认值的写法# enable configuring message 1 via kconfig CONFIG_KCONFIG_APP_MSG_1y # change message 1 text CONFIG_APP_MSG_1_TEXTMessage 1 defined in app.config file # enable printing message 2 CONFIG_APP_MSG_2y # enable configuration of external packages via kconfig CONFIG_KCONFIG_EXTERNAL_PKG_1y CONFIG_KCONFIG_EXTERNAL_PKG_2y而 main.c 展示了应用代码如何消费这些配置宏puts(CONFIG_APP_MSG_1_TEXT); if (IS_ACTIVE(CONFIG_APP_MSG_2)) { puts(MSG_2 is active); }其中IS_ACTIVE()宏来自kernel_defines.h专门用于在 C 条件编译中判断bool类型配置宏是否为真详见附录 D。该测试还通过USEMODULE/USEPKG引入外部模块与外部包并在EXTERNAL_MODULE_DIRS/EXTERNAL_PKG_DIRS中声明其目录见 Makefile用于验证外部模块/包的 Kconfig 集成。4. 通过环境变量配置调试专用为方便调试配置或快速把新模块编译进现有应用RIOT 还支持以RIOT_CONFIG_前缀的环境变量注入配置。实现文档中同样的效果可以写成RIOT_CONFIG_KCONFIG_MODULE_SOCK_UTIL1 \ RIOT_CONFIG_SOCK_UTIL_SCHEME_MAXLEN24 \ make环境变量方式与.config文件走完全相同的校验流程。但请注意这种方式仅面向开发调试生产环境请务必通过.config文件配置。环境变量的底层实现在 makefiles/kconfig.mk 中构建系统把所有RIOT_CONFIG_前缀的环境变量转换为键值对写入$(GENERATED_DIR)/env.config并作为MERGE_SOURCES的最后一个来源参与合并从而保证其优先级最高KCONFIG_ENV_CONFIG $(patsubst RIOT_%,%,$(foreach v,$(filter RIOT_CONFIG_%,$(.VARIABLES)),$(v)$($(v)))) $(KCONFIG_GENERATED_ENV_CONFIG): FORCE | $(GENERATED_DIR) $(Q)printf %s\n $(KCONFIG_ENV_CONFIG) \ | $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $同时env.config也被纳入构建依赖环境变量一旦变化就会强制重新运行配置生成genconfig避免陈旧配置被误用。5. 关于 CFLAGS 的注意事项当一个模块正在通过 Kconfig 进行配置时其配置宏将不再允许通过 CFLAGS 覆盖例如在编译命令行或 Makefile 中传入-DCONFIG_XXX...。如果在编译时看到 redefined warning通常就是因为同一宏同时被 Kconfig 和 CFLAGS 定义——请检查是否重复配置。三、构建系统集成五步配置流水线Kconfig 与构建系统的集成主要实现在 makefiles/kconfig.mk 中。官方文档 kconfig_integration.svg 描绘了完整流程可概括为以下五个阶段。第 0 步模块依赖解析构建系统首先解析模块依赖把所有将参与编译的模块与包分别汇总到USEMODULE与USEPKGMakefile 变量中。输入各 Makefile如 Makefile.dep。输出USEMODULE、USEPKG变量。第 1 步模块列表生成Kconfig.dep把USEMODULE/USEPKG中的每个模块翻译成一个 Kconfig 符号写入$(GENERATED_DIR)/Kconfig.dep。符号命名规则见附录 A。在 makefiles/kconfig.mk 中这一步由如下规则实现对每个USEMODULE_MOD/USEPKG_PKG生成config 符号、bool、default y三段声明并把连字符-替换为下划线、转为大写$(KCONFIG_GENERATED_DEPENDENCIES): FORCE | $(GENERATED_DIR) $(Q)printf %s $(USEMODULE_W_PREFIX) $(USEPKG_W_PREFIX) \ | awk BEGIN {RS }{ gsub(-, _, $$0); \ printf config %s\n\tbool\n\tdefault y\n, toupper($$0)} \ | $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $输入USEMODULE、USEPKG。输出$(GENERATED_DIR)/Kconfig.dep。第 2 步合并所有配置来源out.config本步把来自多个来源的配置值合并为一份临时的out.config。合并顺序至关重要后合并的文件优先级更高即最后一个赋值的参数胜出。若没有任何配置文件则全部采用默认值。在 makefiles/kconfig.mk 中合并来源的定义为MERGE_SOURCES $(KCONFIG_CPU_CONFIG) MERGE_SOURCES $(KCONFIG_BOARD_CONFIG) MERGE_SOURCES $(KCONFIG_ADD_CONFIG) MERGE_SOURCES $(wildcard $(KCONFIG_APP_CONFIG)) MERGE_SOURCES $(wildcard $(KCONFIG_USER_CONFIG)) MERGE_SOURCES $(KCONFIG_GENERATED_ENV_CONFIG)其中KCONFIG_APP_CONFIG $(APPDIR)/app.config、KCONFIG_USER_CONFIG $(APPDIR)/user.config各来源按CPU/板级默认 → 追加配置 → 应用默认 → 用户配置 → 环境变量的优先级依次生效。合并动作由genconfig脚本完成$(KCONFIG_OUT_CONFIG): $(GENERATED_DEPENDENCIES_DEP) $(GENCONFIG) $(MERGE_SOURCES) $(GENERATED_DIR_DEP) $(Q) $(GENCONFIG) \ --config-out$(KCONFIG_OUT_CONFIG) \ --file-list $(KCONFIG_OUT_DEP) \ --kconfig-filename $(KCONFIG) $(if $(Q),,--debug )\ $(if $(filter 1,$(KCONFIG_IGNORE_CONFIG_ERRORS)), --ignore-config-errors) \ --config-sources $(MERGE_SOURCES) \ touch $(KCONFIG_OUT_CONFIG)本步还会生成out.config.d它以 Makefile 格式记录生成out.config时实际用到的所有 Kconfig 文件随后被构建系统-include从而在任一 Kconfig 文件被修改时自动重新触发out.config与autoconf.h的生成# Try to load the list of Kconfig files used -include $(KCONFIG_OUT_DEP)out.config是临时文件make clean时会被移除如需保存某套配置请用 menuconfig 的 Save 功能另存备份如user.config。输入可选$(APPDIR)/app.config、$(APPDIR)/user.config等。输出$(GENERATED_DIR)/out.config、$(GENERATED_DIR)/out.config.d。第 3 步menuconfig 交互可选本步使用根Kconfig文件展示系统全部可配置参数。Kconfig 会根据第 1 步生成的Kconfig.dep自动过滤掉未使用模块的参数。根 Kconfig 的加载顺序为应用Kconfig→ 板级Kconfig→ CPUKconfig→ 核心模块core、drivers、sys、pkg→ 外部模块/包mainmenu RIOT Configuration rsource kconfigs/Kconfig.consts osource $(KCONFIG_GENERATED_DEPENDENCIES) osource $(APPDIR)/Kconfig orsource $(BOARDDIR)/Kconfig orsource $(RIOTCPU)/$(CPU)/Kconfig rsource $(RIOTBOARD)/Kconfig rsource $(RIOTCPU)/Kconfig rsource core/Kconfig rsource drivers/Kconfig rsource sys/Kconfig rsource pkg/Kconfig menu External Modules osource $(KCONFIG_EXTERNAL_MODULE_CONFIGS) endmenu # External Modules menu External Packages osource $(KCONFIG_EXTERNAL_PKG_CONFIGS) endmenu # External Packagesout.config是 menuconfig 的输入之一因此应用在app.config或备份在user.config中的配置会在首次进入 menuconfig 时被加载这一交互陷阱详见附录 C。menuconfig 的目标规则为menuconfig: $(MENUCONFIG) $(KCONFIG_OUT_CONFIG) $(Q)KCONFIG_CONFIG$(KCONFIG_OUT_CONFIG) $(MENUCONFIG) $(KCONFIG) $(MAKE) $(KCONFIG_GENERATED_AUTOCONF_HEADER_C)用户在界面中完成选择并保存后out.config被更新旧版本备份为out.config.old只要out.config发生变化就会自动触发下一步autoconf.h的重新生成。输入根Kconfig可选app.config、user.config、out.config。输出更新后的out.config与备份out.config.old。第 4 步生成 autoconf.h$(GENERATED_DIR)/autoconf.h是 Kconfig 配置系统的主产物包含所有形如CONFIG_module_parameter的宏。其生成同样调用genconfig但输入改为最终的out.config$(KCONFIG_GENERATED_AUTOCONF_HEADER_C): $(KCONFIG_OUT_CONFIG) $(GENERATED_DIR_DEP) $(Q) $(GENCONFIG) \ --header-path $(KCONFIG_GENERATED_AUTOCONF_HEADER_C) \ --sync-deps $(KCONFIG_SYNC_DIR) \ --kconfig-filename $(KCONFIG) $(if $(Q),,--debug ) \ $(if $(filter 1,$(KCONFIG_IGNORE_CONFIG_ERRORS)), --ignore-config-errors) \ --config-sources $(KCONFIG_OUT_CONFIG) \ touch $(KCONFIG_GENERATED_AUTOCONF_HEADER_C)--sync-deps $(KCONFIG_SYNC_DIR)即$(GENERATED_DIR)/deps会为每个配置符号生成独立的占位头文件用于支持增量编译——只有真正用到的CONFIG_*宏发生变化时才触发对应源文件的重编译。在构建阶段autoconf.h通过-imacros被全局注入到每个编译单元见 makefiles/kconfig.mkBUILDDEPS $(KCONFIG_GENERATED_AUTOCONF_HEADER_C) $(FIXDEP) CFLAGS -imacros $(KCONFIG_GENERATED_AUTOCONF_HEADER_C)输入$(GENERATED_DIR)/out.config、根Kconfig。输出$(GENERATED_DIR)/autoconf.h可选$(GENERATED_DIR)/deps/*/*.h增量编译占位头文件。何时才运行 Kconfigmakefiles/kconfig.mk 中还有一个关键逻辑默认情况下迁移阶段只有满足下列任一条件 Kconfig 才会运行应用目录中存在任意.config文件应用目录中存在Kconfig文件本次 make 目标是menuconfig检测到先前已生成的out.config例如之前运行过 menuconfig此时即使未显式设置也会强制执行并给出提示。SHOULD_RUN_KCONFIG ? $(or $(wildcard $(APPDIR)/*.config), \ $(wildcard $(APPDIR)/Kconfig))这也解释了为何模块默认不通过 Kconfig 配置只要应用目录干净构建就完全走传统 CFLAGS 头文件默认值的路径Kconfig 不会介入。文件清单汇总下表列出 Kconfig 流水线涉及的核心文件均定义于 makefiles/kconfig.mk文件说明Kconfig定义各模块的配置选项仓库根 Kconfig 为入口。Kconfig.dep记录本次编译涉及的模块列表位于$(GENERATED_DIR)。app.config应用默认配置值位于应用目录。user.config用户自定义配置值位于应用目录。out.config合并所有来源后的最终配置其符号全集与autoconf.h一致。out.config.dout.config的依赖文件记录生成它所使用的全部 Kconfig 文件。autoconf.h承载最终配置宏的头文件随编译注入。四、在 Makefile 中访问 Kconfig 符号.config文件采用 Makefile 语法因此构建系统可以直接include它从而在 Makefile 中读取已应用的配置。这在迁移阶段尤其有用可以判断某个参数是否已由 Kconfig 接管若未接管再通过 CFLAGS 注入默认值。文档给出的示例ifndef CONFIG_USB_VID CFLAGS -DCONFIG_USB_VID0x1209 endif符号名与配置宏一致始终带CONFIG_前缀。需要留意的是.config文件是在Makefile.include中加载的通过-include $(KCONFIG_OUT_CONFIG)因此在应用自己的 Makefile 中必须在包含Makefile.include之后才能安全地读取这些符号。五、迁移阶段模块、CPU 与 Board 的 Kconfig 建模在向 Kconfig 全量迁移的过渡期RIOT 的默认行为仍是传统方式头文件暴露配置项、CFLAGS 作为输入。为此建立了一套建模约定。1. 模块的可选 Kconfig 配置每个模块的配置项应包裹在独立的menu中且该menu声明对其对应模块的依赖depends on USEMODULE_MOD用户即可按模块粒度决定是否启用 Kconfig 配置。模块的 Kconfig 启用状态通过 make 依赖建模CONFIG_KCONFIG_MODULE_MOD符号来驱动。2. CPU 层次模型CPU 的 Kconfig 建模采用四级层次从具体到抽象依次为------------ More Specific | CPU_MODEL | ------------ | | ------------ | | CPU_FAM | | ------------ | | ------------ | | CPU_CORE | | ------------ | | ------------ v | CPU_ARCH | Less Specific ------------各级含义CPU_MODEL具体 CPU 型号标识部分实现用它区分不同的内存布局CPU_FAM厂商 CPU 子系列介于 CPU 与 CPU_MODEL 之间CPU_CORECPU 内核心的标识CPU_ARCHCPU_CORE所属的体系架构标识。建模规则每一级都需要声明一个隐藏的 bool 符号符号名 前缀 具体取值例如 samd21 系列符号为CPU_FAM_SAMD21同时为对应通用符号CPU_MODEL、CPU_FAM、CPU_CORE、CPU_ARCH提供受该 bool 符号守护的默认值。特性features通常由任意层次的符号提供一般由更具体的符号select更抽象的符号。部分厂商还允许中间分组层如 STM32 的CPU_LINE_xxx也可用CPU_COMMON_前缀符号避免重复。此外还需为CPU符号赋默认值使其与构建系统的CPUMakefile 变量一致。符号声明应放在对应层次的目录的Kconfig文件中由包含最具体符号的文件source较抽象的符号只有/cpu/CPU/Kconfig会被根Kconfig包含。文档给出的samd21/samr21示例在仓库 cpu/samd21/Kconfig 中有近乎一致的实现config CPU_COMMON_SAMD21 bool select CPU_COMMON_SAM0 select CPU_CORE_CORTEX_M0PLUS config CPU_FAM_SAMD21 bool select CPU_COMMON_SAMD21 ## Common CPU symbols config CPU_FAM default samd10 if CPU_FAM_SAMD10 default samd20 if CPU_FAM_SAMD20 default samd21 if CPU_FAM_SAMD21 default samr21 if CPU_FAM_SAMR21 config CPU default samd21 if CPU_COMMON_SAMD21可以看到CPU_FAM_SAMD21通过select CPU_COMMON_SAMD21关联到公共符号CPU与CPU_FAM的默认值都受到对应 bool 符号守护且文件末尾source了更具体的型号文件与sam0_common/Kconfig。3. Board 建模板级建模规则在/boards/BOARD/Kconfig中声明隐藏 bool 符号BOARD_BOARD默认y它必须select对应板载 CPU 的CPU_MODEL_model符号以及该板提供的特性符号同一文件中还需为通用BOARD符号赋受守护的默认值。多板共享代码时可在公共板目录如/boards/common/...声明BOARD_COMMON_前缀符号来承载共享特性。文档给出的samr21-xpro示例与仓库 boards/samr21-xpro/Kconfig 完全一致# /boards/samr21-xpro/Kconfig config BOARD default samr21-xpro if BOARD_SAMR21_XPRO config BOARD_SAMR21_XPRO bool default y select CPU_MODEL_SAMR21G18A4. 板级 / CPU 级默认配置与优先级板级、公共板目录、CPU 与公共 CPU 目录也可能需要覆盖默认配置。为此提供两个 Makefile 变量KCONFIG_CPU_CONFIG由 CPU 或公共 CPU 目录追加的.config来源KCONFIG_BOARD_CONFIG由板级或公共板目录追加的.config来源。两者通过Makefile.features基础设施填充。由于合并顺序决定优先级后合并者优先来源应按从通用到具体排列。又因为板级Makefile.features先于 CPU 级被包含所以必须用两个独立列表来保证正确的优先级。文档示例include $(RIOTCPU)/cortexm_common/Makefile.features # Add stm32 configs after including cortexm_common so stm32 takes precedence KCONFIG_CPU_CONFIG $(RIOTCPU)/stm32/stm32.config5. 保留前缀一览下列符号前缀被赋予了特定语义并保留使用按字母序前缀描述BOARD_建模一个板卡BOARD_COMMON_供多个板卡共享的公共符号CPU_ARCH_建模 CPU 体系架构CPU_COMMON_供多个 CPU 共享的公共符号CPU_CORE_建模 CPU 核心CPU_FAM_建模 CPU 家族CPU_MODEL_建模具体 CPU 型号USEMODULE_建模一个 RIOT 模块由USEMODULE变量生成USEPKG_建模一个外部软件包由USEPKG变量生成六、附录附录 A判断模块或包是否被使用为了让 Kconfig 只展示与当前应用、当前板卡相关的参数构建系统通过Makefile.dep完成模块依赖解析并以$(GENERATED_DIR)/Kconfig.dep作为声明已用模块与包的接口。每个在USEMODULE或USEPKG中的模块/包都会对应一个符号符号名取模块名大写、连字符转下划线。基于这些符号即可实现depends on依赖。文档示例menu Configure Sock Utilities depends on USEMODULE_SOCK_UTIL config SOCK_UTIL_SCHEME_MAXLEN int Maximum length of the scheme part for sock_urlsplit default 16 ... endmenu # Configure Sock Utilities仓库 sys/net/sock/Kconfig 中的depends on USEMODULE_SOCK_UTIL即为该模式的现行实例。附录 BKconfig 文件与.config文件的区别Kconfig 文件描述的是一个配置数据库——按树形结构组织的配置选项集合选项可带有依赖、类型、提示与默认值等属性使用 Linux 内核定义的 Kconfig 语言编写。例如menu Buffer Sizes config GCOAP_PDU_BUF_SIZE int Request or response buffer size default 128 endmenu.config文件则是对配置选项的赋值采用 Makefile 语法也可以作为配置快照备份# enable Kconfig configuration for gcoap CONFIG_KCONFIG_MODULE_GCOAPy # set the value CONFIG_GCOAP_PDU_BUF_SIZE12345一句话概括Kconfig 文件定义有哪些选项、怎么定义.config文件决定选项被赋成什么值。附录 C混用不同配置界面的陷阱当前流程允许用户混用 menuconfig 与手写.config两种方式但二者对out.config的处理不同手改.config会触发out.config的重新合并构建menuconfig 则直接修改out.config旧值备份为out.config.old。由于合并顺序遵循后合并者优先两种方式交替使用容易产生与预期不符的结果。强烈建议务必保存配置备份——任何对配置来源的改动都会重新触发合并过程并覆盖out.config。推荐以 menuconfig 的 Save 功能把配置备份为user.config等持久文件因为它能展示关于依赖与默认值的更完整信息。附录 D把宏暴露到 Kconfig 的若干关键实践0/1 宏建模为bool值为 0 或 1 的宏应建模为bool符号源码中用kernel_defines.h提供的IS_ACTIVE()宏配合 C 条件编译进行判断示例见 tests/build_system/kconfig/main.c 中IS_ACTIVE(CONFIG_APP_MSG_2)的用法。默认TRUE的宏需要反转语义若某宏默认被定义为TRUE推荐新增一个语义相反的符号并将其暴露到 Kconfig旧符号标记为弃用deprecated逐步迁移。受限取值宏的建模若宏只能取特定值例如GNRC_IPV6_MSG_QUEUE_SIZE必须是 2 的幂可以引入一个承载受限数值的新宏再通过运算符在代码中推导出最终值从而在 Kconfig 层只暴露合法取值。这些做法确保了 Kconfig 符号与 C 宏之间的语义一致避免条件编译出现歧义。七、延伸阅读构建系统集成主文件makefiles/kconfig.mk根配置入口Kconfig模块级 Kconfig 实例sys/net/sock/Kconfig、cpu/samd21/Kconfig、boards/samr21-xpro/Kconfig应用级配置与外部模块/包测试tests/build_system/kconfig/构建流程图示doc/guides/build-system/img/kconfig_integration.svgKconfig 语言规范可参考 Linux 内核官方 Kconfig 语言与宏语言文档以及 Zephyr 项目的 Kconfig 最佳实践tips.rst。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表