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 jet.modules.Module;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.jet.cli.common.CLICompiler;
026 import org.jetbrains.jet.cli.common.CLIConfigurationKeys;
027 import org.jetbrains.jet.cli.common.ExitCode;
028 import org.jetbrains.jet.cli.common.messages.*;
029 import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
030 import org.jetbrains.jet.cli.jvm.compiler.CommandLineScriptUtils;
031 import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil;
032 import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
033 import org.jetbrains.jet.cli.jvm.compiler.KotlinToJVMBytecodeCompiler;
034 import org.jetbrains.jet.cli.jvm.repl.ReplFromTerminal;
035 import org.jetbrains.jet.codegen.BuiltinToJavaTypesMapping;
036 import org.jetbrains.jet.codegen.CompilationException;
037 import org.jetbrains.jet.config.CommonConfigurationKeys;
038 import org.jetbrains.jet.config.CompilerConfiguration;
039 import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
040 import org.jetbrains.jet.utils.KotlinPaths;
041 import org.jetbrains.jet.utils.KotlinPathsFromHomeDir;
042 import org.jetbrains.jet.utils.PathUtil;
043
044 import java.io.File;
045 import java.io.PrintStream;
046 import java.util.Arrays;
047 import java.util.Collections;
048 import java.util.List;
049
050 import static org.jetbrains.jet.cli.common.ExitCode.*;
051
052 @SuppressWarnings("UseOfSystemOutOrSystemErr")
053 public 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 }