You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:37:27