4

使用 sbt 在 Scala 上构建我的项目,我想要一个在实际 Scala 编译之前运行的任务,并将生成一个Version.scala包含项目版本信息的文件。这是我想出的一个任务:

lazy val generateVersionTask = Def.task {
  // Generate contents of Version.scala
  val contents = s"""package io.kaitai.struct
                    |
                    |object Version {
                    |  val name = "${name.value}"
                    |  val version = "${version.value}"
                    |}
                    |""".stripMargin

  // Update Version.scala file, if needed
  val file = (sourceManaged in Compile).value / "version" / "Version.scala"
  println(s"Version file generated: $file")
  IO.write(file, contents)
  Seq(file)
}

这个任务似乎可行,但问题是如何插入它,因为它是一个跨项目,针对 Scala/JVM、Scala/JS 等。

这是build.sbt我开始触摸它之前的样子:

lazy val root = project.in(file(".")).
  aggregate(fooJS, fooJVM).
  settings(
    publish := {},
    publishLocal := {}
  )

lazy val foo = crossProject.in(file(".")).
  settings(
    name := "foo",
    version := sys.env.getOrElse("CI_VERSION", "0.1"),
    // ...
  ).
  jvmSettings(/* JVM-specific settings */).
  jsSettings(/* JS-specific settings */)

lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js

而且,在文件系统上,我有:

  • shared/ — 在 JS/JVM 构建之间共享的跨平台代码
  • jvm/ — JVM 特定的代码
  • js/ — JS 特定的代码

到目前为止,我想出的最好的方法是将此任务添加到foocrossProject:

lazy val foo = crossProject.in(file(".")).
  settings(
    name := "foo",
    version := sys.env.getOrElse("CI_VERSION", "0.1"),
    sourceGenerators in Compile += generateVersionTask.taskValue, // <== !
    // ...
  ).
  jvmSettings(/* JVM-specific settings */).
  jsSettings(/* JS-specific settings */)

这可行,但以一种非常尴尬的方式,与“共享”代码库并不真正兼容。它为 JS 和 JVM 生成 2 个不同的 Version.scala 文件:

sbt:root> compile
Version file generated: /foo/js/target/scala-2.12/src_managed/main/version/Version.scala
Version file generated: /foo/jvm/target/scala-2.12/src_managed/main/version/Version.scala

自然,不可能从 访问这些文件的内容shared,而这正是我想要访问的地方。

到目前为止,我提出了一个非常草率的解决方法:

  • var在共享的单例对象中有一个声明
  • 在 JVM 和 JS 主入口点中,我做的第一件事就是分配该变量以匹配定义在Version.scala

另外,我用sbt-buildinfo插件尝试了同样的技巧——结果完全一样,它生成 per-platform BuildInfo.scala,我不能直接从共享源中使用它。

有没有更好的解决方案?

4

1 回答 1

2

考虑像这样sourceManaged指向shared/src/main/scala/src_managed目录和generateVersionTask项目范围root

val sharedSourceManaged = Def.setting(
  baseDirectory.value / "shared" / "src" / "main" / "scala" / "src_managed"
)

lazy val root = project.in(file(".")).
  aggregate(fooJS, fooJVM).
  settings(
    publish := {},
    publishLocal := {},
    sourceManaged := sharedSourceManaged.value,
    sourceGenerators in Compile += generateVersionTask.taskValue,
    cleanFiles += sharedSourceManaged.value
  )

现在sbt compile应该输出类似

Version file generated: /Users/mario/IdeaProjects/scalajs-cross-compile-example/shared/src/main/scala/src_managed/version/Version.scala
...
[info] Compiling 3 Scala sources to /Users/mario/IdeaProjects/scalajs-cross-compile-example/js/target/scala-2.12/classes ...
[info] Compiling 1 Scala source to /Users/mario/IdeaProjects/scalajs-cross-compile-example/target/scala-2.12/classes ...
[info] Compiling 3 Scala sources to /Users/mario/IdeaProjects/scalajs-cross-compile-example/jvm/target/scala-2.12/classes ...
于 2019-04-22T11:22:42.793 回答