如何防止SBT重新编译修改后的.class文件?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何防止SBT重新编译修改后的.class文件?相关的知识,希望对你有一定的参考价值。

在我们的项目中,我们对通过编译生成的.class文件进行了增强后处理。此增强步骤实际上会修改生成的.class文件,然后覆盖它。

enhance <<= enhance triggeredBy (compile in Compile)

问题是sbt有一种称为增量重新编译的机制。它监视生成的.class文件。每次增强器覆盖生成的.class文件时,sbt都会识别这些修改并在下一个编译命令中重新编译相关的源。

对我们来说,重新编译是一项非常耗时的工作。我们希望阻止sbt重新编译修改后的.class文件。这可能意味着使sbt仅监视源更改,而不是输出更改。

我做了一些搜索。但我发现了一些关于这一点的事情。现在我知道一个名为Analysis的特性可能负责从源到输出.class文件的映射。所以我向你们求助。

Ps:我们可以通过将增强的输出放到另一个文件夹来解决这个问题,但不是首选。

答案

sbt strongly discourages mutations to files。您应该生成不同的文件。通过这样做,您将解决您的问题,因为sbt的增量编译器仍将查看未更改的.class文件。你会做一些重新布线:

在其他地方发送compile任务的输出:

classDirectory in Compile := crossTarget.value / "classes-orig"

使用您的工具处理这些.class文件,并将它们发送到crossTarget.value / "classes"(原始的classDirectory

enhance <<= enhance triggeredBy (compile in Compile)

enhance := {
  val fromDir := (classesDirectory in Compile).value
  val toDir := crossTarget.value / "classes"
  ...
}

无论如何,rewire productDirectories使用crossTarget.value / "classes"(否则它将继续查看你修改过的classDirectory

productDirectories in Compile := Seq(crossTarget.value / "classes")

确保products取决于你的enhance任务:

products in Compile <<= (products in Compile) dependsOn enhance

如果您有资源,可能需要更多重新布线(请参阅copyResources)。但基本上你应该能够到达那里。

另一答案

我说过sbt监视输出.class文件。修改.class文件时,它会重新编译.class文件的源代码。

经过一些研究,我们发现sbt通知文件按其上次修改时间进行修改。也就是说,我们可以通过回滚修改后的最后修改时间来欺骗sbt,以便sbt不会注意到任何更改。

所以,我们的解决方案很简单但有效:

  1. 找到所有.class文件
  2. 记下他们上次修改时间
  3. 加强
  4. 放回前一个修改时间

这是一个小技巧。我们仍期待更强大的解决方案。

另一答案

描述:

有点像Chenyu,我不得不为SBT 1.x编写一个插件,这将增强编译类,后来我想确保这些增强类用于构建jar

我不想破解这个解决方案,所以Chenyu's answer不被我接受,sjrd's answer非常有帮助,但调整到SBT 0.13

所以这是我的工作解决方案,几乎没有评论:

码:

object autoImport {
  val enhancedDest = settingKey[File]("Output dir for enhanced sources")
}

def enhanceTask: Def.Initialize[Task[Unit]] = Def.task {
  val inputDir = (classDirectory in Compile).value
  val outputDir = enhancedDest.value
  enhance(inputDir, outputDir)
  ...
}

override def projectSettings: Seq[Def.Setting[_]] = Seq(
  enhancedDest := crossTarget.value / "classes-enhanced",
  products in Compile := Seq(enhancedDest.value), // mark enhanced folder to use for packaging

  // https://www.scala-sbt.org/1.0/docs/Howto-Dynamic-Task.html#build.sbt+v2
  compile in Compile := Def.taskDyn {
    val c = (compile in Compile).value // compile 1st.
    Def.task {
      (copyResources in Compile).value // copy resources before enhance        
      enhanceTask.value                // enhance
      c
    }
  }.value
)

以上是关于如何防止SBT重新编译修改后的.class文件?的主要内容,如果未能解决你的问题,请参考以下文章

sbt总是重新编译CI中的完整项目,即使使用缓存?

Tomcat无法编译加载class文件

使用 SBT 将编译后的 Scala 文件打包到 jar 中

eclipse编译后的class文件在哪

gitlab ci:sbt 在每个阶段重新编译

修改代码运行的还是旧代码