chipsalliance / chisel

Chisel: A Modern Hardware Design Language
https://www.chisel-lang.org/
Apache License 2.0
3.99k stars 597 forks source link

[mill] Get unit testing working #4384

Closed jackkoenig closed 2 months ago

jackkoenig commented 2 months ago

Fixes https://github.com/chipsalliance/chisel/issues/4353.

Another step toward replacing SBT.

I went ahead and used the way of defining tests in Mill rather than doing it more manually. This ensures we get the SBT default src/test/scala and src/test/resource directories for free. It's also just more idiomatic as this is what the Mill examples do.

These tests can be run in parallel with ./mill -j0 __.test. I also figured out how to create "aggregate commands" that run in parallel (if you tell mill to use parallelism with -j):

object utils {
  // Copied from https://github.com/com-lihaoyi/mill/blob/4caadfb62581b4c1772c14c6f8dc8963011eaec7/main/define/src/mill/define/Task.scala#L55
  // This makes it possible to run multiple tasks in parallel (when passing `-j <n>` to mill)
  // Mill's source has MIT license
  class Sequence[+T](inputs0: Seq[Task[T]]) extends Task[Seq[T]] {
    val inputs: Seq[Task[_]] = inputs0
    def evaluate(ctx: mill.api.Ctx): mill.api.Result[Seq[T]] = {
      for (i <- 0 until ctx.args.length)
        yield ctx.args(i).asInstanceOf[T]
    }
  }
  // end copied from Mill

  // Sugar API over Sequence
  def parallelize[T](tasks: Seq[Task[T]]): Task[Seq[T]] = new Sequence(tasks)
}

object test extends TaskModule {

  override def defaultCommandName() = "run"

  val tasks = Seq(
    svsim(v.scalaVersion).test.test(),
    firrtl(v.scalaVersion).test.test(),
    chisel(v.scalaVersion).test.test(),
    integrationTests(v.scalaVersion).test.test()
  ) 
  def run() = T.command {
    utils.parallelize(tasks)()
  }
}

I don't think we need this yet, but if we ever want command "aliases", this approach might be useful.

Contributor Checklist

Type of Improvement

Desired Merge Strategy

Release Notes

Reviewer Checklist (only modified by reviewer)

jackkoenig commented 2 months ago

From a mill dev, you can just do T.sequence(tasks)(), we don't need to copy the Sequence class into our build.sc.