为什么下面的makefile重建了目标;“建立”;每次

为什么下面的makefile重建了目标;“建立”;每次,makefile,gnu-make,Makefile,Gnu Make,我有以下代码来解压目录中的所有文件,并将其移动到build目录。如果我多次调用make,它每次都会尝试执行“build”目标,即使build目录已经存在。有人见过这个吗 我发现了这个问题,但它不一样。 操作系统:Ubuntu 12.04 节目:GNU Make 3.81 build: mkBuildDir untar chmod 700 build .PHONY: mkBuildDir untar mkBuildDir: mkdir build untar: *.

我有以下代码来解压目录中的所有文件,并将其移动到build目录。如果我多次调用make,它每次都会尝试执行“build”目标,即使build目录已经存在。有人见过这个吗

我发现了这个问题,但它不一样。

操作系统:Ubuntu 12.04 节目:GNU Make 3.81

build: mkBuildDir untar 
    chmod 700 build

.PHONY: mkBuildDir untar 

mkBuildDir: 
    mkdir build 

untar: *.tar.gz
    for prefix in *.tar.gz; do \
        tar xvf $$prefix --directory=build; \
    done

clean: 
    rm -Rf build
这与您链接的问题基本相同。您从未创建名为
mkBuildDir
的文件,因此它总是过期的,所以
build
总是过期的

您的
mkBuildDir
目标没有做任何有用的事情(尽管我认为这是一个精简的makefile)。如果你这样做了

# it'd be better to list the TARFILES explicitly, though this will probably work
TARFILES=`ls *.tar.gz`

all: build untar

build: $(TARFILES)
    test -d build || mkdir build
    chmod 700 build
    for prefix in $(TARFILES); do \
        tar xvf $$prefix --directory=build; \
    done

clean: 
    rm -Rf build
这可能会完成你想要的


在Makefile中有太多虚假目标通常是Makefile的“代码气味”。它们很少是最好的/惯用的做事方式。

我认为最好使用
TARFILES=$(wildcard*.tar.gz)
。在原始情况下,如果没有匹配的文件名,则
TARFILES
将是
*.tar.gz
而不是空列表。更重要的是,只需要创建一个进程就可以了。没错,但这种通配符行为只适用于某些shell中的某些设置。另外,
$(通配符…
是GNU Make扩展,因此不可移植(这可能是个问题,也可能不是问题)。最后,每一个操作行都会创建一个新的进程,因此在这里保存一个进程并没有多大好处。如果使用两个目标都需要构建目录,那么并行生成似乎会失败。mkdir-p将修复它(尽管您可能会得到不必要的命令输出)。