Makefile中eval变量控制Recipe补丁条件执行异常问题排查
Makefile Patch 执行问题排查与解决
问题1:ifeq 判断总是进入 else 分支
你遇到的ifeq判断失效,核心原因是变量PATCH_PRESENT的值包含了换行符,导致和0的字符串匹配失败。
看你在applypatch规则里的这段代码:
echo 0 > .tmp/PATCH_PRESENT_file # ... $(eval PATCH_PRESENT := $(shell cat .tmp/PATCH_PRESENT_file))
默认情况下,echo命令会在输出末尾添加换行符,所以.tmp/PATCH_PRESENT_file里的内容其实是0\n(0加换行)。当你用$(shell cat ...)读取时,这个换行符会被保留,最终PATCH_PRESENT的值是"0\n",而不是你预期的"0"。ifeq ($(PATCH_PRESENT), 0)自然匹配失败,直接进入else分支。
修复方案(二选一即可):
- 写入文件时避免换行:用
echo -n代替echo,禁止添加换行符:echo -n 0 > .tmp/PATCH_PRESENT_file echo -n 1 > .tmp/PATCH_PRESENT_file - 读取变量时去除空白字符:用
$(strip)函数过滤掉变量中的换行、空格等空白字符:$(eval PATCH_PRESENT := $(strip $(shell cat .tmp/PATCH_PRESENT_file)))
问题2:Shell多行语句中git apply丢失错误码
你提到的错误码丢失,大概率是因为Makefile默认每行命令启动一个独立的Shell进程,导致cd和git apply不在同一个环境执行,或者错误码被Shell逻辑意外覆盖。
比如你原来的写法(当ifeq条件满足时):
@echo "Applying the patch $(PATCH_PRESENT)" cd ~/code && git apply -v ${C_PATCH_FILE}
这里cd ~/code是一个Shell进程执行的,执行完就退出了,下一行的git apply是在当前目录(Makefile执行目录)启动的新Shell,根本没进入~/code,自然会报错,但你可能误以为是错误码丢失。另外,如果是多行Shell语句用;或\连接,但没有正确传递错误码,也会导致Makefile无法感知git apply的失败。
修复方案:
- 将相关命令合并为一行:用
&&或分号连接,确保在同一个Shell进程执行,同时保留错误码:@echo "Applying the patch $(PATCH_PRESENT)" && cd ~/code && git apply -v ${C_PATCH_FILE} - 使用
.ONESHELL特殊目标(GNU Make 3.82及以上版本支持):在Makefile顶部添加这个目标,让整个规则的所有命令都在同一个Shell进程中执行,这样cd的效果会持续到后续命令:.ONESHELL: SHELL := /bin/bash # 可选,指定Shell类型,避免兼容性问题 applypatch: @echo "Patching ${C_FILE_CODE}" if grep -Fq '${C_FILE_PATCH_SIG}' ${C_FILE_CODE} ; \ then \ echo -n 1 > .tmp/PATCH_PRESENT_file; \ else \ echo -n 0 > .tmp/PATCH_PRESENT_file;\ fi # ... 其他命令 ifeq ($(PATCH_PRESENT), 0) @echo "Applying the patch $(PATCH_PRESENT)" cd ~/code && git apply -v ${C_PATCH_FILE} else @echo "NOT Applying the patch $(PATCH_PRESENT)" endif - 确保错误码被Makefile捕获:不要给
git apply命令加-前缀(-git apply ...会忽略错误),这样当git apply失败时,整个applypatch规则会返回非0退出码,触发后续的helppatch规则。
另外,补充一个小优化:你可以直接用$(shell)判断补丁是否存在,不需要临时文件,简化代码:
applypatch: @echo "Patching ${C_FILE_CODE}" $(eval PATCH_PRESENT := $(shell grep -Fq '${C_FILE_PATCH_SIG}' ${C_FILE_CODE} && echo 1 || echo 0)) @echo "WWWWWW PATCH_PRESENT=[$(PATCH_PRESENT)] WWWWWWW" ifeq ($(PATCH_PRESENT), 0) @echo "Applying the patch $(PATCH_PRESENT)" cd ~/code && git apply -v ${C_PATCH_FILE} else @echo "NOT Applying the patch $(PATCH_PRESENT)" endif
这样省去了临时文件的创建和读取,减少出错概率。
内容的提问来源于stack exchange,提问作者Shashi Ranjan
相关产品推荐
相关产品推荐

