使用eval时,Makefile规则不是目标

使用eval时,Makefile规则不是目标,makefile,gnu-make,Makefile,Gnu Make,我有一个makefile,它将tar文件提取到运行时确定的可变数量的文件夹中(在下面的示例中,这是硬编码的): 当第二行被注释掉时,我得到以下输出和错误: 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. 当我使用-pRr运行make时,我看到d3/a.txt规则的以下输出: # Not a target: d3

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

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

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.
当我使用
-pRr
运行make时,我看到
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: 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
将此与
d1/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: 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
当通过
make-pRr
查看时,
d3/a.txt
的规则与上述
d1/a.txt
的规则类似

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

@echo $(1) $(DIR) $$@ $$< $$*
请注意,目标现在是
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.

两者都没有帮助我找出原因。

我必须承认,我从来没有真正理解
的更高级功能使其运行的确切规则(因为当我开始对它们感兴趣时,我转而使用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, $_)))
输出:

Makefile:21: ' d1'
Makefile:21: ' d2'
Makefile:21: ' d3'
罪魁祸首:

$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))
                                            ^
解决方案:

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

(请注意
$之前删除的空格,它已成为
$(1)
标记的一部分。)

@DevSolar复制和粘贴时,必须将空格转换为选项卡。不幸的是,这并没有保存它们。脸掌。。。。{咒骂删除}/我很笨。Thx-)@DevSolar相关问题-谢谢。这解决了测试用例,但也帮助我认识到测试用例并不能代表我的真实世界。用<代码> EVA/COD>创建的目标在路径中间有参数。我用一些额外的信息更新了这个问题。哇!干得好。我不知道
$(警告)
,所以知道也很好。我现在还记得,最后一段是关于空格的警告。不过,我很惊讶它在标记前加上了空格。@Jon:专业的维护编码员。当某些东西不起作用时,我首先要寻找的总是某种形式的“打印”功能来检查假设
DIR=$(1)
(或者更准确地说
$(DIR)
)失败的原因是
eval
在内容扩展为makefile语法之前扩展了所有内容,用
$(DIR)
替换
$(DIR)
也解决了这个问题。@Jon:检查上面的注释,这是对行为的解释。除了
$(DIR)
;-)之外,所有的
$
都翻了一番
Makefile:21: ' d1'
Makefile:21: ' d2'
Makefile:21: ' d3'
$(foreach _, $(DIRS), $(eval $(call AddRule, $_)))
                                            ^
$(foreach _, $(DIRS), $(eval $(call AddRule,$_)))