0

I have a bunch of C files in different directories and I'm getting a make: nothing to be done for 'all' error with my recursive Makefile; however if I tweak the dependences I can get it to work... but I don't understand why I have to.

Here's my original Makefile:

APP_DIRS=rescoco ressys resvm

.PHONY: all

all: $(APP_DIRS)

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

clean:
    $(RM) *~

Now if I change my line: .PHONY to .PHONY: all $(APP_DIRS) it builds fine.

Another possibility is if I change the line: $(APP_DIRS): to $(APP_DIRS): clean it builds fine.

(NOTE: removing .PHONY target doesn't change anything)


So what's going on here? Is the Makefile trying to tell me I haven't listed dependencies correctly? I was thinking make would do something like:

  • to build .PHONY I first have to build all
  • to build all I first have to build $(APP_DIRS)
  • $(APP_DIRS) has no prereqs so execute the command for that (which would cause the recursive makes to run).

Clearly I am wrong; but why?


FYI, if it matters my files are structured something like this:

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

and my build command is simply make. When I run with make -n or make -n all I get no output at all:

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

3 回答 3

2

首先你应该知道的事情:

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

所以你的 Makefile 基本上只告诉这个:

  • 要构建目标all,我需要构建$(APP_DIRS). 由于all是 PHONY 目标,我将始终执行all.
  • $(APP_DIRS)不是PHONY目标,也没有任何依赖关系。所以*仅当 $(APP_DIRS)不存在时(即文件或目录),我将执行配方,否则我不会为这个目标做任何事情。
  • clean没有先决条件,也没有 a PHONY,所以我希望只有在 make 显式调用(从命令行或另一个 Makefile)时才执行此规则。clean也不是 a PHONY,所以我希望配方创建一个在执行后调用的文件(clean这对您的情况不正确)

因此将.PHONY行更改为:

.PHONY: all $(APP_DIRS)

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

因此,如果您希望 make 始终遍历所有 $(APP_DIRS) 目录并在它们上再次调用 make,则需要添加$(APP_DIRS)to .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) (ie 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是假的,而target1被重建只是因为target2被重建。

于 2013-03-21T17:54:27.857 回答
0

这是你可以做到的,如果你不想要它,只需删除通配符。
制作通配符子目录目标

于 2013-03-21T17:59:24.600 回答
0

您正在使用目录列表定义一个名为“APP_DIRS”的变量。那也行。

然后你做

$(APP_DIRS): make blah blah,这基本上相当于rescoco ressys resvm: make blah blah

这显然是无效的。

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

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

于 2013-03-21T17:57:26.567 回答