| /* |
| * Copyright 2013-present Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| * not use this file except in compliance with the License. You may obtain |
| * a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.facebook.buck.java; |
| |
| import com.facebook.buck.rules.RuleKey; |
| import com.facebook.buck.rules.RuleKeyAppendable; |
| import com.facebook.buck.util.ImmutableProcessExecutorParams; |
| import com.facebook.buck.util.ProcessExecutor; |
| import com.facebook.buck.util.ProcessExecutorParams; |
| import com.facebook.buck.util.immutables.BuckStyleImmutable; |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Function; |
| import com.google.common.base.Functions; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Optional; |
| import com.google.common.base.Preconditions; |
| import com.google.common.base.Strings; |
| import com.google.common.collect.FluentIterable; |
| import com.google.common.collect.ImmutableList; |
| |
| import org.immutables.value.Value; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Represents the command line options that should be passed to javac. Note that the options do not |
| * include either the classpath or the directory for storing class files. |
| */ |
| @Value.Immutable |
| @BuckStyleImmutable |
| public abstract class JavacOptions implements RuleKeyAppendable { |
| |
| protected abstract Optional<ProcessExecutor> getProcessExecutor(); |
| |
| protected abstract Optional<Path> getJavacPath(); |
| protected abstract Optional<Path> getJavacJarPath(); |
| |
| @Value.Default |
| protected boolean isProductionBuild() { |
| return false; |
| } |
| |
| @Value.Default |
| protected boolean isVerbose() { |
| return false; |
| } |
| |
| public abstract String getSourceLevel(); |
| @VisibleForTesting |
| abstract String getTargetLevel(); |
| |
| @Value.Default |
| public AnnotationProcessingParams getAnnotationProcessingParams() { |
| return AnnotationProcessingParams.EMPTY; |
| } |
| |
| public abstract List<String> getExtraArguments(); |
| protected abstract Optional<String> getBootclasspath(); |
| protected abstract Map<String, String> getSourceToBootclasspath(); |
| |
| protected boolean isDebug() { |
| return !isProductionBuild(); |
| } |
| |
| @Value.Lazy |
| public Javac getJavac() { |
| Optional<Path> externalJavac = getJavacPath(); |
| if (externalJavac.isPresent()) { |
| |
| if (!getProcessExecutor().isPresent()) { |
| throw new RuntimeException("Misconfigured JavacOptions --- no process executor"); |
| } |
| |
| ProcessExecutorParams params = ImmutableProcessExecutorParams.builder() |
| .setCommand(ImmutableList.of(externalJavac.get().toString(), "-version")) |
| .build(); |
| ProcessExecutor.Result result; |
| try { |
| result = getProcessExecutor().get().launchAndExecute(params); |
| } catch (InterruptedException | IOException e) { |
| throw new RuntimeException(e); |
| } |
| |
| Optional<JavacVersion> version; |
| Optional<String> stderr = result.getStderr(); |
| if (Strings.isNullOrEmpty(stderr.orNull())) { |
| version = Optional.absent(); |
| } else { |
| version = Optional.of((JavacVersion) ImmutableJavacVersion.of(stderr.get())); |
| } |
| return new ExternalJavac(externalJavac.get(), version); |
| } |
| return new Jsr199Javac(getJavacJarPath()); |
| } |
| |
| public void appendOptionsToList( |
| ImmutableList.Builder<String> optionsBuilder, |
| final Function<Path, Path> pathRelativizer) { |
| |
| // Add some standard options. |
| optionsBuilder.add("-source", getSourceLevel()); |
| optionsBuilder.add("-target", getTargetLevel()); |
| |
| // Set the sourcepath to stop us reading source files out of jars by mistake. |
| optionsBuilder.add("-sourcepath", ""); |
| |
| if (isDebug()) { |
| optionsBuilder.add("-g"); |
| } |
| |
| if (isVerbose()) { |
| optionsBuilder.add("-verbose"); |
| } |
| |
| // Override the bootclasspath if Buck is building Java code for Android. |
| if (getBootclasspath().isPresent()) { |
| optionsBuilder.add("-bootclasspath", getBootclasspath().get()); |
| } else { |
| String bcp = getSourceToBootclasspath().get(getSourceLevel()); |
| if (bcp != null) { |
| optionsBuilder.add("-bootclasspath", bcp); |
| } |
| } |
| |
| // Add annotation processors. |
| if (!getAnnotationProcessingParams().isEmpty()) { |
| |
| // Specify where to generate sources so IntelliJ can pick them up. |
| Path generateTo = getAnnotationProcessingParams().getGeneratedSourceFolderName(); |
| if (generateTo != null) { |
| optionsBuilder.add("-s").add(pathRelativizer.apply(generateTo).toString()); |
| } |
| |
| // Specify processorpath to search for processors. |
| optionsBuilder.add("-processorpath", |
| Joiner.on(File.pathSeparator).join( |
| FluentIterable.from(getAnnotationProcessingParams().getSearchPathElements()) |
| .transform(pathRelativizer) |
| .transform(Functions.toStringFunction()))); |
| |
| // Specify names of processors. |
| if (!getAnnotationProcessingParams().getNames().isEmpty()) { |
| optionsBuilder.add( |
| "-processor", |
| Joiner.on(',').join(getAnnotationProcessingParams().getNames())); |
| } |
| |
| // Add processor parameters. |
| for (String parameter : getAnnotationProcessingParams().getParameters()) { |
| optionsBuilder.add("-A" + parameter); |
| } |
| |
| if (getAnnotationProcessingParams().getProcessOnly()) { |
| optionsBuilder.add("-proc:only"); |
| } |
| } |
| |
| // Add extra arguments. |
| optionsBuilder.addAll(getExtraArguments()); |
| } |
| |
| @Override |
| public RuleKey.Builder appendToRuleKey(RuleKey.Builder builder, String key) { |
| // TODO(simons): Include bootclasspath params. |
| builder.setReflectively(key + ".sourceLevel", getSourceLevel()) |
| .setReflectively(key + ".targetLevel", getTargetLevel()) |
| .setReflectively(key + ".extraArguments", Joiner.on(',').join(getExtraArguments())) |
| .setReflectively(key + ".debug", isDebug()); |
| |
| getJavac().appendToRuleKey(builder, "javac"); |
| |
| return getAnnotationProcessingParams().appendToRuleKey(builder, key); |
| } |
| |
| static ImmutableJavacOptions.Builder builderForUseInJavaBuckConfig() { |
| return ImmutableJavacOptions.builder(); |
| } |
| |
| public static ImmutableJavacOptions.Builder builder(JavacOptions options) { |
| Preconditions.checkNotNull(options); |
| |
| ImmutableJavacOptions.Builder builder = ImmutableJavacOptions.builder(); |
| |
| builder.setVerbose(options.isVerbose()); |
| builder.setProductionBuild(options.isProductionBuild()); |
| |
| builder.setProcessExecutor(options.getProcessExecutor()); |
| builder.setJavacPath(options.getJavacPath()); |
| builder.setJavacJarPath(options.getJavacJarPath()); |
| builder.setAnnotationProcessingParams(options.getAnnotationProcessingParams()); |
| builder.putAllSourceToBootclasspath(options.getSourceToBootclasspath()); |
| builder.setBootclasspath(options.getBootclasspath()); |
| builder.setSourceLevel(options.getSourceLevel()); |
| builder.setTargetLevel(options.getTargetLevel()); |
| builder.addAllExtraArguments(options.getExtraArguments()); |
| |
| return builder; |
| } |
| } |