In the macro example #2 about the PackageSearch, we saw that cached files calling a macro will not be recompiled if another file only referenced in a macro splice changes.
DISCLAIMER: I'm not good at SBT, there are probably way better ways of doing this, if you know any, please help with a PR to this file
Let's define our keys:
lazy val clearUncached = taskKey[Unit]("Clear target classes in `uncachedClasses`")
lazy val uncachedClasses = settingKey[Seq[String]]("Classes that should not be cached during compilation")
Let's define a utility task to help us delete certain compiled files before each compilation:
// These are the extensions that compiler output can have for a source file (jvm and scalajs)
lazy val Appendages = Seq(
".class",
".sjsir",
".tasty",
"$package.class",
"$package.sjsir",
"$package.tasty",
"$package$.class",
"$package$.sjsir"
)
// In case we don't want any uncached classes
lazy val defaultUncachedClasses =
uncachedClasses := Seq()
lazy val ensureUncaching = clearUncached := {
println("Forcefully invalidating caches...")
val targetFile = target.value
val classesFile = targetFile / ("scala-" + scalaVersion.value) / "classes"
for(className <- uncachedClasses.value) {
val path = (classesFile / className).getAbsolutePath()
for(appendage <- Appendages) {
val file = new File(path + appendage)
val deleted = file.delete()
}
}
}
// This value is actually the act of setting the compile operation to something new
lazy val uncachingCompile =
(compile) := {
val res = (Compile / compile).value
clearUncached.value
res
}
// Only required for scalajs, you might want to do the same with fullOptJS
lazy val uncachingFastOptJS =
(fastOptJS) := {
val res = (Compile / fastOptJS).value
clearUncached.value
res
}
Then in our project we can just use it like:
lazy val myProj = project.in(file(...))
.settings(
ensureUncaching, // Set our uncaching method
uncachingCompile, // Make our compile task do uncaching
uncachingFastOptJS, // Only for scalajs
uncachedClasses := Seq("myname/mydomain/myproject/MainClass") // Define all uncached classes (use / instead of . for packages)
// ... your other settings
)
You should be able to test by running compile
repeatedly in the sbt terminal and you will see that it always compiles at least 1 file (or however many you defined in your project's uncachedClasses
)