我在不同目录中有一堆C文件,并且我的递归Makefile出现了make: nothing to be done for 'all'错误。但是,如果我调整依赖关系,就可以使它正常工作...但是我不明白为什么必须这样做。

这是我的原始Makefile:

APP_DIRS=rescoco ressys resvm

.PHONY: all

all: $(APP_DIRS)

$(APP_DIRS):
    $(MAKE) --directory $@

clean:
    $(RM) *~


现在,如果我将行从.PHONY更改为.PHONY: all $(APP_DIRS),它可以正常运行。

另一种可能性是,如果我将行从$(APP_DIRS):更改为$(APP_DIRS): clean,则可以正常运行。

(注意:删除.PHONY目标不会改变任何内容)

那么这是怎么回事? Makefile是否试图告诉我我没有正确列出依赖项?我当时想make会做类似的事情:


建立.PHONY我首先必须建立all
建立all我首先必须建立$(APP_DIRS)
$(APP_DIRS)没有先决条件,因此请为此执行命令(这将导致递归make运行)。


显然我错了。但为什么?



仅供参考,如果很重要,我的文件的结构如下:

Makefile       #top level makefile as seen above
/rescoco
    rescoco.c
    Makefile   #builds rescoco src and moves archive to ../lib directory
/ressys
    ressys.c
    Makefile   #same as above but for ressys
/resvm
    resvm.c
    Makefile   #same as above but for resvm
/lib


而我的构建命令就是make。当我使用make -nmake -n all运行时,我根本没有输出:

:~/proj$ make -n all
make: Nothing to be done for 'all'.
:~/proj$

最佳答案

首先应该注意的事情:


如果您将目录作为依赖项,则仅当更新目录的修改时间戳时,make才会考虑构建目标(即,执行此类目录目标的配方)。
仅当您在目录中添加新文件时才会发生这种情况,而目录中的文件修改则不会发生。在子目录中添加文件不会更改目录的时间戳。
在执行此类目标时,如果不使用目标名称创建文件,则应使用PHONY目标。换句话说,无论文件是否已存在,您都希望make执行规则。


因此,您的Makefile本质上只能告诉您以下信息:


要构建目标all,我需要构建$(APP_DIRS)。由于all是PHONY目标,因此我将始终执行all的配方。
$(APP_DIRS)不是PHONY目标,没有任何依赖性。因此*仅当$(APP_DIRS)不存在(即文件或目录)时,我才执行配方,否则将不对该目标执行任何操作。
clean没有先决条件,也不是PHONY,因此我希望仅在由make(从命令行或其他Makefile)显式调用时执行此规则。此外,clean不是PHONY,因此我希望配方在执行后创建一个名为clean的文件(这对您而言不正确)


因此,将.PHONY行更改为:

.PHONY: all $(APP_DIRS)


使Makefile进入并始终执行$(APP_DIRS)的配方。

因此,如果您希望make始终遍历所有$(APP_DIRS)目录并在其上再次调用make,则需要在$(APP_DIRS)中添加.PHONY,这会使$(APP_DIRS)成为PHONY目标,并执行配方,无论文件/目录的时间戳是否存在。

对于您的特定用例,我认为这是您应该使用的Makefile:

APP_DIRS=rescoco ressys resvm

.PHONY: all clean $(APP_DIRS)

all: $(APP_DIRS)

$(APP_DIRS):
    $(MAKE) --directory $@

clean:
    $(RM) *~


奖金:


$(APP_DIRS):更改为$(APP_DIRS): clean意味着$(APP_DIRS)取决于clean目标。
尽管clean没有标记为PHONY,但make在当前目录中看不到名为clean的文件。因此,它继续尝试执行clean的配方。
由于建立了$(APP_DIRS)的依存关系(即clean),因此使Makefile执行构建$(APP_DIRS)的方法。


这给我们带来了一个有趣的观察:
-任何依赖于PHONY目标的目标都将始终被重建(即将执行配方)。

使用以下简单的Makefile:

all: target1

target1: target2
    @echo "$@"
    @touch $@

target2: target3
    @echo "$@"
    @touch $@

target3:
    @echo "$@"

.PHONY: all target3


我第一次运行make时,看到以下输出:

target3
target2
target1


此后,将创建文件target1target2。即使这样,如果再次运行make,也会看到输出:

target3
target2
target1


如您所见,PHONY依赖关系向上传播,而不是向下传播。 target2仅由于target3是PHONY而被重建,而target1仅由于target2被重建而被重建。

07-24 21:15