diff --git a/build.sc b/build.sc index 5b670199e8..070e32aaba 100644 --- a/build.sc +++ b/build.sc @@ -11,10 +11,10 @@ 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.common -import $file.tests -object v { +import $file.panama + +object v extends Module { val javaVersion = { val rawVersion = sys.props("java.specification.version") @@ -22,6 +22,10 @@ object v { 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. @@ -32,9 +36,13 @@ object v { val versions = minVersion to latest213 versions.map(v => s"2.13.$v").toSeq } + val scalaCrossVersions = Seq( "2.13.15" ) + + def isScala3(ver: String): Boolean = ver.startsWith("3.") + val scalaVersion = scalaCrossVersions.head val jmhVersion = "1.37" val osLib = ivy"com.lihaoyi::os-lib:0.10.0" @@ -47,21 +55,14 @@ object v { 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 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" - - // 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" + 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 warnConf = Seq( + val scala2WarnConf = Seq( "msg=APIs in chisel3.internal:s", "msg=Importing from firrtl:s", "msg=migration to the MLIR:s", @@ -76,7 +77,7 @@ object v { ) // ScalacOptions - val commonOptions = Seq( + val scala2CommonOptions = Seq( "-deprecation", "-feature", "-unchecked", @@ -87,74 +88,10 @@ object v { "-Xlint:infer-any", "-Xlint:missing-interpolator", "-language:reflectiveCalls", - s"-Wconf:${warnConf.mkString(",")}" + s"-Wconf:${scala2WarnConf.mkString(",")}" ) } -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-") - } - - // 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 = v.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 = v.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 ChiselPublishModule extends CiReleaseModule { // Publish information def pomSettings = PomSettings( @@ -182,29 +119,63 @@ trait ChiselPublishModule extends CiReleaseModule { } -object firrtl extends Cross[Firrtl](v.scalaCrossVersions) +trait HasScala2MacroAnno extends CrossSbtModule { + override def scalacOptions = T { + if (!v.isScala3(crossScalaVersion)) { + super.scalacOptions() ++ Agg("-Ymacro-annotations") + } else super.scalacOptions() + } +} -trait Firrtl extends common.FirrtlModule with CrossSbtModule with ScalafmtModule { - def millSourcePath = super.millSourcePath / os.up / "firrtl" +trait HasScala2Plugin extends CrossSbtModule { + def pluginModule: Plugin - override def scalacOptions = v.commonOptions ++ Seq( - "-language:reflectiveCalls", - "-language:existentials", - "-language:implicitConversions", - "-Yrangepos", // required by SemanticDB compiler plugin - "-Xsource:3", - "-Xsource-features:infer-override" - ) + override def scalacOptions = T { + if (!v.isScala3(crossScalaVersion)) { + super.scalacOptions() ++ Agg(s"-Xplugin:${pluginModule.jar().path}") + } else super.scalacOptions() + } - def osLibModuleIvy = v.osLib + override def scalacPluginClasspath = T { + if (!v.isScala3(crossScalaVersion)) { + super.scalacPluginClasspath() ++ Agg(pluginModule.jar()) + } else super.scalacPluginClasspath() + } +} - def json4sIvy = v.json4s +object firrtl extends Cross[Firrtl](v.scalaCrossVersions) - def dataclassIvy = v.dataclass +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" + ) + } + } - def commonTextIvy = v.commonText + val commonDeps = Agg( + v.scopt, + v.commonText, + v.osLib, + v.json4s + ) - def scoptIvy = v.scopt + 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) @@ -212,14 +183,19 @@ trait Firrtl extends common.FirrtlModule with CrossSbtModule with ScalafmtModule } object svsim extends Cross[Svsim](v.scalaCrossVersions) - -trait Svsim extends common.SvsimModule with CrossSbtModule with ScalafmtModule { +trait Svsim extends CrossSbtModule with ScalafmtModule { def millSourcePath = super.millSourcePath / os.up / "svsim" - override def scalacOptions = v.commonOptions ++ Seq( - "-Xsource:3", - "-Xsource-features:case-apply-copy-access" - ) + 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) @@ -227,35 +203,54 @@ trait Svsim extends common.SvsimModule with CrossSbtModule with ScalafmtModule { } object macros extends Cross[Macros](v.scalaCrossVersions) - -trait Macros extends common.MacrosModule with CrossSbtModule with ScalafmtModule { +trait Macros extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { def millSourcePath = super.millSourcePath / os.up / "macros" - override def scalacOptions = v.commonOptions ++ Seq( - "-Xsource:3" - ) + override def scalacOptions = T { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-Xsource:3" + ) + } + } - def scalaReflectIvy = v.scalaReflect(crossScalaVersion) + override def ivyDeps = super.ivyDeps() ++ Seq(ivy"org.scala-lang:scala-reflect:$scalaVersion") } object core extends Cross[Core](v.scalaCrossVersions) - -trait Core extends common.CoreModule with CrossSbtModule with ScalafmtModule { +trait Core extends CrossSbtModule with HasScala2MacroAnno with ScalafmtModule { + def scalaVersion = crossScalaVersion def millSourcePath = super.millSourcePath / os.up / "core" - override def scalacOptions = v.commonOptions ++ Seq( - "-Xsource:3" - ) - - def firrtlModule = firrtl(crossScalaVersion) + override def scalacOptions = T { + if (v.isScala3(crossScalaVersion)) { + Seq.empty[String] + } else { + v.scala2CommonOptions ++ Seq( + "-Xsource:3" + ) + } + } - def macrosModule = macros(crossScalaVersion) + val crossModuleDeps = Seq(firrtl(crossScalaVersion)) ++ { + if (v.isScala3(crossScalaVersion)) Seq.empty + else Seq(macros(crossScalaVersion)) + } - def osLibModuleIvy = v.osLib + override def moduleDeps = super.moduleDeps ++ crossModuleDeps - def upickleModuleIvy = v.upickle + val commonDeps = Agg( + v.osLib, + v.upickle + ) - def firtoolResolverModuleIvy = v.firtoolResolver + override def ivyDeps = if (v.isScala3(crossScalaVersion)) { + super.ivyDeps() ++ commonDeps + } 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. @@ -270,10 +265,9 @@ trait Core extends common.CoreModule with CrossSbtModule with ScalafmtModule { dirtyHashDigits = 0 ) } - def buildInfo = T { val outputFile = T.dest / "chisel3" / "BuildInfo.scala" - val firtoolVersionString = "Some(\"" + utils.firtoolVersion + "\")" + val firtoolVersionString = "Some(\"" + v.firtoolVersion + "\")" val contents = s""" |package chisel3 @@ -294,44 +288,34 @@ trait Core extends common.CoreModule with CrossSbtModule with ScalafmtModule { 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 common.PluginModule with CrossSbtModule with ScalafmtModule with ChiselPublishModule { +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 = super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) } object chisel extends Cross[Chisel](v.scalaCrossVersions) - -trait Chisel extends common.ChiselModule with CrossSbtModule with ScalafmtModule { +trait Chisel extends CrossSbtModule with HasScala2MacroAnno with HasScala2Plugin with ScalafmtModule { override def millSourcePath = super.millSourcePath / os.up - - // Make sure to include super.scalacOptions for Chisel Plugin - override def scalacOptions = T(super.scalacOptions() ++ v.commonOptions) - def svsimModule = svsim(crossScalaVersion) - - def macrosModule = macros(crossScalaVersion) - def coreModule = core(crossScalaVersion) + def pluginModule = plugin() - def pluginModule = plugin(crossScalaVersion) + override def moduleDeps = super.moduleDeps ++ Seq(coreModule, svsimModule) object test extends SbtModuleTests with TestModule.ScalaTest with ScalafmtModule { def ivyDeps = Agg(v.scalatest, v.scalacheck) @@ -343,11 +327,8 @@ trait Chisel extends common.ChiselModule with CrossSbtModule with ScalafmtModule } object integrationTests extends Cross[IntegrationTests](v.scalaCrossVersions) - -trait IntegrationTests extends CrossSbtModule with ScalafmtModule with common.HasChiselPlugin { - +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 { @@ -357,63 +338,65 @@ trait IntegrationTests extends CrossSbtModule with ScalafmtModule with common.Ha } object stdlib extends Cross[Stdlib](v.scalaCrossVersions) - -trait Stdlib extends common.StdLibModule with CrossSbtModule with ScalafmtModule { +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 common.CIRCTPanamaBindingModule { - +trait CIRCTPanamaBinding extends panama.CIRCTPanamaBindingModule { def header = T(PathRef(millSourcePath / "jextract-headers.h")) - - def circtInstallPath = T(utils.circtInstallDir()) - - def jextractBinary = T(utils.jextractInstallDir() / "bin" / "jextract") - + 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 common.PanamaLibModule with CrossModuleBase with ScalafmtModule { +trait PanamaLib extends panama.PanamaLibModule with CrossModuleBase with ScalafmtModule { def circtPanamaBindingModule = circtpanamabinding } object panamaom extends Cross[PanamaOM](v.scalaCrossVersions) -trait PanamaOM extends common.PanamaOMModule with CrossModuleBase with ScalafmtModule { +trait PanamaOM extends panama.PanamaOMModule with CrossModuleBase with ScalafmtModule { def panamaLibModule = panamalib(crossScalaVersion) } object panamaconverter extends Cross[PanamaConverter](v.scalaCrossVersions) -trait PanamaConverter extends common.PanamaConverterModule with CrossModuleBase with ScalafmtModule { +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 tests.LitUtilityModule with CrossModuleBase with ScalafmtModule { +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 tests.LitModule with Cross.Module[String] { +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)) @@ -487,7 +470,7 @@ object unipublish extends ScalaModule with ChiselPublishModule { } // Needed for ScalaDoc - override def scalacOptions = v.commonOptions + override def scalacOptions = v.scala2CommonOptions def scalaDocRootDoc = T.source { T.workspace / "root-doc.txt" } diff --git a/common.sc b/common.sc deleted file mode 100644 index ade22ade63..0000000000 --- a/common.sc +++ /dev/null @@ -1,235 +0,0 @@ -import mill._ -import mill.scalalib._ - -trait MacrosModule extends ScalaModule { - def scalaReflectIvy: Dep - - override def ivyDeps = super.ivyDeps() ++ Some(scalaReflectIvy) -} - -trait FirrtlModule extends ScalaModule { - def osLibModuleIvy: Dep - - def json4sIvy: Dep - - def dataclassIvy: Dep - - def commonTextIvy: Dep - - def scoptIvy: Dep - - override def ivyDeps = super.ivyDeps() ++ Agg( - osLibModuleIvy, - json4sIvy, - dataclassIvy, - commonTextIvy, - scoptIvy - ) -} - -trait SvsimModule extends ScalaModule {} - -trait CoreModule extends ScalaModule { - def firrtlModule: FirrtlModule - - def macrosModule: MacrosModule - - def osLibModuleIvy: Dep - - def upickleModuleIvy: Dep - - def firtoolResolverModuleIvy: Dep - - override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, firrtlModule) - - override def ivyDeps = super.ivyDeps() ++ Agg( - osLibModuleIvy, - upickleModuleIvy, - firtoolResolverModuleIvy - ) -} - -trait PluginModule extends ScalaModule { - def scalaLibraryIvy: Dep - - def scalaReflectIvy: Dep - - def scalaCompilerIvy: Dep - - override def ivyDeps = super.ivyDeps() ++ Agg(scalaLibraryIvy, scalaReflectIvy, scalaCompilerIvy) -} - -trait HasChiselPlugin extends ScalaModule { - def pluginModule: PluginModule - - override def scalacOptions = T { - super.scalacOptions() ++ Agg(s"-Xplugin:${pluginModule.jar().path}") - } - - override def scalacPluginClasspath = T { - super.scalacPluginClasspath() ++ Agg( - pluginModule.jar() - ) - } -} - -trait StdLibModule extends ScalaModule with HasChisel - -trait ChiselModule extends ScalaModule with HasChiselPlugin { - def macrosModule: MacrosModule - - def svsimModule: SvsimModule - - def coreModule: CoreModule - - override def scalacPluginClasspath = T(super.scalacPluginClasspath() ++ Agg(pluginModule.jar())) - - override def moduleDeps = super.moduleDeps ++ Seq(macrosModule, coreModule, svsimModule) -} - -trait HasChisel extends ScalaModule with HasChiselPlugin { - def chiselModule: ChiselModule - - override def moduleDeps = super.moduleDeps ++ Some(chiselModule) -} - -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 - Lib - .findSourceFiles(os.walk(T.dest).map(PathRef(_)), Seq("java")) - .distinct - .map(PathRef(_)) - } - } - - 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 with HasChisel - -trait HasPanamaConverterModule extends ScalaModule with HasCIRCTPanamaBindingModule with HasChisel { - def panamaConverterModule: PanamaConverterModule - - def circtPanamaBindingModule = panamaConverterModule.circtPanamaBindingModule - - override def chiselModule = panamaConverterModule.chiselModule - - override def pluginModule = panamaConverterModule.pluginModule - - override def moduleDeps = super.moduleDeps ++ Some(panamaConverterModule) -} diff --git a/panama.sc b/panama.sc new file mode 100644 index 0000000000..e90085332d --- /dev/null +++ b/panama.sc @@ -0,0 +1,252 @@ +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 + Lib + .findSourceFiles(os.walk(T.dest).map(PathRef(_)), Seq("java")) + .distinct + .map(PathRef(_)) + } + } + + 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/tests.sc b/tests.sc deleted file mode 100644 index 84456aeeed..0000000000 --- a/tests.sc +++ /dev/null @@ -1,40 +0,0 @@ -import mill._ -import mill.api.Result -import mill.scalalib._ -import mill.scalalib.api.CompilationResult -import mill.util.Jvm - -import java.util -import scala.jdk.StreamConverters.StreamHasToScala - -trait LitUtilityModule extends ScalaModule with common.HasPanamaConverterModule with common.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))) - ) -}