ARTICLE DETAIL

资讯详情

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

RIOT 构建系统 CFLAGS 空格处理实战:Makefile、增量重建与 Docker 三种场景全解析

RIOT 构建系统 CFLAGS 空格处理实战:Makefile、增量重建与 Docker 三种场景全解析 RIOT 构建系统 CFLAGS 空格处理实战Makefile、增量重建与 Docker 三种场景全解析【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOTRIOT 是面向 IoT 的开源操作系统其基于 GNU Make 的构建系统允许开发者通过CFLAGS向编译过程注入宏定义与编译选项。当这些值本身包含空格例如传递一个带空格的字符串宏时Makefile 解析、增量重建触发以及 Docker 容器环境传递都会出现边界问题。本文以 tests/build_system/cflags_spaces/README.md 为主线结合 tests/build_system/cflags_spaces/Makefile、main.c、自动化测试 tests/build_system/cflags_spaces/tests/01-run.py 以及 makefiles/docker.inc.mk 等仓库源码系统讲解在 Makefile 中、Makefile.include 之后以及 Docker 构建三种场景下正确处理带空格 CFLAGS 的完整方案。读完本文你将掌握三类可复制的实操手段CFLAGS 的直接拼接、基于CONFIGURATION_VALUE的增量重建验证以及通过DOCKER_ENVIRONMENT_CMDLINE配合 shell 转义把含空格宏安全传入容器的方法。测试用例概述构建系统对带空格 CFLAGS 的支持该测试位于tests/build_system/cflags_spaces/目标非常明确验证 RIOT 构建系统能够正确处理带空格的 CFLAGS。RIOT 的构建系统基于 GNU MakeCFLAGS 本质上是一个空格分隔的字符串列表每个参数内部再含空格时Make 的默认分词行为就会破坏参数语义因此必须显式测试。整个测试目录包含四个文件构成了一个完整、可独立运行的验证闭环文件作用Makefile定义带空格的CFLAGS宏并通过CONFIGURATION_VALUE触发重建main.c打印三个配置宏的实际值作为运行期验证输出tests/01-run.py基于 testrunner 的自动化断言脚本README.md说明自动化与两类手动测试的方法其中Makefile还通过include ../Makefile.build_system_common见 tests/build_system/Makefile.build_system_common接入 RIOT 的公共测试框架Makefile.tests_common。自动化测试Makefile 中定义带空格 CFLAGS自动化测试覆盖的场景是CFLAGS 在 Makefile 中定义时就包含空格。对应代码位于 tests/build_system/cflags_spaces/Makefileinclude ../Makefile.build_system_common CFLAGS -DSUPER_STRINGI love sentences with spaces include $(RIOTBASE)/Makefile.include关键在于-DSUPER_STRINGI love sentences with spaces的写法外层单引号由 Make 在向 shell 传递命令行时剥除内层双引号则保留下来交给编译器使SUPER_STRING宏的值为完整的I love sentences with spaces。而测试程序 main.c 会在运行期将其打印出来puts(The output of the configuration variables:); printf(SUPER_STRING: %s\n, SUPER_STRING); printf(DEFINED_AFTER_MAKEFILE_INCLUDE: %u\n, DEFINED_AFTER_MAKEFILE_INCLUDE); printf(CFLAGS_STRING_FROM_DOCKER: %s\n, STRING_FROM_DOCKER);自动化测试脚本 tests/01-run.py 则对输出做精确断言def testfunc(child): child.expect_exact(The output of the configuration variables:) child.expect_exact(SUPER_STRING: I love sentences with spaces) child.expect_exact(DEFINED_AFTER_MAKEFILE_INCLUDE: %s % CONFIGURATION_VALUE) child.expect(rCFLAGS_STRING_FROM_DOCKER: .*)脚本通过os.environ[CONFIGURATION_VALUE]读取环境变量由 Makefile 中test: export CONFIGURATION_VALUE ?导出与程序输出的DEFINED_AFTER_MAKEFILE_INCLUDE逐字比对。注意CFLAGS_STRING_FROM_DOCKER只做宽松正则匹配这是因为该宏在常规本地构建下为空字符串main.c中#ifndef STRING_FROM_DOCKER的默认值其完整验证放在 Docker 场景的手动测试中。手动测试一在 Makefile.include 之后修改 CFLAGS 并触发重建RIOT 应用 Makefile 的常规写法是先追加自定义 CFLAGS再include $(RIOTBASE)/Makefile.include引入核心构建逻辑。那么如果在 include 之后继续追加 CFLAGS能否被正确识别并触发增量重建这是第二个测试场景。测试 Makefile 的对应部分include $(RIOTBASE)/Makefile.include # Changing this value should trigger a rebuild even if defined after # Makefile.include CONFIGURATION_VALUE ? 0 CFLAGS -DDEFINED_AFTER_MAKEFILE_INCLUDE$(CONFIGURATION_VALUE)这里CONFIGURATION_VALUE默认是0并追加了宏DEFINED_AFTER_MAKEFILE_INCLUDE。验证流程如下make flash test CONFIGURATION_VALUE1 make flash test第一次make flash test使用默认值0构建、烧录并运行测试应当通过第二次通过命令行变量赋值CONFIGURATION_VALUE1再次构建此时CFLAGS的实际内容发生了变化必须触发一次重新编译程序输出的DEFINED_AFTER_MAKEFILE_INCLUDE: 1才与自动化测试脚本中CONFIGURATION_VALUE1的环境断言一致测试才能通过。增量重建的底层机制从源码层面看这一行为由 RIOT 的依赖追踪机制保证。Makefile.base 中所有编译规则都带有-MD -MP参数$(OBJC): CFLAGS $(KCONFIG_CFLAGS) $(Q)$(CC) $(CFLAGS) $(RCFLAGS) $(INCLUDES) -MQ $ -MD -MP -c -o $ $(abspath $) $(Q)$(FIXDEP) $(:.o.d) $ $(KCONFIG_SYNC_DIR) $(:.o.tmp) $(Q)mv $(:.o.tmp) $(:.o.d)gcc 在编译时通过-MD -MP生成.d依赖文件随后FIXDEP工具重写依赖并同步 Kconfig 配置目录最后在文件末尾通过-include $(DEP)见 Makefile.base把已有的.d文件拉入构建。由于CFLAGS本身参与了.d依赖关系的生成命令行宏值变化时重新生成的依赖信息与旧.o不一致从而驱动 make 判定目标过时并重建。这也是 README 中修改 include 之后的 CFLAGS 会触发重建这一断言能够成立的根本原因。手动测试二Docker 构建时传递带空格的 CFLAGS第三个场景最具技巧性在BUILD_IN_DOCKER1的容器化构建中如何把含空格的宏定义传给容器内的编译器。为什么普通方式失效RIOT 的 Docker 集成在 makefiles/docker.inc.mk 中实现。其中DOCKER_ENV_VARS明确把CFLAGS列为需要传入容器的环境变量之一见该文件第 66 行CFLAGS \并通过如下逻辑自动收集来自命令行或环境变量的值DOCKER_ENVIRONMENT_CMDLINE_AUTO : $(foreach varname,$(DOCKER_ENV_VARS), \ $(if $(filter environment command,$(origin $(varname))), \ -e $(varname)$(subst ,\,$($(varname))), \ )) DOCKER_ENVIRONMENT_CMDLINE $(strip $(DOCKER_ENVIRONMENT_CMDLINE_AUTO))问题在于如果 CFLAGS 是在应用 Makefile内部通过CFLAGS 追加的例如本文测试用例中的-DSUPER_STRING...make 会把它标记为 file 来源而非 environment/command 来源$(origin ...)检查不通过自动收集机制不会将其传入容器。同时DOCKER_ENVIRONMENT_CMDLINE采用:立即赋值且发生在Makefile.include解析之前这正是 README 所说Cannot be detected automatically in the docker handling的原因。通过 DOCKER_ENVIRONMENT_CMDLINE 手动传递解决方案是绕过自动检测手动把 CFLAGS 附加到DOCKER_ENVIRONMENT_CMDLINE上。由于 docker 命令行参数本身也要经过 shell 解析带空格的值必须手工转义空格DOCKER_ENVIRONMENT_CMDLINE$-e CFLAGS-DSTRING_FROM_DOCKER\\\\with\ space\\\\ \ BUILD_IN_DOCKER1 make grep #define STRING_FROM_DOCKER with space bin/native/riotbuild/riotbuild.h \ || { echo ERROR CFLAGS not passed correctly 2; false; }逐层拆解这条命令的转义链片段含义$...bash ANSI-C quoting使内部\、\等按字面解析-e CFLAGS-DSTRING_FROM_DOCKER...传给docker run的环境变量参数\\\\最终变成编译器看到的\即字符串字面量中的转义双引号with\ spaceshell 层转义空格保证-e参数整体不被拆断执行后RIOT 会在bin/native/riotbuild/riotbuild.h中生成构建期配置头文件其中应包含#define STRING_FROM_DOCKER with spaceREADME 给出的grep命令正是对这一产物做文本断言验证宏确实以带空格的完整值落盘。在程序中消费该宏main.c中的对应处理位于/* Define a CFLAGS string with spaces from outside docker */ /* DOCKER_ENVIRONMENT_CMDLINE$-e CFLAGS-DSTRING_FROM_DOCKER\\\\with\ space\\\\*/ #ifndef STRING_FROM_DOCKER #define STRING_FROM_DOCKER #endif当未通过 Docker 传参时宏回退为空字符串保证本地构建也能通过通过 Docker 传参时则打印完整值with space供人工核对grep结果与程序输出一致。使用边界与注意事项综合三个场景在使用 RIOT 构建系统处理带空格 CFLAGS 时需注意Makefile 内定义的带空格宏使用CFLAGS -DNAMEvalue with spaces的双引号包裹写法这是 RIOT 官方自动化测试验证过的形态include 之后的 CFLAGS 修改通过CONFIGURATION_VALUE ? 0这类命令行可覆盖变量配合CFLAGS 追加依靠 Makefile.base 的-MD -MP依赖文件机制自动触发增量重建无需手工清理bin/目录Docker 场景Makefile 内追加的 CFLAGS 无法被 makefiles/docker.inc.mk 的$(origin ...)自动检测机制识别必须通过DOCKER_ENVIRONMENT_CMDLINE手动注入且 shell、make、docker、gcc 四层转义缺一不可用grep bin/native/riotbuild/riotbuild.h验证产物是可靠手段测试框架集成自动化验证依赖 tests/build_system/Makefile.build_system_common 引入的 testrunner运行测试前需通过make flash test保证固件与脚本状态一致。这套方法不仅适用于本文的native目标也同样适用于任何BUILD_IN_DOCKER1的 RIOT 应用构建场景当你需要向固件注入包含空格、引号等特殊字符的编译期配置时上述三种手段可以覆盖从本地 Makefile 到容器化 CI 的全链路需求。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表