使用eval时Makefile规则不是目标

乔恩

我有一个makefile,可将tar文件提取到可变数量的文件夹中,这些文件夹在运行时确定(在下面的示例中,这是硬编码的):

firstTarget: start
.PHONY: start

DIRS = d1 d2 d3

TAR_FILES = $(wildcard ?.tar)
TAR_FILE_NAMES := $(TAR_FILES:%.tar=%)
FILES = $(foreach _, $(DIRS), $(TAR_FILE_NAMES:%=$_/%.txt))

define AddRule
DIR = $(1)
$(DIR)/%.txt: %.tar
    @echo $(1) $(DIR) $$@ $$< $$*
    @mkdir -p $(DIR)
    @tar -xvf $$< > /dev/null
    @mv $$*.txt $(DIR)
endef
$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))
#$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))

start: $(FILES)
    @echo "Finished"

setup:
    @touch a.txt
    @tar -cvf a.tar a.txt > /dev/null
    @rm a.txt

clean:
    @rm -rf d1/ d2/ d3/

在运行时为每个变量案例生成规则,并使用eval和将其解析为制作指令call

请注意以下几行:

$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))
#$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))

当第二行被注释掉时,我得到以下输出和错误:

d2 d1 d1/a.txt a.tar a
d3 d2 d2/a.txt a.tar a
make: *** No rule to make target 'd3/a.txt', needed by 'start'.  Stop.

当我运行make with时,-pRr我看到以下规则的输出d3/a.txt

# Not a target:
d3/a.txt:
#  Implicit rule search has been done.
#  File does not exist.
#  File has not been updated.

将此与以下规则进行比较d1/a.txt

d1/a.txt: a.tar
#  Implicit rule search has been done.
#  Implicit/static pattern stem: 'a'
#  Last modified 2016-02-18 09:36:24
#  File has been updated.
#  Successfully updated.
# automatic
# @ := d1/a.txt
# automatic
# % := 
# automatic
# * := a
# automatic
# + := a.tar
# automatic
# | := 
# automatic
# < := a.tar
# automatic
# ^ := a.tar
# automatic
# ? := a.tar
# variable set hash-table stats:
# Load=8/32=25%, Rehash=0, Collisions=1/25=4%
#  recipe to execute (from 'Makefile', line 18):
    @echo  d2 d1 $@ $< $*
    @mkdir -p d1
    @tar -xvf $< > /dev/null
    @mv $*.txt d1

添加第二行,意味着每个规则被调用并评估两次,它可以正常工作:

d2 d1 d1/a.txt a.tar a
d3 d2 d2/a.txt a.tar a
d1 d3 d3/a.txt a.tar a
Finished

该规则d3/a.txt也类似于用于上述规则d1/a.txt通过观察时make -pRr

值得注意的是,在规则中,我输出以下内容:

@echo $(1) $(DIR) $$@ $$< $$*

现在的问题是:

  1. 为什么不d3正确评估规则
  2. 为什么在规则中$(1)不等于$(DIR)?这是奇怪的,因为$(1)被分配给$(DIR)。
  3. 为什么调用和评估规则可以使其正常工作?

如果要重复该问题,make setup请先运行,然后再运行make

更新1:18/02/2016

@DevSolar的回答解决了上面的问题,但是让我意识到我的测试用例并不是真实问题的完美表示。在实际问题中,动态规则的参数不在目标的开头:

FILES = $(foreach _, $(DIRS), $(TAR_FILE_NAMES:%=somedir/$_/%.txt))

define AddRule
somedir/$(1)/%.txt: %.tar
    @echo $(1) $$@ $$< $$*
    @mkdir -p somedir/$(1)
    @tar -xvf $$< > /dev/null
    @mv $$*.txt $(1)
endef

请注意,目标现在是somedir/$(1)/%.txt: %.tar这会在make 3.81中导致以下错误:

Makefile:17: warning: overriding commands for target `somedir'
Makefile:17: warning: ignoring old commands for target `somedir'
Makefile:17: warning: overriding commands for target `somedir'
Makefile:17: warning: ignoring old commands for target `somedir'

有趣的是,make 4.1还有其他要说的话:

Makefile:17: *** mixed implicit and normal rules: deprecated syntax
Makefile:17: warning: overriding recipe for target 'somedir/'
Makefile:17: warning: ignoring old recipe for target 'somedir/'
Makefile:17: *** mixed implicit and normal rules: deprecated syntax
Makefile:17: warning: overriding recipe for target 'somedir/'
Makefile:17: warning: ignoring old recipe for target 'somedir/'
Makefile:17: *** mixed implicit and normal rules: deprecated syntax
make: *** No rule to make target 'somedir/d1/a.txt', needed by 'start'.  Stop.

都没有帮助我找出原因。

开发太阳能

我必须承认,我从来没有真正理解过更高级的make操作功能所依据的确切规则(因为当我开始对它们感兴趣时,我改用了CMake)。

因此,我无法为您提供详尽的“为什么”(发生这种情况),而只能为您提供“如何”(解决此问题)。

不分配DIR = $(1)$(1)直接使用

define AddRule
$(1)/%.txt: %.tar
    @mkdir -p $(1)
    @tar -xvf $$< > /dev/null
    @mv $$*.txt $(1)
endef
$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))

这按预期工作。我只能假定本地分配不能与s一起使用,但是make可以处理defines。

正如@ user657267在评论中指出的那样:

DIR = $(1)(或更确切地说$(DIR))失败的原因是因为在内容作为makefile语法eval扩展之前先扩展所有内容。替换$(DIR)$$(DIR)还可以解决此问题。


更新:

通过查看$(1)实际解决的问题来解决您的更新问题define

define AddRule
$(warning '$(1)')
...

输出:

Makefile:21: ' d1'
Makefile:21: ' d2'
Makefile:21: ' d3'

罪魁祸首:

$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))
                                            ^

解:

$(foreach _, $(DIRS), $(eval $(call AddRule,$_)))

(请注意,之前已删除的空间$_已成为$(1)令牌的一部分。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章