根据目标变量

时间:2018-10-16 00:59:53

标签: makefile

是否有一种方法可以强制目标规则作为在变量中设置某些内容的一部分运行?

例如,假设我们有一个目标和规则:

all_mp3s:
    find / -name "*.mp3" > all_mp3s

然后是一个变量:

MP3S := $(file < all_mp3s)

有没有一种方法可以确保在评估all_mp3s变量之前创建MP3S文件?

1 个答案:

答案 0 :(得分:0)

没有简单直接的方法可以在分配变量之前强制评估规则。有更复杂的方法。以下是针对GNU make的。

首先让我们假设仅在文件find不存在的情况下才想运行{slow} all_mp3s命令,否则使用其内容。您可以使用GNU make条件句:

ifeq ($(wildcard all_mp3s),all_mp3s)

MP3S := $(shell cat all_mp3s)

else

MP3S := $(shell $(MAKE) all_mp3s ; cat all_mp3s)

endif

all_mp3s:
    find / -name "*.mp3" > $@

但是如果您的Makefile比这更复杂,我会多次使用MP3S,而您真正想要的是:

  • 避免多次运行超慢的find
  • 仅在需要时运行(并且仅运行一次)
  • 将结果保存到文件(all_mp3s)和make变量(MP3S)中,

MadScientist具有wonderful GNU make trick,可在此处使用:

MP3S = $(eval MP3S := $$(shell find / -name "*.mp3"))$(MP3S)

all_mp3s:
    printf '%s\n' '$(MP3S)' > all_mp3s

.PHONY: help clean

help:
    printf 'MP3 finder\n'

clean:
    rm -f all_mp3s

如果MP3S recursively expanded make variable因评估Makefile的某些部分并需要其值而被扩展(例如,如果make all_mp3s不存在时运行all_mp3s), find命令将运行,其结果存储在变量中……并且该变量将被转换为simply expanded make variable,如果有进一步的扩展,它将重新使用已经计算出的相同值。

否则,如果您对make的调用(例如make cleanmake help)不需要MP3S值,则find命令甚至不会运行。

all_mp3s文件是根据MP3S的值生成的(而不是其他解决方案中的相反值)。

但是,还有另外一件重要的事情要决定:您是否想将all_mp3s声明为假目标:

.PHONY: all_mp3s

还是不?

  • 如果您将其声明为虚假,则find命令将仅在您每次调用make all_mp3s(或依赖于all_mp3s的另一个目标)时运行一次。但是取决于all_mp3s的目标也将始终被重建,这不一定是您想要的。

  • 如果您未将其声明为phony并且文件已经存在,则find命令将根本不会运行(除非您的其他位置需要MP3S的值) Makefile),并且all_mp3s的内容不会更新,这不一定是您想要的。

由于您没有在问题中提供足够的信息来决定,所以这取决于您。