001/* 002 * Copyright 2010-2013 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 017package org.jetbrains.jet.cli.jvm; 018 019import com.google.common.base.Splitter; 020import com.google.common.collect.Lists; 021import com.intellij.openapi.Disposable; 022import com.intellij.openapi.util.text.StringUtil; 023import jet.modules.Module; 024import org.jetbrains.annotations.NotNull; 025import org.jetbrains.jet.cli.common.CLICompiler; 026import org.jetbrains.jet.cli.common.CLIConfigurationKeys; 027import org.jetbrains.jet.cli.common.ExitCode; 028import org.jetbrains.jet.cli.common.messages.*; 029import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; 030import org.jetbrains.jet.cli.jvm.compiler.CommandLineScriptUtils; 031import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil; 032import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; 033import org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler; 034import org.jetbrains.jet.cli.jvm.repl.ReplFromTerminal; 035import org.jetbrains.jet.codegen.BuiltinToJavaTypesMapping; 036import org.jetbrains.jet.codegen.CompilationException; 037import org.jetbrains.jet.config.CommonConfigurationKeys; 038import org.jetbrains.jet.config.CompilerConfiguration; 039import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; 040import org.jetbrains.jet.utils.KotlinPaths; 041import org.jetbrains.jet.utils.KotlinPathsFromHomeDir; 042import org.jetbrains.jet.utils.PathUtil; 043 044import java.io.File; 045import java.io.PrintStream; 046import java.util.Arrays; 047import java.util.Collections; 048import java.util.List; 049 050import static org.jetbrains.jet.cli.common.ExitCode.*; 051 052@SuppressWarnings("UseOfSystemOutOrSystemErr") 053public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> { 054 055 public static void main(String... args) { 056 doMain(new K2JVMCompiler(), args); 057 } 058 059 @Override 060 @NotNull 061 protected ExitCode doExecute(K2JVMCompilerArguments arguments, MessageCollector messageCollector, Disposable rootDisposable) { 062 KotlinPaths paths = arguments.kotlinHome != null 063 ? new KotlinPathsFromHomeDir(new File(arguments.kotlinHome)) 064 : PathUtil.getKotlinPathsForCompiler(); 065 066 messageCollector.report(CompilerMessageSeverity.LOGGING, 067 "Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION); 068 069 CompilerConfiguration configuration = new CompilerConfiguration(); 070 071 try { 072 configuration.addAll(JVMConfigurationKeys.CLASSPATH_KEY, getClasspath(paths, arguments)); 073 configuration.addAll(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, getAnnotationsPath(paths, arguments)); 074 } 075 catch (Throwable t) { 076 MessageCollectorUtil.reportException(messageCollector, t); 077 return INTERNAL_ERROR; 078 } 079 080 List<String> argumentsSourceDirs = arguments.getSourceDirs(); 081 if (!arguments.script && 082 arguments.module == null && 083 arguments.src == null && 084 arguments.freeArgs.isEmpty() && 085 (argumentsSourceDirs == null || argumentsSourceDirs.size() == 0)) { 086 087 ReplFromTerminal.run(rootDisposable, configuration); 088 return ExitCode.OK; 089 } 090 else if (arguments.module != null) { 091 } 092 else if (arguments.script) { 093 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, arguments.freeArgs.get(0)); 094 } 095 else { 096 // TODO ideally we'd unify to just having a single field that supports multiple files/dirs 097 if (arguments.getSourceDirs() != null) { 098 for (String source : arguments.getSourceDirs()) { 099 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, source); 100 } 101 } 102 else { 103 if (arguments.src != null) { 104 List<String> sourcePathsSplitByPathSeparator 105 = Arrays.asList(arguments.src.split(StringUtil.escapeToRegexp(File.pathSeparator))); 106 configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, sourcePathsSplitByPathSeparator); 107 } 108 for (String freeArg : arguments.freeArgs) { 109 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, freeArg); 110 } 111 } 112 } 113 114 boolean builtins = arguments.builtins; 115 116 configuration.put(JVMConfigurationKeys.SCRIPT_PARAMETERS, arguments.script 117 ? CommandLineScriptUtils.scriptParameters() 118 : Collections.<AnalyzerScriptParameter>emptyList()); 119 configuration.put(JVMConfigurationKeys.STUBS, builtins); 120 configuration.put(JVMConfigurationKeys.BUILTIN_TO_JAVA_TYPES_MAPPING_KEY, 121 builtins ? BuiltinToJavaTypesMapping.DISABLED : BuiltinToJavaTypesMapping.ENABLED); 122 123 configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_ASSERTIONS, arguments.notNullAssertions); 124 configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_PARAMETER_ASSERTIONS, arguments.notNullParamAssertions); 125 126 configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector); 127 128 messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment", 129 CompilerMessageLocation.NO_LOCATION); 130 try { 131 configureEnvironment(configuration, arguments); 132 133 File jar = arguments.jar != null ? new File(arguments.jar) : null; 134 File outputDir = arguments.outputDir != null ? new File(arguments.outputDir) : null; 135 136 if (arguments.module != null) { 137 MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector); 138 List<Module> modules = CompileEnvironmentUtil.loadModuleDescriptions(paths, arguments.module, sanitizedCollector); 139 140 File directory = new File(arguments.module).getAbsoluteFile().getParentFile(); 141 KotlinToJVMBytecodeCompiler.compileModules(configuration, modules, 142 directory, jar, outputDir, 143 arguments.includeRuntime); 144 } 145 else if (arguments.script) { 146 List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size()); 147 JetCoreEnvironment environment = new JetCoreEnvironment(rootDisposable, configuration); 148 KotlinToJVMBytecodeCompiler.compileAndExecuteScript(paths, environment, scriptArgs); 149 } 150 else { 151 JetCoreEnvironment environment = new JetCoreEnvironment(rootDisposable, configuration); 152 KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime); 153 } 154 return OK; 155 } 156 catch (CompilationException e) { 157 messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(e), 158 MessageUtil.psiElementToMessageLocation(e.getElement())); 159 return INTERNAL_ERROR; 160 } 161 } 162 163 164 /** 165 * Allow derived classes to add additional command line arguments 166 */ 167 @NotNull 168 @Override 169 protected K2JVMCompilerArguments createArguments() { 170 return new K2JVMCompilerArguments(); 171 } 172 173 // TODO this method is here only to workaround KT-2498 174 @Override 175 protected void configureEnvironment(@NotNull CompilerConfiguration configuration, @NotNull K2JVMCompilerArguments arguments) { 176 super.configureEnvironment(configuration, arguments); 177 } 178 179 //TODO: Hacked! Be sure that our kotlin stuff builds correctly before you remove. 180 // our compiler throws method not found error 181 // probably relates to KT-1863... well, may be not 182 @NotNull 183 @Override 184 public ExitCode exec(@NotNull PrintStream errStream, @NotNull K2JVMCompilerArguments arguments) { 185 return super.exec(errStream, arguments); 186 } 187 188 @NotNull 189 private static List<File> getClasspath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 190 List<File> classpath = Lists.newArrayList(); 191 if (!arguments.noJdk) { 192 classpath.add(PathUtil.findRtJar()); 193 } 194 if (!arguments.noStdlib) { 195 classpath.add(paths.getRuntimePath()); 196 } 197 if (arguments.classpath != null) { 198 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.classpath)) { 199 classpath.add(new File(element)); 200 } 201 } 202 return classpath; 203 } 204 205 @NotNull 206 private static List<File> getAnnotationsPath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) { 207 List<File> annotationsPath = Lists.newArrayList(); 208 if (!arguments.noJdkAnnotations) { 209 annotationsPath.add(paths.getJdkAnnotationsPath()); 210 } 211 if (arguments.annotations != null) { 212 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.annotations)) { 213 annotationsPath.add(new File(element)); 214 } 215 } 216 return annotationsPath; 217 } 218 219 private static class FilteringMessageCollector implements MessageCollector { 220 private final MessageCollector messageCollector; 221 222 public FilteringMessageCollector(@NotNull MessageCollector messageCollector) { 223 this.messageCollector = messageCollector; 224 } 225 226 @Override 227 public void report( 228 @NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location 229 ) { 230 if (!CompilerMessageSeverity.VERBOSE.contains(severity)) { 231 messageCollector.report(severity, message, location); 232 } 233 } 234 } 235}