diff --git a/interface/src/main/java/xsbti/compile/ClasspathOptions.java b/interface/src/main/java/xsbti/compile/ClasspathOptions.java new file mode 100644 index 000000000..e4aba32b7 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/ClasspathOptions.java @@ -0,0 +1,29 @@ +package xsbti.compile; + +/** +* Configures modifications to the classpath based on the Scala instance used for compilation. +* This is typically used for the Scala compiler only and all values set to false for the Java compiler. +*/ +public interface ClasspathOptions +{ + /** If true, includes the Scala library on the boot classpath. This should usually be true.*/ + boolean bootLibrary(); + + /** If true, includes the Scala compiler on the standard classpath. + * This is typically false and is instead managed by the build tool or environment. + */ + boolean compiler(); + + /** If true, includes extra jars from the Scala instance on the standard classpath. + * This is typically false and is instead managed by the build tool or environment. + */ + boolean extra(); + + /** If true, automatically configures the boot classpath. This should usually be true.*/ + boolean autoBoot(); + + /** If true, the Scala library jar is filtered from the standard classpath. + * This should usually be true because the library should be included on the boot classpath of the Scala compiler and not the standard classpath. + */ + boolean filterLibrary(); +} \ No newline at end of file diff --git a/interface/src/main/java/xsbti/compile/CompileOrder.java b/interface/src/main/java/xsbti/compile/CompileOrder.java new file mode 100644 index 000000000..62b15bf1f --- /dev/null +++ b/interface/src/main/java/xsbti/compile/CompileOrder.java @@ -0,0 +1,34 @@ +package xsbti.compile; + +/** +* Defines the order in which Scala and Java sources are compiled when compiling a set of sources with both Java and Scala sources. +* This setting has no effect if only Java sources or only Scala sources are being compiled. +* It is generally more efficient to use JavaThenScala or ScalaThenJava when mixed compilation is not required. +*/ +public enum CompileOrder +{ + /** + * Allows Scala sources to depend on Java sources and allows Java sources to depend on Scala sources. + * + * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources. + * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources. + * The Scala classes compiled in the first step are included on the classpath to the Java compiler. + */ + Mixed, + /** + * Allows Scala sources to depend on the Java sources in the compilation, but does not allow Java sources to depend on Scala sources. + * + * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources. + * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources. + * The Scala classes compiled in the first step are included on the classpath to the Java compiler. + */ + JavaThenScala, + /** + * Allows Java sources to depend on the Scala sources in the compilation, but does not allow Scala sources to depend on Java sources. + * + * In this mode, both Java and Scala sources are passed to the Scala compiler, which generates class files for the Scala sources. + * Then, Java sources are passed to the Java compiler, which generates class files for the Java sources. + * The Scala classes compiled in the first step are included on the classpath to the Java compiler. + */ + ScalaThenJava; +} \ No newline at end of file diff --git a/interface/src/main/java/xsbti/compile/Compilers.java b/interface/src/main/java/xsbti/compile/Compilers.java new file mode 100644 index 000000000..0bb194534 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/Compilers.java @@ -0,0 +1,8 @@ +package xsbti.compile; + +public interface Compilers +{ + JavaCompiler javac(); + // should be cached by client if desired + ScalaCompiler scalac(); +} diff --git a/interface/src/main/java/xsbti/compile/DefinesClass.java b/interface/src/main/java/xsbti/compile/DefinesClass.java new file mode 100644 index 000000000..6369c2661 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/DefinesClass.java @@ -0,0 +1,14 @@ +package xsbti.compile; + +import java.io.File; + +/** +* Determines if an entry on a classpath contains a class. +*/ +public interface DefinesClass +{ + /** + * Returns true if the classpath entry contains the requested class. + */ + boolean apply(String className); +} diff --git a/interface/src/main/java/xsbti/compile/IncrementalCompiler.java b/interface/src/main/java/xsbti/compile/IncrementalCompiler.java new file mode 100644 index 000000000..9fe301029 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/IncrementalCompiler.java @@ -0,0 +1,60 @@ +package xsbti.compile; + +import xsbti.Logger; +import java.io.File; + +/* +* This API is subject to change. +* +* It is the client's responsibility to: +* 1. Manage class loaders. Usually the client will want to: +* i. Keep the class loader used by the ScalaInstance warm. +* ii. Keep the class loader of the incremental recompilation classes (xsbti.compile) warm. +* iii. Share the class loader for Scala classes between the incremental compiler implementation and the ScalaInstance where possible (must be binary compatible) +* 2. Manage the compiler interface jar. The interface must be compiled against the exact Scala version used for compilation and a compatible Java version. +* 3. Manage compilation order between different compilations. +* i. Execute a compilation for each dependency, obtaining an Analysis for each. +* ii. Provide the Analysis from previous compilations to dependent compilations in the analysis map. +* 4. Provide an implementation of JavaCompiler for compiling Java sources. +* 5. Define a function that determines if a classpath entry contains a class (Setup.definesClass). +* i. This is provided by the client so that the client can cache this information across compilations when compiling multiple sets of sources. +* ii. The cache should be cleared for each new compilation run or else recompilation will not properly account for changes to the classpath. +* 6. Provide a cache directory. +* i. This directory is used by IncrementalCompiler to persist data between compilations. +* ii. It should be a different directory for each set of sources being compiled. +* 7. Manage parallel execution. +* i. Each compilation may be performed in a different thread as long as the dependencies have been compiled already. +* ii. Implementations of all types should be immutable and arrays treated as immutable. +* 8. Ensure general invariants: +* i. The implementations of all types are immutable, except for the already discussed Setup.definesClass. +* ii. Arrays are treated as immutable. +* iii. No value is ever null. +*/ +public interface IncrementalCompiler +{ + /** + * Performs an incremental compilation as configured by `in`. + * The returned Analysis should be provided to compilations depending on the classes from this compilation. + */ + Analysis compile(Inputs in, Logger log); + + /** + * Creates a compiler instance that can be used by the `compile` method. + * + * @param instance The Scala version to use + * @param interfaceJar The compiler interface jar compiled for the Scala version being used + * @param options Configures how arguments to the underlying Scala compiler will be built. + */ + ScalaCompiler newScalaCompiler(ScalaInstance instance, File interfaceJar, ClasspathOptions options, Logger log); + + /** + * Compiles the source interface for a Scala version. The resulting jar can then be used by the `newScalaCompiler` method + * to create a ScalaCompiler for incremental compilation. It is the client's responsibility to manage compiled jars for + * different Scala versions. + * + * @param sourceJar The jar file containing the compiler interface sources. These are published as sbt's compiler-interface-src module. + * @param targetJar Where to create the output jar file containing the compiled classes. + * @param instance The ScalaInstance to compile the compiler interface for. + * @param log The logger to use during compilation. */ + void compileInterfaceJar(File sourceJar, File targetJar, ScalaInstance instance, Logger log); +} diff --git a/interface/src/main/java/xsbti/compile/Inputs.java b/interface/src/main/java/xsbti/compile/Inputs.java new file mode 100644 index 000000000..5c9ded425 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/Inputs.java @@ -0,0 +1,14 @@ +package xsbti.compile; + +/** Configures a single compilation of a single set of sources.*/ +public interface Inputs +{ + /** The Scala and Java compilers to use for compilation.*/ + Compilers compilers(); + + /** Standard compilation options, such as the sources and classpath to use. */ + Options options(); + + /** Configures incremental compilation.*/ + Setup setup(); +} diff --git a/interface/src/main/java/xsbti/compile/JavaCompiler.java b/interface/src/main/java/xsbti/compile/JavaCompiler.java new file mode 100644 index 000000000..05bafdfe1 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/JavaCompiler.java @@ -0,0 +1,15 @@ +package xsbti.compile; + +import java.io.File; +import xsbti.Logger; + +/** +* Interface to a Java compiler. +*/ +public interface JavaCompiler +{ + /** Compiles Java sources using the provided classpath, output directory, and additional options. + * If supported, the number of reported errors should be limited to `maximumErrors`. + * Output should be sent to the provided logger.*/ + void compile(File[] sources, File[] classpath, File outputDirectory, String[] options, int maximumErrors, Logger log); +} diff --git a/interface/src/main/java/xsbti/compile/Options.java b/interface/src/main/java/xsbti/compile/Options.java new file mode 100644 index 000000000..9e0d03e98 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/Options.java @@ -0,0 +1,33 @@ +package xsbti.compile; + +import java.io.File; + +/** Standard compilation options.*/ +public interface Options +{ + /** The classpath to use for compilation. + * This will be modified according to the ClasspathOptions used to configure the ScalaCompiler.*/ + File[] classpath(); + + /** All sources that should be recompiled. + * This should include Scala and Java sources, which are identified by their extension. */ + File[] sources(); + + /** The directory where class files should be generated. + * Incremental compilation will manage the class files in this directory. + * In particular, outdated class files will be deleted before compilation. + * It is important that this directory is exclusively used for one set of sources. */ + File classesDirectory(); + + /** The options to pass to the Scala compiler other than the sources and classpath to use. */ + String[] options(); + + /** The options to pass to the Java compiler other than the sources and classpath to use. */ + String[] javacOptions(); + + /** The maximum number of errors that the Scala compiler should report.*/ + int maxErrors(); + + /** Controls the order in which Java and Scala sources are compiled.*/ + CompileOrder order(); +} diff --git a/interface/src/main/java/xsbti/compile/ScalaInstance.java b/interface/src/main/java/xsbti/compile/ScalaInstance.java new file mode 100644 index 000000000..fd66d9a9c --- /dev/null +++ b/interface/src/main/java/xsbti/compile/ScalaInstance.java @@ -0,0 +1,34 @@ +package xsbti.compile; + +import java.io.File; + +/** +* Defines Scala instance, which is a reference version String, a unique version String, a set of jars, and a class loader for a Scala version. +* +* Note that in this API a 'jar' can actually be any valid classpath entry. +*/ +public interface ScalaInstance +{ + /** The version used to refer to this Scala version. + * It need not be unique and can be a dynamic version like 2.10.0-SNAPSHOT. + */ + String version(); + + /** A class loader providing access to the classes and resources in the library and compiler jars. */ + ClassLoader loader(); + + /** The library jar file.*/ + File libraryJar(); + + /** The compiler jar file.*/ + File compilerJar(); + + /** Jars provided by this Scala instance other than the compiler and library jars. */ + File[] extraJars(); + + /** All jar files provided by this Scala instance.*/ + File[] jars(); + + /** The unique identifier for this Scala instance. An implementation should usually obtain this from the compiler.properties file in the compiler jar. */ + String actualVersion(); +} diff --git a/interface/src/main/java/xsbti/compile/Setup.java b/interface/src/main/java/xsbti/compile/Setup.java new file mode 100644 index 000000000..ca9999978 --- /dev/null +++ b/interface/src/main/java/xsbti/compile/Setup.java @@ -0,0 +1,24 @@ +package xsbti.compile; + +import java.io.File; +import xsbti.Maybe; + +/** Configures incremental recompilation. */ +public interface Setup +{ + /** Provides the Analysis for the given classpath entry.*/ + Maybe analysisMap(File file); + + /** Provides a function to determine if classpath entry `file` contains a given class. + * The returned function should generally cache information about `file`, such as the list of entries in a jar. + */ + DefinesClass definesClass(File file); + + /** If true, no sources are actually compiled and the Analysis from the previous compilation is returned.*/ + boolean skip(); + + /** The directory used to cache information across compilations. + * This directory can be removed to force a full recompilation. + * The directory should be unique and not shared between compilations. */ + File cacheDirectory(); +}