blob: 9e36dc06afd4858e704002d597ca1922e9408a91 [file] [log] [blame]
/*
* 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;
}
}