可以让 Make 理解 a/../z 和 b/../z 是同一个位置吗?

Can Make be made to understand that a/../z and b/../z are the same location?

我有一个有点大且复杂的 Makefile 设置,用于对一些数据文件进行后处理。总的来说它工作得很好,但是我 运行 遇到了一个烦人的问题,即 Make 在不同的目录名称下多次构建相同的目标。

作为一个简单的例子,考虑 Makefile

foo : 1/foo 2/foo
    cat $^ > $@

%/foo : %/../bar
    cat $^ > $@

%/bar : %/baz
    cat $^ > $@

使用文件 baz 和目录 12 初始化,当以并行模式完成时,make 将生成以下一系列构建:

cat 1/../baz > 1/../bar
cat 2/../baz > 2/../bar
cat 2/../bar > 2/foo
cat 1/../bar > 1/foo
cat 1/foo 2/foo > foo
rm 2/../bar

请注意前两个命令是如何做完全相同的事情的。

有没有办法让 Make 相信 1/../bar2/../bar 是同一个文件,所以它只应该做一次那个食谱?

您可以使用 realpath or abspath 函数使用绝对路径,而不是使用相对路径:

$(realpath names…)

For each file name in names return the canonical absolute name. A canonical name does not contain any . or .. components, nor any repeated path separators (/) or symlinks. In case of a failure the empty string is returned. Consult the realpath(3) documentation for a list of possible failure causes.

$(abspath names…)

For each file name in names return an absolute name that does not contain any . or .. components, nor any repeated path separators (/). Note that, in contrast to realpath function, abspath does not resolve symlinks and does not require the file names to refer to an existing file or directory. Use the wildcard function to test for existence.

$(abspath foo): $(abspath 1/foo) $(abspath 2/foo)
        cat $^ > $@

%/foo: $(abspath %/../bar)
        cat $^ > $@

%/bar: %/baz
        cat $^ > $@

或类似的东西:

TOP := $(abspath .)

$(TOP)/foo: $(TOP)/1/foo $(TOP)/2/foo
        cat $^ > $@

%/foo: $(abspath %/../bar)
        cat $^ > $@

%/bar: %/baz
        cat $^ > $@

这是结果

jmlemetayer@prometheus:~/foobar$ make -j5
cat /home/jmlemetayer/foobar/baz > /home/jmlemetayer/foobar/bar
cat /home/jmlemetayer/foobar/bar > /home/jmlemetayer/foobar/1/foo
cat /home/jmlemetayer/foobar/bar > /home/jmlemetayer/foobar/2/foo
cat /home/jmlemetayer/foobar/1/foo /home/jmlemetayer/foobar/2/foo > /home/jmlemetayer/foobar/foo
rm /home/jmlemetayer/foobar/bar