diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 834951664e7..f8281b95b7b 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -29,11 +29,12 @@ import org.jetbrains.kotlin.cli.common.messages.FilteringMessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageUtil import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil +import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder +import org.jetbrains.kotlin.cli.common.modules.ModuleChunk import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentUtil import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler -import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal import org.jetbrains.kotlin.codegen.CompilationException @@ -46,6 +47,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion +import org.jetbrains.kotlin.modules.JavaRootPath import org.jetbrains.kotlin.utils.KotlinPaths import org.jetbrains.kotlin.utils.PathUtil import java.io.File @@ -72,26 +74,8 @@ class K2JVMCompiler : CLICompiler() { val pluginLoadResult = loadPlugins(arguments, configuration) if (pluginLoadResult != ExitCode.OK) return pluginLoadResult - val commonSources = arguments.commonSources?.toSet().orEmpty() - if (!arguments.script && arguments.buildFile == null) { - for (arg in arguments.freeArgs) { - val file = File(arg) - if (file.extension == JavaFileType.DEFAULT_EXTENSION) { - configuration.addJavaSourceRoot(file, arguments.javaPackagePrefix) - } else { - configuration.addKotlinSourceRoot(arg, isCommon = arg in commonSources) - if (file.isDirectory) { - configuration.addJavaSourceRoot(file, arguments.javaPackagePrefix) - } - } - } - - for (path in arguments.javaSourceRoots ?: emptyArray()) { - configuration.addJavaSourceRoot(File(path), arguments.javaPackagePrefix) - } - } - - configuration.put(CommonConfigurationKeys.MODULE_NAME, arguments.moduleName ?: JvmAbi.DEFAULT_MODULE_NAME) + val moduleName = arguments.moduleName ?: JvmAbi.DEFAULT_MODULE_NAME + configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName) configuration.configureExplicitContentRoots(arguments) configuration.configureStandardLibs(paths, arguments) @@ -109,9 +93,26 @@ class K2JVMCompiler : CLICompiler() { messageCollector.report(LOGGING, "Configuring the compilation environment") try { - val destination = arguments.destination + if (arguments.script) { + val sourcePath = arguments.freeArgs.first() + configuration.addKotlinSourceRoot(sourcePath) - if (arguments.buildFile != null) { + val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) + ?: return COMPILATION_ERROR + + val scriptingEvaluator = ScriptEvaluationExtension.getInstances(environment.project).find { it.isAccepted(arguments) } + if (scriptingEvaluator == null) { + messageCollector.report(ERROR, "Unable to evaluate script, no scripting plugin found") + return COMPILATION_ERROR + } + + return scriptingEvaluator.eval(arguments, environment) + } + + val destination = arguments.destination?.let { File(it) } + val buildFile = arguments.buildFile?.let { File(it) } + + val moduleChunk = if (buildFile != null) { fun strongWarning(message: String) { messageCollector.report(STRONG_WARNING, message) } @@ -126,66 +127,37 @@ class K2JVMCompiler : CLICompiler() { } val sanitizedCollector = FilteringMessageCollector(messageCollector, VERBOSE::contains) - val buildFile = File(arguments.buildFile) - val moduleChunk = CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector) - configuration.put(JVMConfigurationKeys.MODULE_XML_FILE, buildFile) - - KotlinToJVMBytecodeCompiler.configureSourceRoots(configuration, moduleChunk.modules, buildFile) - - val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) - ?: return COMPILATION_ERROR - - environment.registerJavacIfNeeded(arguments).let { - if (!it) return COMPILATION_ERROR - } - - KotlinToJVMBytecodeCompiler.compileModules(environment, buildFile, moduleChunk.modules) - } else if (arguments.script) { - val sourcePath = arguments.freeArgs.first() - configuration.addKotlinSourceRoot(sourcePath) - - val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) - ?: return COMPILATION_ERROR - - val scriptingEvaluator = ScriptEvaluationExtension.getInstances(environment.project).find { it.isAccepted(arguments) } - if (scriptingEvaluator == null) { - messageCollector.report(ERROR, "Unable to evaluate script, no scripting plugin found") - return COMPILATION_ERROR - } - - return scriptingEvaluator.eval(arguments, environment) + CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector) } else { if (destination != null) { - if (destination.endsWith(".jar")) { - configuration.put(JVMConfigurationKeys.OUTPUT_JAR, File(destination)) + if (destination.path.endsWith(".jar")) { + configuration.put(JVMConfigurationKeys.OUTPUT_JAR, destination) } else { - configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, File(destination)) + configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination) } } - val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) - ?: return COMPILATION_ERROR + val module = ModuleBuilder(moduleName, destination?.path ?: ".", "java-production") + module.configureFromArgs(arguments) - environment.registerJavacIfNeeded(arguments).let { - if (!it) return COMPILATION_ERROR - } + if (module.getSourceFiles().isEmpty()) { + if (arguments.version) return OK - if (environment.getSourceFiles().isEmpty()) { - if (arguments.version) { - return OK - } messageCollector.report(ERROR, "No source files") return COMPILATION_ERROR } - KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment) - - compileJavaFilesIfNeeded(environment, arguments).let { - if (!it) return COMPILATION_ERROR - } + ModuleChunk(listOf(module)) } + KotlinToJVMBytecodeCompiler.configureSourceRoots(configuration, moduleChunk.modules, buildFile) + val environment = createCoreEnvironment(rootDisposable, configuration, messageCollector) + ?: return COMPILATION_ERROR + environment.registerJavacIfNeeded(arguments).let { + if (!it) return COMPILATION_ERROR + } + KotlinToJVMBytecodeCompiler.compileModules(environment, buildFile, moduleChunk.modules) return OK } catch (e: CompilationException) { messageCollector.report( @@ -197,6 +169,30 @@ class K2JVMCompiler : CLICompiler() { } } + private fun ModuleBuilder.configureFromArgs(args: K2JVMCompilerArguments) { + args.friendPaths?.forEach { addFriendDir(it) } + args.classpath?.split(File.pathSeparator)?.forEach { addClasspathEntry(it) } + args.javaSourceRoots?.forEach { + addJavaSourceRoot(JavaRootPath(it, args.javaPackagePrefix)) + } + + val commonSources = args.commonSources?.toSet().orEmpty() + for (arg in args.freeArgs) { + if (arg.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) { + addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix)) + } else { + addSourceFiles(arg) + if (arg in commonSources) { + addCommonSourceFiles(arg) + } + + if (File(arg).isDirectory) { + addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix)) + } + } + } + } + private fun loadPlugins(arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration): ExitCode { var pluginClasspaths: Iterable = arguments.pluginClasspaths?.asIterable() ?: emptyList() val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList() @@ -240,16 +236,6 @@ class K2JVMCompiler : CLICompiler() { return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration) } - private fun compileJavaFilesIfNeeded( - environment: KotlinCoreEnvironment, - arguments: K2JVMCompilerArguments - ): Boolean { - if (arguments.compileJava) { - return JavacWrapper.getInstance(environment.project).use { it.compile() } - } - return true - } - private fun createCoreEnvironment( rootDisposable: Disposable, configuration: CompilerConfiguration, diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index 3bd15ca78bb..ea7ceb8fb8d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -45,10 +45,7 @@ import org.jetbrains.kotlin.cli.jvm.config.* import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.javac.JavacWrapper @@ -101,7 +98,7 @@ object KotlinToJVMBytecodeCompiler { } } - internal fun compileModules(environment: KotlinCoreEnvironment, buildFile: File, chunk: List): Boolean { + internal fun compileModules(environment: KotlinCoreEnvironment, buildFile: File?, chunk: List): Boolean { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project) @@ -131,22 +128,37 @@ object KotlinToJVMBytecodeCompiler { for (module in chunk) { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() - val (moduleSourceDirs, moduleSourceFiles) = - getAbsolutePaths(buildFile, module.getSourceFiles()) + + val ktFiles = if (chunk.size > 1) { + // filter out source files from other modules + assert(buildFile != null) { "Compiling multiple modules, but build file is null" } + val (moduleSourceDirs, moduleSourceFiles) = + getBuildFilePaths(buildFile, module.getSourceFiles()) .mapNotNull(localFileSystem::findFileByPath) .partition(VirtualFile::isDirectory) - val ktFiles = environment.getSourceFiles().filter { file -> - val virtualFile = file.virtualFile - virtualFile in moduleSourceFiles || moduleSourceDirs.any { dir -> - VfsUtilCore.isAncestor(dir, virtualFile, true) + environment.getSourceFiles().filter { file -> + val virtualFile = file.virtualFile + virtualFile in moduleSourceFiles || moduleSourceDirs.any { dir -> + VfsUtilCore.isAncestor(dir, virtualFile, true) + } } + } else { + environment.getSourceFiles() } if (!checkKotlinPackageUsage(environment, ktFiles)) return false val moduleConfiguration = projectConfiguration.copy().apply { - put(JVMConfigurationKeys.OUTPUT_DIRECTORY, File(module.getOutputDirectory())) + if (buildFile != null) { + fun checkKeyIsNull(key: CompilerConfigurationKey<*>, name: String) { + assert(get(key) == null) { "$name should be null, when buildFile is used" } + } + + checkKeyIsNull(JVMConfigurationKeys.OUTPUT_DIRECTORY, "OUTPUT_DIRECTORY") + checkKeyIsNull(JVMConfigurationKeys.OUTPUT_JAR, "OUTPUT_JAR") + put(JVMConfigurationKeys.OUTPUT_DIRECTORY, File(module.getOutputDirectory())) + } } outputs[module] = generate(environment, moduleConfiguration, result, ktFiles, module) @@ -180,11 +192,11 @@ object KotlinToJVMBytecodeCompiler { } } - internal fun configureSourceRoots(configuration: CompilerConfiguration, chunk: List, buildFile: File) { + internal fun configureSourceRoots(configuration: CompilerConfiguration, chunk: List, buildFile: File? = null) { for (module in chunk) { - val commonSources = getAbsolutePaths(buildFile, module.getCommonSourceFiles()).toSet() + val commonSources = getBuildFilePaths(buildFile, module.getCommonSourceFiles()).toSet() - for (path in getAbsolutePaths(buildFile, module.getSourceFiles())) { + for (path in getBuildFilePaths(buildFile, module.getSourceFiles())) { configuration.addKotlinSourceRoot(path, isCommon = path in commonSources) } } @@ -226,8 +238,9 @@ object KotlinToJVMBytecodeCompiler { configuration.addAll(JVMConfigurationKeys.MODULES, chunk) } - private fun getAbsolutePaths(buildFile: File, sourceFilePaths: List): List = - sourceFilePaths.map { path -> + private fun getBuildFilePaths(buildFile: File?, sourceFilePaths: List): List = + if (buildFile == null) sourceFilePaths + else sourceFilePaths.map { path -> (File(path).takeIf(File::isAbsolute) ?: buildFile.resolveSibling(path)).absolutePath }