Makefile是DV高频使用的脚本工具之一。对于包含CPU的芯片验证,基本都会使用Makefile进行case的编译,DV平台也会使用Makefile进行各种自动化构建。
近期在定位一个历史平台的C编译问题,遇到一个Makfile的立即展开(immediate expansion)和延时展开(deferred expansion)的问题,分享如下。
CPU有很多case,每个case有单独的目录,每个目录下存放对应的C代码和Makefile,执行具体的编译命令;另外有一个顶层的Makefile用于设置些环境变量,同时include子目录的Makefile。简化后的结构如下:
|-- Makefile
|-- src_1
| -- case.mk
`-- src_2
-- case.mk
Makfefile内容如下:
include src_1/case.mk src_2/case.mk
clean:
@echo "Enter clean target..."
case.mk内容如下,在每个case的makefile中,给testcase设置不同的变量。
testcase := case_1
#testcase := case_2
$(testcase):
@echo "Enter Target: $@, testcase=$(testcase)"
按照上面的code执行,make case_1 case_2的结果如下:
Enter Target: case_1, testcase=case_2
Enter Target: case_2, testcase=case_2
Makefile中target中的$$@代表目标变量,从执行结果看,case_1和case_2的$@都可以"正确"获取到target的值:case_1和case_2。
而$$testcae变量则被最后的case_2覆盖!!!
这是由于target会被立即展开,而普通变量则是延后展开。因此上面的Makfile两个include展开后,可以等效成下面:
testcase := case_1
case_1:
@echo "Enter Target: $@, testcase=case_2"
testcase := case_2
case_2:
@echo "Enter Target: $@, testcase=case_2"
关于立即扩展和延后扩展,可参考Makefile的手册说明:
We say that expansion is immediate if it happens during the first phase: make will expand that part of the construct as the makefile is parsed. We say that expansion is deferred if it is not immediate. Expansion of a deferred construct part is delayed until the expansion is used: either when it is referenced in an immediate context, or when it is needed during the second phase.
That is, the target and prerequisite sections are expanded immediately, and the recipe used to build the target is always deferred. This is true for explicit rules, pattern rules, suffix rules, static pattern rules, and simple prerequisite definitions.