我有两个用GNU make构建的项目。项目B依赖于项目A的一个输出。我们称之为OUTPUT。所以项目B的Makefile包含这样的内容:
target: ../ProjectA/OUTPUT
do stuff
为了确保OUTPUT是最新的,我希望B的Makefile为A启动make,然后只做"做东西"如果OUTPUT被重建(或者已经比目标更新)。
我首先尝试这样做:
../ProjectA/OUTPUT:
(cd ../ProjectA; $(MAKE) OUTPUT)
但由于没有给出OUTPUT的依赖关系,make会假设它是最新的,如果它存在并且不会运行sub-make。
将OUTPUT声明为虚假确保子make将运行:
.PHONY: ../ProjectA/OUTPUT
../ProjectA/OUTPUT:
(cd ../ProjectA; $(MAKE) OUTPUT)
但现在make将忽略OUTPUT上的实际日期,并始终认为它比目标更新,意思是"做东西"将永远执行。
我唯一能找到工作的是在B&#39的Makefile中复制OUTPUT的整个依赖树。这太可怕了。只有稍微不那么可怕的是将OUTPUT的依赖树放在一个单独的文件中,两个项目的Makefile包括在内。
有没有更好的方法可以让我做我想做的事情?
答案 0 :(得分:1)
你可以添加一个虚假的目标,其中包含制作另一个项目的配方,即使没有任何事情可以制作它,然后启动第二个子制作来制作你的实际目标:
.PHONY: all
all:
$(MAKE) -C ../ProjectA OUTPUT
$(MAKE) target
target: ../ProjectA/OUTPUT
do stuff
不是很优雅而且效率不高但它应该做你想做的事情:
../ProjectA/OUTPUT
。../ProjectA/OUTPUT
发生了更改,请重建target
。还有另一种方式,更优雅和高效,但它使用了一个相当模糊的GNU make功能:双冒号规则(参见this section of the manual),以一种相当不寻常的方式,并且它肯定不是发明:
target: ../ProjectA/OUTPUT
do stuff
../ProjectA/OUTPUT::
$(MAKE) -C ../ProjectA OUTPUT
所以,如果你不喜欢默默无闻,那就选择第一个。至少,它更容易理解,并且没有人会通过删除额外的冒号来打破它,肯定是错字......
答案 1 :(得分:0)
嗯,我不知道双重冒号规则是这样的。这非常有用。
只是为了记录,有一种方法可以让 make 尝试重建../ProjectA/OUTPUT
每次稍微不那么模糊(?)。基本上,您使用中间.PHONY
目标。
.PHONY: FORCE
FORCE: ;
../ProjectA/OUTPUT: FORCE
${MAKE} -C ${@D} ${@F}
由于FORCE
, make 会意识到OUTPUT
可能已过期。它将运行配方,然后检查OUTPUT
是否实际更新。
(FWIW我喜欢双结肠配方。对我来说似乎更清洁了。)