Makefile中$(shell)与直接执行命令的区别及sleep用法差异
Makefile中$(shell)与直接执行命令的区别
问题1:$(shell)和直接执行命令的核心差异
Makefile的执行分为两个关键阶段,这是两者区别的根源:
- 解析阶段:Make加载并解析整个Makefile,处理变量定义、执行所有函数调用(包括$(shell)),但不会运行规则里的命令。
- 执行阶段:Make确定要构建的目标后,将规则中已经解析完成的命令逐行交给shell执行。
两者的具体区别:
- 执行时机不同:
$(shell)是在解析阶段执行,只要Make解析到它(不管是变量定义还是命令行里),就会立刻调用shell运行对应命令,把输出作为函数返回值。- 规则里的直接命令(比如
sleep 1)要等到执行阶段,Make开始运行目标的命令时,才会交给shell执行。
- 作用场景不同:
$(shell)常用于在解析阶段获取外部命令输出,用来给变量赋值或生成动态规则内容。- 直接命令用于执行阶段完成实际构建操作,比如编译、文件拷贝等。
- 对变量的影响不同:如果
$(shell)放在递归展开变量(比如AA = $(shell date))里,每次引用变量时都会重新执行$(shell);而直接命令不会改变变量的展开时机。
问题2:sleep 1和$(shell sleep 1)的区别
结合提供的代码和输出,具体差异一目了然:
$(shell sleep 1):
在解析阶段执行,会让Make进程本身暂停1秒,执行完后返回空字符串,所以规则里的这一行最终会变成空命令(什么都不做)。在目标a中,每次遇到它,Make都会先等1秒再处理下一行,所以后续的echo $(AA)会获取到更新后的时间,导致输出的三个时间依次递增。sleep 1:
在执行阶段由shell执行,会让shell进程暂停1秒,但此时目标b里的$(AA)已经在解析阶段完成了三次展开,值已经固定,所以即使sleep了1秒,后续echo的还是同一个时间,最终输出三个相同的时间。
示例代码
AA = $(shell date) a: @echo $(AA) $(shell sleep 1) @echo $(AA) $(shell sleep 1) @echo $(AA) b: @echo $(AA) @sleep 1 @echo $(AA) @sleep 1 @echo $(AA)
运行输出
>make a Wed Apr 26 20:24:14 PDT 2023 Wed Apr 26 20:24:15 PDT 2023 Wed Apr 26 20:24:16 PDT 2023 >make b Wed Apr 26 20:24:18 PDT 2023 Wed Apr 26 20:24:18 PDT 2023 Wed Apr 26 20:24:18 PDT 2023
内容的提问来源于stack exchange,提问作者lionel319
相关产品推荐
相关产品推荐

