Makefile GNU make with VPATH:target,它看起来是圆形的,但实际上不应该';不可能

Makefile GNU make with VPATH:target,它看起来是圆形的,但实际上不应该';不可能,makefile,gnu-make,circular-dependency,Makefile,Gnu Make,Circular Dependency,我的Makefile中有一条规则,用于创建指向不同目录中文件的符号链接: VPATH = ../source foo: foo ln -s $< $@ VPATH=../source 福:福 ln-s$

我的
Makefile
中有一条规则,用于创建指向不同目录中文件的符号链接:

VPATH = ../source
foo: foo
    ln -s $< $@
VPATH=../source
福:福
ln-s$<$@

尽管我希望目标解析为
/foo
,依赖解析为
。/source/foo
,但我理解为什么
make
将其视为循环。是否有一种非循环的方式来表达此规则?

请注意,链接不依赖于链接目标的更改;它只需要存在。因此,根本不需要普通的先决条件,要想做什么,最简单的片段就是

foo:
    ln -sf ../source/$@
但是,如果您仍需要
VPATH
用于其他目的,则此功能无法正常工作。如果是这样,那么在我看来,最简单的方法就是使用绝对路径忽略此规则的
VPATH

VPATH := ../source
$(CURDIR)/foo:
    ln -sf ../source/$(@F)
最后,如果文件
。/source/foo
也是Make生成的目标,那么最好的方法可能是:

VPATH := ../source

.SECONDEXPANSION:
$(CURDIR)/foo: | ../source/$$(@F)
    ln -sf $|
请注意,这里我们并不依赖于先决条件的变化,只依赖于它的存在


顺便说一下,我之所以使用
-f
选项,是因为Make应该支持
-B
选项。除非在此处使用
-f
,否则该选项将不起作用

我认为你在这里尝试的属于“虚拟路径滥用”的范畴

我的经验不断地向我指出“显式优于隐式”这是其中一个原因。与GNU make手册中的断言相反,我的经验让我相信,在更大、更复杂的项目中,您需要更明确,而不是更少,因为文件的大小使得定位文件更加困难,除非它们的路径是明确的

我还认为,使用VPATH的许多需求源于使用递归make,在这里您没有构建完整的依赖树;正确地编写构建系统,您根本不需要VPATH

在一个相关主题上,我坚信只指定一个或两个
-I
目录:您的顶级
src/
include/
目录,并使所有inclusion都与这些路径相关。同样,在更大、更复杂的项目中,seing
#include“my/really/cool/thing.h”
比简单的
#include“thing.h”
信息量大得多


也就是说,我愿意为库使用VPATH,特别是系统库,因为您可以使用
-lfoo
语法,但我不想将其作为一般规则使用,因为它可能威胁到构建的可复制性。

为什么不将
foo
作为依赖项删除并更改
$将依赖项更改为
。/source/foo
并删除
VPATH
似乎可行,尽管这意味着我必须修改
Makefile
中依赖于
VPATH
的任何其他内容。我希望避免这样,但这不是太多的工作。