blob: eb66c19b9ff5c186850adf921ac6e9963f5883aa [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.rules.java;
import static com.google.devtools.build.lib.rules.java.JavaStarlarkCommon.checkPrivateAccess;
import com.google.auto.value.AutoValue;
import com.google.common.base.Ascii;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.PlatformOptions;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.CoreOptionConverters.StrictDepsMode;
import com.google.devtools.build.lib.analysis.config.Fragment;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.config.RequiresOptions;
import com.google.devtools.build.lib.analysis.starlark.annotations.StarlarkConfigurationField;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.BuiltinRestriction;
import com.google.devtools.build.lib.starlarkbuildapi.java.JavaConfigurationApi;
import java.util.Map;
import javax.annotation.Nullable;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.StarlarkThread;
/** A java compiler configuration containing the flags required for compilation. */
@Immutable
@RequiresOptions(options = {JavaOptions.class, PlatformOptions.class})
public final class JavaConfiguration extends Fragment implements JavaConfigurationApi {
/** Values for the --java_classpath option */
public enum JavaClasspathMode {
/** Use full transitive classpaths, the default behavior. */
OFF,
/** JavaBuilder computes the reduced classpath before invoking javac. */
JAVABUILDER,
/** Bazel computes the reduced classpath and tries it in a separate action invocation. */
BAZEL
}
/** Values for the --experimental_one_version_enforcement option */
public enum OneVersionEnforcementLevel {
/** Don't attempt to check for one version violations (the default) */
OFF,
/**
* Check for one version violations, emit warnings to stderr if any are found, but don't break
* the binary.
*/
WARNING,
/**
* Check for one version violations, emit warnings to stderr if any are found, and break the
* rule if it's found.
*/
ERROR
}
/** Values for the --experimental_import_deps_checking option */
public enum ImportDepsCheckingLevel {
/** Turn off the import_deps checking. */
OFF,
/** Emit warnings when the dependencies of java_import/aar_import are not complete. */
WARNING,
/** Emit errors when the dependencies of java_import/aar_import are not complete. */
ERROR
}
private final NestedSet<String> commandLineJavacFlags;
private final Label javaLauncherLabel;
private final boolean useIjars;
private final boolean useHeaderCompilation;
private final boolean generateJavaDeps;
private final boolean strictDepsJavaProtos;
private final boolean isDisallowStrictDepsForJpl;
private final OneVersionEnforcementLevel enforceOneVersion;
private final boolean enforceOneVersionOnJavaTests;
private final ImportDepsCheckingLevel importDepsCheckingLevel;
private final boolean allowRuntimeDepsOnNeverLink;
private final JavaClasspathMode javaClasspath;
private final boolean inmemoryJdepsFiles;
private final ImmutableList<String> defaultJvmFlags;
private final StrictDepsMode strictJavaDeps;
private final String fixDepsTool;
private final Label proguardBinary;
private final NamedLabel bytecodeOptimizer;
private final boolean runLocalJavaOptimizations;
private final Label localJavaOptimizationConfiguration;
private final boolean splitBytecodeOptimizationPass;
private final int bytecodeOptimizationPassActions;
private final boolean enforceProguardFileExtension;
private final boolean runAndroidLint;
private final boolean limitAndroidLintToAndroidCompatible;
private final boolean explicitJavaTestDeps;
private final boolean jplPropagateCcLinkParamsStore;
private final boolean addTestSupportToCompileTimeDeps;
private final ImmutableList<Label> pluginList;
private final boolean disallowResourceJars;
private final boolean experimentalTurbineAnnotationProcessing;
private final boolean experimentalEnableJspecify;
private final boolean multiReleaseDeployJars;
private final boolean disallowJavaImportExports;
private final boolean disallowJavaImportEmptyJars;
private final boolean autoCreateDeployJarForJavaTests;
// TODO(dmarting): remove once we have a proper solution for #2539
private final boolean useLegacyBazelJavaTest;
public JavaConfiguration(BuildOptions buildOptions) throws InvalidConfigurationException {
JavaOptions javaOptions = buildOptions.get(JavaOptions.class);
this.commandLineJavacFlags =
JavaHelper.detokenizeJavaOptions(JavaHelper.tokenizeJavaOptions(javaOptions.javacOpts));
this.javaLauncherLabel = javaOptions.javaLauncher;
this.useIjars = javaOptions.useIjars;
this.useHeaderCompilation = javaOptions.headerCompilation;
this.generateJavaDeps =
javaOptions.javaDeps || javaOptions.javaClasspath != JavaClasspathMode.OFF;
this.javaClasspath = javaOptions.javaClasspath;
this.inmemoryJdepsFiles = javaOptions.inmemoryJdepsFiles;
this.defaultJvmFlags = ImmutableList.copyOf(javaOptions.jvmOpts);
this.strictJavaDeps = javaOptions.strictJavaDeps;
this.fixDepsTool = javaOptions.fixDepsTool;
this.proguardBinary = javaOptions.proguard;
this.runLocalJavaOptimizations = javaOptions.runLocalJavaOptimizations;
this.localJavaOptimizationConfiguration = javaOptions.localJavaOptimizationConfiguration;
this.splitBytecodeOptimizationPass = javaOptions.splitBytecodeOptimizationPass;
this.bytecodeOptimizationPassActions = javaOptions.bytecodeOptimizationPassActions;
this.enforceProguardFileExtension = javaOptions.enforceProguardFileExtension;
this.useLegacyBazelJavaTest = javaOptions.legacyBazelJavaTest;
this.strictDepsJavaProtos = javaOptions.strictDepsJavaProtos;
this.isDisallowStrictDepsForJpl = javaOptions.isDisallowStrictDepsForJpl;
this.enforceOneVersion = javaOptions.enforceOneVersion;
this.enforceOneVersionOnJavaTests = javaOptions.enforceOneVersionOnJavaTests;
this.importDepsCheckingLevel = javaOptions.importDepsCheckingLevel;
this.allowRuntimeDepsOnNeverLink = javaOptions.allowRuntimeDepsOnNeverLink;
this.explicitJavaTestDeps = javaOptions.explicitJavaTestDeps;
this.jplPropagateCcLinkParamsStore = javaOptions.jplPropagateCcLinkParamsStore;
this.disallowResourceJars = javaOptions.disallowResourceJars;
this.addTestSupportToCompileTimeDeps = javaOptions.addTestSupportToCompileTimeDeps;
this.runAndroidLint = javaOptions.runAndroidLint;
this.limitAndroidLintToAndroidCompatible = javaOptions.limitAndroidLintToAndroidCompatible;
this.multiReleaseDeployJars = javaOptions.multiReleaseDeployJars;
this.disallowJavaImportExports = javaOptions.disallowJavaImportExports;
this.disallowJavaImportEmptyJars = javaOptions.disallowJavaImportEmptyJars;
this.autoCreateDeployJarForJavaTests = javaOptions.autoCreateDeployJarForJavaTests;
Map<String, Label> optimizers = javaOptions.bytecodeOptimizers;
if (optimizers.size() != 1) {
throw new InvalidConfigurationException(
String.format(
"--experimental_bytecode_optimizers can only accept exactly one mapping, but %d"
+ " mappings were provided.",
optimizers.size()));
}
Map.Entry<String, Label> optimizer = Iterables.getOnlyElement(optimizers.entrySet());
String mnemonic = optimizer.getKey();
Label optimizerLabel = optimizer.getValue();
if (optimizerLabel == null && !"Proguard".equals(mnemonic)) {
throw new InvalidConfigurationException("Must supply label for optimizer " + mnemonic);
}
this.bytecodeOptimizer = NamedLabel.create(mnemonic, Optional.fromNullable(optimizerLabel));
if (runLocalJavaOptimizations && optimizerLabel == null) {
throw new InvalidConfigurationException(
"--experimental_local_java_optimizations cannot be provided without "
+ "--experimental_bytecode_optimizers.");
}
this.pluginList = ImmutableList.copyOf(javaOptions.pluginList);
this.experimentalTurbineAnnotationProcessing =
javaOptions.experimentalTurbineAnnotationProcessing;
this.experimentalEnableJspecify = javaOptions.experimentalEnableJspecify;
if (javaOptions.disallowLegacyJavaToolchainFlags) {
checkLegacyToolchainFlagIsUnset("javabase", javaOptions.javaBase);
checkLegacyToolchainFlagIsUnset("host_javabase", javaOptions.hostJavaBase);
checkLegacyToolchainFlagIsUnset("java_toolchain", javaOptions.javaToolchain);
checkLegacyToolchainFlagIsUnset("host_java_toolchain", javaOptions.hostJavaToolchain);
}
boolean oldToolchainFlagSet =
javaOptions.javaBase != null
|| javaOptions.hostJavaBase != null
|| javaOptions.javaToolchain != null
|| javaOptions.hostJavaToolchain != null;
boolean newToolchainFlagSet =
javaOptions.javaLanguageVersion != null
|| javaOptions.hostJavaLanguageVersion != null
|| javaOptions.javaRuntimeVersion != null
|| javaOptions.hostJavaRuntimeVersion != null;
if (oldToolchainFlagSet && !newToolchainFlagSet) {
throw new InvalidConfigurationException(
"At least one of the deprecated no-op toolchain configuration flags is set (--javabase,"
+ " --host_javabase, --java_toolchain, --host_java_toolchain) and none of the new"
+ " toolchain configuration flags is set (--java_language_version,"
+ " --tool_java_language_version, --java_runtime_version,"
+ " --tool_java_runtime_version). This may result in incorrect toolchain selection "
+ "(see https://github.com/bazelbuild/bazel/issues/7849).");
}
}
private static void checkLegacyToolchainFlagIsUnset(String flag, Label label)
throws InvalidConfigurationException {
if (label != null) {
throw new InvalidConfigurationException(
String.format(
"--%s=%s is no longer supported, use --platforms instead (see #7849)", flag, label));
}
}
public NestedSet<String> getDefaultJavacFlags() {
return commandLineJavacFlags;
}
@Override
// TODO(bazel-team): this is the command-line passed options, we should remove from Starlark
// probably.
public ImmutableList<String> getDefaultJavacFlagsForStarlarkAsList() {
return JavaHelper.tokenizeJavaOptions(commandLineJavacFlags);
}
@Override
// TODO(bazel-team): this is the command-line passed options, we should remove from Starlark
// probably.
public Depset getDefaultJavacFlagsStarlark() {
return Depset.of(String.class, commandLineJavacFlags);
}
@Override
public String getStrictJavaDepsName() {
return Ascii.toLowerCase(strictJavaDeps.name());
}
/** Returns true iff Java compilation should use ijars. */
public boolean getUseIjars() {
return useIjars;
}
/**
* Returns true iff Java compilation should use ijars. Checks if the functions is been called from
* builtins.
*/
@Override
public boolean getUseIjarsInStarlark(StarlarkThread thread) throws EvalException {
checkPrivateAccess(thread);
return useIjars;
}
/** Returns true iff Java header compilation is enabled. */
public boolean useHeaderCompilation() {
return useHeaderCompilation;
}
@Override
public boolean useHeaderCompilationStarlark(StarlarkThread thread) throws EvalException {
checkPrivateAccess(thread);
return useHeaderCompilation();
}
/** Returns true iff dependency information is generated after compilation. */
public boolean getGenerateJavaDeps() {
return generateJavaDeps;
}
@Override
public boolean getGenerateJavaDepsStarlark(StarlarkThread thread) throws EvalException {
checkPrivateAccess(thread);
return getGenerateJavaDeps();
}
public JavaClasspathMode getReduceJavaClasspath() {
return javaClasspath;
}
@Override
public String getReduceJavaClasspathStarlark(StarlarkThread thread) throws EvalException {
checkPrivateAccess(thread);
return getReduceJavaClasspath().name();
}
public boolean inmemoryJdepsFiles() {
return inmemoryJdepsFiles;
}
@Override
public ImmutableList<String> getDefaultJvmFlags() {
return defaultJvmFlags;
}
public StrictDepsMode getStrictJavaDeps() {
return strictJavaDeps;
}
public StrictDepsMode getFilteredStrictJavaDeps() {
StrictDepsMode strict = getStrictJavaDeps();
switch (strict) {
case STRICT:
case DEFAULT:
return StrictDepsMode.ERROR;
default: // OFF, WARN, ERROR
return strict;
}
}
/** Which tool to use for fixing dependency errors. */
public String getFixDepsTool() {
return fixDepsTool;
}
/** Returns proper label only if --java_launcher= is specified, otherwise null. */
@StarlarkConfigurationField(
name = "launcher",
doc = "Returns the label provided with --java_launcher, if any.",
defaultInToolRepository = true)
@Nullable
public Label getJavaLauncherLabel() {
return javaLauncherLabel;
}
/** Returns the label provided with --proguard_top, if any. */
@StarlarkConfigurationField(
name = "proguard_top",
doc = "Returns the label provided with --proguard_top, if any.",
defaultInToolRepository = true)
@Nullable
public Label getProguardBinary() {
return proguardBinary;
}
/**
* Returns whether the OPTIMIZATION stage of the bytecode optimizer will be split across two
* actions.
*/
@Override
public boolean splitBytecodeOptimizationPass() {
return splitBytecodeOptimizationPass;
}
/**
* This specifies the number of actions to divide the OPTIMIZATION stage of the bytecode optimizer
* into. Note that if split_bytecode_optimization_pass is set, this will only change behavior if
* it is > 2.
*/
@Override
public int bytecodeOptimizationPassActions() {
return bytecodeOptimizationPassActions;
}
/** Returns whether ProGuard configuration files are required to use a *.pgcfg extension. */
public boolean enforceProguardFileExtension() {
return enforceProguardFileExtension;
}
/** Stores a String name and an optional associated label. */
@AutoValue
public abstract static class NamedLabel {
public static NamedLabel create(String name, Optional<Label> label) {
return new AutoValue_JavaConfiguration_NamedLabel(name, label);
}
public abstract String name();
public abstract Optional<Label> label();
}
/** Returns bytecode optimizer to run. */
@Nullable
public NamedLabel getBytecodeOptimizer() {
return bytecodeOptimizer;
}
@Override
public String getBytecodeOptimizerMnemonic() {
return bytecodeOptimizer.name();
}
@StarlarkConfigurationField(
name = "bytecode_optimizer",
doc = "Returns the label provided with --proguard_top, if any.",
defaultInToolRepository = true)
@Nullable
public Label getBytecodeOptimizerLabel() {
return bytecodeOptimizer.label().orNull();
}
/** Returns true if the bytecode optimizer should incrementally optimize all Java artifacts. */
public boolean runLocalJavaOptimizations() {
return runLocalJavaOptimizations;
}
@StarlarkConfigurationField(
name = "java_toolchain_bytecode_optimizer",
documented = false,
defaultInToolRepository = true)
@Nullable
public Label getBytecodeOptimizerLabelForJavaToolchain() {
if (runLocalJavaOptimizations) {
return bytecodeOptimizer.label().orNull();
} else {
return null;
}
}
/** Returns the optimization configuration for local Java optimizations if they are enabled. */
@StarlarkConfigurationField(name = "local_java_optimization_configuration", documented = false)
@Nullable
public Label getLocalJavaOptimizationConfiguration() {
if (runLocalJavaOptimizations) {
return localJavaOptimizationConfiguration;
} else {
return null;
}
}
/**
* Returns true if java_test in Bazel should behave in legacy mode that existed before we
* open-sourced our test runner.
*/
public boolean useLegacyBazelJavaTest() {
return useLegacyBazelJavaTest;
}
/**
* Make it mandatory for java_test targets to explicitly declare any JUnit or Hamcrest
* dependencies instead of accidentally obtaining them from the TestRunner's dependencies.
*/
public boolean explicitJavaTestDeps() {
return explicitJavaTestDeps;
}
@Override
public boolean explicitJavaTestDepsStarlark(StarlarkThread thread) throws EvalException {
checkPrivateAccess(thread);
return explicitJavaTestDeps();
}
/**
* Returns an enum representing whether or not Bazel should attempt to enforce one-version
* correctness on java_binary rules using the 'oneversion' tool in the java_toolchain.
*
* <p>One-version correctness will inspect for multiple non-identical versions of java classes in
* the transitive dependencies for a java_binary.
*/
public OneVersionEnforcementLevel oneVersionEnforcementLevel() {
return enforceOneVersion;
}
@Override
public boolean multiReleaseDeployJars() {
return multiReleaseDeployJars;
}
public boolean disallowJavaImportExports() {
return disallowJavaImportExports;
}
/** Returns true if empty java_import jars are not allowed. */
public boolean disallowJavaImportEmptyJars() {
return disallowJavaImportEmptyJars;
}
/** Returns true if empty java_import jars are not allowed. */
@Override
public boolean getDisallowJavaImportEmptyJarsInStarlark(StarlarkThread thread)
throws EvalException {
checkPrivateAccess(thread);
return disallowJavaImportEmptyJars;
}
/** Returns true if java_import exports are not allowed. */
@Override
public boolean getDisallowJavaImportExportsInStarlark(StarlarkThread thread)
throws EvalException {
checkPrivateAccess(thread);
return disallowJavaImportExports;
}
@Override
public String starlarkOneVersionEnforcementLevel() {
return oneVersionEnforcementLevel().name();
}
@Override
public boolean enforceOneVersionOnJavaTests() {
return enforceOneVersionOnJavaTests;
}
public ImportDepsCheckingLevel getImportDepsCheckingLevel() {
return importDepsCheckingLevel;
}
public boolean getAllowRuntimeDepsOnNeverLink() {
return allowRuntimeDepsOnNeverLink;
}
public boolean strictDepsJavaProtos() {
return strictDepsJavaProtos;
}
public boolean isDisallowStrictDepsForJpl() {
return isDisallowStrictDepsForJpl;
}
public boolean jplPropagateCcLinkParamsStore() {
return jplPropagateCcLinkParamsStore;
}
@Override
public boolean addTestSupportToCompileTimeDeps() {
return addTestSupportToCompileTimeDeps;
}
@Override
public boolean runAndroidLint() {
return runAndroidLint;
}
public boolean limitAndroidLintToAndroidCompatible() {
return limitAndroidLintToAndroidCompatible;
}
@Override
public ImmutableList<Label> getPlugins() {
return pluginList;
}
public boolean disallowResourceJars() {
return disallowResourceJars;
}
public boolean experimentalTurbineAnnotationProcessing() {
return experimentalTurbineAnnotationProcessing;
}
public boolean experimentalEnableJspecify() {
return experimentalEnableJspecify;
}
@Override
public boolean autoCreateJavaTestDeployJars(StarlarkThread thread) throws EvalException {
BuiltinRestriction.failIfCalledOutsideBuiltins(thread);
return autoCreateDeployJarForJavaTests;
}
}