【问题标题】:How to prevent SBT from recompiling modified .class files?如何防止 SBT 重新编译修改的 .class 文件?
【发布时间】:2014-11-17 11:35:18
【问题描述】:

在我们的项目中,我们对 compile 生成的 .class 文件进行了增强后处理。这个增强步骤实际上修改了生成的 .class 文件然后覆盖它。

enhance <<= enhance triggeredBy (compile in Compile)

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

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

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

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

【问题讨论】:

  • 使用已编译的类创建单独的项目,并将其作为依赖项(库)添加到您的游戏项目中。
  • @AndrzejJozwik 感谢您的评论。您建议的方式不是首选,因为它距离我们的目标还有很长的路要走。由于我们的项目是一个非常大的项目,增加的复杂性可能会导致更多的问题。我们想要一种直接解决问题的方法。

标签: scala sbt incremental-compiler


【解决方案1】:

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"
  ...
}

无论如何都要重新连接productDirectories 以使用crossTarget.value / "classes"(否则它会在您修改后的classDirectory 中查找:

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

确保products 依赖于您的enhance 任务:

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

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

【讨论】:

    【解决方案2】:

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

    经过一番研究,我们发现 sbt 会通过上次修改时间来通知文件的修改。也就是说,我们可以通过在修改后回滚上次修改时间来愚弄sbt,这样sbt就不会注意到任何变化。

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

    1. 查找所有 .class 文件
    2. 记下他们的上次修改时间
    3. 做增强
    4. 放回以前的上次修改时间

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

    【讨论】:

      【解决方案3】:

      说明:

      有点像Chenyu,我必须为SBT 1.x写一个插件,它会增强编译类,后来我想确保那些增强类用于构建 jar

      我不想破解这个解决方案,所以Chenyu's answer 对我来说是不可接受的,sjrd's answer 非常有帮助,但调整为SBT 0.13

      所以这是我的工作解决方案,只有很少的 cmets:

      代码:

      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
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-15
        • 1970-01-01
        • 2018-08-08
        • 1970-01-01
        • 2019-02-17
        • 2011-03-18
        相关资源
        最近更新 更多