make --dry-run(-n)为何执行规则体中本应跳过的操作?
关于
make -n(dry-run)模式的执行逻辑疑问解答 核心问题
使用make --dry-run(即make -n)时,工具本该只打印将要执行的命令、不实际执行,但示例中的递归make调用却看起来被“执行”了,这是怎么回事?
示例代码
FOLDERS = path1 path2 path3 all: for T in $(FOLDERS); cd ./$$T; $(MAKE) -s; cd ../; done;
问题解析
首先明确make -n的核心行为:它不会调用shell执行规则体中的命令,只会展开所有make变量,把最终要执行的命令完整打印到终端。你觉得三次make被执行了,本质是混淆了“命令打印”和“实际执行”:
- 当你执行
make -n时,外层make会先展开变量:$(FOLDERS)被替换为path1 path2 path3$(MAKE)被替换为make(GNU make会自动带上外层的参数,比如-n)
- 最终规则体的命令会被展开成:
for T in path1 path2 path3; cd ./$T; make -n -s; cd ../; done; - 外层make只会把这个完整的shell命令打印出来,不会让shell去执行这个循环——你看到的“三次make调用”只是打印的内容,并非实际执行。
如果确实出现了子make被实际执行的情况,大概率是以下原因之一:
- 命令行中遗漏了
-n参数,或者误加了-B(强制重新生成所有目标)等会触发执行的参数 - 规则体中的命令前面加了
+前缀(+会强制make在dry-run模式下执行该命令)
递归make的最佳实践
- 永远用
$(MAKE)代替直接写make:这样外层make的参数(比如-n、-j并行编译参数)会自动传递给子make,保证递归行为的一致性 - 你的示例可以改写为更规范的形式,避免循环带来的误解:
这种写法在FOLDERS = path1 path2 path3 all: $(FOLDERS) $(FOLDERS): $(MAKE) -C $@ -smake -n时会清晰打印每个子目录的make命令,不会产生混淆。
内容的提问来源于stack exchange,提问作者ABu
相关产品推荐
相关产品推荐

