3

我有这样的规则:

"foo" *> \out do
  need something
  create "foo" somehow

它已正确构建,并且运行构建两次不会构建目标。然后我在这个规则中添加一个系统:

"foo" *> \out do
  ...
  system' something

现在运行shake 不会重建“foo”目标,因为没有更改依赖项。总之,规则变了。所以我希望新添加的系统动作会改变规则的历史,进而强制重建“foo”,但事实并非如此。通常在 autoconf/automake 系统中,甚至在非平凡的 makefile 中,规则依赖于 Makefile 本身,因此无论何时更改项目都会重新构建。在 Shake 中,我希望它能够工作并且是细粒度的。

在 system' 的源代码中,我看不到任何对正在运行的命令添加隐式依赖的内容。

难道我做错了什么?是有意不支持这种依赖关系,还是根本没有实现?

4

1 回答 1

2

您看到的行为是预期的,ICFP 2012 论文S6.2 概述了一些应对策略。如果每个输出都依赖于用于构建它的规则,那将是理想的,但这需要一些规则上的相等性(它们只是在执行期间源代码不可用的函数)。有一天,我希望 Shake 能像你描述的那样工作,但我认为目前在 GHC 中是不可能的。

为了最大限度地减少构建系统更改的数量,最好将您认为会定期更改的任何内容保留在构建系统之外。任何文件列表(例如链接 C 可执行文件所需的文件)都可以放入配置文件中,或者通过使用 oracle 机制正确依赖。

当然,规则仍会不时更改,您可以采取两种方法:

如果有任何变化,重建一切

许多 Makefile 采用的一种简单的保守方法是,如果有任何变化,则重新构建所有内容。实现此策略的一种简单方法是对 Shake 脚本进行哈希处理,并将其用作shakeVersion字段。对于重建速度相当快的项目,这可以很好地工作。

手动控制重建

对于较大的项目,构建系统通常每天都在变化,但构建系统的大部分部分对大多数规则没有影响。对于某些规则,我在规则中明确need了一些源文件,例如,如果文件中有一个大型生成器,我会need在规则中生成生成的输出。如果您还使用writeFileChanged编写生成的文件,那么对生成器的许多修改只会导致最小的重建。

如果更改更具侵入性,我手动增加shakeVersion 字段,并强制完全重建。在具有适当依赖跟踪的成熟构建系统中,此事件可能每年仅发生几次。

于 2013-02-14T22:41:59.853 回答