1

让我们假设,我想打电话

make somepath/abc.pot

这取决于 somepath/somefiles.c

到目前为止我创建的目标看起来像

%.pot: $(dir $@)*.c
    @echo "it works"
ifeq (,$(wildcard $@))
#   pot-file does not exist, do something
else
#   pot-file already exists, do something else
endif

但不起作用,因为像 $@ 这样的自动变量 在先决条件中不可用。

如果找到,我可以启用第二次扩展

.SECONDEXPANSION:
%.pot: $$(dir $$@)*.c
    @echo "it works"
ifeq (,$(wildcard $@))
#   pot-file does not exist, do something
else
#   pot-file already exists, do something else
endif

这允许我在先决条件中使用 $@ ,但会破坏我的 ifeq 语句,这总是会导致第一个分支。如果我将 ifeq 更改为

ifeq (,$$(wildcard $$@))

它再次起作用,但我真的不明白为什么。

现在有两个问题:

A)除了启用第二次扩展以在我的先决条件中包含目标路径之外,还有其他方法吗?

B) 如果启用了第二个扩展,为什么该ifeq (,$(wildcard $@))语句总是导致第一个分支?

4

1 回答 1

0

根本不要ifeq在食谱中使用。只需使用普通的 shell 功能。它工作得更好。

.SECONDEXPANSION:
%.pot: $$(dir $$@)*.c
    @echo "it works"
    if [ ! -f $@ ]; then \
        : pot-file does not exist, do something; \
    else \
        : pot-file already exists, do something else; \
    fi

也就是说,在先决条件列表中使用通配符通常不是一个好主意,因为通配符的时间不可靠并且可能导致奇怪的行为。有关问题的一个示例,请参阅使用通配符的陷阱。

如果您需要根据某些外部因素(如操作系统)编写不同的配方内容,那么您需要在 make 解析时检测到该内容,并拥有两个正确切换的配方/makefile 副本。您可以内联执行操作,但不能内联执行每个食谱。

您最初的尝试(ifeq在食谱中使用)不起作用。他们不会做你认为他们会做的事。它们可能看起来有效,但并没有按照您期望的方式工作。

考虑这个makefile:

全部:c

a:
        @touch a

c: a

.SECONDEXPANSION:

c d:
ifeq (,$(wildcard a))
        @echo "a doesn't exist (make)"
else
        @echo 'a does exist (make)'
endif
        @if [ ! -f a ]; then \
            echo "a doesn't exist (sh)"; \
        else \
            echo 'a does exist (sh)'; \
        fi
ifeq (,$$(wildcard a))
        @echo "a doesn't exist (make se)"
else
        @echo 'a does exist (make se)'
endif

在一个空目录中,您希望make输出(假设ifeq按您希望的方式工作):

a does exist (make)
a does exist (sh)
a does exist (make se)

正确的?但事实并非如此。你得到:

a doesn't exist (make)
a does exist (sh)
a does exist (make se)

好吧,你认为,这只是没有二次扩展的事情。但二级扩展版本工作正常。但事实并非如此。

如果你make d在一个空目录中运行(注意d目标没有a作为先决条件列出,所以它不会创建它)你会期望以下输出:

a doesn't exist (make)
a doesn' exist (sh)
a doesn' exist (make se)

正确的?但你实际得到的是:

a doesn't exist (make)
a doesn't exist (sh)
a does exist (make se)

所以看起来二级扩展版本也不起作用。

查看 make 数据库可以解释为什么不这样做。

make -qprR | awk '/c: a/,/^$/; /d:/,/^$/'在一个空目录中运行,你会看到:

c: a
#  Implicit rule search has not been done.
#  File does not exist.
#  File has been updated.
#  Needs to be updated (-q is set).
# variable set hash-table stats:
# Load=0/32=0%, Rehash=0, Collisions=0/2=0%
#  commands to execute (from `Makefile', line 12):
        @echo "a doesn't exist (make)"
        @if [ ! -f a ]; then \
        echo "a doesn't exist (sh)"; \
        else \
        echo 'a does exist (sh)'; \
        fi
        @echo 'a does exist (make se)'


d:
#  Implicit rule search has not been done.
#  Modification time never checked.
#  File has not been updated.
#  commands to execute (from `Makefile', line 12):
        @echo "a doesn't exist (make)"
        @if [ ! -f a ]; then \
        echo "a doesn't exist (sh)"; \
        else \
        echo 'a does exist (sh)'; \
        fi
        @echo 'a does exist (make se)'

如您所见,其中不包含行,而仅包含逻辑ifeq的“正确”分支。ifeq

这就是问题所在,ifeq条件是在 make parse 时评估的,这在任何配方运行之前(因此在任何文件可以创建之前,等等)。

于 2015-11-09T17:26:28.040 回答