mirror of https://github.com/sbt/sbt.git
Make recompilation on macro definition optional.
Introduce a new incremental compiler option that controls incremental compiler's treatment of macro definitions and their clients. The current strategy is that whenever a source file containing a macro definition is touched it will cause recompilation of all direct dependencies of that file. That strategy has proven to be too conservative for some projects like Scala compiler of specs2 leading to too many source files being recompiled. We make this behavior optional by introducing a new option `recompileOnMacroDef` in `IncOptions` class. The default value is set to `true` which preserves the previous behavior.
This commit is contained in:
parent
a6f04cf53b
commit
39036e7c20
|
|
@ -46,42 +46,62 @@ final class IncOptions(
|
|||
*/
|
||||
val apiDumpDirectory: Option[java.io.File],
|
||||
/** Creates a new ClassfileManager that will handle class file deletion and addition during a single incremental compilation run. */
|
||||
val newClassfileManager: () => ClassfileManager
|
||||
val newClassfileManager: () => ClassfileManager,
|
||||
/**
|
||||
* Determines whether incremental compiler should recompile all dependencies of a file
|
||||
* that contains a macro definition.
|
||||
*/
|
||||
val recompileOnMacroDef: Boolean
|
||||
) extends Product with Serializable {
|
||||
|
||||
/**
|
||||
* Secondary constructor introduced to make IncOptions to be binary compatible with version that didn't have
|
||||
* `recompileOnMacroDef` filed defined.
|
||||
*/
|
||||
def this(transitiveStep: Int, recompileAllFraction: Double, relationsDebug: Boolean, apiDebug: Boolean,
|
||||
apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File], newClassfileManager: () => ClassfileManager) = {
|
||||
this(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, IncOptions.recompileOnMacroDefDefault)
|
||||
}
|
||||
|
||||
def withTransitiveStep(transitiveStep: Int): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withRecompileAllFraction(recompileAllFraction: Double): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withRelationsDebug(relationsDebug: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withApiDebug(apiDebug: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withApiDiffContextSize(apiDiffContextSize: Int): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withApiDumpDirectory(apiDumpDirectory: Option[File]): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withNewClassfileManager(newClassfileManager: () => ClassfileManager): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
def withRecompileOnMacroDef(recompileOnMacroDef: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
|
||||
//- EXPANDED CASE CLASS METHOD BEGIN -//
|
||||
|
|
@ -147,7 +167,8 @@ final class IncOptions(
|
|||
}
|
||||
|
||||
object IncOptions extends Serializable {
|
||||
val Default = new IncOptions(
|
||||
private val recompileOnMacroDefDefault: Boolean = true
|
||||
val Default = IncOptions(
|
||||
// 1. recompile changed sources
|
||||
// 2(3). recompile direct dependencies and transitive public inheritance dependencies of sources with API changes in 1(2).
|
||||
// 4. further changes invalidate all dependencies transitively to avoid too many steps
|
||||
|
|
@ -157,16 +178,24 @@ object IncOptions extends Serializable {
|
|||
apiDebug = false,
|
||||
apiDiffContextSize = 5,
|
||||
apiDumpDirectory = None,
|
||||
newClassfileManager = ClassfileManager.deleteImmediately
|
||||
newClassfileManager = ClassfileManager.deleteImmediately,
|
||||
recompileOnMacroDef = recompileOnMacroDefDefault
|
||||
)
|
||||
//- EXPANDED CASE CLASS METHOD BEGIN -//
|
||||
final override def toString(): String = "IncOptions"
|
||||
@deprecated("Use overloaded variant of `apply` with complete list of arguments instead.", "0.13.2")
|
||||
def apply(transitiveStep: Int, recompileAllFraction: Double, relationsDebug: Boolean, apiDebug: Boolean,
|
||||
apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File],
|
||||
newClassfileManager: () => ClassfileManager): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager)
|
||||
}
|
||||
def apply(transitiveStep: Int, recompileAllFraction: Double, relationsDebug: Boolean, apiDebug: Boolean,
|
||||
apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File],
|
||||
newClassfileManager: () => ClassfileManager, recompileOnMacroDef: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef)
|
||||
}
|
||||
@deprecated("Methods generated for case class will be removed in the future.", "0.13.2")
|
||||
def unapply(x$0: IncOptions): Option[(Int, Double, Boolean, Boolean, Int, Option[java.io.File], () => AnyRef)] = {
|
||||
if (x$0 == null) None
|
||||
|
|
@ -187,7 +216,8 @@ object IncOptions extends Serializable {
|
|||
val relationsDebugKey = "relationsDebug"
|
||||
val apiDebugKey = "apiDebug"
|
||||
val apiDumpDirectoryKey = "apiDumpDirectory"
|
||||
val apiDiffContextSize = "apiDiffContextSize"
|
||||
val apiDiffContextSizeKey = "apiDiffContextSize"
|
||||
val recompileOnMacroDefKey = "recompileOnMacroDefKey"
|
||||
|
||||
def fromStringMap(m: java.util.Map[String, String]): IncOptions = {
|
||||
// all the code below doesn't look like idiomatic Scala for a good reason: we are working with Java API
|
||||
|
|
@ -208,7 +238,7 @@ object IncOptions extends Serializable {
|
|||
if (m.containsKey(k)) m.get(k).toBoolean else Default.apiDebug
|
||||
}
|
||||
def getApiDiffContextSize: Int = {
|
||||
val k = apiDiffContextSize
|
||||
val k = apiDiffContextSizeKey
|
||||
if (m.containsKey(k)) m.get(k).toInt else Default.apiDiffContextSize
|
||||
}
|
||||
def getApiDumpDirectory: Option[java.io.File] = {
|
||||
|
|
@ -217,9 +247,13 @@ object IncOptions extends Serializable {
|
|||
Some(new java.io.File(m.get(k)))
|
||||
else None
|
||||
}
|
||||
def getRecompileOnMacroDef: Boolean = {
|
||||
val k = recompileOnMacroDefKey
|
||||
if (m.containsKey(k)) m.get(k).toBoolean else Default.recompileOnMacroDef
|
||||
}
|
||||
|
||||
new IncOptions(getTransitiveStep, getRecompileAllFraction, getRelationsDebug, getApiDebug, getApiDiffContextSize,
|
||||
getApiDumpDirectory, ClassfileManager.deleteImmediately)
|
||||
getApiDumpDirectory, ClassfileManager.deleteImmediately, getRecompileOnMacroDef)
|
||||
}
|
||||
|
||||
def toStringMap(o: IncOptions): java.util.Map[String, String] = {
|
||||
|
|
@ -229,7 +263,8 @@ object IncOptions extends Serializable {
|
|||
m.put(relationsDebugKey, o.relationsDebug.toString)
|
||||
m.put(apiDebugKey, o.apiDebug.toString)
|
||||
o.apiDumpDirectory.foreach(f => m.put(apiDumpDirectoryKey, f.toString))
|
||||
m.put(apiDiffContextSize, o.apiDiffContextSize.toString)
|
||||
m.put(apiDiffContextSizeKey, o.apiDiffContextSize.toString)
|
||||
m.put(recompileOnMacroDefKey, o.recompileOnMacroDef.toString)
|
||||
m
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ object Incremental
|
|||
{
|
||||
val oldApis = lastSources.toSeq map oldAPI
|
||||
val newApis = lastSources.toSeq map newAPI
|
||||
val apiChanges = (lastSources, oldApis, newApis).zipped.flatMap { (src, oldApi, newApi) => sameSource(src, oldApi, newApi, log) }
|
||||
val apiChanges = (lastSources, oldApis, newApis).zipped.flatMap { (src, oldApi, newApi) => sameSource(src, oldApi, newApi, log, options) }
|
||||
|
||||
if (apiDebug(options) && apiChanges.nonEmpty) {
|
||||
logApiChanges(apiChanges, oldAPI, newAPI, log, options)
|
||||
|
|
@ -150,13 +150,13 @@ object Incremental
|
|||
|
||||
new APIChanges(apiChanges)
|
||||
}
|
||||
def sameSource[T](src: T, a: Source, b: Source, log: Logger): Option[APIChange[T]] = {
|
||||
def sameSource[T](src: T, a: Source, b: Source, log: Logger, options: IncOptions): Option[APIChange[T]] = {
|
||||
// Clients of a modified source file (ie, one that doesn't satisfy `shortcutSameSource`) containing macros must be recompiled.
|
||||
val hasMacro = a.hasMacro || b.hasMacro
|
||||
if (shortcutSameSource(a, b)) {
|
||||
None
|
||||
} else {
|
||||
if (hasMacro) {
|
||||
if (hasMacro && options.recompileOnMacroDef) {
|
||||
Some(APIChangeDueToMacroDefinition(src))
|
||||
} else sameAPI(src, a, b, log)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue