使用GNU make处理项目间依赖项

时间:2017-08-08 11:00:43

标签: makefile gnu-make

我有两个用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包括在内。

有没有更好的方法可以让我做我想做的事情?

2 个答案:

答案 0 :(得分:1)

你可以添加一个虚假的目标,其中包含制作另一个项目的配方,即使没有任何事情可以制作它,然后启动第二个子制作来制作你的实际目标:

.PHONY: all

all:
    $(MAKE) -C ../ProjectA OUTPUT
    $(MAKE) target

target: ../ProjectA/OUTPUT
    do stuff

不是很优雅而且效率不高但它应该做你想做的事情:

  1. 始终尝试重建../ProjectA/OUTPUT
  2. 如果../ProjectA/OUTPUT发生了更改,请重建target
  3. 还有另一种方式,更优雅和高效,但它使用了一个相当模糊的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我喜欢双结肠配方。对我来说似乎更清洁了。)