Makefile中的$$

1 $$的用处

在uboot/kernel的顶层Makefile中我们可以看到,当执行make时同时传入多个目标是这样处理的:

__build_one_by_one:
	$(Q)set -e; \
	for i in $(MAKECMDGOALS); do \
		$(MAKE) -f $(srctree)/Makefile $$i; \
	done

其中的$$i比较奇怪,Makefile引用变量只需要一个$符号就够了,为什么这里要两个呢?因为变量i是在shell的for循环中定义的,是属于shell中的变量。make在读到$$i的时候会把它扩展成$i有点转义字符的意味),然后交给shell解释程序执行。而如果读到$i,由于变量i没有在Makefile中定义,因此就会被扩展成空。要知道make会把Makefile规则中的命令部分交给shell执行,而它自己只对其做简单的处理,比如展开被引用的变量。换句话说,make根本不认识for i in这样的语句,只知道要它们交给shell,因此在make看来,$i中的i是没有定义的。

通过上面这个例子,不难看出,$$的用处可以概括为阻止一次Makefile的变量扩展,或者说施加了$$的变量,需要两次展开,才能得到变量的值。第二次展开,可能是在shell中进行的,正如上例;也可能是在Makefile中,并且被阻止的动作除了变量扩展还可以是函数执行,下面就举个例子:

OBJS_LIST := aa bb cc dd ee

define test
DEP_OBJS_$(1) = $$(foreach l,$$(OBJS_LIST),$(1)_$$(l).o)
endef

all:
        @echo $(DEP_OBJS_TTT)

CREATE_OBJS := TTT
$(foreach objs,$(CREATE_OBJS),$(eval $(call test,$(objs))))

本例在多行变量test中使用了$$,在make读取Makefile时,当读取到最下面的foreach时,会去call多行变量,也就是使用参数TTT替换$(1),同时将$$替换为$,进而得到变量DEP_OBJS_TTT

DEP_OBJS_TTT = $(foreach l,$(OBJS_LIST),TTT_$(l).o)

执行make all,make处理@echo $(DEP_OBJS_TTT),对DEP_OBJS_TTT进行展开,执行其中的foreach,得到结果如下:

TTT_aa.o TTT_bb.o TTT_cc.o TTT_dd.o TTT_ee.o

不难看出此处$$的作用是阻止了call多行变量的时候就执行其中的foreach。但在本例中不用$$也行,也能得到同样的结果。将本例略作改变,将OBJS_LIST的定义调整到call多行变量的后面,此时如果不使用$$就得不到预期的结果了:

define test
DEP_OBJS_$(1) = $(foreach l,$(OBJS_LIST),$(1)_$(l).o)
endef

all:
        @echo $(DEP_OBJS_TTT)

CREATE_OBJS := TTT
$(foreach objs,$(CREATE_OBJS),$(eval $(call test,$(objs))))

OBJS_LIST := aa bb cc dd ee

这是因为当make在call多行变量时,OBJS_LIST还未定义,若立即执行多行变量中的foreach,那么$(OBJS_LIST)为空。

不妨再对这个例子做个修改:

define test
# 将'='修改为':='
DEP_OBJS_$(1) := $$(foreach l,$$(OBJS_LIST),$(1)_$$(l).o)
endef

all:
        @echo $(DEP_OBJS_TTT)

CREATE_OBJS := TTT
$(foreach objs,$(CREATE_OBJS),$(eval $(call test,$(objs))))

OBJS_LIST := aa bb cc dd ee

这时,即便使用$$也不行了,因为:=会导致直接展开引用的变量。

2 二次展开(SECONDEXPANSION)

通过上文,我们已经知道了$$需要两次展开才能够解引用变量或者执行函数。除此之外,make还提供了针对依赖的二次展开特性,需要使用特殊目标.SECONDEXPANSION,在这个特殊目标之后定义的依赖,都可以进行二次展开,当然,这仍需要借助$$的转义特性。举个例子:

.SECONDEXPANSION:
VAR = first
one: $(VAR)
two: $$(VAR)
VAR = second

first:
        @echo "this is first"
second:
        @echo "this is second"
one:
        @echo $^
two:
        @echo $^

执行make one将得到:

this is first
first

执行make two将得到:

this is second
second

需要注意的是,如果不加特殊目标,那么执行make two时会报错(依赖的二次展开特性没有使能):

make: *** No rule to make target ‘$(VAR)’, needed by ‘two’. Stop.

变量函数以及依赖的二次展开在Makefile中可以实现很多有用的功能,无法尽说,本文着重介绍机制,用法的举例或许不是非常合适,更多用法可以搜索相关资料或实际的Makefile工程获取。

参考

[1] Makefile – 二次展开(SECONDEXPANSION)
​[2] Makefile中$$使用

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值