Corrected and simplified compilation of module chunk.

This commit is contained in:
Evgeny Gerashchenko
2014-06-03 21:51:46 +04:00
parent ad8affe07c
commit 601a691e18
14 changed files with 243 additions and 159 deletions
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2013 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.cli.common.output
import java.io.File
public trait OutputDirector {
public fun getOutputDirectory(sourceFiles: Collection<File>): File
}
public class SingleDirectoryDirector(private val dir: File): OutputDirector {
override public fun getOutputDirectory(sourceFiles : Collection<File>) : File = dir
}
@@ -21,15 +21,13 @@ import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation
import org.jetbrains.jet.cli.common.messages.OutputMessageUtil
import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.jet.cli.common.messages.MessageCollector
import org.jetbrains.jet.cli.common.output.OutputDirector
import java.io.File
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.jet.cli.common.output.SingleDirectoryDirector
public fun OutputFileCollection.writeAll(outputDirector: OutputDirector, report: (sources: List<File>, output: File) -> Unit) {
public fun OutputFileCollection.writeAll(outputDir: File, report: (sources: List<File>, output: File) -> Unit) {
for (file in asList()) {
val sources = file.sourceFiles
val output = File(outputDirector.getOutputDirectory(sources), file.relativePath)
val output = File(outputDir, file.relativePath)
report(sources, output)
FileUtil.writeToFile(output, file.asByteArray())
}
@@ -38,11 +36,11 @@ public fun OutputFileCollection.writeAll(outputDirector: OutputDirector, report:
private val REPORT_NOTHING = { (sources: List<File>, output: File) -> }
public fun OutputFileCollection.writeAllTo(outputDir: File) {
writeAll(SingleDirectoryDirector(outputDir), REPORT_NOTHING)
writeAll(outputDir, REPORT_NOTHING)
}
public fun OutputFileCollection.writeAll(outputDirector: OutputDirector, messageCollector: MessageCollector) {
writeAll(outputDirector) { sources, output ->
public fun OutputFileCollection.writeAll(outputDir: File, messageCollector: MessageCollector) {
writeAll(outputDir) { sources, output ->
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output), CompilerMessageLocation.NO_LOCATION)
}
}
@@ -38,8 +38,6 @@ import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport;
import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.jet.cli.common.messages.MessageCollector;
import org.jetbrains.jet.cli.common.output.OutputDirector;
import org.jetbrains.jet.cli.common.output.SingleDirectoryDirector;
import org.jetbrains.jet.cli.common.output.outputUtils.OutputUtilsPackage;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.jet.config.CommonConfigurationKeys;
@@ -136,8 +134,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
OutputFileCollection outputFiles = translate(mainCallParameters, config, sourcesFiles, outputFile, outputPrefixFile, outputPostfixFile);
OutputDirector outputDirector = new SingleDirectoryDirector(outputFile.getParentFile());
OutputUtilsPackage.writeAll(outputFiles, outputDirector, messageCollector);
OutputUtilsPackage.writeAll(outputFiles, outputFile.getParentFile(), messageCollector);
return OK;
}
@@ -19,7 +19,11 @@ package org.jetbrains.jet.cli.jvm.compiler
import kotlin.modules.Module
class ChunkAsOneModule(private val chunk: ModuleChunk) : Module {
override fun getModuleName(): String = "chunk" + chunk.getModules().map { it.getModuleName() }.toString()
fun getModules(): List<Module> {
return chunk.getModules()
}
override fun getModuleName(): String = "chunk" + getModules().map { it.getModuleName() }.toString()
override fun getOutputDirectory(): String {
throw UnsupportedOperationException("Each module in a chunk has its own output directory")
@@ -32,7 +32,6 @@ import org.jetbrains.jet.cli.common.messages.MessageCollector;
import org.jetbrains.jet.cli.common.messages.MessageRenderer;
import org.jetbrains.jet.cli.common.modules.ModuleDescription;
import org.jetbrains.jet.cli.common.modules.ModuleXmlParser;
import org.jetbrains.jet.cli.common.output.OutputDirector;
import org.jetbrains.jet.cli.common.output.outputUtils.OutputUtilsPackage;
import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
import org.jetbrains.jet.codegen.ClassFileFactory;
@@ -249,7 +248,7 @@ public class CompileEnvironmentUtil {
static void writeOutputToDirOrJar(
@Nullable File jar,
@Nullable OutputDirector outputDir,
@Nullable File outputDir,
boolean includeRuntime,
@Nullable FqName mainClass,
@NotNull ClassFileFactory outputFiles,
@@ -16,6 +16,7 @@
package org.jetbrains.jet.cli.jvm.compiler;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.core.CoreApplicationEnvironment;
import com.intellij.core.CoreJavaFileManager;
@@ -31,13 +32,15 @@ import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElementFinder;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.impl.compiled.ClsCustomNavigationPolicy;
import com.intellij.psi.impl.file.impl.JavaFileManager;
import kotlin.Function1;
import kotlin.Unit;
import kotlin.io.IoPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.CompilerModeProvider;
@@ -203,9 +206,14 @@ public class JetCoreEnvironment {
for (File path : configuration.getList(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY)) {
addExternalAnnotationsRoot(path);
}
for (String path : configuration.getList(CommonConfigurationKeys.SOURCE_ROOTS_KEY)) {
addSources(path);
}
sourceFiles.addAll(
getJetFiles(this, configuration.getList(CommonConfigurationKeys.SOURCE_ROOTS_KEY), new Function1<String, Unit>() {
@Override
public Unit invoke(String s) {
report(ERROR, s);
return null;
}
}));
JetScriptDefinitionProvider.getInstance(project).addScriptDefinitions(
configuration.getList(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY));
@@ -240,42 +248,43 @@ public class JetCoreEnvironment {
annotationsManager.addExternalAnnotationsRoot(PathUtil.jarFileOrDirectoryToVirtualFile(path));
}
private void addSources(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File child : files) {
addSources(child);
}
@NotNull
public static List<JetFile> getJetFiles(@NotNull final JetCoreEnvironment environment, @NotNull List<String> sourceRoots, @NotNull Function1<String, Unit> reportError) {
final List<JetFile> result = Lists.newArrayList();
for (String sourceRootPath : sourceRoots) {
if (sourceRootPath == null) {
continue;
}
}
else {
VirtualFile fileByPath = getMyApplicationEnvironment().getLocalFileSystem().findFileByPath(file.getAbsolutePath());
if (fileByPath != null) {
PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(fileByPath);
if (psiFile instanceof JetFile) {
sourceFiles.add((JetFile) psiFile);
}
VirtualFile vFile = environment.getMyApplicationEnvironment().getLocalFileSystem().findFileByPath(sourceRootPath);
if (vFile == null) {
reportError.invoke("Source file or directory not found: " + sourceRootPath);
continue;
}
if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) {
reportError.invoke("Source entry is not a Kotlin file: " + sourceRootPath);
continue;
}
}
}
private void addSources(String path) {
if (path == null) {
return;
IoPackage.recurse(new File(sourceRootPath), new Function1<File, Unit>() {
@Override
public Unit invoke(File file) {
if (file.isFile()) {
VirtualFile fileByPath = environment.getMyApplicationEnvironment().getLocalFileSystem().findFileByPath(file.getAbsolutePath());
if (fileByPath != null) {
PsiFile psiFile = PsiManager.getInstance(environment.getProject()).findFile(fileByPath);
if (psiFile instanceof JetFile) {
result.add((JetFile) psiFile);
}
}
}
return null;
}
});
}
VirtualFile vFile = getMyApplicationEnvironment().getLocalFileSystem().findFileByPath(path);
if (vFile == null) {
report(ERROR, "Source file or directory not found: " + path);
return;
}
if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) {
report(ERROR, "Source entry is not a Kotlin file: " + path);
return;
}
addSources(new File(path));
return result;
}
private void addToClasspath(File path) {
@@ -17,10 +17,14 @@
package org.jetbrains.jet.cli.jvm.compiler;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiFile;
import kotlin.Function0;
import kotlin.Function1;
import kotlin.Unit;
import kotlin.modules.AllModules;
import kotlin.modules.Module;
import org.jetbrains.annotations.NotNull;
@@ -31,8 +35,6 @@ import org.jetbrains.jet.cli.common.CompilerPlugin;
import org.jetbrains.jet.cli.common.CompilerPluginContext;
import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport;
import org.jetbrains.jet.cli.common.messages.MessageCollector;
import org.jetbrains.jet.cli.common.output.OutputDirector;
import org.jetbrains.jet.cli.common.output.SingleDirectoryDirector;
import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
@@ -56,26 +58,73 @@ import org.jetbrains.jet.utils.KotlinPaths;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class KotlinToJVMBytecodeCompiler {
private static final boolean COMPILE_CHUNK_AS_ONE_MODULE = true;
private KotlinToJVMBytecodeCompiler() {
}
@Nullable
public static ClassFileFactory compileModule(CompilerConfiguration configuration, Module module, File directory) {
List<String> sourceFiles = module.getSourceFiles();
if (sourceFiles.isEmpty()) {
throw new CompileEnvironmentException("No source files where defined in module " + module.getModuleName());
public static Map<Module, ClassFileFactory> compileModule(
@NotNull CompilerConfiguration configuration,
@NotNull List<Module> modules,
@NotNull File directory
) {
CompilerConfiguration compilerConfiguration = configuration.copy();
for (Module module : modules) {
compilerConfiguration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, getAbsolutePaths(directory, module));
for (String classpathRoot : module.getClasspathRoots()) {
compilerConfiguration.add(JVMConfigurationKeys.CLASSPATH_KEY, new File(classpathRoot));
}
for (String annotationsRoot : module.getAnnotationsRoots()) {
compilerConfiguration.add(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, new File(annotationsRoot));
}
}
CompilerConfiguration compilerConfiguration = configuration.copy();
for (String sourceFile : sourceFiles) {
Disposable parentDisposable = Disposer.newDisposable();
JetCoreEnvironment moduleEnvironment = null;
try {
moduleEnvironment = JetCoreEnvironment.createForProduction(parentDisposable, compilerConfiguration);
AnalyzeExhaust exhaust = analyze(moduleEnvironment);
if (exhaust == null) {
return null;
}
exhaust.throwIfError();
Map<Module, ClassFileFactory> result = Maps.newHashMap();
for (Module module : modules) {
List<JetFile> jetFiles = JetCoreEnvironment.getJetFiles(
moduleEnvironment, getAbsolutePaths(directory, module), new Function1<String, Unit>() {
@Override
public Unit invoke(String s) {
return null;
}
});
GenerationState generationState = generate(moduleEnvironment, exhaust, jetFiles);
result.put(module, generationState.getFactory());
}
return result;
}
finally {
if (moduleEnvironment != null) {
Disposer.dispose(parentDisposable);
}
}
}
@NotNull
private static List<String> getAbsolutePaths(@NotNull File directory, @NotNull Module module) {
List<String> result = Lists.newArrayList();
for (String sourceFile : module.getSourceFiles()) {
File source = new File(sourceFile);
if (!source.isAbsolute()) {
source = new File(directory, sourceFile);
@@ -85,39 +134,15 @@ public class KotlinToJVMBytecodeCompiler {
throw new CompileEnvironmentException("'" + source + "' does not exist in module " + module.getModuleName());
}
compilerConfiguration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, source.getPath());
}
for (String classpathRoot : module.getClasspathRoots()) {
compilerConfiguration.add(JVMConfigurationKeys.CLASSPATH_KEY, new File(classpathRoot));
}
for (String annotationsRoot : module.getAnnotationsRoots()) {
compilerConfiguration.add(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, new File(annotationsRoot));
}
Disposable parentDisposable = Disposer.newDisposable();
JetCoreEnvironment moduleEnvironment = null;
try {
moduleEnvironment = JetCoreEnvironment.createForProduction(parentDisposable, compilerConfiguration);
GenerationState generationState = analyzeAndGenerate(moduleEnvironment);
if (generationState == null) {
return null;
}
return generationState.getFactory();
} finally {
if (moduleEnvironment != null) {
Disposer.dispose(parentDisposable);
}
result.add(source.getAbsolutePath());
}
return result;
}
private static void writeOutput(
CompilerConfiguration configuration,
ClassFileFactory outputFiles,
OutputDirector outputDir,
File outputDir,
File jarPath,
boolean jarRuntime,
FqName mainClass
@@ -127,37 +152,20 @@ public class KotlinToJVMBytecodeCompiler {
}
public static boolean compileModules(
CompilerConfiguration configuration,
@NotNull final ModuleChunk chunk,
@NotNull CompilerConfiguration configuration,
@NotNull ModuleChunk chunk,
@NotNull File directory,
@Nullable File jarPath,
boolean jarRuntime
) {
List<Module> modules = chunk.getModules();
if (COMPILE_CHUNK_AS_ONE_MODULE && modules.size() > 1) {
modules = Collections.<Module>singletonList(new ChunkAsOneModule(chunk));
Map<Module, ClassFileFactory> outputFiles = compileModule(configuration, modules, directory);
if (outputFiles == null) {
return false;
}
for (Module module : modules) {
ClassFileFactory outputFiles = compileModule(configuration, module, directory);
if (outputFiles == null) {
return false;
}
OutputDirector outputDir = new OutputDirector() {
@NotNull
@Override
public File getOutputDirectory(@NotNull Collection<? extends File> sourceFiles) {
for (File sourceFile : sourceFiles) {
// Note that here we track original modules:
Module module = chunk.findModuleBySourceFile(sourceFile);
if (module != null) {
return new File(module.getOutputDirectory());
}
}
throw new IllegalStateException("No module found for source files: " + sourceFiles);
}
};
writeOutput(configuration, outputFiles, outputDir, jarPath, jarRuntime, null);
writeOutput(configuration, outputFiles.get(module), new File(module.getOutputDirectory()), jarPath, jarRuntime, null);
}
return true;
}
@@ -194,8 +202,7 @@ public class KotlinToJVMBytecodeCompiler {
FqName mainClass = findMainClass(generationState, environment.getSourceFiles());
try {
OutputDirector outputDirector = outputDir != null ? new SingleDirectoryDirector(outputDir) : null;
writeOutput(environment.getConfiguration(), generationState.getFactory(), outputDirector, jar, includeRuntime, mainClass);
writeOutput(environment.getConfiguration(), generationState.getFactory(), outputDir, jar, includeRuntime, mainClass);
return true;
}
finally {
@@ -262,7 +269,7 @@ public class KotlinToJVMBytecodeCompiler {
exhaust.throwIfError();
return generate(environment, exhaust);
return generate(environment, exhaust, environment.getSourceFiles());
}
@Nullable
@@ -301,11 +308,15 @@ public class KotlinToJVMBytecodeCompiler {
}
@NotNull
private static GenerationState generate(@NotNull JetCoreEnvironment environment, @NotNull AnalyzeExhaust exhaust) {
private static GenerationState generate(
@NotNull JetCoreEnvironment environment,
@NotNull AnalyzeExhaust exhaust,
@NotNull List<JetFile> sourceFiles
) {
CompilerConfiguration configuration = environment.getConfiguration();
GenerationState generationState = new GenerationState(
environment.getProject(), ClassBuilderFactories.BINARIES, Progress.DEAF,
exhaust.getModuleDescriptor(), exhaust.getBindingContext(), environment.getSourceFiles(),
exhaust.getModuleDescriptor(), exhaust.getBindingContext(), sourceFiles,
configuration.get(JVMConfigurationKeys.GENERATE_NOT_NULL_ASSERTIONS, false),
configuration.get(JVMConfigurationKeys.GENERATE_NOT_NULL_PARAMETER_ASSERTIONS, false),
GenerationState.GenerateClassFilter.GENERATE_ALL,
@@ -16,39 +16,24 @@
package org.jetbrains.jet.cli.jvm.compiler;
import com.google.common.collect.Maps;
import kotlin.modules.Module;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ModuleChunk {
public static final ModuleChunk EMPTY = new ModuleChunk(Collections.<Module>emptyList());
private final List<Module> modules;
private final Map<File, Module> sourceFileToModule = Maps.newHashMap();
public ModuleChunk(@NotNull List<Module> modules) {
this.modules = modules;
for (Module module : modules) {
for (String file : module.getSourceFiles()) {
sourceFileToModule.put(new File(file).getAbsoluteFile(), module);
}
}
}
@NotNull
public List<Module> getModules() {
return modules;
}
@Nullable
public Module findModuleBySourceFile(@NotNull File sourceFile) {
return sourceFileToModule.get(sourceFile.getAbsoluteFile());
}
}