Makefile依赖项不适用于虚假目标

时间:2012-12-13 03:38:09

标签: makefile dependencies

这是我的Makefile的简化版本:

.PHONY: all 

all: src/server.coffee
  mkdir -p bin
  ./node_modules/.bin/coffee -c -o bin src/server.coffee

我想运行make并且仅在src/server.coffee发生更改时重新编译它。但是,每次运行make时都会重新编译:

$ make
mkdir -p bin
./node_modules/.bin/coffee -c -o bin src/server.coffee
$ make
mkdir -p bin
./node_modules/.bin/coffee -c -o bin src/server.coffee

如果我将Makefile更改为不使用虚假目标,则按预期工作。新的Makefile:

bin/server.js: src/server.coffee
  mkdir -p bin
  ./node_modules/.bin/coffee -c -o bin src/server.coffee

结果:

$ make
mkdir -p bin
./node_modules/.bin/coffee -c -o bin src/server.coffee
$ make
make: `bin/server.js' is up to date.

为什么它不尊重我对虚假目标的依赖?我问的原因是因为实际上,我不仅仅是将一个文件编译成一个其他文件,所以我不想跟踪所有输出文件的名称以便使用作为目标。

4 个答案:

答案 0 :(得分:12)

根据Make文档:

The prerequisites of the special target .PHONY are considered
to be phony targets. When it is time to consider such a target, 
make will run its recipe unconditionally, regardless of whether 
a file with that name exists or what its last-modification time is.

http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

无条件地运行PHONY目标的配方 - 先决条件无关紧要。

答案 1 :(得分:11)

而不是虚假的目标(正如@cmotley指出的那样,正如它应该的那样工作)当你想要避免额外的工作时你可以使用的是"empty target"

  

空目标是伪目标的变体;它用于保存您不时明确请求的操作的配方。与虚假目标不同,此目标文件确实存在;但文件的内容无关紧要,通常都是空的。

     

空目标文件的目的是记录上次修改时间,上次执行规则的配方时。这样做是因为配方中的一个命令是用于更新目标文件的触摸命令。

然而,在这种情况下,实际上不需要添加额外的空输出文件 - 您已经拥有了CoffeeScript编译的输出!这符合更典型的Makefile模式,正如您在问题中已经证明的那样。你能做的是重构这种方法:

.PHONY: all
all: bin/server.js

bin/server.js: src/server.coffee
  mkdir -p bin
  ./node_modules/.bin/coffee -c -o bin src/server.coffee

现在你有两件事:一个很好的传统“全部”目标是正确的虚假,但不会做额外的工作。您也可以更好地使其更通用,以便您可以轻松添加更多文件:

.PHONY: all
all: bin/server.js bin/other1.js bin/other2.js

bin/%.js: src/%.coffee
  mkdir -p bin
  ./node_modules/.bin/coffee -c -o bin $<

答案 2 :(得分:5)

需要有一些目标文件与server.coffee文件的修改时间进行比较。由于您没有具体的目标make无法知道输出是否比依赖项更新,因此它始终会构建all

答案 3 :(得分:2)

正如其他人所提到的,make会查看文件的时间戳,以确定依赖项是否已更改。

如果你想&#34;模仿&#34;如果是具有依赖关系的虚假目标,则必须使用该名称创建一个真实文件并使用touch命令(在Unix系统上)。

如果更改了makefile,我需要一个只清理目录的解决方案(即编译器标志已更改,因此需要重新编译目标文件)。

这是我使用名为makefile_clean的文件时使用(并在每次编译之前运行):

makefile_clean: makefile
    @rm '*.o'
    @sudo touch makefile_clean

touch命令将上次修改的时间戳更新为当前时间。