12

$(error ...)如果不满足某些先决条件,我想用它来中止我的制作过程。fails_to_work失败时目标应该test -d /foobar中止。

坏的.mk

all: this_works fails_to_work

this_works:
        @echo echo works...
        @test -d ~ || echo ~ is not a directory
        @test -d /foobar || echo /foobar is not a directory

fails_to_work:
        @echo error does not work...
        @test -d ~ || $(error ~ is not a directory)
        @test -d /foobar || $(error /foobar is not a directory)

$ make -f BAD.mk

echo works...
/foobar is not a directory
BAD.mk:9: *** ~ is not a directory.  Stop.

如您所见,甚至“错误不起作用......”都不会回显到屏幕上。fails_to_work在它开始之前失败的秘诀。我该如何解决这个问题?我的用例之一是@test -d $(MY_ENV_VAR),但我认为这与示例中给出的硬编码路径没有什么不同。

更新(版本信息)

$ 制作--版本

GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for x86_64-pc-linux-gnu
4

3 回答 3

11

用于制作配方的 Shell 命令有效地存储为单个递归扩展变量。在 make 决定运行配方时,它会扩展变量,然后在其自己的 shell 调用中运行每一行。即使在调用第一个命令之前,任何 $(error ...)扩展都会导致 make 中止。

请注意,a $(if ...)or $(or ...)&c 的未使用分支。不会扩大。因此,你可以做

.PHONY: rule-with-assert
rule-with-assert:
    $(if $(realpath ${should-be-file}/),$(error Assertion failure: ${should-be-file} is a folder!))
    ⋮

请注意,/realpath.

当然,宏有助于整理很多东西。

assert-is-file = $(if $(realpath $1/),$(error Assertion failure: [$1] is a folder!))

.PHONY: rule-with-assert
rule-with-assert:
    $(call assert-is-file,${should-be-file})
    ⋮

再次值得注意的是,你把它放在$(call assert-is-file,…)食谱中的哪个位置并不重要。Any$(error)将在配方扩展时生成, 任何 shell 命令运行之前。

于 2013-02-28T13:30:50.427 回答
10

您正在尝试在配方中获取 shell 内容以有条件地调用 makefile 内容,这不起作用,正如您所发现的那样。

我可以想到两个选择:

  1. 只需删除这些$(error)东西。如果test失败,那么它将返回非零退出状态,并且 Make 过程将在该点终止。

  2. 将测试排除在规则之外,并使用 Make 条件(进而调用 shell 功能),例如:

    ifeq ($(shell test -d /foobar; echo $$?),1)
    $(error Not a directory)
    endif
    
于 2012-06-18T20:05:08.397 回答
3

为什么不直接使用exit 1shell 命令而不是$(error ...)?有什么理由使用后者吗?

try_this:
    @test -d /foobar || { echo /foobar is not a directory; exit 1; }

or_this:
    @if [ ! -d /foobar ]; then echo /foobar is not a directory; exit 1; fi

-k除非指定标志,否则这两个都将中止制作过程。

-k --keep-going

出错后尽可能继续。虽然失败的目标以及依赖它的目标无法重新制作,但这些目标的其他先决条件可以全部处理。

于 2012-06-18T21:23:18.137 回答