CompileEnvironment removed

What used to be CompileEnvironment, now is split into data (in CompileEnvironmentConfiguration) and utility methods (in CompileEnvironmentUtil).
CompilerDependencies should be removed later.
All the relevant stuff sits in the JetCoreEnvironment class
This commit is contained in:
Andrey Breslav
2012-04-20 11:51:47 +04:00
parent d09916ca38
commit 4da91ee3d6
8 changed files with 308 additions and 282 deletions
@@ -20,11 +20,11 @@ import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.sampullara.cli.Args;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.CompileEnvironment;
import org.jetbrains.jet.compiler.CompileEnvironmentException;
import org.jetbrains.jet.compiler.CompilerPlugin;
import org.jetbrains.jet.compiler.*;
import org.jetbrains.jet.compiler.messages.CompilerMessageLocation;
import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity;
import org.jetbrains.jet.compiler.messages.MessageCollector;
@@ -135,23 +135,30 @@ public class KotlinCompiler {
runtimeJar = null;
}
CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar,runtimeJar);
CompilerDependencies dependencies = new CompilerDependencies(mode, jdkHeadersJar, runtimeJar);
PrintingMessageCollector messageCollector = new PrintingMessageCollector(errStream, messageRenderer, arguments.verbose);
CompileEnvironment environment = new CompileEnvironment(messageCollector, dependencies);
Disposable rootDisposable = CompileEnvironmentUtil.createMockDisposable();
JetCoreEnvironment environment = new JetCoreEnvironment(rootDisposable, dependencies);
CompileEnvironmentConfiguration configuration = new CompileEnvironmentConfiguration(environment, dependencies, messageCollector);
try {
configureEnvironment(environment, arguments);
configureEnvironment(configuration, arguments);
boolean noErrors;
if (arguments.module != null) {
noErrors = environment.compileModuleScript(arguments.module, arguments.jar, arguments.outputDir, arguments.includeRuntime);
noErrors = KotlinToJVMBytecodeCompiler.compileModuleScript(configuration,
arguments.module, arguments.jar, arguments.outputDir,
arguments.includeRuntime);
}
else {
// TODO ideally we'd unify to just having a single field that supports multiple files/dirs
if (arguments.getSourceDirs() != null) {
noErrors = environment.compileBunchOfSourceDirectories(arguments.getSourceDirs(), arguments.jar, arguments.outputDir, arguments.includeRuntime);
noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSourceDirectories(configuration,
arguments.getSourceDirs(), arguments.jar, arguments.outputDir, arguments.includeRuntime);
}
else {
noErrors = environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime);
noErrors = KotlinToJVMBytecodeCompiler.compileBunchOfSources(configuration,
arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime);
}
}
return noErrors ? OK : COMPILATION_ERROR;
@@ -161,7 +168,7 @@ public class KotlinCompiler {
return INTERNAL_ERROR;
}
finally {
environment.dispose();
Disposer.dispose(rootDisposable);
messageCollector.printToErrStream();
}
}
@@ -228,20 +235,20 @@ public class KotlinCompiler {
* Strategy method to configure the environment, allowing compiler
* based tools to customise their own plugins
*/
protected void configureEnvironment(CompileEnvironment environment, CompilerArguments arguments) {
protected void configureEnvironment(CompileEnvironmentConfiguration configuration, CompilerArguments arguments) {
// install any compiler plugins
List<CompilerPlugin> plugins = arguments.getCompilerPlugins();
if (plugins != null) {
environment.getEnvironment().getCompilerPlugins().addAll(plugins);
configuration.getEnvironment().getCompilerPlugins().addAll(plugins);
}
if (environment.getCompilerDependencies().getRuntimeJar() != null) {
environment.addToClasspath(environment.getCompilerDependencies().getRuntimeJar());
if (configuration.getCompilerDependencies().getRuntimeJar() != null) {
CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar());
}
if (arguments.classpath != null) {
final Iterable<String> classpath = Splitter.on(File.pathSeparatorChar).split(arguments.classpath);
environment.addToClasspath(Iterables.toArray(classpath, String.class));
CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), Iterables.toArray(classpath, String.class));
}
}
@@ -1,243 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.compiler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.LocalTimeCounter;
import jet.modules.Module;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.plugin.JetMainDetector;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;
/**
* The environment for compiling a bunch of source files or
*
* @author yole
*/
public class CompileEnvironment {
private final Disposable rootDisposable;
private JetCoreEnvironment environment;
private final MessageCollector messageCollector;
@NotNull
private final CompilerDependencies compilerDependencies;
/**
* NOTE: It's very important to call dispose for every object of this class or there will be memory leaks.
* @see Disposer
*/
public CompileEnvironment(@NotNull MessageCollector messageCollector, @NotNull CompilerDependencies compilerDependencies) {
this.messageCollector = messageCollector;
this.compilerDependencies = compilerDependencies;
this.rootDisposable = new Disposable() {
@Override
public void dispose() {
}
};
this.environment = new JetCoreEnvironment(rootDisposable, compilerDependencies);
}
public void dispose() {
Disposer.dispose(rootDisposable);
}
public boolean compileModuleScript(String moduleScriptFile, @Nullable String jarPath, @Nullable String outputDir, boolean jarRuntime) {
List<Module> modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, messageCollector);
if (modules == null) {
throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed");
}
if (modules.isEmpty()) {
throw new CompileEnvironmentException("No modules where defined by " + moduleScriptFile);
}
final String directory = new File(moduleScriptFile).getParent();
for (Module moduleBuilder : modules) {
if (compilerDependencies.getRuntimeJar() != null) {
addToClasspath(compilerDependencies.getRuntimeJar());
}
ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory);
if (moduleFactory == null) {
return false;
}
if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(moduleFactory, outputDir);
}
else {
String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath();
try {
CompileEnvironmentUtil.writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime);
}
catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + path, e);
}
}
}
return true;
}
public ClassFileFactory compileModule(Module moduleBuilder, String directory) {
if (moduleBuilder.getSourceFiles().isEmpty()) {
throw new CompileEnvironmentException("No source files where defined");
}
for (String sourceFile : moduleBuilder.getSourceFiles()) {
File source = new File(sourceFile);
if (!source.isAbsolute()) {
source = new File(directory, sourceFile);
}
if (!source.exists()) {
throw new CompileEnvironmentException("'" + source + "' does not exist");
}
environment.addSources(source.getPath());
}
for (String classpathRoot : moduleBuilder.getClasspathRoots()) {
environment.addToClasspath(new File(classpathRoot));
}
CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies);
return analyze();
}
public ClassLoader compileText(String code) {
environment.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code));
ClassFileFactory factory = analyze();
if (factory == null) {
return null;
}
return new GeneratedClassLoader(factory);
}
public boolean compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) {
environment.addSources(sourceFileOrDir);
return compileBunchOfSources(jar, outputDir, includeRuntime);
}
public boolean compileBunchOfSourceDirectories(List<String> sources, String jar, String outputDir, boolean includeRuntime) {
for (String source : sources) {
environment.addSources(source);
}
return compileBunchOfSources(jar, outputDir, includeRuntime);
}
private boolean compileBunchOfSources(String jar, String outputDir, boolean includeRuntime) {
FqName mainClass = null;
for (JetFile file : environment.getSourceFiles()) {
if (JetMainDetector.hasMain(file.getDeclarations())) {
FqName fqName = JetPsiUtil.getFQName(file);
mainClass = fqName.child(JvmAbi.PACKAGE_CLASS);
break;
}
}
CompileEnvironmentUtil.ensureRuntime(environment, compilerDependencies);
ClassFileFactory factory = analyze();
if (factory == null) {
return false;
}
if (jar != null) {
try {
CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime);
} catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + jar, e);
}
}
else if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir);
}
else {
throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk");
}
return true;
}
private ClassFileFactory analyze() {
boolean stubs = compilerDependencies.getCompilerSpecialMode().isStubs();
GenerationState generationState =
KotlinToJVMBytecodeCompiler
.analyzeAndGenerate(environment, compilerDependencies, messageCollector, stubs);
if (generationState == null) {
return null;
}
return generationState.getFactory();
}
/**
* Add path specified to the compilation environment.
* @param paths paths to add
*/
public void addToClasspath(File ... paths) {
for (File path : paths) {
if (!path.exists()) {
throw new CompileEnvironmentException("'" + path + "' does not exist");
}
environment.addToClasspath(path);
}
}
/**
* Add path specified to the compilation environment.
* @param paths paths to add
*/
public void addToClasspath(String ... paths) {
for (String path : paths) {
addToClasspath( new File(path));
}
}
public void setStdlib(String stdlib) {
File file = new File(stdlib);
addToClasspath(file);
}
public JetCoreEnvironment getEnvironment() {
return environment;
}
@NotNull
public CompilerDependencies getCompilerDependencies() {
return compilerDependencies;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.compiler;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.messages.MessageCollector;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
/**
* @author abreslav
*/
public class CompileEnvironmentConfiguration {
private final JetCoreEnvironment environment;
private final CompilerDependencies compilerDependencies;
private final MessageCollector messageCollector;
/**
* NOTE: It's very important to call dispose for every object of this class or there will be memory leaks.
* @see Disposer
*/
public CompileEnvironmentConfiguration(@NotNull JetCoreEnvironment environment,
@NotNull CompilerDependencies compilerDependencies, @NotNull MessageCollector messageCollector) {
this.messageCollector = messageCollector;
this.compilerDependencies = compilerDependencies;
this.environment = environment;
}
public JetCoreEnvironment getEnvironment() {
return environment;
}
@NotNull
public CompilerDependencies getCompilerDependencies() {
return compilerDependencies;
}
@NotNull
public MessageCollector getMessageCollector() {
return messageCollector;
}
}
@@ -51,9 +51,17 @@ import java.util.jar.*;
* @author abreslav
*/
public class CompileEnvironmentUtil {
public static Disposable createMockDisposable() {
return new Disposable() {
@Override
public void dispose() {
}
};
}
@Nullable
public static File getUnpackedRuntimePath() {
URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class");
URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("file")) {
return new File(url.getPath()).getParentFile().getParentFile();
}
@@ -62,7 +70,7 @@ public class CompileEnvironmentUtil {
@Nullable
public static File getRuntimeJarPath() {
URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class");
URL url = CompileEnvironmentConfiguration.class.getClassLoader().getResource("jet/JetObject.class");
if (url != null && url.getProtocol().equals("jar")) {
String path = url.getPath();
return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/")));
@@ -187,7 +195,7 @@ public class CompileEnvironmentUtil {
}
}
else {
loader = new GeneratedClassLoader(factory, CompileEnvironment.class.getClassLoader());
loader = new GeneratedClassLoader(factory, CompileEnvironmentConfiguration.class.getClassLoader());
}
try {
Class namespaceClass = loader.loadClass(JvmAbi.PACKAGE_CLASS);
@@ -301,4 +309,29 @@ public class CompileEnvironmentUtil {
}
}
}
/**
* Add path specified to the compilation environment.
* @param environment compilation environment to add to
* @param paths paths to add
*/
public static void addToClasspath(JetCoreEnvironment environment, File ... paths) {
for (File path : paths) {
if (!path.exists()) {
throw new CompileEnvironmentException("'" + path + "' does not exist");
}
environment.addToClasspath(path);
}
}
/**
* Add path specified to the compilation environment.
* @param environment compilation environment to add to
* @param paths paths to add
*/
public static void addToClasspath(JetCoreEnvironment environment, String ... paths) {
for (String path : paths) {
addToClasspath(environment, new File(path));
}
}
}
@@ -25,12 +25,13 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.LocalTimeCounter;
import jet.modules.Module;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.codegen.ClassBuilderFactories;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.compiler.messages.CompilerMessageLocation;
import org.jetbrains.jet.compiler.messages.CompilerMessageSeverity;
import org.jetbrains.jet.compiler.messages.MessageCollector;
@@ -41,12 +42,20 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.FqName;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.plugin.JetMainDetector;
import org.jetbrains.jet.utils.Progress;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.List;
@@ -56,6 +65,163 @@ import java.util.List;
*/
public class KotlinToJVMBytecodeCompiler {
@Nullable
public static ClassFileFactory compileModule(
CompileEnvironmentConfiguration configuration,
Module moduleBuilder,
String directory
) {
if (moduleBuilder.getSourceFiles().isEmpty()) {
throw new CompileEnvironmentException("No source files where defined");
}
for (String sourceFile : moduleBuilder.getSourceFiles()) {
File source = new File(sourceFile);
if (!source.isAbsolute()) {
source = new File(directory, sourceFile);
}
if (!source.exists()) {
throw new CompileEnvironmentException("'" + source + "' does not exist");
}
configuration.getEnvironment().addSources(source.getPath());
}
for (String classpathRoot : moduleBuilder.getClasspathRoots()) {
configuration.getEnvironment().addToClasspath(new File(classpathRoot));
}
CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies());
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return null;
}
return generationState.getFactory();
}
public static boolean compileModuleScript(
CompileEnvironmentConfiguration configuration,
@NotNull String moduleScriptFile,
@Nullable String jarPath,
@Nullable String outputDir,
boolean jarRuntime) {
List<Module> modules = CompileEnvironmentUtil.loadModuleScript(moduleScriptFile, configuration.getMessageCollector());
if (modules == null) {
throw new CompileEnvironmentException("Module script " + moduleScriptFile + " compilation failed");
}
if (modules.isEmpty()) {
throw new CompileEnvironmentException("No modules where defined by " + moduleScriptFile);
}
final String directory = new File(moduleScriptFile).getParent();
for (Module moduleBuilder : modules) {
// TODO: this should be done only once for the environment
if (configuration.getCompilerDependencies().getRuntimeJar() != null) {
CompileEnvironmentUtil.addToClasspath(configuration.getEnvironment(), configuration.getCompilerDependencies().getRuntimeJar());
}
ClassFileFactory moduleFactory = KotlinToJVMBytecodeCompiler.compileModule(configuration, moduleBuilder, directory);
if (moduleFactory == null) {
return false;
}
if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(moduleFactory, outputDir);
}
else {
String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath();
try {
CompileEnvironmentUtil.writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime);
}
catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + path, e);
}
}
}
return true;
}
private static boolean compileBunchOfSources(
CompileEnvironmentConfiguration configuration,
String jar,
String outputDir,
boolean includeRuntime
) {
FqName mainClass = null;
for (JetFile file : configuration.getEnvironment().getSourceFiles()) {
if (JetMainDetector.hasMain(file.getDeclarations())) {
FqName fqName = JetPsiUtil.getFQName(file);
mainClass = fqName.child(JvmAbi.PACKAGE_CLASS);
break;
}
}
CompileEnvironmentUtil.ensureRuntime(configuration.getEnvironment(), configuration.getCompilerDependencies());
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return false;
}
ClassFileFactory factory = generationState.getFactory();
if (jar != null) {
try {
CompileEnvironmentUtil.writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime);
} catch (FileNotFoundException e) {
throw new CompileEnvironmentException("Invalid jar path " + jar, e);
}
}
else if (outputDir != null) {
CompileEnvironmentUtil.writeToOutputDirectory(factory, outputDir);
}
else {
throw new CompileEnvironmentException("Output directory or jar file is not specified - no files will be saved to the disk");
}
return true;
}
public static boolean compileBunchOfSources(
CompileEnvironmentConfiguration configuration,
String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) {
configuration.getEnvironment().addSources(sourceFileOrDir);
return compileBunchOfSources(configuration, jar, outputDir, includeRuntime);
}
public static boolean compileBunchOfSourceDirectories(
CompileEnvironmentConfiguration configuration,
List<String> sources, String jar, String outputDir, boolean includeRuntime) {
for (String source : sources) {
configuration.getEnvironment().addSources(source);
}
return compileBunchOfSources(configuration, jar, outputDir, includeRuntime);
}
@Nullable
public static ClassLoader compileText(
CompileEnvironmentConfiguration configuration,
String code) {
configuration.getEnvironment().addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code));
GenerationState generationState = analyzeAndGenerate(configuration);
if (generationState == null) {
return null;
}
return new GeneratedClassLoader(generationState.getFactory());
}
@Nullable
public static GenerationState analyzeAndGenerate(CompileEnvironmentConfiguration configuration) {
return analyzeAndGenerate(configuration.getEnvironment(), configuration.getCompilerDependencies(), configuration.getMessageCollector(), configuration.getCompilerDependencies().getCompilerSpecialMode().isStubs());
}
@Nullable
public static GenerationState analyzeAndGenerate(
JetCoreEnvironment environment,