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