是什么决定SBT中的重新编译?

时间:2015-01-13 17:39:33

标签: caching sbt targets

背景

我有一个SBT项目将会有大量的子项目。在VCS更改(拉动,切换分支等)之后,可能需要时间来重新编译。我希望通过采用策略在每个子项目的基础上拥有分布式缓存来减少时间。 Buck对这种策略有很好的解释:

  

构建规则知道可能影响其输出的所有输入,因此它可以将该信息组合成表示总输入的哈希。

     

当Buck开始构建构建规则时,它首先要做的是计算规则的缓存密钥。如果.buckconfig中指定的任何缓存中都有命中,那么它将从缓存中获取规则的输出,而不是在本地构建规则。

     

如果您正在使用某种持续集成(CI)系统,您可能希望CI构建填充可由本地构建读取的缓存。这样,当开发人员同步到已在CI系统上构建的修订版时,运行buck build不应在本地构建任何内容,因为所有输出都应该能够从缓存中提取。

所以我希望能够在满足缓存键时填充target


问题

问题是,我似乎无法弄清楚SBT何时想要重新编译。

build.properties

sbt.version=0.13.7

的src /主/阶/ Foo.scala

class Foo {}

首先编译:

$ sbt compile
[info] Compiling 1 Scala source
[success]

更改源会触发重新编译

$ echo >> src/main/scala/Foo.scala
$ sbt compile
[info] Compiling 1 Scala source
[success]

更改源时间戳不会触发重新编译

$ touch src/main/scala/Foo.scala
$ sbt compile
[success]

更改目标时间戳会触发重新编译

$ touch target/scala_2.10/classes/Foo.class
$ sbt compile
[info] Compiling 1 Scala source
[success]

SBT如何知道目标何时与来源不匹配? (我能否以SBT接受目标的方式放置目标?)

1 个答案:

答案 0 :(得分:1)

答案有点复杂。我们采用类似于buck的一些方法,但没有预先考虑具有全局可分布缓存。

基本上,这是一般要点:

  1. 我们看看文件的哈希值。我相信这是可配置的,但只是触摸文件可能不足以将其标记为已更改。您可能还需要添加一个影响文件SHA-1的空格或其他内容。
  2. 我们查看文件公开的API。这是使用我们称之为“名称哈希”的方式完成的。这实质上是尝试构造源文件中使用的名称哈希,以确定一个源文件中的更改是否会影响另一个源文件。
  3. 我们检查生成的二进制文件,看看自上次生成它们后它们是否已更改。如果是这样,我们就会抛弃我们所知道的事情,并假设我们必须重新做一遍以保证安全(即我们的沙盒中已经有一些外部过程在玩,我们不知道表面下方是否有某些东西隐藏) 。
    1. 我们检查是否有任何JAR依赖项被修改,或者是否有任何新的
    2. 我们检查是否有任何编译器标志发生了变化(例如-optimise需要重新编译)。
  4. 最近的第三点让我们遇到了外部字节码操作库的问题。我们最近扩展了默认构建以适应构建之前我们构建关于我们所做的哈希/缓存信息,请参阅:https://github.com/sbt/sbt/pull/1714

    希望这有助于澄清。我们的支票可能还有更多。其中大部分位于sbt。{/ p>的compile/目录中