我在不同目录中有一堆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 -n
或make -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
此后,将创建文件
target1
和target2
。即使这样,如果再次运行make
,也会看到输出:target3
target2
target1
如您所见,
PHONY
依赖关系向上传播,而不是向下传播。 target2
仅由于target3
是PHONY而被重建,而target1
仅由于target2
被重建而被重建。