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

Caching 什么决定了SBT中的重新编译?,caching,sbt,targets,Caching,Sbt,Targets,背景 我有一个SBT项目,将有大量的子项目。VCS更改(拉、切换分支等)后,重新编译可能需要很长时间。我想通过采用一种策略来减少时间,即在每个子项目的基础上拥有一个分布式缓存。对这种策略有很好的解释: 构建规则知道可能影响其输出的所有输入,因此它可以将这些信息组合成表示总输入的哈希 当Buck开始构建一个构建规则时,它要做的第一件事就是计算该规则的缓存键。如果在.buckconfig中指定的任何缓存中有命中,那么它将从缓存中获取规则的输出,而不是在本地构建规则 如果您正在使用某种类型的持续集成(

背景

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

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

当Buck开始构建一个构建规则时,它要做的第一件事就是计算该规则的缓存键。如果在.buckconfig中指定的任何缓存中有命中,那么它将从缓存中获取规则的输出,而不是在本地构建规则

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

因此,我希望能够在满足缓存键时填充
target


问题

问题是,我似乎无法确定SBT何时想要重新编译

build.properties

sbt.version=0.13.7
src/main/scala/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]
更改源时间戳不会触发重新编译

$ 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]
更改目标时间戳会触发重新编译

$ 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接受的方式放置目标吗?

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

基本上,这里是总体要点:

  • 我们查看文件的散列。我相信这是可配置的,但仅仅触摸一个文件可能不足以将其标记为已更改。您可能还需要添加影响文件SHA-1的空间或其他内容
  • 我们看一下该文件公开的API。这是通过使用我们称之为“名称哈希器”来完成的。这实际上是试图构造源文件中使用的名称的散列,以确定一个源文件中的更改是否会影响另一个源文件

  • 我们检查生成的二进制文件,看看它们自上次生成以来是否发生了更改。如果是这样的话,我们扔掉我们所知道的关于我们所做的事情,并假设我们必须重新做一遍以确保安全(即,一些外部过程一直在我们的沙箱中进行,我们不知道是否有东西隐藏在表面下)。
  • 我们检查是否有任何JAR依赖项被修改,或者是否有任何新的依赖项
  • 我们检查编译器标志是否已更改(例如,
    -optimize
    需要重新编译)
  • 第三点最近给我们带来了外部字节码操作库的麻烦。我们最近扩展了默认构建,以便在构建有关我们所做工作的哈希/缓存信息之前,将这些内容纳入构建中,请参见:


    希望这有助于澄清。我们的支票上可能还有更多。大部分都在sbt的
    compile/
    目录中。

    “例如,一些外部进程一直在我们的沙箱中运行”…是的,就是我:)你知道我如何从外部填充目标吗?你可能想问游戏开发人员他们现在使用的解决方法。我认为您必须更新并重新持久化增量编译器缓存。直到sbt 0.13.8,您才能将字节码生成器注入到公开的钩子中。。。。。