From 8594e4443dc1fd5f0eb7f9872efc33196fd6cfac Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Wed, 18 Apr 2012 08:07:53 -0400 Subject: [PATCH] reorganize compilation modules --- compile/AnalyzingCompiler.scala | 18 ++---- compile/CompilerArguments.scala | 3 +- compile/CompilerInterfaceProvider.scala | 15 +++++ compile/integration/AggressiveCompile.scala | 55 ++++++++++++++++++- compile/{ => ivy}/ComponentCompiler.scala | 11 ++++ .../src/main/java/xsbti/ArtifactInfo.java | 9 +++ ivy/IvyScala.scala | 10 ++-- .../actions}/Compiler.scala | 53 +----------------- project/Sbt.scala | 5 +- 9 files changed, 106 insertions(+), 73 deletions(-) create mode 100644 compile/CompilerInterfaceProvider.scala rename compile/{ => ivy}/ComponentCompiler.scala (87%) create mode 100644 interface/src/main/java/xsbti/ArtifactInfo.java rename {compile/integration => main/actions}/Compiler.scala (67%) diff --git a/compile/AnalyzingCompiler.scala b/compile/AnalyzingCompiler.scala index f66fa2375..98239aa3b 100644 --- a/compile/AnalyzingCompiler.scala +++ b/compile/AnalyzingCompiler.scala @@ -12,9 +12,9 @@ package compiler * provided by scalaInstance. This class requires a ComponentManager in order to obtain the interface code to scalac and * the analysis plugin. Because these call Scala code for a different Scala version than the one used for this class, they must * be compiled for the version of Scala being used.*/ -class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager, val cp: ClasspathOptions, log: Logger) +class AnalyzingCompiler(val scalaInstance: ScalaInstance, val provider: CompilerInterfaceProvider, val cp: ClasspathOptions, log: Logger) { - def this(scalaInstance: ScalaInstance, manager: ComponentManager, log: Logger) = this(scalaInstance, manager, ClasspathOptions.auto, log) + def this(scalaInstance: ScalaInstance, provider: CompilerInterfaceProvider, log: Logger) = this(scalaInstance, provider, ClasspathOptions.auto, log) def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger) { val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options) @@ -48,7 +48,7 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[String], classOf[ClassLoader], classOf[Array[String]], classOf[Array[Any]], classOf[xLogger])( options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, cleanupCommands, loader.orNull, names.toArray[String], values.toArray[Any], log) } - def force(log: Logger): Unit = getInterfaceJar(log) + def force(log: Logger): Unit = provider(scalaInstance, log) private def call(interfaceClassName: String, log: Logger)(argTypes: Class[_]*)(args: AnyRef*) { val interfaceClass = getInterfaceClass(interfaceClassName, log) @@ -59,20 +59,12 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component } private[this] def loader = { - val interfaceJar = getInterfaceJar(log) + val interfaceJar = provider(scalaInstance, log) // this goes to scalaInstance.loader for scala classes and the loader of this class for xsbti classes val dual = createDualLoader(scalaInstance.loader, getClass.getClassLoader) new URLClassLoader(Array(interfaceJar.toURI.toURL), dual) } private def getInterfaceClass(name: String, log: Logger) = Class.forName(name, true, loader) - private def getInterfaceJar(log: Logger) = - { - // this is the instance used to compile the interface component - val componentCompiler = newComponentCompiler(log) - log.debug("Getting " + ComponentCompiler.compilerInterfaceID + " from component compiler for Scala " + scalaInstance.version) - componentCompiler(ComponentCompiler.compilerInterfaceID) - } - def newComponentCompiler(log: Logger) = new ComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager) protected def createDualLoader(scalaLoader: ClassLoader, sbtLoader: ClassLoader): ClassLoader = { val xsbtiFilter = (name: String) => name.startsWith("xsbti.") @@ -80,4 +72,4 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component new classpath.DualLoader(scalaLoader, notXsbtiFilter, x => true, sbtLoader, xsbtiFilter, x => false) } override def toString = "Analyzing compiler (Scala " + scalaInstance.actualVersion + ")" -} \ No newline at end of file +} diff --git a/compile/CompilerArguments.scala b/compile/CompilerArguments.scala index e2e6af4ea..888dc6437 100644 --- a/compile/CompilerArguments.scala +++ b/compile/CompilerArguments.scala @@ -4,6 +4,7 @@ package sbt package compiler + import xsbti.ArtifactInfo import scala.util import java.io.File import CompilerArguments.{abs, absString, BootClasspathOption} @@ -48,7 +49,7 @@ final class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions originalBoot } def filterLibrary(classpath: Seq[File]) = - if(cp.filterLibrary) classpath.filterNot(_.getName contains ScalaArtifacts.LibraryID) else classpath + if(cp.filterLibrary) classpath.filterNot(_.getName contains ArtifactInfo.ScalaLibraryID) else classpath def bootClasspathOption = if(cp.autoBoot) Seq(BootClasspathOption, createBootClasspath) else Nil def bootClasspath = if(cp.autoBoot) IO.parseClasspath(createBootClasspath) else Nil } diff --git a/compile/CompilerInterfaceProvider.scala b/compile/CompilerInterfaceProvider.scala new file mode 100644 index 000000000..d0c641681 --- /dev/null +++ b/compile/CompilerInterfaceProvider.scala @@ -0,0 +1,15 @@ +package sbt +package compiler + + import java.io.File + +trait CompilerInterfaceProvider +{ + def apply(scalaInstance: ScalaInstance, log: Logger): File +} +object CompilerInterfaceProvider +{ + def constant(file: File): CompilerInterfaceProvider = new CompilerInterfaceProvider { + def apply(scalaInstance: ScalaInstance, log: Logger): File = file + } +} \ No newline at end of file diff --git a/compile/integration/AggressiveCompile.scala b/compile/integration/AggressiveCompile.scala index b4dfad7ad..86adb9d30 100644 --- a/compile/integration/AggressiveCompile.scala +++ b/compile/integration/AggressiveCompile.scala @@ -2,11 +2,11 @@ * Copyright 2010 Mark Harrah */ package sbt +package compiler import inc._ import java.io.File - import compiler.{AnalyzingCompiler, CompilerArguments, JavaCompiler} import classpath.ClasspathUtilities import classfile.Analyze import xsbti.api.Source @@ -108,7 +108,7 @@ class AggressiveCompile(cacheFile: File) import AnalysisFormats._ val store = AggressiveCompile.staticCache(cacheFile, AnalysisStore.sync(AnalysisStore.cached(FileBasedStore(cacheFile)))) } -private object AggressiveCompile +object AggressiveCompile { import collection.mutable import java.lang.ref.{Reference,SoftReference} @@ -121,4 +121,53 @@ private object AggressiveCompile b } } -} \ No newline at end of file + + def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaCompiler = + if(javaHome.isDefined) + JavaCompiler.fork(cpOptions, instance)(forkJavac(javaHome)) + else + JavaCompiler.directOrFork(cpOptions, instance)(forkJavac(None)) + + def forkJavac(javaHome: Option[File]): JavaCompiler.Fork = + { + import Path._ + def exec(jc: JavacContract) = javaHome match { case None => jc.name; case Some(jh) => (jh / "bin" / jc.name).absolutePath } + (contract: JavacContract, args: Seq[String], log: Logger) => { + log.debug("Forking " + contract.name + ": " + exec(contract) + " " + args.mkString(" ")) + val javacLogger = new JavacLogger(log) + var exitCode = -1 + try { + exitCode = Process(exec(contract), args) ! javacLogger + } finally { + javacLogger.flush(exitCode) + } + exitCode + } + } +} + +private[sbt] class JavacLogger(log: Logger) extends ProcessLogger { + import scala.collection.mutable.ListBuffer + import Level.{Info, Warn, Error, Value => LogLevel} + + private val msgs: ListBuffer[(LogLevel, String)] = new ListBuffer() + + def info(s: => String): Unit = + synchronized { msgs += ((Info, s)) } + + def error(s: => String): Unit = + synchronized { msgs += ((Error, s)) } + + def buffer[T](f: => T): T = f + + private def print(desiredLevel: LogLevel)(t: (LogLevel, String)) = t match { + case (Info, msg) => log.info(msg) + case (Error, msg) => log.log(desiredLevel, msg) + } + + def flush(exitCode: Int): Unit = { + val level = if (exitCode == 0) Warn else Error + msgs foreach print(level) + msgs.clear() + } +} diff --git a/compile/ComponentCompiler.scala b/compile/ivy/ComponentCompiler.scala similarity index 87% rename from compile/ComponentCompiler.scala rename to compile/ivy/ComponentCompiler.scala index ea575f23b..e4431c127 100644 --- a/compile/ComponentCompiler.scala +++ b/compile/ivy/ComponentCompiler.scala @@ -14,6 +14,17 @@ object ComponentCompiler val compilerInterfaceID = "compiler-interface" val compilerInterfaceSrcID = compilerInterfaceID + srcExtension val javaVersion = System.getProperty("java.class.version") + + def interfaceProvider(manager: ComponentManager): CompilerInterfaceProvider = new CompilerInterfaceProvider + { + def apply(scalaInstance: ScalaInstance, log: Logger): File = + { + // this is the instance used to compile the interface component + val componentCompiler = new ComponentCompiler(new RawCompiler(scalaInstance, ClasspathOptions.auto, log), manager) + log.debug("Getting " + compilerInterfaceID + " from component compiler for Scala " + scalaInstance.version) + componentCompiler(compilerInterfaceID) + } + } } /** This class provides source components compiled with the provided RawCompiler. * The compiled classes are cached using the provided component manager according diff --git a/interface/src/main/java/xsbti/ArtifactInfo.java b/interface/src/main/java/xsbti/ArtifactInfo.java new file mode 100644 index 000000000..6f2eedae5 --- /dev/null +++ b/interface/src/main/java/xsbti/ArtifactInfo.java @@ -0,0 +1,9 @@ +package xsbti; + +public final class ArtifactInfo +{ + public static final String ScalaOrganization = "org.scala-lang"; + public static final String ScalaLibraryID = "scala-library"; + public static final String ScalaCompilerID = "scala-compiler"; + public static final String SbtOrganization = "org.scala-sbt"; +} \ No newline at end of file diff --git a/ivy/IvyScala.scala b/ivy/IvyScala.scala index 647df693f..a4654eb51 100644 --- a/ivy/IvyScala.scala +++ b/ivy/IvyScala.scala @@ -14,14 +14,16 @@ import plugins.matcher.ExactPatternMatcher object ScalaArtifacts { - val Organization = "org.scala-lang" - val LibraryID = "scala-library" - val CompilerID = "scala-compiler" + import xsbti.ArtifactInfo._ + val Organization = ScalaOrganization + val LibraryID = ScalaLibraryID + val CompilerID = ScalaCompilerID def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version) } object SbtArtifacts { - val Organization = "org.scala-sbt" + import xsbti.ArtifactInfo._ + val Organization = SbtOrganization } import ScalaArtifacts._ diff --git a/compile/integration/Compiler.scala b/main/actions/Compiler.scala similarity index 67% rename from compile/integration/Compiler.scala rename to main/actions/Compiler.scala index b6818fcae..7b978aeb0 100644 --- a/compile/integration/Compiler.scala +++ b/main/actions/Compiler.scala @@ -46,7 +46,7 @@ object Compiler def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File])(implicit app: AppConfiguration, log: Logger): Compilers = { - val javac = directOrFork(instance, cpOptions, javaHome) + val javac = AggressiveCompile.directOrFork(instance, cpOptions, javaHome) compilers(instance, cpOptions, javac) } def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: JavaCompiler.Fork)(implicit app: AppConfiguration, log: Logger): Compilers = @@ -63,29 +63,8 @@ object Compiler { val launcher = app.provider.scalaProvider.launcher val componentManager = new ComponentManager(launcher.globalLock, app.provider.components, Option(launcher.ivyHome), log) - new AnalyzingCompiler(instance, componentManager, cpOptions, log) - } - def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaCompiler = - if(javaHome.isDefined) - JavaCompiler.fork(cpOptions, instance)(forkJavac(javaHome)) - else - JavaCompiler.directOrFork(cpOptions, instance)(forkJavac(None)) - - def forkJavac(javaHome: Option[File]): JavaCompiler.Fork = - { - import Path._ - def exec(jc: JavacContract) = javaHome match { case None => jc.name; case Some(jh) => (jh / "bin" / jc.name).absolutePath } - (contract: JavacContract, args: Seq[String], log: Logger) => { - log.debug("Forking " + contract.name + ": " + exec(contract) + " " + args.mkString(" ")) - val javacLogger = new JavacLogger(log) - var exitCode = -1 - try { - exitCode = Process(exec(contract), args) ! javacLogger - } finally { - javacLogger.flush(exitCode) - } - exitCode - } + val provider = ComponentCompiler.interfaceProvider(componentManager) + new AnalyzingCompiler(instance, provider, cpOptions, log) } def apply(in: Inputs, log: Logger): Analysis = @@ -98,29 +77,3 @@ object Compiler agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, definesClass, maxErrors, order, skip)(log) } } - -private[sbt] class JavacLogger(log: Logger) extends ProcessLogger { - import scala.collection.mutable.ListBuffer - import Level.{Info, Warn, Error, Value => LogLevel} - - private val msgs: ListBuffer[(LogLevel, String)] = new ListBuffer() - - def info(s: => String): Unit = - synchronized { msgs += ((Info, s)) } - - def error(s: => String): Unit = - synchronized { msgs += ((Error, s)) } - - def buffer[T](f: => T): T = f - - private def print(desiredLevel: LogLevel)(t: (LogLevel, String)) = t match { - case (Info, msg) => log.info(msg) - case (Error, msg) => log.log(desiredLevel, msg) - } - - def flush(exitCode: Int): Unit = { - val level = if (exitCode == 0) Warn else Error - msgs foreach print(level) - msgs.clear() - } -} diff --git a/project/Sbt.scala b/project/Sbt.scala index 3ea36b9b1..fbf96d087 100644 --- a/project/Sbt.scala +++ b/project/Sbt.scala @@ -102,10 +102,11 @@ object Sbt extends Build // Persists the incremental data structures using SBinary lazy val compilePersistSub = baseProject(compilePath / "persist", "Persist") dependsOn(compileIncrementalSub, apiSub) settings(sbinary) // sbt-side interface to compiler. Calls compiler-side interface reflectively - lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", ivySub, ioSub, classpathSub, + lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", logSub, ioSub, classpathSub, logSub % "test->test", launchSub % "test->test", apiSub % "test") settings( compilerSettings : _*) lazy val compilerIntegrationSub = baseProject(compilePath / "integration", "Compiler Integration") dependsOn( compileIncrementalSub, compilerSub, compilePersistSub, apiSub, classfileSub) + lazy val compilerIvySub = baseProject(compilePath / "ivy", "Compiler Ivy Integration") dependsOn(ivySub, compilerSub ) lazy val scriptedBaseSub = baseProject(scriptedPath / "base", "Scripted Framework") dependsOn(ioSub, processSub) lazy val scriptedSbtSub = baseProject(scriptedPath / "sbt", "Scripted sbt") dependsOn(ioSub, logSub, processSub, scriptedBaseSub, launchInterfaceSub % "provided") @@ -114,7 +115,7 @@ object Sbt extends Build // Implementation and support code for defining actions. lazy val actionsSub = baseProject(mainPath / "actions", "Actions") dependsOn( - classpathSub, completeSub, apiSub, compilerIntegrationSub, + classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub, interfaceSub, ioSub, ivySub, logSub, processSub, runSub, stdTaskSub, taskSub, trackingSub, testingSub) lazy val commandSub = testedBaseProject(commandPath, "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub)