如何为Mill项目的RootModule实现Scala跨版本构建?
问题描述
我有一个基于Scala 3构建的Mill项目,现在要适配Scala 2.13做跨版本构建。当前的build.sc代码如下:
import mill._, scalalib._ import publish._ // qw 是我的项目名 object qw extends Cross[QwModule]("2.13.11", "3.3.0") { def defaultCrossSegments = Seq("3.3.0") } trait QwModule extends Cross.Module[String] with RootModule with ScalaModule with PublishModule with Cross.Module[String] { def scalaVersion = crossValue // ... }
执行构建命令mill 'qw[3.3.0].compile'时出现数组越界错误,报错信息如下:
% mill 'qw[3.3.0].compile' [39/1074] [build.sc] [43/52] compile [info] compiling 1 Scala source to /home/windymelt/src/github.com/windymelt/qw.scala/out/mill-build/compile.dest/classes ... [info] done compiling [build.sc] [52/52] methodCodeHashSignatures Exception in thread "MillServerActionRunner" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 at scala.collection.immutable.ArraySeq$ofRef.apply(ArraySeq.scala:331) at scala.collection.IndexedSeqOps.head(IndexedSeq.scala:94) at scala.collection.IndexedSeqOps.head$(IndexedSeq.scala:94) at scala.collection.immutable.ArraySeq.head(ArraySeq.scala:35) at mill.resolve.Resolve$.mill$resolve$Resolve$$instantiateTarget(Resolve.scala:92) at mill.resolve.Resolve$Tasks$.$anonfun$handleResolved$3(Resolve.scala:46) at scala.util.Either.flatMap(Either.scala:352) at mill.resolve.Resolve$Tasks$.$anonfun$handleResolved$2(Resolve.scala:46) at scala.collection.immutable.List.map(List.scala:246) at scala.collection.immutable.List.map(List.scala:79) at mill.resolve.Resolve$Tasks$.handleResolved(Resolve.scala:42) at mill.resolve.Resolve.$anonfun$resolveNonEmptyAndHandle$3(Resolve.scala:241) at scala.util.Either.flatMap(Either.scala:352) at mill.resolve.Resolve.resolveNonEmptyAndHandle(Resolve.scala:241) at mill.resolve.Resolve.resolveNonEmptyAndHandle$(Resolve.scala:223) at mill.resolve.Resolve$Tasks$.resolveNonEmptyAndHandle(Resolve.scala:34) at mill.resolve.Resolve.$anonfun$resolve0$4(Resolve.scala:207) at scala.util.Either.map(Either.scala:382) at mill.resolve.Resolve.$anonfun$resolve0$3(Resolve.scala:206) at scala.collection.immutable.List.map(List.scala:246) at scala.collection.immutable.List.map(List.scala:79) at mill.resolve.Resolve.$anonfun$resolve0$2(Resolve.scala:205) ...
请问如何为RootModule实现Scala跨版本构建?
解决方案
报错的核心原因是不能让跨版本模块(Cross.Module)同时作为根模块(RootModule)。RootModule是整个Mill构建的入口根节点,而Cross.Module是用于生成多版本子模块的抽象,两者职责冲突,会导致Mill解析目标时出现数组越界这类异常。
以下是两种可行的修改方案:
方案1:独立根模块 + 跨版本子模块
新增一个单独的root对象作为RootModule,将跨版本模块作为其子节点:
import mill._, scalalib._ import publish._ object root extends RootModule { // 把跨版本模块作为根的子模块 object qw extends Cross[QwModule]("2.13.11", "3.3.0") { def defaultCrossSegments = Seq("3.3.0") } } trait QwModule extends Cross.Module[String] with ScalaModule with PublishModule { def scalaVersion = crossValue // ... 其他原有配置 }
执行构建命令时,可使用简化路径:
mill 'qw[3.3.0].compile'
(因为root是默认根节点,无需显式指定)
方案2:移除RootModule继承,直接用顶层跨版本模块
如果不需要根级别的聚合逻辑,直接移除QwModule中的RootModule继承即可:
import mill._, scalalib._ import publish._ object qw extends Cross[QwModule]("2.13.11", "3.3.0") { def defaultCrossSegments = Seq("3.3.0") } trait QwModule extends Cross.Module[String] with ScalaModule with PublishModule { def scalaVersion = crossValue // ... 其他原有配置 }
此时原构建命令mill 'qw[3.3.0].compile'即可正常执行。
关键注意点
- 原代码中
QwModule重复继承了Cross.Module[String],需要移除重复声明,避免冗余。 RootModule仅在需要聚合多个子模块(多项目构建)时才需要显式声明;单一跨版本项目直接用顶层跨版本模块即可,无需额外的RootModule。
内容的提问来源于stack exchange,提问作者Windymelt
相关产品推荐
相关产品推荐

