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