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.arguments.K2JVMCompilerArguments;
028 import org.jetbrains.jet.cli.common.messages.*;
029 import org.jetbrains.jet.cli.jvm.compiler.*;
030 import org.jetbrains.jet.cli.jvm.repl.ReplFromTerminal;
031 import org.jetbrains.jet.codegen.CompilationException;
032 import org.jetbrains.jet.config.CommonConfigurationKeys;
033 import org.jetbrains.jet.config.CompilerConfiguration;
034 import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
035 import org.jetbrains.jet.utils.KotlinPaths;
036 import org.jetbrains.jet.utils.KotlinPathsFromHomeDir;
037 import org.jetbrains.jet.utils.PathUtil;
038
039 import java.io.File;
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(
058 @NotNull K2JVMCompilerArguments arguments,
059 @NotNull MessageCollector messageCollector,
060 @NotNull Disposable rootDisposable
061 ) {
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 if (!arguments.script &&
081 arguments.module == null &&
082 arguments.src == null &&
083 arguments.freeArgs.isEmpty()
084 ) {
085 ReplFromTerminal.run(rootDisposable, configuration);
086 return ExitCode.OK;
087 }
088 else if (arguments.module != null) {
089 }
090 else if (arguments.script) {
091 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, arguments.freeArgs.get(0));
092 }
093 else {
094 if (arguments.src != null) {
095 List<String> sourcePathsSplitByPathSeparator
096 = Arrays.asList(arguments.src.split(StringUtil.escapeToRegexp(File.pathSeparator)));
097 configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, sourcePathsSplitByPathSeparator);
098 }
099 for (String freeArg : arguments.freeArgs) {
100 configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, freeArg);
101 }
102 }
103
104 configuration.put(JVMConfigurationKeys.SCRIPT_PARAMETERS, arguments.script
105 ? CommandLineScriptUtils.scriptParameters()
106 : Collections.<AnalyzerScriptParameter>emptyList());
107
108 configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_ASSERTIONS, arguments.notNullAssertions);
109 configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_PARAMETER_ASSERTIONS, arguments.notNullParamAssertions);
110 configuration.put(JVMConfigurationKeys.ENABLE_INLINE, !"off".equalsIgnoreCase(arguments.enableInline));
111
112 configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector);
113
114 messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment",
115 CompilerMessageLocation.NO_LOCATION);
116 try {
117 configureEnvironment(configuration, arguments);
118
119 File jar = arguments.jar != null ? new File(arguments.jar) : null;
120 File outputDir = arguments.outputDir != null ? new File(arguments.outputDir) : null;
121
122 if (arguments.module != null) {
123 MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector, in(CompilerMessageSeverity.VERBOSE));
124 ModuleChunk modules = CompileEnvironmentUtil.loadModuleDescriptions(paths, arguments.module, sanitizedCollector);
125
126 if (outputDir != null) {
127 messageCollector.report(CompilerMessageSeverity.WARNING, "The '-output' option is ignored because '-module' is specified",
128 CompilerMessageLocation.NO_LOCATION);
129 }
130
131 File directory = new File(arguments.module).getAbsoluteFile().getParentFile();
132 KotlinToJVMBytecodeCompiler.compileModules(configuration, modules,
133 directory, jar,
134 arguments.includeRuntime);
135 }
136 else if (arguments.script) {
137 List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size());
138 JetCoreEnvironment environment = JetCoreEnvironment.createForProduction(rootDisposable, configuration);
139 KotlinToJVMBytecodeCompiler.compileAndExecuteScript(paths, environment, scriptArgs);
140 }
141 else {
142 JetCoreEnvironment environment = JetCoreEnvironment.createForProduction(rootDisposable, configuration);
143 KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime);
144 }
145 return OK;
146 }
147 catch (CompilationException e) {
148 messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(e),
149 MessageUtil.psiElementToMessageLocation(e.getElement()));
150 return INTERNAL_ERROR;
151 }
152 }
153
154
155 /**
156 * Allow derived classes to add additional command line arguments
157 */
158 @NotNull
159 @Override
160 protected K2JVMCompilerArguments createArguments() {
161 return new K2JVMCompilerArguments();
162 }
163
164 @NotNull
165 private static List<File> getClasspath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) {
166 List<File> classpath = Lists.newArrayList();
167 if (!arguments.noJdk) {
168 classpath.addAll(PathUtil.getJdkClassesRoots());
169 }
170 if (!arguments.noStdlib) {
171 classpath.add(paths.getRuntimePath());
172 }
173 if (arguments.classpath != null) {
174 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.classpath)) {
175 classpath.add(new File(element));
176 }
177 }
178 return classpath;
179 }
180
181 @NotNull
182 private static List<File> getAnnotationsPath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) {
183 List<File> annotationsPath = Lists.newArrayList();
184 if (!arguments.noJdkAnnotations) {
185 annotationsPath.add(paths.getJdkAnnotationsPath());
186 }
187 if (arguments.annotations != null) {
188 for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.annotations)) {
189 annotationsPath.add(new File(element));
190 }
191 }
192 return annotationsPath;
193 }
194
195 @Override
196 protected void checkArguments(@NotNull K2JVMCompilerArguments argument) {
197 super.checkArguments(argument);
198
199 String inline = argument.enableInline;
200 if (inline != null) {
201 if (!"on".equalsIgnoreCase(inline) && !"off".equalsIgnoreCase(inline)) {
202 throw new IllegalArgumentException("Wrong value for inline option: '" + inline + "'. Should be 'on' or 'off'");
203 }
204 }
205 }
206 }