001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.cli.jvm; 018 019 import com.google.common.base.Splitter; 020 import com.google.common.collect.Lists; 021 import com.intellij.openapi.Disposable; 022 import org.jetbrains.annotations.NotNull; 023 import org.jetbrains.kotlin.cli.common.CLICompiler; 024 import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys; 025 import org.jetbrains.kotlin.cli.common.ExitCode; 026 import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; 027 import org.jetbrains.kotlin.cli.common.messages.*; 028 import org.jetbrains.kotlin.cli.common.modules.ModuleScriptData; 029 import org.jetbrains.kotlin.cli.jvm.compiler.*; 030 import org.jetbrains.kotlin.cli.jvm.config.JVMConfigurationKeys; 031 import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal; 032 import org.jetbrains.kotlin.codegen.CompilationException; 033 import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException; 034 import org.jetbrains.kotlin.compiler.plugin.PluginCliOptionProcessingException; 035 import org.jetbrains.kotlin.compiler.plugin.PluginPackage; 036 import org.jetbrains.kotlin.config.CompilerConfiguration; 037 import org.jetbrains.kotlin.config.Services; 038 import org.jetbrains.kotlin.load.kotlin.incremental.cache.IncrementalCacheProvider; 039 import org.jetbrains.kotlin.resolve.AnalyzerScriptParameter; 040 import org.jetbrains.kotlin.utils.KotlinPaths; 041 import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir; 042 import org.jetbrains.kotlin.utils.PathUtil; 043 044 import java.io.File; 045 import java.util.Collections; 046 import java.util.List; 047 048 import static com.google.common.base.Predicates.in; 049 import static org.jetbrains.kotlin.cli.common.ExitCode.*; 050 import static org.jetbrains.kotlin.cli.jvm.config.ConfigPackage.*; 051 import static org.jetbrains.kotlin.config.ConfigPackage.addKotlinSourceRoot; 052 053 @SuppressWarnings("UseOfSystemOutOrSystemErr") 054 public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> { 055 056 public static void main(String... args) { 057 doMain(new K2JVMCompiler(), args); 058 } 059 060 @Override 061 @NotNull 062 protected ExitCode doExecute( 063 @NotNull K2JVMCompilerArguments arguments, 064 @NotNull Services services, 065 @NotNull MessageCollector messageCollector, 066 @NotNull Disposable rootDisposable 067 ) { 068 KotlinPaths paths = arguments.kotlinHome != null 069 ? new KotlinPathsFromHomeDir(new File(arguments.kotlinHome)) 070 : PathUtil.getKotlinPathsForCompiler(); 071 072 messageCollector.report(CompilerMessageSeverity.LOGGING, 073 "Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION); 074 075 CompilerConfiguration configuration = new CompilerConfiguration(); 076 configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector); 077 078 IncrementalCacheProvider incrementalCacheProvider = services.get(IncrementalCacheProvider.class); 079 if (incrementalCacheProvider != null) { 080 configuration.put(JVMConfigurationKeys.INCREMENTAL_CACHE_PROVIDER, incrementalCacheProvider); 081 } 082 083 CompilerJarLocator locator = services.get(CompilerJarLocator.class); 084 if (locator != null) { 085 configuration.put(JVMConfigurationKeys.COMPILER_JAR_LOCATOR, locator); 086 } 087 088 try { 089 if (!arguments.noJdk) { 090 addJvmClasspathRoots(configuration, PathUtil.getJdkClassesRoots()); 091 } 092 } 093 catch (Throwable t) { 094 MessageCollectorUtil.reportException(messageCollector, t); 095 return INTERNAL_ERROR; 096 } 097 098 try { 099 PluginCliParser.loadPlugins(arguments, configuration); 100 } 101 catch (PluginCliOptionProcessingException e) { 102 String message = e.getMessage() + "\n\n" + PluginPackage.cliPluginUsageString(e.getPluginId(), e.getOptions()); 103 messageCollector.report(CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION); 104 return INTERNAL_ERROR; 105 } 106 catch (CliOptionProcessingException e) { 107 messageCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION); 108 return INTERNAL_ERROR; 109 } 110 catch (Throwable t) { 111 MessageCollectorUtil.reportException(messageCollector, t); 112 return INTERNAL_ERROR; 113 } 114 115 if (arguments.script) { 116 if (arguments.freeArgs.isEmpty()) { 117 messageCollector.report(CompilerMessageSeverity.ERROR, "Specify script source path to evaluate", 118 CompilerMessageLocation.NO_LOCATION); 119 return COMPILATION_ERROR; 120 } 121 addKotlinSourceRoot(configuration, arguments.freeArgs.get(0)); 122 } 123 else if (arguments.module == null) { 124 for (String arg : arguments.freeArgs) { 125 addKotlinSourceRoot(configuration, arg); 126 File file = new File(arg); 127 if (file.isDirectory()) { 128 addJavaSourceRoot(configuration, file); 129 } 130 } 131 } 132 133 addJvmClasspathRoots(configuration, getClasspath(paths, arguments)); 134 135 configuration.addAll(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, getAnnotationsPath(paths, arguments)); 136 137 if (arguments.module == null && arguments.freeArgs.isEmpty() && !arguments.version) { 138 ReplFromTerminal.run(rootDisposable, configuration); 139 return ExitCode.OK; 140 } 141 142 configuration.put(JVMConfigurationKeys.SCRIPT_PARAMETERS, arguments.script 143 ? CommandLineScriptUtils.scriptParameters() 144 : Collections.<AnalyzerScriptParameter>emptyList()); 145 146 putAdvancedOptions(configuration, arguments); 147 148 messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment", 149 CompilerMessageLocation.NO_LOCATION); 150 try { 151 configureEnvironment(configuration, arguments); 152 153 String destination = arguments.destination; 154 155 File jar; 156 File outputDir; 157 if (destination != null) { 158 boolean isJar = destination.endsWith(".jar"); 159 jar = isJar ? new File(destination) : null; 160 outputDir = isJar ? null : new File(destination); 161 } 162 else { 163 jar = null; 164 outputDir = null; 165 } 166 167 if (arguments.module != null) { 168 MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector, in(CompilerMessageSeverity.VERBOSE)); 169 ModuleScriptData moduleScript = CompileEnvironmentUtil.loadModuleDescriptions(arguments.module, sanitizedCollector); 170 171 if (outputDir != null) { 172 messageCollector.report(CompilerMessageSeverity.WARNING, 173 "The '-d' option with a directory destination is ignored because '-module' is specified", 174 CompilerMessageLocation.NO_LOCATION); 175 } 176 177 File directory = new File(arguments.module).getAbsoluteFile().getParentFile(); 178 KotlinToJVMBytecodeCompiler.compileModules( 179 configuration, moduleScript.getModules(), directory, jar, arguments.includeRuntime 180 ); 181 } 182 else if (arguments.script) { 183 List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size()); 184 KotlinCoreEnvironment environment = 185 KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); 186 KotlinToJVMBytecodeCompiler.compileAndExecuteScript(configuration, paths, environment, scriptArgs); 187 } 188 else { 189 KotlinCoreEnvironment environment = 190 KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); 191 KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime); 192 } 193 return OK; 194 } 195 catch (CompilationException e) { 196 messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e), 197 MessageUtil.psiElementToMessageLocation(e.getElement())); 198 return INTERNAL_ERROR; 199 } 200 } 201 202 private static void putAdvancedOptions(@NotNull CompilerConfiguration configuration, @NotNull K2JVMCompilerArguments arguments) { 203 configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions); 204 configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions); 205 configuration.put(JVMConfigurationKeys.DISABLE_INLINE, arguments.noInline); 206 configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize); 207 } 208 209 /** 210 * Allow derived classes to add additional command line arguments 211 */ 212 @NotNull 213 @Override 214 protected K2JVMCompilerArguments createArguments() { 215 return new K2JVMCompilerArguments(); 216 } 217 218 @NotNull 219 private static List<File> getClasspath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 220 List<File> classpath = Lists.newArrayList(); 221 if (arguments.classpath != null) { 222 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.classpath)) { 223 classpath.add(new File(element)); 224 } 225 } 226 if (!arguments.noStdlib) { 227 classpath.add(paths.getRuntimePath()); 228 } 229 return classpath; 230 } 231 232 @NotNull 233 private static List<File> getAnnotationsPath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 234 List<File> annotationsPath = Lists.newArrayList(); 235 if (arguments.annotations != null) { 236 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.annotations)) { 237 annotationsPath.add(new File(element)); 238 } 239 } 240 if (!arguments.noJdkAnnotations) { 241 annotationsPath.add(paths.getJdkAnnotationsPath()); 242 } 243 return annotationsPath; 244 } 245 }