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.repl.ReplFromTerminal; 031 import org.jetbrains.kotlin.codegen.CompilationException; 032 import org.jetbrains.kotlin.compiler.plugin.*; 033 import org.jetbrains.kotlin.config.CommonConfigurationKeys; 034 import org.jetbrains.kotlin.config.CompilerConfiguration; 035 import org.jetbrains.kotlin.config.Services; 036 import org.jetbrains.kotlin.load.kotlin.incremental.cache.IncrementalCacheProvider; 037 import org.jetbrains.kotlin.resolve.AnalyzerScriptParameter; 038 import org.jetbrains.kotlin.utils.KotlinPaths; 039 import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir; 040 import org.jetbrains.kotlin.utils.PathUtil; 041 042 import java.io.File; 043 import java.util.Collections; 044 import java.util.List; 045 046 import static com.google.common.base.Predicates.in; 047 import static org.jetbrains.kotlin.cli.common.ExitCode.*; 048 049 @SuppressWarnings("UseOfSystemOutOrSystemErr") 050 public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> { 051 052 public static void main(String... args) { 053 doMain(new K2JVMCompiler(), args); 054 } 055 056 @Override 057 @NotNull 058 protected ExitCode doExecute( 059 @NotNull K2JVMCompilerArguments arguments, 060 @NotNull Services services, 061 @NotNull MessageCollector messageCollector, 062 @NotNull Disposable rootDisposable 063 ) { 064 KotlinPaths paths = arguments.kotlinHome != null 065 ? new KotlinPathsFromHomeDir(new File(arguments.kotlinHome)) 066 : PathUtil.getKotlinPathsForCompiler(); 067 068 messageCollector.report(CompilerMessageSeverity.LOGGING, 069 "Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION); 070 071 CompilerConfiguration configuration = new CompilerConfiguration(); 072 configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector); 073 074 IncrementalCacheProvider incrementalCacheProvider = services.get(IncrementalCacheProvider.class); 075 if (incrementalCacheProvider != null) { 076 configuration.put(JVMConfigurationKeys.INCREMENTAL_CACHE_PROVIDER, incrementalCacheProvider); 077 } 078 079 CompilerJarLocator locator = services.get(CompilerJarLocator.class); 080 if (locator != null) { 081 configuration.put(JVMConfigurationKeys.COMPILER_JAR_LOCATOR, locator); 082 } 083 084 try { 085 if (!arguments.noJdk) { 086 configuration.addAll(JVMConfigurationKeys.CLASSPATH_KEY, PathUtil.getJdkClassesRoots()); 087 } 088 } 089 catch (Throwable t) { 090 MessageCollectorUtil.reportException(messageCollector, t); 091 return INTERNAL_ERROR; 092 } 093 094 try { 095 PluginCliParser.loadPlugins(arguments, configuration); 096 } 097 catch (PluginCliOptionProcessingException e) { 098 String message = e.getMessage() + "\n\n" + PluginPackage.cliPluginUsageString(e.getPluginId(), e.getOptions()); 099 messageCollector.report(CompilerMessageSeverity.ERROR, message, CompilerMessageLocation.NO_LOCATION); 100 return INTERNAL_ERROR; 101 } 102 catch (CliOptionProcessingException e) { 103 messageCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION); 104 return INTERNAL_ERROR; 105 } 106 catch (Throwable t) { 107 MessageCollectorUtil.reportException(messageCollector, t); 108 return INTERNAL_ERROR; 109 } 110 111 if (arguments.script) { 112 if (arguments.freeArgs.isEmpty()) { 113 messageCollector.report(CompilerMessageSeverity.ERROR, "Specify script source path to evaluate", 114 CompilerMessageLocation.NO_LOCATION); 115 return COMPILATION_ERROR; 116 } 117 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, arguments.freeArgs.get(0)); 118 } 119 else if (arguments.module == null) { 120 configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, arguments.freeArgs); 121 122 // Adding all directory sources to classpath to resolve Java symbols from Kotlin 123 for (String source : arguments.freeArgs) { 124 File file = new File(source); 125 if (file.isDirectory()) { 126 configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, file); 127 } 128 } 129 } 130 131 configuration.addAll(JVMConfigurationKeys.CLASSPATH_KEY, getClasspath(paths, arguments)); 132 configuration.addAll(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, getAnnotationsPath(paths, arguments)); 133 134 if (arguments.module == null && arguments.freeArgs.isEmpty() && !arguments.version) { 135 ReplFromTerminal.run(rootDisposable, configuration); 136 return ExitCode.OK; 137 } 138 139 configuration.put(JVMConfigurationKeys.SCRIPT_PARAMETERS, arguments.script 140 ? CommandLineScriptUtils.scriptParameters() 141 : Collections.<AnalyzerScriptParameter>emptyList()); 142 143 putAdvancedOptions(configuration, arguments); 144 145 messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment", 146 CompilerMessageLocation.NO_LOCATION); 147 try { 148 configureEnvironment(configuration, arguments); 149 150 String destination = arguments.destination; 151 152 File jar; 153 File outputDir; 154 if (destination != null) { 155 boolean isJar = destination.endsWith(".jar"); 156 jar = isJar ? new File(destination) : null; 157 outputDir = isJar ? null : new File(destination); 158 } 159 else { 160 jar = null; 161 outputDir = null; 162 } 163 164 if (arguments.module != null) { 165 MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector, in(CompilerMessageSeverity.VERBOSE)); 166 ModuleScriptData moduleScript = CompileEnvironmentUtil.loadModuleDescriptions( 167 paths, arguments.module, sanitizedCollector); 168 169 if (outputDir != null) { 170 messageCollector.report(CompilerMessageSeverity.WARNING, 171 "The '-d' option with a directory destination is ignored because '-module' is specified", 172 CompilerMessageLocation.NO_LOCATION); 173 } 174 175 File directory = new File(arguments.module).getAbsoluteFile().getParentFile(); 176 KotlinToJVMBytecodeCompiler.compileModules( 177 configuration, moduleScript.getModules(), directory, jar, arguments.includeRuntime 178 ); 179 } 180 else if (arguments.script) { 181 List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size()); 182 JetCoreEnvironment environment = 183 JetCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); 184 KotlinToJVMBytecodeCompiler.compileAndExecuteScript(configuration, paths, environment, scriptArgs); 185 } 186 else { 187 JetCoreEnvironment environment = 188 JetCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); 189 KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime); 190 } 191 return OK; 192 } 193 catch (CompilationException e) { 194 messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e), 195 MessageUtil.psiElementToMessageLocation(e.getElement())); 196 return INTERNAL_ERROR; 197 } 198 } 199 200 private static void putAdvancedOptions(@NotNull CompilerConfiguration configuration, @NotNull K2JVMCompilerArguments arguments) { 201 configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions); 202 configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions); 203 configuration.put(JVMConfigurationKeys.DISABLE_INLINE, arguments.noInline); 204 configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize); 205 } 206 207 /** 208 * Allow derived classes to add additional command line arguments 209 */ 210 @NotNull 211 @Override 212 protected K2JVMCompilerArguments createArguments() { 213 return new K2JVMCompilerArguments(); 214 } 215 216 @NotNull 217 private static List<File> getClasspath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 218 List<File> classpath = Lists.newArrayList(); 219 if (arguments.classpath != null) { 220 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.classpath)) { 221 classpath.add(new File(element)); 222 } 223 } 224 if (!arguments.noStdlib) { 225 classpath.add(paths.getRuntimePath()); 226 } 227 return classpath; 228 } 229 230 @NotNull 231 private static List<File> getAnnotationsPath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 232 List<File> annotationsPath = Lists.newArrayList(); 233 if (arguments.annotations != null) { 234 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.annotations)) { 235 annotationsPath.add(new File(element)); 236 } 237 } 238 if (!arguments.noJdkAnnotations) { 239 annotationsPath.add(paths.getJdkAnnotationsPath()); 240 } 241 return annotationsPath; 242 } 243 }