diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fea333dde76..477d3e13f7a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -90,7 +90,7 @@ jobs: $CHISEL_FIRTOOL_PATH/firtool -version >> $GITHUB_STEP_SUMMARY echo \`\`\` >> $GITHUB_STEP_SUMMARY - name: Test - run: ./mill -j0 firrtl[].test + svsim[].test + chisel[].test + run: ./mill -j0 firrtl.cross[].test + svsim[].test + chisel[].test - name: Binary compatibility # TODO either make this also check the plugin or decide that we don't # support binary compatibility for the plugin @@ -183,7 +183,7 @@ jobs: dir=$(dirname $(which firtool)) echo "CHISEL_FIRTOOL_PATH=$dir" >> "$GITHUB_ENV" - name: Integration Tests - run: ./mill -j0 integrationTests[].test + run: ./mill -j0 integration-tests.cross[].test # Currently just a sanity check that the benchmarking flow works benchmark: @@ -221,7 +221,7 @@ jobs: distribution: 'adopt' java-version: '11' - name: Compile - run: ./mill stdlib[_].compile + run: ./mill stdlib.cross[_].compile website: name: Build Mdoc & Website diff --git a/.mill-version b/.mill-version index 1ee43fc53c1..43c2417ca0c 100644 --- a/.mill-version +++ b/.mill-version @@ -1 +1 @@ -0.11.8 +0.12.5 diff --git a/benchmark/package.mill b/benchmark/package.mill new file mode 100644 index 00000000000..466b729ce3b --- /dev/null +++ b/benchmark/package.mill @@ -0,0 +1,16 @@ +package build.benchmark + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import $ivy.`com.lihaoyi::mill-contrib-jmh:` +import mill.contrib.jmh.JmhModule + +import build._ + +object `package` extends RootModule with ScalaModule with JmhModule with ScalafmtModule { + def scalaVersion = v.scalaVersion + def jmhCoreVersion = v.jmhVersion + + override def moduleDeps = Seq(chisel(v.scalaVersion)) +} diff --git a/build.mill b/build.mill new file mode 100644 index 00000000000..0e6c8d19b53 --- /dev/null +++ b/build.mill @@ -0,0 +1,435 @@ +package build + +import mill._ +import mill.scalalib._ +import mill.scalalib.publish._ +import mill.scalalib.scalafmt._ +import mill.api.Result +import mill.scalalib.api.ZincWorkerUtil.matchingVersions +import mill.util.Jvm.createJar +import $ivy.`io.chris-kipp::mill-ci-release::0.1.10` +import io.kipp.mill.ci.release.{CiReleaseModule, SonatypeHost} +import de.tobiasroeser.mill.vcs.version.VcsVersion // pulled in by mill-ci-release + +import $packages._ +import build._ + +object v extends Module { + + val javaVersion = { + val rawVersion = sys.props("java.specification.version") + // Older versions of Java started with 1., e.g. 1.8 == 8 + rawVersion.stripPrefix("1.").toInt + } + + val firtoolVersion = { + val j = _root_.upickle.default.read[Map[String, String]](os.read(millSourcePath / os.up / "etc" / "circt.json")) + j("version").stripPrefix("firtool-") + } + // Java 21 only works with 2.13.11+, but Project Panama uses Java 21 + // Only publish plugin for 2.13.11+ when using Java > 11, but still + // publish all versions when Java version <= 11. + val pluginScalaCrossVersions = { + val latest213 = 15 + val java21Min213 = 11 + val minVersion = if (javaVersion > 11) java21Min213 else 0 + val versions = minVersion to latest213 + val versionSeq = versions.map(v => s"2.13.$v").toSeq + versionSeq ++ Seq("3.3.4") + } + + val scalaCrossVersions = Seq( + "2.13.15", + "3.3.4" + ) + + def isScala3(ver: String): Boolean = ver.startsWith("3.") + + def buildUnits(): Seq[ScalaModule] = { + scalaCrossVersions.flatMap { ver => + Seq(chisel(ver), stdlib.cross(ver), unipublish) + } ++ scalaCrossVersions.filterNot(isScala3(_)).flatMap { ver2 => + Seq( + chisel(ver2).test, + firrtl.cross(ver2).test, + svsim.cross(ver2).test, + `integration-tests`.cross(ver2).test, + lit.utility.cross(ver2), + panamaconverter.cross(ver2), + panamalib.cross(ver2), + panamaom.cross(ver2) + ) + } + } + + val scalaVersion = scalaCrossVersions.head + val jmhVersion = "1.37" + val osLib = ivy"com.lihaoyi::os-lib:0.10.0" + val upickle = ivy"com.lihaoyi::upickle:3.3.1" + val firtoolResolver = ivy"org.chipsalliance::firtool-resolver:2.0.0" + val scalatest = ivy"org.scalatest::scalatest:3.2.19" + val scalacheck = ivy"org.scalatestplus::scalacheck-1-18:3.2.19.0" + val json4s = ivy"org.json4s::json4s-native:4.0.7" + val dataclass = ivy"io.github.alexarchambault::data-class:0.2.6" + val commonText = ivy"org.apache.commons:commons-text:1.12.0" + val scopt = ivy"com.github.scopt::scopt:4.1.0" + + def scalaReflect(scalaVersion: String) = ivy"org.scala-lang:scala-reflect:$scalaVersion" + def scalaCompiler(scalaVersion: String) = ivy"org.scala-lang:scala-compiler:$scalaVersion" + def scalaLibrary(scalaVersion: String) = ivy"org.scala-lang:scala-library:$scalaVersion" + + def circt(version: String, os: String, platform: String) = + s"https://github.com/llvm/circt/releases/download/firtool-${version}/circt-full-shared-${os}-${platform}.tar.gz" + + val scala2WarnConf = Seq( + "msg=APIs in chisel3.internal:s", + "msg=Importing from firrtl:s", + "msg=migration to the MLIR:s", + "msg=method hasDefiniteSize in trait IterableOnceOps is deprecated:s", // replacement `knownSize` is not in 2.12 + "msg=object JavaConverters in package collection is deprecated:s", + "msg=undefined in comment for method cf in class PrintableHelper:s", + // This is deprecated for external users but not internal use + "cat=deprecation&origin=firrtl\\.options\\.internal\\.WriteableCircuitAnnotation:s", + "cat=deprecation&origin=chisel3\\.util\\.experimental\\.BoringUtils.*:s", + "cat=deprecation&origin=chisel3\\.experimental\\.IntrinsicModule:s", + "cat=deprecation&origin=chisel3\\.ltl.*:s", + // Deprecated for external users, will eventually be removed. + "cat=deprecation&msg=Looking up Modules is deprecated:s", + // Only for testing of deprecated APIs + "cat=deprecation&msg=Use of @instantiable on user-defined types is deprecated:s" + ) + + // ScalacOptions + val scala2CommonOptions = Seq( + "-deprecation", + "-feature", + "-unchecked", + "-Werror", + "-Ymacro-annotations", + "-explaintypes", + "-Xcheckinit", + "-Xlint:infer-any", + "-Xlint:missing-interpolator", + "-language:reflectiveCalls", + s"-Wconf:${scala2WarnConf.mkString(",")}" + ) +} + +def compileAll() = Task.Command { + Task.traverse(v.buildUnits())(_.compile)() +} + +trait ChiselPublishModule extends CiReleaseModule { + // Publish information + def pomSettings = PomSettings( + description = artifactName(), + organization = "org.chipsalliance", + url = "https://www.chisel-lang.org", + licenses = Seq(License.`Apache-2.0`), + versionControl = VersionControl.github("chipsalliance", "chisel"), + developers = Seq( + Developer("jackkoenig", "Jack Koenig", "https://github.com/jackkoenig"), + Developer("azidar", "Adam Izraelevitz", "https://github.com/azidar"), + Developer("seldridge", "Schuyler Eldridge", "https://github.com/seldridge") + ) + ) + + override def sonatypeHost = Some(SonatypeHost.s01) + + override def publishVersion = VcsVersion + .vcsState() + .format( + countSep = "+", + revHashDigits = 8, + untaggedSuffix = "-SNAPSHOT" + ) + +} + +trait HasScala2MacroAnno extends CrossModuleBase { + override def scalacOptions = Task { + if (!v.isScala3(crossScalaVersion)) { + super.scalacOptions() ++ Agg("-Ymacro-annotations") + } else super.scalacOptions() + } +} + +trait HasScala2Plugin extends CrossModuleBase { + import $file.plugin.Plugin + def pluginModule: Plugin + + override def scalacOptions = Task { + if (!v.isScala3(crossScalaVersion)) { + super.scalacOptions() ++ Agg(s"-Xplugin:${pluginModule.jar().path}") + } else super.scalacOptions() + } + + override def scalacPluginClasspath = Task { + if (!v.isScala3(crossScalaVersion)) { + super.scalacPluginClasspath() ++ Agg(pluginModule.jar()) + } else super.scalacPluginClasspath() + } +} + +trait HasJextractGeneratedSources extends JavaModule { + + def jextractBinary: T[os.Path] + + def includePaths: T[Seq[PathRef]] + + def libraryPaths: T[Seq[PathRef]] + + def header: T[PathRef] + + def includeFunctions: T[Seq[String]] + + def includeConstants: T[Seq[String]] + + def includeStructs: T[Seq[String]] + + def includeTypedefs: T[Seq[String]] + + def includeUnions: T[Seq[String]] + + def includeVars: T[Seq[String]] + + def linkLibraries: T[Seq[String]] + + def target: T[String] + + def headerClassName: T[String] + + def dumpAllIncludes = Task { + val f = os.temp() + os.proc( + Seq(jextractBinary().toString, header().path.toString) + ++ includePaths().flatMap(p => Seq("-I", p.path.toString)) + ++ Seq("--dump-includes", f.toString) + ).call() + os.read.lines(f).filter(s => s.nonEmpty && !s.startsWith("#")) + } + + override def generatedSources: T[Seq[PathRef]] = Task { + super.generatedSources() ++ { + // @formatter:off + os.proc( + Seq(jextractBinary().toString, header().path.toString) + ++ includePaths().flatMap(p => Seq("-I", p.path.toString)) + ++ Seq( + "-t", target(), + "--header-class-name", headerClassName(), + "--source", + "--output", Task.dest.toString + ) ++ includeFunctions().flatMap(f => Seq("--include-function", f)) ++ + includeConstants().flatMap(f => Seq("--include-constant", f)) ++ + includeStructs().flatMap(f => Seq("--include-struct", f)) ++ + includeTypedefs().flatMap(f => Seq("--include-typedef", f)) ++ + includeUnions().flatMap(f => Seq("--include-union", f)) ++ + includeVars().flatMap(f => Seq("--include-var", f)) ++ + linkLibraries().flatMap(l => Seq("-l", l)) + ).call(Task.dest) + // @formatter:on + Seq(PathRef(Task.dest)) + } + } + + override def javacOptions = Task(super.javacOptions() ++ Seq("--enable-preview", "--release", "21")) +} + +trait HasCIRCTPanamaBindingModule extends JavaModule { + import $file.circtpanamabinding.CIRCTPanamaBinding + def circtPanamaBindingModule: CIRCTPanamaBinding + + override def moduleDeps = super.moduleDeps ++ Some(circtPanamaBindingModule) + // + override def javacOptions = Task(super.javacOptions() ++ Seq("--enable-preview", "--release", "21")) + + override def forkArgs: T[Seq[String]] = Task( + super.forkArgs() ++ Seq("--enable-native-access=ALL-UNNAMED", "--enable-preview") + ++ circtPanamaBindingModule + .libraryPaths() + .map(p => s"-Djava.library.path=${p.path}") + ) +} + +trait HasPanamaLibModule extends ScalaModule with HasCIRCTPanamaBindingModule { + import $file.panamalib.PanamaLib + def panamaLibModule: PanamaLib + + def circtPanamaBindingModule = panamaLibModule.circtPanamaBindingModule + + override def moduleDeps = super.moduleDeps ++ Some(panamaLibModule) +} + +trait HasPanamaOMModule extends ScalaModule with HasCIRCTPanamaBindingModule { + import $file.panamaom.PanamaOM + def panamaOMModule: PanamaOM + + def circtPanamaBindingModule = panamaOMModule.circtPanamaBindingModule + + override def moduleDeps = super.moduleDeps ++ Some(panamaOMModule) +} + +trait HasPanamaConverterModule extends ScalaModule with HasCIRCTPanamaBindingModule { + import $file.panamaconverter.PanamaConverter + def panamaConverterModule: PanamaConverter + + def circtPanamaBindingModule = panamaConverterModule.circtPanamaBindingModule + + override def moduleDeps = super.moduleDeps ++ Some(panamaConverterModule) +} + +object chisel extends Cross[Chisel](v.scalaCrossVersions) + +trait Chisel extends CrossSbtModule with HasScala2MacroAnno with HasScala2Plugin with ScalafmtModule { + override def millSourcePath = super.millSourcePath / os.up + def svsimModule = svsim.cross(crossScalaVersion) + def coreModule = core.cross(crossScalaVersion) + def pluginModule = plugin.cross() + + override def scalacOptions = Task { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + super.scalacOptions() ++ v.scala2CommonOptions + } + } + + override def moduleDeps = super.moduleDeps ++ Seq(coreModule, svsimModule) + + object test extends SbtTests with TestModule.ScalaTest with ScalafmtModule { + def ivyDeps = Agg(v.scalatest, v.scalacheck) + + // Suppress Scala 3 behavior requiring explicit types on implicit definitions + // Note this must come before the -Wconf is warningSuppression + override def scalacOptions = Task { super.scalacOptions() :+ "-Wconf:cat=other-implicit-type:s" } + } +} + +/** Aggregate project for publishing Chisel as a single artifact + */ +object unipublish extends ScalaModule with ChiselPublishModule { + + def scalaVersion = v.scalaVersion + + // This is published as chisel + override def artifactName = "chisel" + + // Older versions of Scala do not work with newer versions of the JVM + // This is a hack to ensure we always use Java 8 to publish Chisel with Scala 2.13 + // We could use Java 11 with -release 8 + // Note that this target is used by real publishing but not by publishLocal + override def publishArtifacts = Task { + // TODO when we publish for Scala 3, only do this check for Scala 2.13 + if (v.javaVersion != 8) { + throw new Exception(s"Publishing requires Java 8, current JDK is ${v.javaVersion}") + } + super.publishArtifacts + } + + /** Publish both this project and the plugin (for the default Scala version) */ + override def publishLocal(localIvyRepo: String = null) = Task.Command { + // TODO consider making this parallel and publishing all cross-versions for plugin + plugin.cross(v.scalaVersion).publishLocal(localIvyRepo)() + super.publishLocal(localIvyRepo)() + } + + // Explicitly not using moduleDeps because that influences so many things + def components = Seq(firrtl.cross, svsim.cross, macros.cross, core.cross, chisel).map(_(v.scalaVersion)) + + /** Aggregated ivy deps to include as dependencies in POM */ + def ivyDeps = Task { Task.traverse(components)(_.ivyDeps)().flatten } + + /** Aggregated local classpath to include in jar */ + override def localClasspath = Task { Task.traverse(components)(_.localClasspath)().flatten } + + /** Aggreagted sources from all component modules */ + def aggregatedSources = Task { Task.traverse(components)(_.allSources)().flatten } + + /** Aggreagted resources from all component modules */ + def aggregatedResources = Task { Task.traverse(components)(_.resources)().flatten } + + /** Aggreagted compile resources from all component modules */ + def aggregatedCompileResources = Task { Task.traverse(components)(_.compileResources)().flatten } + + /** Aggregated sourceJar from all component modules + */ + override def sourceJar: T[PathRef] = Task { + // This is based on the implementation of sourceJar in PublishModule, may need to be kept in sync. + val allDirs = aggregatedSources() ++ aggregatedResources() ++ aggregatedCompileResources() + createJar(allDirs.map(_.path).filter(os.exists), manifest()) + } + + // Needed for ScalaDoc + override def scalacOptions = v.scala2CommonOptions + + def scalaDocRootDoc = Task.Source { Task.workspace / "root-doc.txt" } + + def unidocOptions = Task { + scalacOptions() ++ Seq[String]( + "-classpath", + unidocCompileClasspath().map(_.path).mkString(sys.props("path.separator")), + "-diagrams", + "-groups", + "-skip-packages", + "chisel3.internal", + "-diagrams-max-classes", + "25", + "-doc-version", + publishVersion(), + "-doc-title", + "chisel", + "-doc-root-content", + scalaDocRootDoc().path.toString, + "-sourcepath", + Task.workspace.toString, + "-doc-source-url", + unidocSourceUrl(), + "-language:implicitConversions", + "-implicits" + ) + } + + // Built-in UnidocModule is insufficient so we need to implement it ourselves + // We could factor this out into a utility + def unidocSourceUrl: T[String] = Task { + val base = "https://github.com/chipsalliance/chisel/tree" + val branch = if (publishVersion().endsWith("-SNAPSHOT")) "main" else s"v${publishVersion()}" + s"$base/$branch/€{FILE_PATH_EXT}#L€{FILE_LINE}" + } + + def unidocVersion: T[Option[String]] = None + + def unidocCompileClasspath = Task { + Seq(compile().classes) ++ Task.traverse(components)(_.compileClasspath)().flatten + } + + def unidocSourceFiles = Task { + allSourceFiles() ++ Task.traverse(components)(_.allSourceFiles)().flatten + } + + // Based on UnidocModule and docJar in Mill, may need to be kept in sync. + override def docJar = Task { + Task.log.info(s"Building unidoc for ${unidocSourceFiles().length} files") + + val javadocDir = Task.dest / "javadoc" + os.makeDir(javadocDir) + + val fullOptions = unidocOptions() ++ + Seq("-d", javadocDir.toString) ++ + unidocSourceFiles().map(_.path.toString) + + zincWorker() + .worker() + .docJar( + scalaVersion(), + scalaOrganization(), + scalaDocClasspath(), + scalacPluginClasspath(), + fullOptions + ) match { + case true => Result.Success(createJar(Agg(javadocDir))(Task.dest)) + case false => Result.Failure("docJar generation failed") + } + } +} diff --git a/build.sc b/build.sc deleted file mode 100644 index bce888a8d5c..00000000000 --- a/build.sc +++ /dev/null @@ -1,585 +0,0 @@ -import mill._ -import mill.scalalib._ -import mill.scalalib.publish._ -import mill.scalalib.scalafmt._ -import mill.api.Result -import mill.define.Cross -import mill.scalalib.api.ZincWorkerUtil.matchingVersions -import mill.util.Jvm.createJar -import $ivy.`com.lihaoyi::mill-contrib-jmh:` -import mill.contrib.jmh.JmhModule -import $ivy.`io.chris-kipp::mill-ci-release::0.1.10` -import io.kipp.mill.ci.release.{CiReleaseModule, SonatypeHost} -import de.tobiasroeser.mill.vcs.version.VcsVersion // pulled in by mill-ci-release - -import $file.panama - -object v extends Module { - - val javaVersion = { - val rawVersion = sys.props("java.specification.version") - // Older versions of Java started with 1., e.g. 1.8 == 8 - rawVersion.stripPrefix("1.").toInt - } - - val firtoolVersion = { - val j = _root_.upickle.default.read[Map[String, String]](os.read(millSourcePath / os.up / "etc" / "circt.json")) - j("version").stripPrefix("firtool-") - } - // Java 21 only works with 2.13.11+, but Project Panama uses Java 21 - // Only publish plugin for 2.13.11+ when using Java > 11, but still - // publish all versions when Java version <= 11. - val pluginScalaCrossVersions = { - val latest213 = 15 - val java21Min213 = 11 - val minVersion = if (javaVersion > 11) java21Min213 else 0 - val versions = minVersion to latest213 - val versionSeq = versions.map(v => s"2.13.$v").toSeq - versionSeq ++ Seq("3.3.4") - } - - val scalaCrossVersions = Seq( - "2.13.15", - "3.3.4" - ) - - def isScala3(ver: String): Boolean = ver.startsWith("3.") - - def buildUnits(): Seq[ScalaModule] = { - scalaCrossVersions.flatMap { ver => - Seq(chisel(ver), stdlib(ver), unipublish) - } ++ scalaCrossVersions.filterNot(isScala3(_)).flatMap { ver2 => - Seq( - chisel(ver2).test, - firrtl(ver2).test, - svsim(ver2).test, - integrationTests(ver2).test, - litutility(ver2), - panamaconverter(ver2), - panamalib(ver2), - panamaom(ver2) - ) - } - } - - val scalaVersion = scalaCrossVersions.head - val jmhVersion = "1.37" - val osLib = ivy"com.lihaoyi::os-lib:0.10.0" - val upickle = ivy"com.lihaoyi::upickle:3.3.1" - val firtoolResolver = ivy"org.chipsalliance::firtool-resolver:2.0.0" - val scalatest = ivy"org.scalatest::scalatest:3.2.19" - val scalacheck = ivy"org.scalatestplus::scalacheck-1-18:3.2.19.0" - val json4s = ivy"org.json4s::json4s-native:4.0.7" - val dataclass = ivy"io.github.alexarchambault::data-class:0.2.6" - val commonText = ivy"org.apache.commons:commons-text:1.12.0" - val scopt = ivy"com.github.scopt::scopt:4.1.0" - - def scalaReflect(scalaVersion: String) = ivy"org.scala-lang:scala-reflect:$scalaVersion" - def scalaCompiler(scalaVersion: String) = ivy"org.scala-lang:scala-compiler:$scalaVersion" - def scalaLibrary(scalaVersion: String) = ivy"org.scala-lang:scala-library:$scalaVersion" - - def circt(version: String, os: String, platform: String) = - s"https://github.com/llvm/circt/releases/download/firtool-${version}/circt-full-shared-${os}-${platform}.tar.gz" - - val scala2WarnConf = Seq( - "msg=APIs in chisel3.internal:s", - "msg=Importing from firrtl:s", - "msg=migration to the MLIR:s", - "msg=method hasDefiniteSize in trait IterableOnceOps is deprecated:s", // replacement `knownSize` is not in 2.12 - "msg=object JavaConverters in package collection is deprecated:s", - "msg=undefined in comment for method cf in class PrintableHelper:s", - // This is deprecated for external users but not internal use - "cat=deprecation&origin=firrtl\\.options\\.internal\\.WriteableCircuitAnnotation:s", - "cat=deprecation&origin=chisel3\\.util\\.experimental\\.BoringUtils.*:s", - "cat=deprecation&origin=chisel3\\.experimental\\.IntrinsicModule:s", - "cat=deprecation&origin=chisel3\\.ltl.*:s", - // Deprecated for external users, will eventually be removed. - "cat=deprecation&msg=Looking up Modules is deprecated:s", - // Only for testing of deprecated APIs - "cat=deprecation&msg=Use of @instantiable on user-defined types is deprecated:s" - ) - - // ScalacOptions - val scala2CommonOptions = Seq( - "-deprecation", - "-feature", - "-unchecked", - "-Werror", - "-Ymacro-annotations", - "-explaintypes", - "-Xcheckinit", - "-Xlint:infer-any", - "-Xlint:missing-interpolator", - "-language:reflectiveCalls", - s"-Wconf:${scala2WarnConf.mkString(",")}" - ) -} - -def compileAll() = T.command { - T.traverse(v.buildUnits())(_.compile)() -} - -trait ChiselPublishModule extends CiReleaseModule { - // Publish information - def pomSettings = PomSettings( - description = artifactName(), - organization = "org.chipsalliance", - url = "https://www.chisel-lang.org", - licenses = Seq(License.`Apache-2.0`), - versionControl = VersionControl.github("chipsalliance", "chisel"), - developers = Seq( - Developer("jackkoenig", "Jack Koenig", "https://github.com/jackkoenig"), - Developer("azidar", "Adam Izraelevitz", "https://github.com/azidar"), - Developer("seldridge", "Schuyler Eldridge", "https://github.com/seldridge") - ) - ) - - override def sonatypeHost = Some(SonatypeHost.s01) - - override def publishVersion = VcsVersion - .vcsState() - .format( - countSep = "+", - revHashDigits = 8, - untaggedSuffix = "-SNAPSHOT" - ) - -} - -trait HasScala2MacroAnno extends CrossModuleBase { - override def scalacOptions = T { - if (!v.isScala3(crossScalaVersion)) { - super.scalacOptions() ++ Agg("-Ymacro-annotations") - } else super.scalacOptions() - } -} - -trait HasScala2Plugin extends CrossModuleBase { - def pluginModule: Plugin - - override def scalacOptions = T { - if (!v.isScala3(crossScalaVersion)) { - super.scalacOptions() ++ Agg(s"-Xplugin:${pluginModule.jar().path}") - } else super.scalacOptions() - } - - override def scalacPluginClasspath = T { - if (!v.isScala3(crossScalaVersion)) { - super.scalacPluginClasspath() ++ Agg(pluginModule.jar()) - } else super.scalacPluginClasspath() - } -} - -object firrtl extends Cross[Firrtl](v.scalaCrossVersions) - -trait Firrtl extends CrossSbtModule with Cross.Module[String] with HasScala2MacroAnno with ScalafmtModule { - def millSourcePath = super.millSourcePath / os.up / "firrtl" - def scalaVersion = crossScalaVersion - - override def scalacOptions = T { - if (v.isScala3(crossScalaVersion)) { - Seq.empty[String] - } else { - v.scala2CommonOptions ++ Seq( - "-language:reflectiveCalls", - "-language:existentials", - "-language:implicitConversions", - "-Yrangepos", // required by SemanticDB compiler plugin - "-Xsource:3", - "-Xsource-features:infer-override" - ) - } - } - - val commonDeps = Agg( - v.scopt, - v.commonText, - v.osLib, - v.json4s - ) - - def ivyDeps = if (v.isScala3(crossScalaVersion)) { - commonDeps - } else { - commonDeps ++ Agg(v.dataclass) - } - - object test extends SbtModuleTests with TestModule.ScalaTest with ScalafmtModule { - def ivyDeps = Agg(v.scalatest, v.scalacheck) - } -} - -object svsim extends Cross[Svsim](v.scalaCrossVersions) -trait Svsim extends CrossSbtModule with ScalafmtModule { - def millSourcePath = super.millSourcePath / os.up / "svsim" - - override def scalacOptions = T { - if (v.isScala3(crossScalaVersion)) { - Seq.empty[String] - } else { - v.scala2CommonOptions ++ Seq( - "-Xsource:3", - "-Xsource-features:case-apply-copy-access" - ) - } - } - - object test extends SbtModuleTests with TestModule.ScalaTest with ScalafmtModule { - def ivyDeps = Agg(v.scalatest, v.scalacheck) - } -} - -object macros extends Cross[Macros](v.scalaCrossVersions) -trait Macros extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { - def millSourcePath = super.millSourcePath / os.up / "macros" - - override def scalacOptions = T { - if (v.isScala3(crossScalaVersion)) { - Seq.empty[String] - } else { - v.scala2CommonOptions ++ Seq( - "-Xsource:3" - ) - } - } - - override def ivyDeps = super.ivyDeps() ++ Seq(v.scalaReflect(crossScalaVersion)) -} - -object core extends Cross[Core](v.scalaCrossVersions) -trait Core extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { - def scalaVersion = crossScalaVersion - def millSourcePath = super.millSourcePath / os.up / "core" - - override def scalacOptions = T { - if (v.isScala3(crossScalaVersion)) { - Seq.empty[String] - } else { - v.scala2CommonOptions ++ Seq( - "-Xsource:3" - ) - } - } - - val crossModuleDeps = Seq(firrtl(crossScalaVersion)) ++ { - if (v.isScala3(crossScalaVersion)) Seq.empty - else Seq(macros(crossScalaVersion)) - } - - override def moduleDeps = super.moduleDeps ++ crossModuleDeps - - val commonDeps = Agg( - v.osLib, - v.upickle - ) - - override def ivyDeps = if (v.isScala3(crossScalaVersion)) { - super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver.withDottyCompat(scalaVersion())) - } else { - super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver) - } - - // Similar to the publish version, but no dirty indicators because otherwise - // this file will change any time any file is changed. - def publishVersion = T { - VcsVersion - .vcsState() - .format( - countSep = "+", - revHashDigits = 8, - untaggedSuffix = "-SNAPSHOT", - dirtySep = "", - dirtyHashDigits = 0 - ) - } - def buildInfo = T { - val outputFile = T.dest / "chisel3" / "BuildInfo.scala" - val firtoolVersionString = "Some(\"" + v.firtoolVersion + "\")" - val contents = - s""" - |package chisel3 - |case object BuildInfo { - | val buildInfoPackage: String = "chisel3" - | val version: String = "${publishVersion()}" - | val scalaVersion: String = "${scalaVersion()}" - | @deprecated("Chisel no longer uses SBT, this field will be removed.", "Chisel 7.0") - | val sbtVersion: String = "" - | val firtoolVersion: scala.Option[String] = $firtoolVersionString - | override val toString: String = { - | "buildInfoPackage: %s, version: %s, scalaVersion: %s, firtoolVersion %s".format( - | buildInfoPackage, version, scalaVersion, firtoolVersion - | ) - | } - |} - |""".stripMargin - os.write(outputFile, contents, createFolders = true) - PathRef(T.dest) - } - override def generatedSources = T { - super.generatedSources() :+ buildInfo() - } -} - -object plugin extends Cross[Plugin](v.pluginScalaCrossVersions) -trait Plugin extends CrossSbtModule with ScalafmtModule with ChiselPublishModule { - override def artifactName = "chisel-plugin" - - // The plugin is compiled for every minor Scala version - override def crossFullScalaVersion = true - - def millSourcePath = super.millSourcePath / os.up / "plugin" - def scalaLibraryIvy = v.scalaLibrary(crossScalaVersion) - def scalaReflectIvy = v.scalaReflect(crossScalaVersion) - def scalaCompilerIvy: Dep = v.scalaCompiler(crossScalaVersion) - - def ivyDeps = T { - if (!v.isScala3(crossScalaVersion)) { - super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) - } else { - super.ivyDeps() - } - } -} - -object chisel extends Cross[Chisel](v.scalaCrossVersions) -trait Chisel extends CrossSbtModule with HasScala2MacroAnno with HasScala2Plugin with ScalafmtModule { - override def millSourcePath = super.millSourcePath / os.up - def svsimModule = svsim(crossScalaVersion) - def coreModule = core(crossScalaVersion) - def pluginModule = plugin() - - override def scalacOptions = T { - if (v.isScala3(crossScalaVersion)) { - Seq.empty[String] - } else { - super.scalacOptions() ++ v.scala2CommonOptions - } - } - - override def moduleDeps = super.moduleDeps ++ Seq(coreModule, svsimModule) - - object test extends SbtModuleTests with TestModule.ScalaTest with ScalafmtModule { - def ivyDeps = Agg(v.scalatest, v.scalacheck) - - // Suppress Scala 3 behavior requiring explicit types on implicit definitions - // Note this must come before the -Wconf is warningSuppression - override def scalacOptions = T { super.scalacOptions() :+ "-Wconf:cat=other-implicit-type:s" } - } -} - -object integrationTests extends Cross[IntegrationTests](v.scalaCrossVersions) -trait IntegrationTests extends CrossSbtModule with HasScala2Plugin with ScalafmtModule { - def pluginModule = plugin() - def millSourcePath = os.pwd / "integration-tests" - - object test extends SbtModuleTests with TestModule.ScalaTest with ScalafmtModule { - override def moduleDeps = super.moduleDeps :+ chisel().test - def ivyDeps = Agg(v.scalatest, v.scalacheck) - } -} - -object stdlib extends Cross[Stdlib](v.scalaCrossVersions) -trait Stdlib extends CrossSbtModule with HasScala2Plugin with ScalafmtModule { - def millSourcePath = super.millSourcePath / os.up / "stdlib" - def chiselModule = chisel(crossScalaVersion) - def pluginModule = plugin(crossScalaVersion) - - override def moduleDeps = Seq(chiselModule, pluginModule) -} - -object circtpanamabinding extends CIRCTPanamaBinding - -trait CIRCTPanamaBinding extends panama.CIRCTPanamaBindingModule { - def header = T(PathRef(millSourcePath / "jextract-headers.h")) - def circtInstallPath = T(panama.utils.circtInstallDir()) - def jextractBinary = T(panama.utils.jextractInstallDir() / "bin" / "jextract") - def includePaths = T(Seq(PathRef(circtInstallPath() / "include"))) - def libraryPaths = T(Seq(PathRef(circtInstallPath() / "lib"))) -} - -object panamalib extends Cross[PanamaLib](v.scalaCrossVersions) - -trait PanamaLib extends panama.PanamaLibModule with CrossModuleBase with ScalafmtModule { - def circtPanamaBindingModule = circtpanamabinding -} - -object panamaom extends Cross[PanamaOM](v.scalaCrossVersions) - -trait PanamaOM extends panama.PanamaOMModule with CrossModuleBase with ScalafmtModule { - def panamaLibModule = panamalib(crossScalaVersion) -} - -object panamaconverter extends Cross[PanamaConverter](v.scalaCrossVersions) - -trait PanamaConverter - extends panama.PanamaConverterModule - with CrossModuleBase - with HasScala2Plugin - with ScalafmtModule { - def panamaOMModule = panamaom(crossScalaVersion) - def chiselModule = chisel(crossScalaVersion) - def pluginModule = plugin(crossScalaVersion) - - override def moduleDeps = super.moduleDeps ++ Some(chiselModule) -} - -object litutility extends Cross[LitUtility](v.scalaCrossVersions) - -trait LitUtility extends panama.LitUtilityModule with CrossModuleBase with HasScala2Plugin with ScalafmtModule { - def chiselModule = chisel(crossScalaVersion) - def pluginModule = plugin(crossScalaVersion) - def millSourcePath = super.millSourcePath / os.up / "lit" / "utility" - def panamaConverterModule = panamaconverter(crossScalaVersion) - def panamaOMModule = panamaom(crossScalaVersion) - - override def moduleDeps = super.moduleDeps ++ Some(chiselModule) -} - -object lit extends Cross[Lit](v.scalaCrossVersions) - -trait Lit extends panama.LitModule with Cross.Module[String] { - def scalaVersion: T[String] = crossValue - def runClasspath: T[Seq[os.Path]] = T(litutility(crossValue).runClasspath().map(_.path)) - def pluginJars: T[Seq[os.Path]] = T(Seq(litutility(crossValue).panamaConverterModule.pluginModule.jar().path)) - def javaLibraryPath: T[Seq[os.Path]] = T( - litutility(crossValue).panamaConverterModule.circtPanamaBindingModule.libraryPaths().map(_.path) - ) - def javaHome: T[os.Path] = T(os.Path(sys.props("java.home"))) - def chiselLitDir: T[os.Path] = T(millSourcePath) - def litConfigIn: T[PathRef] = T.source(millSourcePath / "tests" / "lit.site.cfg.py.in") -} - -object benchmark extends ScalaModule with JmhModule with ScalafmtModule { - def scalaVersion = v.scalaVersion - def jmhCoreVersion = v.jmhVersion - - override def moduleDeps = Seq(chisel(v.scalaVersion)) -} - -/** Aggregate project for publishing Chisel as a single artifact - */ -object unipublish extends ScalaModule with ChiselPublishModule { - - def scalaVersion = v.scalaVersion - - // This is published as chisel - override def artifactName = "chisel" - - // Older versions of Scala do not work with newer versions of the JVM - // This is a hack to ensure we always use Java 8 to publish Chisel with Scala 2.13 - // We could use Java 11 with -release 8 - // Note that this target is used by real publishing but not by publishLocal - override def publishArtifacts = T { - // TODO when we publish for Scala 3, only do this check for Scala 2.13 - if (v.javaVersion != 8) { - throw new Exception(s"Publishing requires Java 8, current JDK is ${v.javaVersion}") - } - super.publishArtifacts - } - - /** Publish both this project and the plugin (for the default Scala version) */ - override def publishLocal(localIvyRepo: String = null) = T.command { - // TODO consider making this parallel and publishing all cross-versions for plugin - plugin(v.scalaVersion).publishLocal(localIvyRepo)() - super.publishLocal(localIvyRepo)() - } - - // Explicitly not using moduleDeps because that influences so many things - def components = Seq(firrtl, svsim, macros, core, chisel).map(_(v.scalaVersion)) - - /** Aggregated ivy deps to include as dependencies in POM */ - def ivyDeps = T { T.traverse(components)(_.ivyDeps)().flatten } - - /** Aggregated local classpath to include in jar */ - override def localClasspath = T { T.traverse(components)(_.localClasspath)().flatten } - - /** Aggreagted sources from all component modules */ - def aggregatedSources = T { T.traverse(components)(_.allSources)().flatten } - - /** Aggreagted resources from all component modules */ - def aggregatedResources = T { T.traverse(components)(_.resources)().flatten } - - /** Aggreagted compile resources from all component modules */ - def aggregatedCompileResources = T { T.traverse(components)(_.compileResources)().flatten } - - /** Aggregated sourceJar from all component modules - */ - override def sourceJar: T[PathRef] = T { - // This is based on the implementation of sourceJar in PublishModule, may need to be kept in sync. - val allDirs = aggregatedSources() ++ aggregatedResources() ++ aggregatedCompileResources() - createJar(allDirs.map(_.path).filter(os.exists), manifest()) - } - - // Needed for ScalaDoc - override def scalacOptions = v.scala2CommonOptions - - def scalaDocRootDoc = T.source { T.workspace / "root-doc.txt" } - - def unidocOptions = T { - scalacOptions() ++ Seq[String]( - "-classpath", - unidocCompileClasspath().map(_.path).mkString(sys.props("path.separator")), - "-diagrams", - "-groups", - "-skip-packages", - "chisel3.internal", - "-diagrams-max-classes", - "25", - "-doc-version", - publishVersion(), - "-doc-title", - "chisel", - "-doc-root-content", - scalaDocRootDoc().path.toString, - "-sourcepath", - T.workspace.toString, - "-doc-source-url", - unidocSourceUrl(), - "-language:implicitConversions", - "-implicits" - ) - } - - // Built-in UnidocModule is insufficient so we need to implement it ourselves - // We could factor this out into a utility - def unidocSourceUrl: T[String] = T { - val base = "https://github.com/chipsalliance/chisel/tree" - val branch = if (publishVersion().endsWith("-SNAPSHOT")) "main" else s"v${publishVersion()}" - s"$base/$branch/€{FILE_PATH_EXT}#L€{FILE_LINE}" - } - - def unidocVersion: T[Option[String]] = None - - def unidocCompileClasspath = T { - Seq(compile().classes) ++ T.traverse(components)(_.compileClasspath)().flatten - } - - def unidocSourceFiles = T { - allSourceFiles() ++ T.traverse(components)(_.allSourceFiles)().flatten - } - - // Based on UnidocModule and docJar in Mill, may need to be kept in sync. - override def docJar = T { - T.log.info(s"Building unidoc for ${unidocSourceFiles().length} files") - - val javadocDir = T.dest / "javadoc" - os.makeDir(javadocDir) - - val fullOptions = unidocOptions() ++ - Seq("-d", javadocDir.toString) ++ - unidocSourceFiles().map(_.path.toString) - - zincWorker() - .worker() - .docJar( - scalaVersion(), - scalaOrganization(), - scalaDocClasspath(), - scalacPluginClasspath(), - fullOptions - ) match { - case true => Result.Success(createJar(Agg(javadocDir))(T.dest)) - case false => Result.Failure("docJar generation failed") - } - } -} diff --git a/circtpanamabinding/package.mill b/circtpanamabinding/package.mill new file mode 100644 index 00000000000..81556034108 --- /dev/null +++ b/circtpanamabinding/package.mill @@ -0,0 +1,108 @@ +package build.circtpanamabinding + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ + +import build._ + +object `package` extends RootModule with CIRCTPanamaBinding + +// Java Codegen for all declared functions. +// All of these functions are not private API which is subject to change. +trait CIRCTPanamaBinding extends HasJextractGeneratedSources { + object utils extends Module { + val architecture = System.getProperty("os.arch") + val operationSystem = System.getProperty("os.name") + + val mac = operationSystem.toLowerCase.startsWith("mac") + val linux = operationSystem.toLowerCase.startsWith("linux") + val windows = operationSystem.toLowerCase.startsWith("win") + val amd64 = architecture.matches("^(x8664|amd64|ia32e|em64t|x64|x86_64)$") + val aarch64 = architecture.equals("aarch64") | architecture.startsWith("armv8") + + val firtoolVersion = { + val j = + _root_.upickle.default.read[Map[String, String]](os.read(millSourcePath / os.up / os.up / "etc" / "circt.json")) + j("version").stripPrefix("firtool-") + } + + def circt(version: String, os: String, platform: String) = + s"https://github.com/llvm/circt/releases/download/firtool-${version}/circt-full-shared-${os}-${platform}.tar.gz" + + // 21, 1-2, {linux-x64, macos-x64, windows-x64} + // 22, 1-2, {linux-x64, macos-aarch64, macos-x64, windows-x64} + def jextract(jdkVersion: Int, jextractVersion: String, os: String, platform: String) = + s"https://download.java.net/java/early_access/jextract/21/1/openjdk-${jdkVersion}-jextract+${jextractVersion}_${os}-${platform}_bin.tar.gz" + + // use Task(persistent = true) to avoid download repeatedly + def circtInstallDir: T[os.Path] = Task(persistent = true) { + Task.ctx().env.get("CIRCT_INSTALL_PATH") match { + case Some(dir) => os.Path(dir) + case None => + Task.ctx().log.info("Use CIRCT_INSTALL_PATH to vendor circt") + val tarPath = Task.dest / "circt.tar.gz" + if (!os.exists(tarPath)) { + val url = circt( + firtoolVersion, + if (linux) "linux" else if (mac) "macos" else throw new Exception("unsupported os"), + // circt does not yet publish for macos-aarch64, use x64 for now + if (amd64 || mac) "x64" else throw new Exception("unsupported arch") + ) + Task.ctx().log.info(s"Downloading circt from ${url}") + mill.util.Util.download(url, os.rel / "circt.tar.gz") + Task.ctx().log.info(s"Download Successfully") + } + os.proc("tar", "xvf", tarPath, "--strip-components=1").call(Task.dest) + Task.dest + } + } + + // use Task(persistent = true) to avoid download repeatedly + def jextractInstallDir: T[os.Path] = Task(persistent = true) { + Task.ctx().env.get("JEXTRACT_INSTALL_PATH") match { + case Some(dir) => os.Path(dir) + case None => + Task.ctx().log.info("Use JEXTRACT_INSTALL_PATH to vendor jextract") + val tarPath = Task.dest / "jextract.tar.gz" + if (!os.exists(tarPath)) { + val url = jextract( + 21, + "1-2", + if (linux) "linux" else if (mac) "macos" else throw new Exception("unsupported os"), + // There is no macos-aarch64 for jextract 21, use x64 for now + if (amd64 || mac) "x64" else if (aarch64) "aarch64" else throw new Exception("unsupported arch") + ) + Task.ctx().log.info(s"Downloading jextract from ${url}") + mill.util.Util.download(url, os.rel / "jextract.tar.gz") + Task.ctx().log.info(s"Download Successfully") + } + os.proc("tar", "xvf", tarPath, "--strip-components=1").call(Task.dest) + Task.dest + } + } + } + + def includeConstants = + Task.Input(os.read.lines(millSourcePath / "includeConstants.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def includeFunctions = + Task.Input(os.read.lines(millSourcePath / "includeFunctions.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def includeStructs = + Task.Input(os.read.lines(millSourcePath / "includeStructs.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def includeTypedefs = + Task.Input(os.read.lines(millSourcePath / "includeTypedefs.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def includeUnions = + Task.Input(os.read.lines(millSourcePath / "includeUnions.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def includeVars = + Task.Input(os.read.lines(millSourcePath / "includeVars.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + def linkLibraries = + Task.Input(os.read.lines(millSourcePath / "linkLibraries.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) + + def target = Task("org.llvm.circt") + def headerClassName = Task("CAPI") + def header = Task(PathRef(millSourcePath / "jextract-headers.h")) + def circtInstallPath = Task(utils.circtInstallDir()) + def jextractBinary = Task(utils.jextractInstallDir() / "bin" / "jextract") + def includePaths = Task(Seq(PathRef(circtInstallPath() / "include"))) + def libraryPaths = Task(Seq(PathRef(circtInstallPath() / "lib"))) +} diff --git a/core/package.mill b/core/package.mill new file mode 100644 index 00000000000..f1976a6e80e --- /dev/null +++ b/core/package.mill @@ -0,0 +1,88 @@ +package build.core + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross +import de.tobiasroeser.mill.vcs.version.VcsVersion // pulled in by mill-ci-release + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Core](v.scalaCrossVersions) +} + +trait Core extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { + def scalaVersion = crossScalaVersion + + def millSourcePath = super.millSourcePath / os.up + + override def scalacOptions = Task { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-Xsource:3" + ) + } + } + + val crossModuleDeps = Seq(firrtl.cross(crossScalaVersion)) ++ { + if (v.isScala3(crossScalaVersion)) Seq.empty + else Seq(macros.cross(crossScalaVersion)) + } + + override def moduleDeps = super.moduleDeps ++ crossModuleDeps + + val commonDeps = Agg( + v.osLib, + v.upickle + ) + + override def ivyDeps = if (v.isScala3(crossScalaVersion)) { + super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver.withDottyCompat(scalaVersion())) + } else { + super.ivyDeps() ++ commonDeps ++ Agg(v.firtoolResolver) + } + + // Similar to the publish version, but no dirty indicators because otherwise + // this file will change any time any file is changed. + def publishVersion = Task { + VcsVersion + .vcsState() + .format( + countSep = "+", + revHashDigits = 8, + untaggedSuffix = "-SNAPSHOT", + dirtySep = "", + dirtyHashDigits = 0 + ) + } + def buildInfo = Task { + val outputFile = Task.dest / "chisel3" / "BuildInfo.scala" + val firtoolVersionString = "Some(\"" + v.firtoolVersion + "\")" + val contents = + s""" + |package chisel3 + |case object BuildInfo { + | val buildInfoPackage: String = "chisel3" + | val version: String = "${publishVersion()}" + | val scalaVersion: String = "${scalaVersion()}" + | @deprecated("Chisel no longer uses SBT, this field will be removed.", "Chisel 7.0") + | val sbtVersion: String = "" + | val firtoolVersion: scala.Option[String] = $firtoolVersionString + | override val toString: String = { + | "buildInfoPackage: %s, version: %s, scalaVersion: %s, firtoolVersion %s".format( + | buildInfoPackage, version, scalaVersion, firtoolVersion + | ) + | } + |} + |""".stripMargin + os.write(outputFile, contents, createFolders = true) + PathRef(Task.dest) + } + override def generatedSources = Task { + super.generatedSources() :+ buildInfo() + } +} diff --git a/firrtl/package.mill b/firrtl/package.mill new file mode 100644 index 00000000000..ebec7ef9853 --- /dev/null +++ b/firrtl/package.mill @@ -0,0 +1,51 @@ +package build.firrtl + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Firrtl](v.scalaCrossVersions) +} + +trait Firrtl extends CrossSbtModule with Cross.Module[String] with HasScala2MacroAnno with ScalafmtModule { + def scalaVersion = crossScalaVersion + + def millSourcePath = super.millSourcePath / os.up + + override def scalacOptions = Task { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-language:reflectiveCalls", + "-language:existentials", + "-language:implicitConversions", + "-Yrangepos", // required by SemanticDB compiler plugin + "-Xsource:3", + "-Xsource-features:infer-override" + ) + } + } + + val commonDeps = Agg( + v.scopt, + v.commonText, + v.osLib, + v.json4s + ) + + def ivyDeps = if (v.isScala3(crossScalaVersion)) { + commonDeps + } else { + commonDeps ++ Agg(v.dataclass) + } + + object test extends SbtTests with TestModule.ScalaTest with ScalafmtModule { + def ivyDeps = Agg(v.scalatest, v.scalacheck) + } +} diff --git a/flake.lock b/flake.lock index 69bc40050c3..ecc41d7664e 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1718209920, - "narHash": "sha256-ZMkzbuNpjKsWqUNOU0GPbtJgz0ejKfTLPcZHLd0L2+Q=", + "lastModified": 1736143365, + "narHash": "sha256-hUT7MWIF17WXwqiF7QxnQf1zRvov7CVhjLMGfTQcpW8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ccacd09436c6d39457eb11b451db538df72c53d9", + "rev": "6663da588d8b6298bed018c6bc23681f8af70399", "type": "github" }, "original": { diff --git a/integration-tests/package.mill b/integration-tests/package.mill new file mode 100644 index 00000000000..12991a7d075 --- /dev/null +++ b/integration-tests/package.mill @@ -0,0 +1,23 @@ +package build.`integration-tests` + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[IntegrationTests](v.scalaCrossVersions) +} + +trait IntegrationTests extends CrossSbtModule with HasScala2Plugin with ScalafmtModule { + def pluginModule = plugin.cross() + def millSourcePath = super.millSourcePath / os.up + + object test extends SbtTests with TestModule.ScalaTest with ScalafmtModule { + override def moduleDeps = super.moduleDeps :+ chisel().test + def ivyDeps = Agg(v.scalatest, v.scalacheck) + } +} diff --git a/lit/package.mill b/lit/package.mill new file mode 100644 index 00000000000..9b09f22adbe --- /dev/null +++ b/lit/package.mill @@ -0,0 +1,46 @@ +package build.lit + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ +import build.lit.utility + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Lit](v.scalaCrossVersions) +} + +trait Lit extends Module with Cross.Module[String] { + def millSourcePath = super.millSourcePath / os.up + + def litConfig: T[PathRef] = Task { + os.write( + Task.dest / "lit.site.cfg.py", + os.read(litConfigIn().path) + .replaceAll("@SCALA_VERSION@", scalaVersion()) + .replaceAll("@RUN_CLASSPATH@", runClasspath().mkString(",")) + .replaceAll("@SCALA_PLUGIN_JARS@", pluginJars().mkString(",")) + .replaceAll("@JAVA_HOME@", javaHome().toString) + .replaceAll("@JAVA_LIBRARY_PATH@", javaLibraryPath().mkString(",")) + .replaceAll("@CHISEL_LIT_DIR@", chiselLitDir().toString) + ) + PathRef(Task.dest) + } + + def run(args: String*) = Task.Command( + os.proc("lit", litConfig().path) + .call(Task.dest, stdout = os.ProcessOutput.Readlines(line => Task.ctx().log.info("[lit] " + line))) + ) + def scalaVersion: T[String] = crossValue + def runClasspath: T[Seq[os.Path]] = Task(utility.cross(crossValue).runClasspath().map(_.path)) + def pluginJars: T[Seq[os.Path]] = Task(Seq(utility.cross(crossValue).panamaConverterModule.pluginModule.jar().path)) + def javaLibraryPath: T[Seq[os.Path]] = Task( + utility.cross(crossValue).panamaConverterModule.circtPanamaBindingModule.libraryPaths().map(_.path) + ) + def javaHome: T[os.Path] = Task(os.Path(sys.props("java.home"))) + def chiselLitDir: T[os.Path] = Task(millSourcePath) + def litConfigIn: T[PathRef] = Task.Source(millSourcePath / "tests" / "lit.site.cfg.py.in") +} diff --git a/lit/utility/package.mill b/lit/utility/package.mill new file mode 100644 index 00000000000..44775dd38cf --- /dev/null +++ b/lit/utility/package.mill @@ -0,0 +1,26 @@ +package build.lit.utility + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[LitUtility](v.scalaCrossVersions) +} + +trait LitUtility extends ScalaModule with HasPanamaConverterModule with HasPanamaOMModule with CrossModuleBase with HasScala2Plugin with ScalafmtModule { + override def scalacOptions = Task { Seq("-Ymacro-annotations") } + override def circtPanamaBindingModule = panamaConverterModule.circtPanamaBindingModule + + def chiselModule = chisel(crossScalaVersion) + def pluginModule = plugin.cross(crossScalaVersion) + def millSourcePath = super.millSourcePath / os.up + def panamaConverterModule = panamaconverter.cross(crossScalaVersion) + def panamaOMModule = panamaom.cross(crossScalaVersion) + + override def moduleDeps = super.moduleDeps ++ Some(chiselModule) +} diff --git a/macros/package.mill b/macros/package.mill new file mode 100644 index 00000000000..12b90c463d0 --- /dev/null +++ b/macros/package.mill @@ -0,0 +1,29 @@ +package build.macros + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Macros](v.scalaCrossVersions) +} + +trait Macros extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + + override def scalacOptions = Task { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-Xsource:3" + ) + } + } + + override def ivyDeps = super.ivyDeps() ++ Seq(v.scalaReflect(crossScalaVersion)) +} diff --git a/mill b/mill index 9d343ff64b8..ddc0c9a41be 100755 --- a/mill +++ b/mill @@ -14,7 +14,7 @@ set -e if [ -z "${DEFAULT_MILL_VERSION}" ] ; then - DEFAULT_MILL_VERSION="0.11.4" + DEFAULT_MILL_VERSION="0.12.5" fi diff --git a/overlay.nix b/overlay.nix index 2498ad5f4f9..b708348037e 100644 --- a/overlay.nix +++ b/overlay.nix @@ -1,10 +1,10 @@ final: prev: { mill = (prev.mill.overrideAttrs (oldAttrs: rec { - version = "0.11.6"; + version = "0.12.5"; src = prev.fetchurl { url = "https://github.com/com-lihaoyi/mill/releases/download/${version}/${version}-assembly"; - hash = "sha256-vGhjnOKvR2RdgFx3WsM217SO9gcKZknPaf7LKo3SJPU="; + hash = "sha256-DHslQS/uzwbZVdATQY3pqQgM51W+26x2AckQnDPVoFc="; }; })).override { jre = final.openjdk21; diff --git a/panama.sc b/panama.sc deleted file mode 100644 index 12d794f4469..00000000000 --- a/panama.sc +++ /dev/null @@ -1,249 +0,0 @@ -import mill._ -import mill.scalalib._ -import mill.api.Result -import mill.scalalib._ -import mill.scalalib.api.CompilationResult -import mill.util.Jvm -import mill.scalalib.scalafmt._ - -import java.util -import scala.jdk.StreamConverters.StreamHasToScala - -object utils extends Module { - val architecture = System.getProperty("os.arch") - val operationSystem = System.getProperty("os.name") - - val mac = operationSystem.toLowerCase.startsWith("mac") - val linux = operationSystem.toLowerCase.startsWith("linux") - val windows = operationSystem.toLowerCase.startsWith("win") - val amd64 = architecture.matches("^(x8664|amd64|ia32e|em64t|x64|x86_64)$") - val aarch64 = architecture.equals("aarch64") | architecture.startsWith("armv8") - - val firtoolVersion = { - val j = _root_.upickle.default.read[Map[String, String]](os.read(millSourcePath / os.up / "etc" / "circt.json")) - j("version").stripPrefix("firtool-") - } - - def circt(version: String, os: String, platform: String) = - s"https://github.com/llvm/circt/releases/download/firtool-${version}/circt-full-shared-${os}-${platform}.tar.gz" - - // 21, 1-2, {linux-x64, macos-x64, windows-x64} - // 22, 1-2, {linux-x64, macos-aarch64, macos-x64, windows-x64} - def jextract(jdkVersion: Int, jextractVersion: String, os: String, platform: String) = - s"https://download.java.net/java/early_access/jextract/21/1/openjdk-${jdkVersion}-jextract+${jextractVersion}_${os}-${platform}_bin.tar.gz" - - // use T.persistent to avoid download repeatedly - def circtInstallDir: T[os.Path] = T.persistent { - T.ctx().env.get("CIRCT_INSTALL_PATH") match { - case Some(dir) => os.Path(dir) - case None => - T.ctx().log.info("Use CIRCT_INSTALL_PATH to vendor circt") - val tarPath = T.dest / "circt.tar.gz" - if (!os.exists(tarPath)) { - val url = circt( - firtoolVersion, - if (linux) "linux" else if (mac) "macos" else throw new Exception("unsupported os"), - // circt does not yet publish for macos-aarch64, use x64 for now - if (amd64 || mac) "x64" else throw new Exception("unsupported arch") - ) - T.ctx().log.info(s"Downloading circt from ${url}") - mill.util.Util.download(url, os.rel / "circt.tar.gz") - T.ctx().log.info(s"Download Successfully") - } - os.proc("tar", "xvf", tarPath, "--strip-components=1").call(T.dest) - T.dest - } - } - - // use T.persistent to avoid download repeatedly - def jextractInstallDir: T[os.Path] = T.persistent { - T.ctx().env.get("JEXTRACT_INSTALL_PATH") match { - case Some(dir) => os.Path(dir) - case None => - T.ctx().log.info("Use JEXTRACT_INSTALL_PATH to vendor jextract") - val tarPath = T.dest / "jextract.tar.gz" - if (!os.exists(tarPath)) { - val url = jextract( - 21, - "1-2", - if (linux) "linux" else if (mac) "macos" else throw new Exception("unsupported os"), - // There is no macos-aarch64 for jextract 21, use x64 for now - if (amd64 || mac) "x64" else if (aarch64) "aarch64" else throw new Exception("unsupported arch") - ) - T.ctx().log.info(s"Downloading jextract from ${url}") - mill.util.Util.download(url, os.rel / "jextract.tar.gz") - T.ctx().log.info(s"Download Successfully") - } - os.proc("tar", "xvf", tarPath, "--strip-components=1").call(T.dest) - T.dest - } - } -} - -trait HasJextractGeneratedSources extends JavaModule { - - def jextractBinary: T[os.Path] - - def includePaths: T[Seq[PathRef]] - - def libraryPaths: T[Seq[PathRef]] - - def header: T[PathRef] - - def includeFunctions: T[Seq[String]] - - def includeConstants: T[Seq[String]] - - def includeStructs: T[Seq[String]] - - def includeTypedefs: T[Seq[String]] - - def includeUnions: T[Seq[String]] - - def includeVars: T[Seq[String]] - - def linkLibraries: T[Seq[String]] - - def target: T[String] - - def headerClassName: T[String] - - def dumpAllIncludes = T { - val f = os.temp() - os.proc( - Seq(jextractBinary().toString, header().path.toString) - ++ includePaths().flatMap(p => Seq("-I", p.path.toString)) - ++ Seq("--dump-includes", f.toString) - ).call() - os.read.lines(f).filter(s => s.nonEmpty && !s.startsWith("#")) - } - - override def generatedSources: T[Seq[PathRef]] = T { - super.generatedSources() ++ { - // @formatter:off - os.proc( - Seq(jextractBinary().toString, header().path.toString) - ++ includePaths().flatMap(p => Seq("-I", p.path.toString)) - ++ Seq( - "-t", target(), - "--header-class-name", headerClassName(), - "--source", - "--output", T.dest.toString - ) ++ includeFunctions().flatMap(f => Seq("--include-function", f)) ++ - includeConstants().flatMap(f => Seq("--include-constant", f)) ++ - includeStructs().flatMap(f => Seq("--include-struct", f)) ++ - includeTypedefs().flatMap(f => Seq("--include-typedef", f)) ++ - includeUnions().flatMap(f => Seq("--include-union", f)) ++ - includeVars().flatMap(f => Seq("--include-var", f)) ++ - linkLibraries().flatMap(l => Seq("-l", l)) - ).call(T.dest) - // @formatter:on - Seq(PathRef(T.dest)) - } - } - - override def javacOptions = T(super.javacOptions() ++ Seq("--enable-preview", "--release", "21")) -} - -// Java Codegen for all declared functions. -// All of these functions are not private API which is subject to change. -trait CIRCTPanamaBindingModule extends HasJextractGeneratedSources { - - def includeConstants = - T.input(os.read.lines(millSourcePath / "includeConstants.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def includeFunctions = - T.input(os.read.lines(millSourcePath / "includeFunctions.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def includeStructs = - T.input(os.read.lines(millSourcePath / "includeStructs.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def includeTypedefs = - T.input(os.read.lines(millSourcePath / "includeTypedefs.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def includeUnions = - T.input(os.read.lines(millSourcePath / "includeUnions.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def includeVars = - T.input(os.read.lines(millSourcePath / "includeVars.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - def linkLibraries = - T.input(os.read.lines(millSourcePath / "linkLibraries.txt").filter(s => s.nonEmpty && !s.startsWith("#"))) - - def target = T("org.llvm.circt") - def headerClassName = T("CAPI") -} - -trait HasCIRCTPanamaBindingModule extends JavaModule { - def circtPanamaBindingModule: CIRCTPanamaBindingModule - - override def moduleDeps = super.moduleDeps ++ Some(circtPanamaBindingModule) - // - override def javacOptions = T(super.javacOptions() ++ Seq("--enable-preview", "--release", "21")) - - override def forkArgs: T[Seq[String]] = T( - super.forkArgs() ++ Seq("--enable-native-access=ALL-UNNAMED", "--enable-preview") - ++ circtPanamaBindingModule - .libraryPaths() - .map(p => s"-Djava.library.path=${p.path}") - ) -} - -// The Scala API for PanamaBinding, API here is experimentally public to all developers -trait PanamaLibModule extends ScalaModule with HasCIRCTPanamaBindingModule - -trait HasPanamaLibModule extends ScalaModule with HasCIRCTPanamaBindingModule { - def panamaLibModule: PanamaLibModule - - def circtPanamaBindingModule = panamaLibModule.circtPanamaBindingModule - - override def moduleDeps = super.moduleDeps ++ Some(panamaLibModule) -} - -trait PanamaOMModule extends ScalaModule with HasPanamaLibModule - -trait HasPanamaOMModule extends ScalaModule with HasCIRCTPanamaBindingModule { - def panamaOMModule: PanamaOMModule - - def circtPanamaBindingModule = panamaOMModule.circtPanamaBindingModule - - override def moduleDeps = super.moduleDeps ++ Some(panamaOMModule) -} - -trait PanamaConverterModule extends ScalaModule with HasPanamaOMModule - -trait HasPanamaConverterModule extends ScalaModule with HasCIRCTPanamaBindingModule { - def panamaConverterModule: PanamaConverterModule - - def circtPanamaBindingModule = panamaConverterModule.circtPanamaBindingModule - - override def moduleDeps = super.moduleDeps ++ Some(panamaConverterModule) -} - -trait PanamaOM extends PanamaOMModule with CrossModuleBase with ScalafmtModule - -trait LitUtilityModule extends ScalaModule with HasPanamaConverterModule with HasPanamaOMModule { - override def scalacOptions = T { Seq("-Ymacro-annotations") } - override def circtPanamaBindingModule = panamaConverterModule.circtPanamaBindingModule -} - -trait LitModule extends Module { - def scalaVersion: T[String] - def runClasspath: T[Seq[os.Path]] - def pluginJars: T[Seq[os.Path]] - def javaLibraryPath: T[Seq[os.Path]] - def javaHome: T[os.Path] - def chiselLitDir: T[os.Path] - def litConfigIn: T[PathRef] - def litConfig: T[PathRef] = T { - os.write( - T.dest / "lit.site.cfg.py", - os.read(litConfigIn().path) - .replaceAll("@SCALA_VERSION@", scalaVersion()) - .replaceAll("@RUN_CLASSPATH@", runClasspath().mkString(",")) - .replaceAll("@SCALA_PLUGIN_JARS@", pluginJars().mkString(",")) - .replaceAll("@JAVA_HOME@", javaHome().toString) - .replaceAll("@JAVA_LIBRARY_PATH@", javaLibraryPath().mkString(",")) - .replaceAll("@CHISEL_LIT_DIR@", chiselLitDir().toString) - ) - PathRef(T.dest) - } - def run(args: String*) = T.command( - os.proc("lit", litConfig().path) - .call(T.dest, stdout = os.ProcessOutput.Readlines(line => T.ctx().log.info("[lit] " + line))) - ) -} diff --git a/panamaconverter/package.mill b/panamaconverter/package.mill new file mode 100644 index 00000000000..aa53f1b0cbb --- /dev/null +++ b/panamaconverter/package.mill @@ -0,0 +1,28 @@ +package build.panamaconverter + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[PanamaConverter](v.scalaCrossVersions) +} + +trait PanamaConverter + extends ScalaModule + with HasPanamaOMModule + with CrossModuleBase + with HasScala2Plugin + with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + + def panamaOMModule = panamaom.cross(crossScalaVersion) + def chiselModule = chisel(crossScalaVersion) + def pluginModule = plugin.cross(crossScalaVersion) + + override def moduleDeps = super.moduleDeps ++ Some(chiselModule) +} diff --git a/panamalib/package.mill b/panamalib/package.mill new file mode 100644 index 00000000000..0ff32e2e56f --- /dev/null +++ b/panamalib/package.mill @@ -0,0 +1,20 @@ +package build.panamalib + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[PanamaLib](v.scalaCrossVersions) +} + +// The Scala API for PanamaBinding, API here is experimentally public to all developers +trait PanamaLib extends ScalaModule with HasCIRCTPanamaBindingModule with CrossModuleBase with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + + def circtPanamaBindingModule = circtpanamabinding +} diff --git a/panamaom/package.mill b/panamaom/package.mill new file mode 100644 index 00000000000..a2d7bcd899c --- /dev/null +++ b/panamaom/package.mill @@ -0,0 +1,19 @@ +package build.panamaom + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[PanamaOM](v.scalaCrossVersions) +} + +trait PanamaOM extends ScalaModule with HasPanamaLibModule with CrossModuleBase with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + + def panamaLibModule = panamalib.cross(crossScalaVersion) +} diff --git a/plugin/package.mill b/plugin/package.mill new file mode 100644 index 00000000000..45a424bc272 --- /dev/null +++ b/plugin/package.mill @@ -0,0 +1,34 @@ +package build.plugin + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Plugin](v.scalaCrossVersions) +} + +trait Plugin extends CrossSbtModule with ScalafmtModule with ChiselPublishModule { + override def artifactName = "chisel-plugin" + + def millSourcePath = super.millSourcePath / os.up + + // The plugin is compiled for every minor Scala version + override def crossFullScalaVersion = true + + def scalaLibraryIvy = v.scalaLibrary(crossScalaVersion) + def scalaReflectIvy = v.scalaReflect(crossScalaVersion) + def scalaCompilerIvy: Dep = v.scalaCompiler(crossScalaVersion) + + def ivyDeps = Task { + if (!v.isScala3(crossScalaVersion)) { + super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) + } else { + super.ivyDeps() + } + } +} diff --git a/stdlib/package.mill b/stdlib/package.mill new file mode 100644 index 00000000000..62088d3e72c --- /dev/null +++ b/stdlib/package.mill @@ -0,0 +1,21 @@ +package build.stdlib + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Stdlib](v.scalaCrossVersions) +} + +trait Stdlib extends CrossSbtModule with HasScala2Plugin with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + def chiselModule = chisel(crossScalaVersion) + def pluginModule = plugin.cross(crossScalaVersion) + + override def moduleDeps = Seq(chiselModule, pluginModule) +} diff --git a/svsim/package.mill b/svsim/package.mill new file mode 100644 index 00000000000..293d63370cf --- /dev/null +++ b/svsim/package.mill @@ -0,0 +1,32 @@ +package build.svsim + +import mill._ +import mill.scalalib._ +import mill.scalalib.scalafmt._ +import mill.define.Cross + +import build._ + +object `package` extends RootModule { + // https://github.com/com-lihaoyi/mill/issues/3693 + object cross extends Cross[Svsim](v.scalaCrossVersions) +} + +trait Svsim extends CrossSbtModule with ScalafmtModule { + def millSourcePath = super.millSourcePath / os.up + + override def scalacOptions = Task { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-Xsource:3", + "-Xsource-features:case-apply-copy-access" + ) + } + } + + object test extends SbtTests with TestModule.ScalaTest with ScalafmtModule { + def ivyDeps = Agg(v.scalatest, v.scalacheck) + } +}