我在不同的目录中有一堆 C 文件,并且我的递归 Makefile 出现 make: Nothing to be do 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
是一个假目标,我将始终执行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
是假冒的,并且 target1
被重建只是因为 target2
已重建。
关于c - 递归生成文件未构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15554172/