Files
2026-07-12 11:01:51 +03:00

461 lines
16 KiB
Scala

// See LICENSE for license details.
enablePlugins(SiteScaladocPlugin)
addCommandAlias("fmt", "; scalafmtAll ; scalafmtSbt")
addCommandAlias("fmtCheck", "; scalafmtCheckAll ; scalafmtSbtCheck")
lazy val firtoolVersion = settingKey[Option[String]]("Determine the version of firtool on the PATH")
ThisBuild / firtoolVersion := {
import scala.sys.process._
val Version = """^CIRCT firtool-(\S+)$""".r
try {
val lines = Process(Seq("firtool", "--version")).lineStream
lines.collectFirst { case Version(v) => v }
} catch {
case e: java.io.IOException => None
}
}
// Previous versions are read from project/previous-versions.txt
// If this file is empty or does not exist, no binary compatibility checking will be done
// Add waivers to the directory defined by key `mimaFiltersDirectory` in files named: <since version>.backwards.excludes
// eg. unipublish/src/main/mima-filters/5.0.0.backwards.excludes
val previousVersions = settingKey[Set[String]]("Previous versions for binary compatibility checking")
ThisBuild / previousVersions := {
val file = new java.io.File("project", "previous-versions.txt")
if (file.isFile) {
scala.io.Source.fromFile(file).getLines.toSet
} else {
Set()
}
}
val emitVersion = taskKey[Unit]("Write the version to version.txt")
emitVersion := {
IO.write(new java.io.File("version.txt"), version.value)
}
lazy val minimalSettings = Seq(
organization := "org.chipsalliance",
scalacOptions := Seq("-deprecation", "-feature"),
scalaVersion := "2.13.12"
)
lazy val commonSettings = minimalSettings ++ Seq(
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
resolvers ++= Resolver.sonatypeOssRepos("releases"),
autoAPIMappings := true,
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
// Macros paradise is integrated into 2.13 but requires a scalacOption
scalacOptions += "-Ymacro-annotations"
)
lazy val fatalWarningsSettings = Seq(
scalacOptions ++= {
if (sys.props.contains("disableFatalWarnings")) {
Nil
} else {
"-Werror" :: Nil
}
}
)
lazy val warningSuppression = Seq(
scalacOptions += "-Wconf:" + 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"
).mkString(",")
)
// This should only be mixed in by projects that are published
// See 'unipublish' project below
lazy val publishSettings = Seq(
versionScheme := Some("semver-spec"),
publishMavenStyle := true,
Test / publishArtifact := false,
pomIncludeRepository := { x => false },
homepage := Some(url("https://www.chisel-lang.org")),
organizationHomepage := Some(url("https://www.chipsalliance.org")),
licenses := List(License.Apache2),
developers := List(
Developer("jackkoenig", "Jack Koenig", "jack.koenig3@gmail.com", url("https://github.com/jackkoenig")),
Developer("azidar", "Adam Izraelevitz", "azidar@gmail.com", url("https://github.com/azidar")),
Developer("seldridge", "Schuyler Eldridge", "schuyler.eldridge@gmail.com", url("https://github.com/seldridge"))
),
sonatypeCredentialHost := "s01.oss.sonatype.org",
sonatypeRepository := "https://s01.oss.sonatype.org/service/local",
// We are just using 'publish / skip' as a hook to run checks required for publishing,
// but that are not necessarily required for local development or running testing in CI
publish / skip := {
// Check that SBT Dynver can properly derive a version which requires unshallow clone
val v = version.value
if (dynverGitDescribeOutput.value.hasNoTags) {
sys.error(s"Failed to derive version from git tags. Maybe run `git fetch --unshallow`? Version: $v")
}
// Check that firtool exists on the PATH so Chisel can use the version it was tested against
// in error messages
if (firtoolVersion.value.isEmpty) {
sys.error(s"Failed to determine firtool version. Make sure firtool is found on the PATH.")
}
(publish / skip).value
},
publishTo := {
val v = version.value
val nexus = "https://s01.oss.sonatype.org/"
if (v.trim.endsWith("SNAPSHOT")) {
Some("snapshots".at(nexus + "content/repositories/snapshots"))
} else {
Some("releases".at(nexus + "service/local/staging/deploy/maven2"))
}
}
)
// FIRRTL SETTINGS
lazy val firrtlSettings = Seq(
name := "firrtl",
addCompilerPlugin(scalafixSemanticdb),
scalacOptions := Seq(
"-deprecation",
"-unchecked",
"-language:reflectiveCalls",
"-language:existentials",
"-language:implicitConversions",
"-Yrangepos" // required by SemanticDB compiler plugin
),
// Always target Java8 for maximum compatibility
javacOptions ++= Seq("-source", "1.8", "-target", "1.8"),
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scalatest" %% "scalatest" % "3.2.14" % "test",
"org.scalatestplus" %% "scalacheck-1-16" % "3.2.14.0" % "test",
"com.github.scopt" %% "scopt" % "4.1.0",
"net.jcazevedo" %% "moultingyaml" % "0.4.2",
"org.json4s" %% "json4s-native" % "4.0.6",
"org.apache.commons" % "commons-text" % "1.10.0",
"io.github.alexarchambault" %% "data-class" % "0.2.6",
"com.lihaoyi" %% "os-lib" % "0.9.1"
),
scalacOptions += "-Ymacro-annotations",
// starting with scala 2.13 the parallel collections are separate from the standard library
libraryDependencies += "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4"
)
lazy val assemblySettings = Seq(
assembly / assemblyJarName := "firrtl.jar",
assembly / test := {},
assembly / assemblyOutputPath := file("./utils/bin/firrtl.jar")
)
lazy val testAssemblySettings = Seq(
Test / assembly / test := {}, // Ditto above
Test / assembly / assemblyMergeStrategy := {
case PathList("firrtlTests", xs @ _*) => MergeStrategy.discard
case x =>
val oldStrategy = (Test / assembly / assemblyMergeStrategy).value
oldStrategy(x)
},
Test / assembly / assemblyJarName := s"firrtl-test.jar",
Test / assembly / assemblyOutputPath := file("./utils/bin/" + (Test / assembly / assemblyJarName).value)
)
lazy val svsim = (project in file("svsim"))
.settings(minimalSettings)
.settings(
// Published as part of unipublish
publish / skip := true,
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.16" % "test",
"org.scalatestplus" %% "scalacheck-1-16" % "3.2.14.0" % "test"
)
)
lazy val firrtl = (project in file("firrtl"))
.enablePlugins(ScalaUnidocPlugin)
.settings(
fork := true,
Test / testForkedParallel := true
)
.settings(commonSettings)
.settings(firrtlSettings)
.settings(assemblySettings)
.settings(inConfig(Test)(baseAssemblySettings))
.settings(testAssemblySettings)
.settings(
// Published as part of unipublish
publish / skip := true
)
.enablePlugins(BuildInfoPlugin)
.settings(
buildInfoPackage := name.value,
buildInfoUsePackageAsPath := true,
buildInfoKeys := Seq[BuildInfoKey](buildInfoPackage, version, scalaVersion, sbtVersion)
)
.settings(warningSuppression: _*)
.settings(fatalWarningsSettings: _*)
lazy val chiselSettings = Seq(
name := "chisel",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.16" % "test",
"org.scalatestplus" %% "scalacheck-1-16" % "3.2.14.0" % "test",
"com.lihaoyi" %% "upickle" % "3.1.0"
)
) ++ (
// Tests from other projects may still run concurrently
// if we're not running with -DminimalResources.
// Another option would be to experiment with:
// concurrentRestrictions in Global += Tags.limit(Tags.Test, 1),
sys.props.contains("minimalResources") match {
case true => Seq(Test / parallelExecution := false)
case false => Seq(fork := true, Test / testForkedParallel := true)
}
)
autoCompilerPlugins := true
autoAPIMappings := true
// Plugin must be fully cross-versioned (published for Scala minor version)
lazy val pluginScalaVersions = Seq(
"2.13.0",
"2.13.1",
"2.13.2",
"2.13.3",
"2.13.4",
"2.13.5",
"2.13.6",
"2.13.7",
"2.13.8",
"2.13.9",
"2.13.10",
"2.13.11",
"2.13.12"
)
lazy val plugin = (project in file("plugin"))
.settings(name := "chisel-plugin")
.settings(commonSettings: _*)
.settings(publishSettings: _*)
.settings(
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value,
crossScalaVersions := pluginScalaVersions,
// Must be published for Scala minor version
crossVersion := CrossVersion.full,
crossTarget := {
// workaround for https://github.com/sbt/sbt/issues/5097
target.value / s"scala-${scalaVersion.value}"
}
)
.settings(fatalWarningsSettings: _*)
.settings(
mimaPreviousArtifacts := previousVersions.value.map { version =>
(organization.value % name.value % version).cross(CrossVersion.full)
}
)
lazy val usePluginSettings = Seq(
Compile / scalacOptions ++= {
val jar = (plugin / Compile / Keys.`package`).value
val addPlugin = "-Xplugin:" + jar.getAbsolutePath
// add plugin timestamp to compiler options to trigger recompile of
// main after editing the plugin. (Otherwise a 'clean' is needed.)
val dummy = "-Jdummy=" + jar.lastModified
Seq(addPlugin, dummy)
}
)
lazy val macros = (project in file("macros"))
.settings(name := "chisel-macros")
.settings(commonSettings: _*)
.settings(
// Published as part of unipublish
publish / skip := true
)
lazy val core = (project in file("core"))
.settings(commonSettings: _*)
.enablePlugins(BuildInfoPlugin)
.settings(
buildInfoPackage := "chisel3",
buildInfoUsePackageAsPath := true,
buildInfoKeys := Seq[BuildInfoKey](buildInfoPackage, version, scalaVersion, sbtVersion, firtoolVersion)
)
.settings(
// Published as part of unipublish
publish / skip := true
)
.settings(warningSuppression: _*)
.settings(fatalWarningsSettings: _*)
.settings(
name := "chisel-core",
libraryDependencies ++= Seq(
"com.lihaoyi" %% "upickle" % "3.1.0",
"com.lihaoyi" %% "os-lib" % "0.9.1"
),
scalacOptions := scalacOptions.value ++ Seq(
"-explaintypes",
"-feature",
"-language:reflectiveCalls",
"-unchecked",
"-Xcheckinit",
"-Xlint:infer-any"
// , "-Xlint:missing-interpolator"
)
)
.dependsOn(macros)
.dependsOn(firrtl)
// This will always be the root project, even if we are a sub-project.
lazy val root = RootProject(file("."))
lazy val chisel = (project in file("."))
.settings(commonSettings: _*)
.settings(chiselSettings: _*)
.settings(
// Published as part of unipublish
publish / skip := true
)
.settings(usePluginSettings: _*)
.dependsOn(macros)
.dependsOn(core)
.dependsOn(firrtl)
.dependsOn(svsim)
.aggregate(macros, core, plugin, firrtl, svsim)
.settings(
// Suppress Scala 3 behavior requiring explicit types on implicit definitions
// Note this must come before the -Wconf is warningSuppression
Test / scalacOptions += "-Wconf:cat=other-implicit-type:s"
)
.settings(warningSuppression: _*)
.settings(fatalWarningsSettings: _*)
.settings(
Test / scalacOptions ++= Seq("-language:reflectiveCalls")
)
def addUnipublishDeps(proj: Project)(deps: Project*): Project = {
def inTestScope(module: ModuleID): Boolean = module.configurations.exists(_ == "test")
deps.foldLeft(proj) {
case (p, dep) =>
p.settings(
libraryDependencies ++= (dep / libraryDependencies).value.filterNot(inTestScope),
Compile / packageBin / mappings ++= (dep / Compile / packageBin / mappings).value,
Compile / packageSrc / mappings ++= (dep / Compile / packageSrc / mappings).value
)
}
}
// This is a pseudo-project that unifies all compilation units (excluding the plugin) into a single artifact
// It should be used for all publishing and MiMa binary compatibility checking
lazy val unipublish =
addUnipublishDeps(project in file("unipublish"))(
firrtl,
svsim,
macros,
core,
chisel
)
.aggregate(plugin) // Also publish the plugin when publishing this project
.settings(name := (chisel / name).value)
.enablePlugins(ScalaUnidocPlugin)
.settings(
// Plugin isn't part of Chisel's public API, exclude from ScalaDoc
ScalaUnidoc / unidoc / unidocProjectFilter := inAnyProject -- inProjects(plugin)
)
.settings(commonSettings: _*)
.settings(publishSettings: _*)
.settings(usePluginSettings: _*)
.settings(warningSuppression: _*)
.settings(fatalWarningsSettings: _*)
.settings(
mimaPreviousArtifacts := previousVersions.value.map { version =>
organization.value %% name.value % version
},
// This is a pseudo-project with no class files, use the package jar instead
mimaCurrentClassfiles := (Compile / packageBin).value,
// Forward doc command to unidoc
Compile / doc := (ScalaUnidoc / doc).value,
// Include unidoc as the ScalaDoc for publishing
Compile / packageDoc / mappings := (ScalaUnidoc / packageDoc / mappings).value,
Compile / doc / scalacOptions ++= Seq(
"-diagrams",
"-groups",
"-skip-packages",
"chisel3.internal",
"-diagrams-max-classes",
"25",
"-doc-version",
version.value,
"-doc-title",
name.value,
"-doc-root-content",
baseDirectory.value + "/root-doc.txt",
"-sourcepath",
(ThisBuild / baseDirectory).value.toString,
"-doc-source-url", {
val branch =
if (version.value.endsWith("-SNAPSHOT")) {
"master"
} else {
s"v${version.value}"
}
s"https://github.com/chipsalliance/chisel/tree/$branch€{FILE_PATH_EXT}#L€{FILE_LINE}"
},
"-language:implicitConversions"
) ++
// Suppress compiler plugin for source files in core
// We don't need this in regular compile because we just don't add the chisel-plugin to core's scalacOptions
// This works around an issue where unidoc uses the exact same arguments for all source files.
// This is probably fundamental to how ScalaDoc works so there may be no solution other than this workaround.
// See https://github.com/sbt/sbt-unidoc/issues/107
(core / Compile / sources).value.map("-P:chiselplugin:INTERNALskipFile:" + _)
++ Seq("-implicits")
)
// End-to-end tests that check the functionality of the emitted design with simulation
lazy val integrationTests = (project in file("integration-tests"))
.dependsOn(chisel % "compile->compile;test->test")
.dependsOn(firrtl) // SBT doesn't seem to be propagating transitive library dependencies...
.dependsOn(standardLibrary)
.settings(commonSettings: _*)
.settings(warningSuppression: _*)
.settings(fatalWarningsSettings: _*)
.settings(chiselSettings: _*)
.settings(usePluginSettings: _*)
// the chisel standard library
lazy val standardLibrary = (project in file("stdlib"))
.dependsOn(chisel)
.settings(commonSettings: _*)
.settings(chiselSettings: _*)
.settings(usePluginSettings: _*)
lazy val docs = project // new documentation project
.in(file("docs-target")) // important: it must not be docs/
.dependsOn(chisel)
.enablePlugins(MdocPlugin)
.settings(usePluginSettings: _*)
.settings(commonSettings)
.settings(
scalacOptions ++= Seq(
"-language:reflectiveCalls",
"-language:implicitConversions",
"-Wconf:msg=firrtl:s,cat=other-implicit-type:s"
),
mdocIn := file("docs/src"),
mdocOut := file("docs/generated"),
// None of our links are hygienic because they're primarily used on the website with .html
mdocExtraArguments := Seq("--cwd", "docs", "--no-link-hygiene"),
mdocVariables := Map(
"BUILD_DIR" -> "docs-target" // build dir for mdoc programs to dump temp files
)
)
.settings(fatalWarningsSettings: _*)