在Makefile中执行两个分支的Shell`if`

时间:2017-04-21 03:05:46

标签: shell makefile gnu-make

我在使用GNU make 4.1编译的Makefile中有以下规则:

multiboot_check: kernel.bin
    if [ $(grub2-file --is-x86-multiboot $^) -eq 0 ]; then \
        $(info $^: valid Multiboot Version 1 header); \
    else \
        $(error $^: invalid Multiboot Version 1 header); \
    fi

当我运行它时,执行true和false分支,产生以下输出:

kernel.bin: valid Multiboot Version 1 header
Makefile:24: *** kernel.bin: invalid Multiboot Version 1 header.  Stop.

为什么会这样?还有更好的方法吗?

我尝试将它放在一行中,甚至将if语句缩减为[ 0 -eq 0 ],它仍然执行两个分支。

1 个答案:

答案 0 :(得分:1)

您的食谱相当于:

multiboot_check: kernel.bin
#   `make` directives evaluated for this target are not part of the recipe
    $(info $^: valid Multiboot Version 1 header)
    $(error $^: invalid Multiboot Version 1 header)
#   The recipe is...
    if [ -eq 0 ]; then \
        ; \
    else \
        ; \
    fi

首先要了解为什么make没有按照你编写的顺序对行进行排序, 阅读this answer

剩余食谱:

    if [ -eq 0 ]; then \
        ; \
    else \
        ; \
    fi

在语法上对shell无效,因为未转义的$(grub2-file ...) 将由make扩展,而不是shell,并将扩展为空。你要 它是一个shell扩展,所以你需要为make转义它:

$$(grub2-file...)

但是,虽然剩余的配方会引发shell语法错误,但是 永远不会看到它,因为make评估:

    $(info $^: valid Multiboot Version 1 header)
    $(error $^: invalid Multiboot Version 1 header)
在配方运行之前

$(error ...)指令终止make 在它尝试执行无效食谱之前。

更正了shell扩展,测试:

[ $$(grub2-file --is-x86-multiboot $^) -eq 0 ]

仍然无法达到您显然想要的效果。这个测试会 确定命令grub2-file --is-x86-multiboot kernel.bin的标准输出 是一个等于0的字符串。据推测,它永远不会是你真正的 想确定命令的退出代码是否为0。

鉴于这一切,更好的方法是:

multiboot_check: kernel.bin
    grub2-file --is-x86-multiboot $^; \
    if [ $$? -eq 0 ]; then \
        echo "$^: valid Multiboot Version 1 header"; \
    else \
        echo "$^: invalid Multiboot Version 1 header"; exit 1; \
    fi