【问题标题】:Makefile test if variable is not emptyMakefile 测试变量是否为空
【发布时间】:2019-01-03 05:41:21
【问题描述】:

在我正在尝试的 makefile 中

  • 运行 shell 命令并在 make 变量中捕获输出
  • 如果变量不为空就做点什么

我创建了这个简化的 makefile 来演示我的问题。 make amake b 都不执行 if 的主体,我不明白为什么不。

.PHONY: a b

a:
    $(eval MY_VAR = $(shell echo whatever))
    @echo MY_VAR is $(MY_VAR)
    $(info $(MY_VAR))
ifneq ($(strip $(MY_VAR)),)
    @echo "should be executed"
endif
    @echo done

b:
    $(eval MY_VAR = $(shell echo ''))
    @echo MY_VAR is $(MY_VAR)
    $(info $(MY_VAR))
ifneq ($(strip $(MY_VAR)),)
    @echo "should not be executed"
endif
    @echo done

我正在使用

$ make --version
GNU Make 3.81

编辑:正如所指出的,vars 不需要是 make vars

【问题讨论】:

  • 有几个问题和误解。您的MY_VAR 是一个make 变量,将其设置为没有<tab> 的值,并且不需要$(eval ...)MY_VAR:=$(shell echo whatever) 就够了。没有<tab>$(info ...) 之前也没有,这是make
  • 如果不为空就要做某事,需要在配方行中使用$(if $(strip $(MY_VAR)),do if,do else)
  • @Zelnes 我只想在运行目标ab 时设置MY_VAR(真正的命令很昂贵,并且还有其他不需要它的目标),如果我删除我得到语法错误的标签。
  • 啊,if的另一种形式,有效!请回答,以便我接受。
  • 如果您只想在ab 目标中设置/使用这些变量,为什么要让它们成为make 变量?为什么不在配方中使用 shell 变量?在这里尝试使用make 变量会增加很多复杂性。

标签: makefile


【解决方案1】:

如果你想动态测试MY_VAR的内容,你可能需要:

a:
    $(eval MY_VAR = $(shell echo ''))
    $(if $(strip $(MY_VAR)),echo ok,echo no)

如果MY_VAR不为空,if评估将变为echo ok,否则将变为echo no

【讨论】:

  • 具体来说,ifneq 条件发生在与内联 $(if ) 条件不同的位置:在解析 Makefile 时,而不是在执行规则时。
【解决方案2】:

请注意,由于评估时间的原因,使条件(ifeqifneq...)不能按照您尝试的方式在配方中使用。请改用 shell 条件,如下所示。

由于您的 MY_VAR 变量仅在配方中使用,它依赖于目标并且您希望仅在需要时计算它,为什么不使用 shell 变量而不是 make 变量?

$ cat Makefile
.PHONY: a b

a:
    MY_VAR=$$(echo 'whatever') && \
    echo '$@: MY_VAR is $$MY_VAR' && \
    if [ -n "$$MY_VAR" ]; then \
      echo '$@: should be executed'; \
    fi && \
    echo '$@: done'

b:
    MY_VAR=$$(echo '') && \
    echo '$@: MY_VAR is $$MY_VAR' && \
    if [ -n "$$MY_VAR" ]; then \
      echo '$@: should not be executed'; \
    fi && \
    echo '$@: done'

$ make a
a: MY_VAR is whatever
a: should be executed
a: done

$ make b
b: MY_VAR is
b: done

如果您绝对需要 MY_VAR 成为特定于目标的 make 变量,但只想(每个目标)执行一次产生其值的 shell 命令,MadScientist 有一个 wonderful trick 您可能应该看看.应用于您的案例,它应该如下所示:

$ make --version
GNU Make 4.1
...

$ cat Makefile
a: MY_VAR = $(eval a: MY_VAR := $$(shell echo 'whatever'))$(MY_VAR)
b: MY_VAR = $(eval b: MY_VAR := $$(shell echo ''))$(MY_VAR)

a:
    @echo '$@: MY_VAR is $(MY_VAR)' && \
    if [ -n "$(MY_VAR)" ]; then \
      echo '$@: should be executed'; \
    fi && \
    echo '$@: done'

b:
    @echo '$@: MY_VAR is $(MY_VAR)' && \
    if [ -n "$(MY_VAR)" ]; then \
      echo '$@: should not be executed'; \
    fi && \
    echo '$@: done'

$ make a
a: MY_VAR is whatever
a: should be executed
a: done

$ make b
b: MY_VAR is
b: done

$ make b a
b: MY_VAR is
b: done
a: MY_VAR is whatever
a: should be executed
a: done

它可能看起来非常奇怪,但它保证当且仅当目标ab 被调用时计算MY_VAR,并且每个最多只调用一次。查看MadScientist's post 了解详细说明。去吧,太棒了。

【讨论】:

  • 哇,这么好的答案。虽然我指定它应该是一个 make var,但它实际上并不需要。谢谢
【解决方案3】:

解析 Makefile 时会评估 ifeq 和条件系列。如果您在扩展规则时想要一个 Make 变量的条件,您需要使用 $(if ) 函数:

.PHONY: a b

a b:
    @$(if $(strip $(MY_VAR)),echo "MY_VAR isn't empty",)
    @echo done

a: MY_VAR =
b: MY_VAR = something

【讨论】:

    【解决方案4】:

    有点左字段,但在我的情况下很有用,所以我认为值得分享:使用 --no-run-if-empty 选项将值传递给 xargs

    echo $(POSSIBLY_EMPTY) | xargs --no-run-if-empty echo
    

    请注意,这将在 OSX 上工作。有关xargs --no-run-if-empty 的更多详细信息,请参阅How to ignore xargs commands if stdin input is empty?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 2011-04-07
      • 2017-10-11
      • 2018-09-01
      • 2011-10-02
      • 1970-01-01
      • 2011-08-05
      相关资源
      最近更新 更多