diff --git a/.github/workflows/stdlib.yaml b/.github/workflows/stdlib.yaml new file mode 100644 index 000000000000..fd35ac6cca44 --- /dev/null +++ b/.github/workflows/stdlib.yaml @@ -0,0 +1,46 @@ +name: Compile Full Standard Library + +on: + push: + branches: + - 'main' + pull_request: + +permissions: + contents: read + +jobs: + compile-nonbootstrapped: + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + cache: 'sbt' + + - uses: sbt/setup-sbt@v1 + - name: Compile `scala-library-nonbootstrapped` + run: ./project/scripts/sbt scala-library-nonbootstrapped/compile + + compile-bootstrapped: + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + cache: 'sbt' + + - uses: sbt/setup-sbt@v1 + - name: Compile `scala-library-bootstrapped` + run: ./project/scripts/sbt scala-library-bootstrapped/compile + diff --git a/build.sbt b/build.sbt index 9425c4eed1e9..9330a1cff20a 100644 --- a/build.sbt +++ b/build.sbt @@ -3,6 +3,8 @@ val `scala3-bootstrapped` = Build.`scala3-bootstrapped` val `scala3-interfaces` = Build.`scala3-interfaces` val `scala3-compiler` = Build.`scala3-compiler` val `scala3-compiler-bootstrapped` = Build.`scala3-compiler-bootstrapped` +val `scala-library-nonbootstrapped` = Build.`scala-library-nonbootstrapped` +val `scala-library-bootstrapped` = Build.`scala-library-bootstrapped` val `scala3-library` = Build.`scala3-library` val `scala3-library-bootstrapped` = Build.`scala3-library-bootstrapped` val `scala3-library-bootstrappedJS` = Build.`scala3-library-bootstrappedJS` diff --git a/project/Build.scala b/project/Build.scala index 158f72f97991..3a614f227e84 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1411,6 +1411,95 @@ object Build { ) ) + // ============================================================================================== + // =================================== SCALA STANDARD LIBRARY =================================== + // ============================================================================================== + + /* Configuration of the org.scala-lang:scala-library:*.**.**-nonboostrapped project */ + lazy val `scala-library-nonbootstrapped` = project.in(file("library")) + .settings( + name := "scala-library-nonbootstrapped", + moduleName := "scala-library", + version := dottyNonBootstrappedVersion, + versionScheme := Some("semver-spec"), + scalaVersion := referenceVersion, // nonbootstrapped artifacts are compiled with the reference compiler (already officially published) + crossPaths := false, // org.scala-lang:scala-library doesn't have a crosspath + autoScalaLibrary := false, // do not add a dependency to stdlib + // Add the source directories for the stdlib (non-boostrapped) + Compile / unmanagedSourceDirectories := Seq(baseDirectory.value / "src"), + Compile / unmanagedSourceDirectories += baseDirectory.value / "src-non-bootstrapped", + // NOTE: The only difference here is that we drop `-Werror` and semanticDB for now + Compile / scalacOptions := Seq("-deprecation", "-feature", "-unchecked", "-encoding", "UTF8", "-language:implicitConversions"), + (Compile / scalacOptions) ++= Seq( + // Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called + "-sourcepath", (Compile / sourceDirectories).value.map(_.getCanonicalPath).distinct.mkString(File.pathSeparator), + ), + // Only publish compilation artifacts, no test artifacts + Compile / publishArtifact := true, + Test / publishArtifact := false, + // Do not allow to publish this project for now + publish / skip := true, + // Project specific target folder. sbt doesn't like having two projects using the same target folder + target := target.value / "scala-library-nonbootstrapped", + ) + + /* Configuration of the org.scala-lang:scala-library:*.**.**-boostrapped project */ + lazy val `scala-library-bootstrapped` = project.in(file("library")) + .settings( + name := "scala-library-bootstrapped", + moduleName := "scala-library", + version := dottyVersion, + versionScheme := Some("semver-spec"), + crossPaths := false, // org.scala-lang:scala-library doesn't have a crosspath + // Add the source directories for the stdlib (non-boostrapped) + Compile / unmanagedSourceDirectories := Seq(baseDirectory.value / "src"), + Compile / unmanagedSourceDirectories += baseDirectory.value / "src-bootstrapped", + // NOTE: The only difference here is that we drop `-Werror` and semanticDB for now + Compile / scalacOptions := Seq("-deprecation", "-feature", "-unchecked", "-encoding", "UTF8", "-language:implicitConversions"), + Compile / scalacOptions ++= Seq( + // Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called + "-sourcepath", (Compile / sourceDirectories).value.map(_.getCanonicalPath).distinct.mkString(File.pathSeparator), + ), + // Only publish compilation artifacts, no test artifacts + Compile / publishArtifact := true, + Test / publishArtifact := false, + // Do not allow to publish this project for now + publish / skip := true, + // Project specific target folder. sbt doesn't like having two projects using the same target folder + target := target.value / "scala-library-bootstrapped", + // Configure the nonbootstrapped compiler + managedScalaInstance := false, + scalaInstance := { + val externalLibraryDeps = (`scala3-library` / Compile / externalDependencyClasspath).value.map(_.data).toSet + val externalCompilerDeps = (`scala3-compiler` / Compile / externalDependencyClasspath).value.map(_.data).toSet + + // IMPORTANT: We need to use actual jars to form the ScalaInstance and not + // just directories containing classfiles because sbt maintains a cache of + // compiler instances. This cache is invalidated based on timestamps + // however this is only implemented on jars, directories are never + // invalidated. + val tastyCore = (`tasty-core` / Compile / packageBin).value + val scala3Library = (`scala3-library` / Compile / packageBin).value + val scala3Interfaces = (`scala3-interfaces` / Compile / packageBin).value + val scala3Compiler = (`scala3-compiler` / Compile / packageBin).value + + val libraryJars = Array(scala3Library) ++ externalLibraryDeps + val compilerJars = Seq(tastyCore, scala3Interfaces, scala3Compiler) ++ (externalCompilerDeps -- externalLibraryDeps) + + Defaults.makeScalaInstance( + scalaVersion.value, + libraryJars = libraryJars, + allCompilerJars = compilerJars, + allDocJars = Seq.empty, + state.value, + scalaInstanceTopLoader.value + ) + }, + scalaCompilerBridgeBinaryJar := { + Some((`scala3-sbt-bridge` / Compile / packageBin).value) + }, + ) + def dottyLibrary(implicit mode: Mode): Project = mode match { case NonBootstrapped => `scala3-library` case Bootstrapped => `scala3-library-bootstrapped`