diff --git a/project/Build.scala b/project/Build.scala index 4cda2cda5135..91ca2d2960b6 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1419,6 +1419,7 @@ object Build { /* Configuration of the org.scala-lang:scala-library:*.**.**-nonboostrapped project */ lazy val `scala-library-nonbootstrapped` = project.in(file("library")) + .enablePlugins(ScalaLibraryPlugin) .settings( name := "scala-library-nonbootstrapped", moduleName := "scala-library", @@ -1448,6 +1449,7 @@ object Build { /* Configuration of the org.scala-lang:scala-library:*.**.**-boostrapped project */ lazy val `scala-library-bootstrapped` = project.in(file("library")) + .enablePlugins(ScalaLibraryPlugin) .settings( name := "scala-library-bootstrapped", moduleName := "scala-library", @@ -1474,8 +1476,11 @@ object Build { 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", + // we need to have the `scala-library` artifact in the classpath for `ScalaLibraryPlugin` to work + // this was the only way to not get the artifact evicted by sbt. Even a custom configuration didn't work + // NOTE: true is the default value, just making things clearer here + managedScalaInstance := true, // 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 @@ -1494,7 +1499,7 @@ object Build { val compilerJars = Seq(tastyCore, scala3Interfaces, scala3Compiler) ++ (externalCompilerDeps -- externalLibraryDeps) Defaults.makeScalaInstance( - scalaVersion.value, + dottyNonBootstrappedVersion, libraryJars = libraryJars, allCompilerJars = compilerJars, allDocJars = Seq.empty, diff --git a/project/ScalaLibraryPlugin.scala b/project/ScalaLibraryPlugin.scala index 2eac7271644a..a0d4dda50883 100644 --- a/project/ScalaLibraryPlugin.scala +++ b/project/ScalaLibraryPlugin.scala @@ -4,13 +4,14 @@ import sbt.* import sbt.Keys.* import scala.jdk.CollectionConverters.* import java.nio.file.Files +import xsbti.VirtualFileRef +import sbt.internal.inc.Stamper object ScalaLibraryPlugin extends AutoPlugin { override def trigger = noTrigger val fetchScala2ClassFiles = taskKey[(Set[File], File)]("Fetch the files to use that were compiled with Scala 2") - //val scala2LibraryVersion = settingKey[String]("Version of the Scala 2 Standard Library") override def projectSettings = Seq ( fetchScala2ClassFiles := { @@ -37,17 +38,29 @@ object ScalaLibraryPlugin extends AutoPlugin { } (Set(scalaLibraryBinaryJar)), target) }, - (Compile / compile) := { + (Compile / manipulateBytecode) := { val stream = streams.value val target = (Compile / classDirectory).value val (files, reference) = fetchScala2ClassFiles.value; - val analysis = (Compile / compile).value - stream.log.info(s"Copying files from Scala 2 Standard Library to $target") - for (file <- files; id <- file.relativeTo(reference).map(_.toString())) { - if (filesToCopy(id)) { - stream.log.debug(s"Copying file '${id}' to ${target / id}") - IO.copyFile(file, target / id) - } + val previous = (Compile / manipulateBytecode).value + val analysis = previous.analysis match { + case analysis: sbt.internal.inc.Analysis => analysis + case _ => sys.error("Unexpected analysis type") + } + + var stamps = analysis.stamps + for (file <- files; + id <- file.relativeTo(reference); + if filesToCopy(id.toString()); // Only Override Some Very Specific Files + dest = target / (id.toString); + ref <- dest.relativeTo((LocalRootProject / baseDirectory).value) + ) { + // Copy the files to the classDirectory + IO.copyFile(file, dest) + // Update the timestamp in the analysis + stamps = stamps.markProduct( + VirtualFileRef.of(s"$${BASE}/$ref"), + Stamper.forFarmHashP(dest.toPath())) } val overwrittenBinaries = Files.walk((Compile / classDirectory).value.toPath()) @@ -56,13 +69,18 @@ object ScalaLibraryPlugin extends AutoPlugin { .map(_.toFile) .map(_.relativeTo((Compile / classDirectory).value).get) .toSet + val diff = files.filterNot(_.relativeTo(reference).exists(overwrittenBinaries)) - IO.copy(diff.map { file => - file -> (Compile / classDirectory).value / file.relativeTo(reference).get.getPath - }) + // Copy all the specialized classes in the stdlib + // no need to update any stamps as these classes exist nowhere in the analysis + for (orig <- diff; dest <- orig.relativeTo(reference)) { + IO.copyFile(orig, ((Compile / classDirectory).value / dest.toString())) + } - analysis + previous + .withAnalysis(analysis.copy(stamps = stamps)) // update the analysis with the correct stamps + .withHasModified(true) // mark it as updated for sbt to update its caches } )