Makefile % match-anything 规则选择 "Makefile" 目标

Makefile % match-anything rule picks up "Makefile" target

我正在尝试编写一个通用的 Makefile 来将源代码树与某个远程主机同步,ssh 进入它并在那里执行 make,转发任何目标或变量覆盖

到目前为止我想到了这个:

HOST ?= host
DIR ?= ~/dev

SRC = src

all:

.PHONY: sync
sync:
    rsync -azP --exclude ".*/" --exclude ".*" $(SRC)/ $(HOST):$(DIR)

%: sync
    ssh $(HOST) 'cd $(DIR) && make $@ MAKEFLAGS=$(MAKEFLAGS)'

只要我在 % 目标的依赖列表中省略 sync 就可以很好地工作。一旦我重新添加它,Makefile 目标由于某种原因被拾取,导致它通过 ssh 进入远程机器和 运行 make Makefile,这不是有效的目标或预期的行为

澄清一下,我自己并没有指定 Makefile 作为目标。我愿意

make
make clean

所有这些都会导致 Makefile 目标成为 运行 而不管

GNU make automatically attempts to rebuild the makefile(s) before building the designated targets or default target。其他 make 实现不一定会这样做。 GNU make 手册包含关于您的特定问题的建议:

If you know that one or more of your makefiles cannot be remade and you want to keep make from performing an implicit rule search on them, perhaps for efficiency reasons, you can use any normal method of preventing implicit rule look-up to do so. For example, you can write an explicit rule with the makefile as the target, and an empty recipe [...]

空配方方法是添加如下规则:

Makefile: ;

有了你的 makefile 中的那个(文件名是 Makefile),当 make 寻找一个规则来重建 Makefile 时,它会选择明确的,空的规则而不是 match-anything 通配符规则。像这样写会更健壮一些,但是:

$(MAKEFILE_LIST): ;

MAKEFILE_LIST 变量包含 make 读取的所有 makefile 的名称,因此即使您向 makefile 添加 include 指令或访问它,它也会覆盖您使用 -f 命令行选项从不同的目录或通过不同的名称。