递归的makefile没有构建

时间:2013-03-21 17:26:38

标签: c recursion makefile

我在不同的目录中有一堆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$ 

3 个答案:

答案 0 :(得分:2)

首先你应该注意的事情:

  • 如果您将目录作为依赖项,则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只是因为{{1}}重建而重建。

答案 1 :(得分:0)

您正在定义一个名为“APP_DIRS”的变量,其中包含目录列表。没关系。

然后你做

$(APP_DIRS): make blah blah,基本上等同于rescoco ressys resvm: make blah blah

显然无效。

所以你需要假装你的$(APP_DIRS)是一个变量,而不是一个目标名称,这似乎是你正在使用它。

话虽如此,想想为什么.PHONY:所有$(APP_DIRS)都有效

答案 2 :(得分:0)

这是你可以做到的,如果你不想要它,只需删除通配符 make wildcard subdirectory targets