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