首页 > 解决方案 > SBT:编译前为子模块生成代码

问题描述

我对 build.sbt 配置有以下问题。我需要在编译之前生成一些代码。这就是它现在的工作方式。

lazy val rootProject = project.in(file("."))

lazy val rootSourceGenerator = Def.task {
  val f: File = (sourceManaged in Compile).value / "com" / "myproject" / "Version.scala"

  IO.write(
    f,
    s"""package com.myproject
       |
       |object Version {
       |  some code ...
       |}
       |""".stripMargin
  )

  Seq(f)
}

inConfig(Compile)(
  Seq(
    sourceGenerators += rootSourceGenerator
  ))

现在我需要为一个新的子模块做同样的事情。

lazy val rootProject = project.in(file(".")).dependsOn(submodule)
lazy val submodule = project.in(file("submodule"))

lazy val submoduleSourceGenerator = Def.task {
  val f: File = (sourceManaged in (submodule, Compile)).value / "com" / "myproject" / "SubmoduleVersion.scala"

  IO.write(
    f,
    s"""package com.myproject
       |
       |object SubmoduleVersion {
       |  some code ...
       |}
       |""".stripMargin
  )

  Seq(f)
}

inConfig(submodule / Compile)(
  Seq(
    sourceGenerators += submoduleSourceGenerator
  ))

并且inConfig(submodule / Compile)不起作用。错误是关于/. 任何建议如何解决这个问题?

标签: scalasbtcode-generation

解决方案


有多种解决方案,但我认为最干净的是遵循。

使用以下内容创建AutoPluginproject/GenerateVersion.scala

import sbt.Keys._
import sbt._

object GenerateVersion extends AutoPlugin {
  override def trigger = noTrigger

  override def projectSettings: Seq[Def.Setting[_]] = {
    Seq(
      sourceGenerators in Compile += Def.task {
        val f: File =
          (sourceManaged in Compile).value / "com" / "myproject" / "Version.scala"
        IO.write(
          f,
          s"""package com.myproject
                 |
                 |object Version {
                 |}
                 |""".stripMargin
        )
        Seq(f)
      }.taskValue
    )
  }
}

GenerateVersion为所有需要Version.scala生成的项目/子模块启用新创建的插件。可以按照以下方式完成build.sbt

lazy val sub = project
  .in(file("sub"))
  .enablePlugins(GenerateVersion)

lazy val root = project
  .in(file("."))
  .enablePlugins(GenerateVersion)
  .aggregate(sub)

aggregate(sub)sub在触发根任务时添加以运行模块中的任务。例如,sbt compile将同时运行sbt "root/compile" "sub/compile"

这个解决方案更容易以 SBT 插件的形式在多个 SBT 项目中共享。

另外,您可能对sbt-builtinfo插件感兴趣


推荐阅读