【问题标题】:Double Dollar "$$@" target name in GNU MakeGNU Make 中的 Double Dollar "$$@" 目标名称
【发布时间】:2019-10-27 04:48:01
【问题描述】:

我有一个来自 OP-TEE 的规则(使用大型 makefile 包含和 make 调用树来编译两个操作系统内核和应用程序),其中包含一些立即扩展的变量——据我所知,这里没有第二个相关的扩展,因为双双美元在规则中,因此不受第二次扩展的影响。它应该始终在第二阶段进行扩展:

$(link-out-dir$(sm))/$(user-ta-uuid).elf: $(objs) $(libdeps) \
                  $(link-script-pp$(sm))
    @$(cmd-echo-silent) '  LD      $$@'
    echo Target '$@', '$$@', "$@", "$$@"

在输出中,可以看到$@$$@的所有出现都被make扩展,而不是sh,但是单美元的没有填充正确的值,双美元没有转义他们自己:

echo Target '', 'out/someuuid.elf', "", "out/someuuid.elf"
Target , out/someuuid.elf, , out/someuuid.elf

我期待的是:

echo Target 'out/someuuid.elf', '$@', "out/someuuid.elf", "$@"
Target out/someuuid.elf, $@, out/someuuid.elf,

哪种 make 机制可能是扩展在此处工作方式不同的原因?

这个目标在其他 makefile 中嵌套了两层,并且有四个 make 调用,因此很难找出构建链在此处的不同配置。


我无法使用最小的 makefile 重现此行为:

all: target1 target2 target3

.PHONY: target1 target2 target3 all
.SUFFIXES:

target1:
        echo Target1 '$@', '$$@', "$@", "$$@"

# should make no difference, since used in immediate context on rule specification
TARGET2 := target2
TARGET3 = target3

$(TARGET2):
        echo Target2 '$@', '$$@', "$@", "$$@"

$(TARGET3):
        echo Target3 '$@', '$$@', "$@", "$$@"

通过 $@ 扩展为目标名称和 $$@ 扩展为字符串或位置 shell 参数的空列表来产生预期的输出:

echo Target1 'target1', '$@', "target1", "$@"
Target1 target1, $@, target1,
echo Target2 'target2', '$@', "target2", "$@"
Target2 target2, $@, target2,
echo Target3 'target3', '$@', "target3", "$@"
Target3 target3, $@, target3,

指定 .SECONDEPANSION 不会像预期的那样改变结果。

【问题讨论】:

    标签: makefile gnu-make gnu op-tee


    【解决方案1】:

    语法突出显示可能很棘手——我不知道整个目标是变量本身的内容——上面的一些目标是define gen-link-t,以多行变量开头,下面的一些目标结束。

    目标实际上是在文件末尾使用 $(eval $(call gen-link-t)) 生成后调用的,而不是逐行读取 - 导致在扩展$(call),使调用将 $ 作为纯文本返回。第二次评估发生在 make 通过 $(eval) 再次读取此目标时

    【讨论】:

    • 一个有趣的案例,也是一个关于过于聪明和在“eval”上使用各种语言变体的警示故事。恭喜你整理出来。