GNU Make-尾部的“ /”被删除了吗?

时间:2019-01-10 01:00:42

标签: makefile gnu-make

我正在制作一个在输出目录中创建多个文件的makefile。为了创建这些文件,输出目录必须已经存在,否则文件创建将失败。

这是一个最小的示例,演示了我遇到的问题:

.PHONY: default
default: dir/file.dat dir/other.dat

# In order to create these files, their parent directory must exist
dir/%.dat: | dir/
    touch "$@"

# To create a directory, use mkdir -p
%/:
    mkdir -p "$@"

运行makefile时,出现错误,提示没有任何规则可以制作dir。调试运行表明make正在从“ dir /”中删除尾随的“ /”:

root@69654136a2ae:~# make -rdf dirs.mk
GNU Make 3.81
[snipped]

Considering target file `default'.
 File `default' does not exist.
  Considering target file `dir/file.dat'.
   File `dir/file.dat' does not exist.
    Considering target file `dir'.
     File `dir' does not exist.
     Looking for an implicit rule for `dir'.
     No implicit rule found for `dir'.
     Finished prerequisites of target file `dir'.
    Must remake target `dir'.
make: *** No rule to make target `dir', needed by `dir/file.dat'.  Stop.

顺便说一句,在命令行中请求目录目标也可以:

root@69654136a2ae:~# make -rdf dirs.mk /some/dir/
GNU Make 3.81
[snipped]

Updating goal targets....
Considering target file `/some/dir/'.
 File `/some/dir/' does not exist.
 Looking for an implicit rule for `/some/dir/'.
 Trying pattern rule with stem `/some/dir'.
 Found an implicit rule for `/some/dir/'.
 Finished prerequisites of target file `/some/dir/'.
Must remake target `/some/dir/'.
mkdir -p "/some/dir/"

我怎样才能做自己想做的事?
理想情况下,我正在寻找通用解决方案。上面的示例只有一个子目录,但是实际的项目将有许多子目录,因此我想避免在任何地方复制粘贴解决方案。

2 个答案:

答案 0 :(得分:0)

是的,/被放置在dir/目标中(问题可以在GNU Make 3.81下重现)。

一种替代解决方案是使用automatic variable $(@D)来获取目标文件名的目录部分,并删除尾部斜杠。并将目录放在touch文件之前:

.PHONY: default
default: dir/file.dat dir/other.dat

# In order to create these files, make their parent directory first
dir/%.dat:
        mkdir -p $(@D)
        touch "$@"

在GNU Make 3.81下通过测试:

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
...

$ make
mkdir -p dir
touch "dir/file.dat"
mkdir -p dir
touch "dir/other.dat"

答案 1 :(得分:0)

您的%/规则仅匹配带有尾随/的目标名称。由于根据您使用的make版本的不同,可以在名称前将/尾部的/删除,也可以不删除它们。

对于一个目录,仅不要使用此结尾的dir/%.dat: | dir touch "$@" dir: mkdir -p "$@" 并且不要使用模式规则:

DIRS := dir ...
$(shell mkdir -p $(DIRS) > /dev/null)

<any-target>: <prerequisites>
    <recipe>

对于更通用的解决方案,leiyc的解决方案很好。还有其他:

  1. 如果您可以获取所有要创建的目录的列表,则可以使用以下方法一次创建所有目录:

    DIRS := dir ...
    
    .SECONDEXPANSION:
    
    <any-target>: <prerequisites> | $$(@D)
        <recipe>
    
    $(DIRS):
        mkdir -p $@
    
  2. 如果可以获取要创建的所有目录的列表,但更喜欢仅订购的先决条件,则可以使用secondary expansion和规则来创建目录:

    explain()

可能还有其他可能性...