// 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.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.LanguageDependentFragment.LibraryLanguage;
import com.google.devtools.build.lib.analysis.OutputGroupProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.Runfiles.Builder;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel;
import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizationMode;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
/**
* Pluggable Java compilation semantics.
*/
public interface JavaSemantics {
LibraryLanguage LANGUAGE = new LibraryLanguage("Java");
SafeImplicitOutputsFunction JAVA_LIBRARY_CLASS_JAR =
fromTemplates("lib%{name}.jar");
SafeImplicitOutputsFunction JAVA_LIBRARY_SOURCE_JAR =
fromTemplates("lib%{name}-src.jar");
SafeImplicitOutputsFunction JAVA_BINARY_CLASS_JAR =
fromTemplates("%{name}.jar");
SafeImplicitOutputsFunction JAVA_BINARY_SOURCE_JAR =
fromTemplates("%{name}-src.jar");
SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_JAR =
fromTemplates("%{name}_deploy.jar");
SafeImplicitOutputsFunction JAVA_BINARY_MERGED_JAR =
fromTemplates("%{name}_merged.jar");
SafeImplicitOutputsFunction JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR =
fromTemplates("%{name}_deploy.jar.unstripped");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_MAP =
fromTemplates("%{name}_proguard.map");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_PROTO_MAP =
fromTemplates("%{name}_proguard.pbmap");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_SEEDS =
fromTemplates("%{name}_proguard.seeds");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_USAGE =
fromTemplates("%{name}_proguard.usage");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_CONFIG =
fromTemplates("%{name}_proguard.config");
SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_SOURCE_JAR =
fromTemplates("%{name}_deploy-src.jar");
SafeImplicitOutputsFunction JAVA_TEST_CLASSPATHS_FILE =
fromTemplates("%{name}_classpaths_file");
FileType JAVA_SOURCE = FileType.of(".java");
FileType JAR = FileType.of(".jar");
FileType PROPERTIES = FileType.of(".properties");
FileType SOURCE_JAR = FileType.of(".srcjar");
// TODO(bazel-team): Rename this metadata extension to something meaningful.
FileType COVERAGE_METADATA = FileType.of(".em");
/**
* Label to the Java Toolchain rule. It is resolved from a label given in the java options.
*/
String JAVA_TOOLCHAIN_LABEL = "//tools/defaults:java_toolchain";
/** The java_toolchain.compatible_javacopts key for Java 7 javacopts */
public static final String JAVA7_JAVACOPTS_KEY = "java7";
/** The java_toolchain.compatible_javacopts key for Android javacopts */
public static final String ANDROID_JAVACOPTS_KEY = "android";
/** The java_toolchain.compatible_javacopts key for proto compilations. */
public static final String PROTO_JAVACOPTS_KEY = "proto";
LateBoundLabel<BuildConfiguration> JAVA_TOOLCHAIN =
new LateBoundLabel<BuildConfiguration>(JAVA_TOOLCHAIN_LABEL, JavaConfiguration.class) {
@Override
public Label resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return configuration.getFragment(JavaConfiguration.class).getToolchainLabel();
}
};
/**
* Name of the output group used for source jars.
*/
String SOURCE_JARS_OUTPUT_GROUP =
OutputGroupProvider.HIDDEN_OUTPUT_GROUP_PREFIX + "source_jars";
/**
* Name of the output group used for gen jars (the jars containing the class files for sources
* generated from annotation processors).
*/
String GENERATED_JARS_OUTPUT_GROUP =
OutputGroupProvider.HIDDEN_OUTPUT_GROUP_PREFIX + "gen_jars";
/**
* Implementation for the :jvm attribute.
*/
LateBoundLabel<BuildConfiguration> JVM =
new LateBoundLabel<BuildConfiguration>(JavaImplicitAttributes.JDK_LABEL, Jvm.class) {
@Override
public Label resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return configuration.getFragment(Jvm.class).getJvmLabel();
}
};
/**
* Implementation for the :host_jdk attribute.
*/
LateBoundLabel<BuildConfiguration> HOST_JDK =
new LateBoundLabel<BuildConfiguration>(JavaImplicitAttributes.JDK_LABEL, Jvm.class) {
@Override
public boolean useHostConfiguration() {
return true;
}
@Override
public Label resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return configuration.getFragment(Jvm.class).getJvmLabel();
}
};
/**
* Implementation for the :java_launcher attribute. Note that the Java launcher is disabled by
* default, so it returns null for the configuration-independent default value.
*/
LateBoundLabel<BuildConfiguration> JAVA_LAUNCHER =
new LateBoundLabel<BuildConfiguration>(JavaConfiguration.class) {
@Override
public Label resolve(Rule rule, AttributeMap attributes, BuildConfiguration configuration) {
// don't read --java_launcher if this target overrides via a launcher attribute
if (attributes != null && attributes.isAttributeValueExplicitlySpecified("launcher")) {
return attributes.get("launcher", LABEL);
}
return configuration.getFragment(JavaConfiguration.class).getJavaLauncherLabel();
}
};
LateBoundLabelList<BuildConfiguration> JAVA_PLUGINS =
new LateBoundLabelList<BuildConfiguration>() {
@Override
public List<Label> resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return ImmutableList.copyOf(configuration.getPlugins());
}
};
/**
* Implementation for the :proguard attribute.
*/
LateBoundLabel<BuildConfiguration> PROGUARD =
new LateBoundLabel<BuildConfiguration>(JavaConfiguration.class) {
@Override
public Label resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return configuration.getFragment(JavaConfiguration.class).getProguardBinary();
}
};
LateBoundLabelList<BuildConfiguration> EXTRA_PROGUARD_SPECS =
new LateBoundLabelList<BuildConfiguration>() {
@Override
public List<Label> resolve(Rule rule, AttributeMap attributes,
BuildConfiguration configuration) {
return ImmutableList.copyOf(
configuration.getFragment(JavaConfiguration.class).getExtraProguardSpecs());
}
};
LateBoundLabelList<BuildConfiguration> BYTECODE_OPTIMIZERS =
new LateBoundLabelList<BuildConfiguration>(JavaConfiguration.class) {
@Override
public List<Label> resolve(
Rule rule, AttributeMap attributes, BuildConfiguration configuration) {
// Use a modicum of smarts to avoid implicit dependencies where we don't need them.
JavaOptimizationMode optMode =
configuration.getFragment(JavaConfiguration.class).getJavaOptimizationMode();
boolean hasProguardSpecs = attributes.has("proguard_specs")
&& !attributes.get("proguard_specs", LABEL_LIST).isEmpty();
if (optMode == JavaOptimizationMode.NOOP
|| (optMode == JavaOptimizationMode.LEGACY && !hasProguardSpecs)) {
return ImmutableList.<Label>of();
}
return ImmutableList.copyOf(
Optional.presentInstances(
configuration
.getFragment(JavaConfiguration.class)
.getBytecodeOptimizers()
.values()));
}
};
String IJAR_LABEL = "//tools/defaults:ijar";
/**
* Verifies if the rule contains any errors.
*
* <p>Errors should be signaled through {@link RuleContext}.
*/
void checkRule(RuleContext ruleContext, JavaCommon javaCommon);
/**
* Verifies there are no conflicts in protos.
*
* <p>Errors should be signaled through {@link RuleContext}.
*/
void checkForProtoLibraryAndJavaProtoLibraryOnSameProto(
RuleContext ruleContext, JavaCommon javaCommon);
void checkProtoDeps(RuleContext ruleContext, Collection<? extends TransitiveInfoCollection> deps);
/**
* Returns the main class of a Java binary.
*/
String getMainClass(RuleContext ruleContext, ImmutableList<Artifact> srcsArtifacts);
/**
* Returns the primary class for a Java binary - either the main class, or, in case of a test,
* the test class (not the test runner main class).
*/
String getPrimaryClass(RuleContext ruleContext, ImmutableList<Artifact> srcsArtifacts);
/**
* Returns the resources contributed by a Java rule (usually the contents of the
* {@code resources} attribute)
*/
ImmutableList<Artifact> collectResources(RuleContext ruleContext);
/**
* Constructs the command line to call SingleJar to join all artifacts from
* {@code classpath} (java code) and {@code resources} into {@code output}.
*/
CustomCommandLine buildSingleJarCommandLine(BuildConfiguration configuration,
Artifact output, String mainClass, ImmutableList<String> manifestLines,
Iterable<Artifact> buildInfoFiles, ImmutableList<Artifact> resources,
Iterable<Artifact> classpath, boolean includeBuildData,
Compression compression, Artifact launcher);
/**
* Creates the action that writes the Java executable stub script.
*
* <p>Returns the launcher script artifact. This may or may not be the same as {@code executable},
* depending on the implementation of this method. If they are the same, then this Artifact should
* be used when creating both the {@code RunfilesProvider} and the {@code RunfilesSupport}. If
* they are different, the new value should be used when creating the {@code RunfilesProvider} (so
* it will be the stub script executed by "bazel run" for example), and the old value should be
* used when creating the {@code RunfilesSupport} (so the runfiles directory will be named after
* it).
*
* <p>For example on Windows we use a double dispatch approach: the launcher is a batch file (and
* is created and returned by this method) which shells out to a shell script (the {@code
* executable} argument).
*/
Artifact createStubAction(
RuleContext ruleContext,
JavaCommon javaCommon,
List<String> jvmFlags,
Artifact executable,
String javaStartClass,
String javaExecutable);
/**
* Optionally creates a file containing the relative classpaths within the runfiles tree. If
* {@link Optional#isPresent()}, then the caller should ensure the file appears in the runfiles.
*/
Optional<Artifact> createClasspathsFile(RuleContext ruleContext, JavaCommon javaCommon)
throws InterruptedException;
/**
* Adds extra runfiles for a {@code java_binary} rule.
*/
void addRunfilesForBinary(RuleContext ruleContext, Artifact launcher,
Runfiles.Builder runfilesBuilder);
/**
* Adds extra runfiles for a {@code java_library} rule.
*/
void addRunfilesForLibrary(RuleContext ruleContext, Runfiles.Builder runfilesBuilder);
/**
* Returns the additional options to be passed to javac.
*/
Iterable<String> getExtraJavacOpts(RuleContext ruleContext);
/**
* Add additional targets to be treated as direct dependencies.
*/
void collectTargetsTreatedAsDeps(
RuleContext ruleContext,
ImmutableList.Builder<TransitiveInfoCollection> builder,
ClasspathType type);
/**
* Enables coverage support for the java target - adds instrumented jar to the classpath and
* modifies main class.
*
* @return new main class
*/
String addCoverageSupport(
JavaCompilationHelper helper,
JavaTargetAttributes.Builder attributes,
Artifact executable,
Artifact instrumentationMetadata,
JavaCompilationArtifacts.Builder javaArtifactsBuilder,
String mainClass)
throws InterruptedException;
/**
* Return the JVM flags to be used in a Java binary.
*/
Iterable<String> getJvmFlags(
RuleContext ruleContext, ImmutableList<Artifact> srcsArtifacts, List<String> userJvmFlags);
/**
* Adds extra providers to a Java target.
* @throws InterruptedException
*/
void addProviders(RuleContext ruleContext,
JavaCommon javaCommon,
List<String> jvmFlags,
Artifact classJar,
Artifact srcJar,
Artifact genJar,
Artifact gensrcJar,
ImmutableMap<Artifact, Artifact> compilationToRuntimeJarMap,
NestedSetBuilder<Artifact> filesBuilder,
RuleConfiguredTargetBuilder ruleBuilder) throws InterruptedException;
/**
* Translates XMB messages to translations artifact suitable for Java targets.
*/
ImmutableList<Artifact> translate(RuleContext ruleContext, JavaConfiguration javaConfig,
List<Artifact> messages);
/**
* Get the launcher artifact for a java binary, creating the necessary actions for it.
*
* @param ruleContext The rule context
* @param common The common helper class.
* @param deployArchiveBuilder the builder to construct the deploy archive action (mutable).
* @param runfilesBuilder the builder to construct the list of runfiles (mutable).
* @param jvmFlags the list of flags to pass to the JVM when running the Java binary (mutable).
* @param attributesBuilder the builder to construct the list of attributes of this target
* (mutable).
* @return the launcher as an artifact
* @throws InterruptedException
*/
Artifact getLauncher(final RuleContext ruleContext, final JavaCommon common,
DeployArchiveBuilder deployArchiveBuilder, Runfiles.Builder runfilesBuilder,
List<String> jvmFlags, JavaTargetAttributes.Builder attributesBuilder, boolean shouldStrip)
throws InterruptedException;
/**
* Add extra dependencies for runfiles of a Java binary.
*/
void addDependenciesForRunfiles(RuleContext ruleContext, Builder builder);
/**
* Add a source artifact to a {@link JavaTargetAttributes.Builder}. It is called when a source
* artifact is processed but is not matched by default patterns in the
* {@link JavaTargetAttributes.Builder#addSourceArtifacts(Iterable)} method. The semantics can
* then detect its custom artifact types and add it to the builder.
*/
void addArtifactToJavaTargetAttribute(JavaTargetAttributes.Builder builder, Artifact srcArtifact);
/**
* Works on the list of dependencies of a java target to builder the {@link JavaTargetAttributes}.
* This work is performed in {@link JavaCommon} for all java targets.
*/
void commonDependencyProcessing(RuleContext ruleContext, JavaTargetAttributes.Builder attributes,
Collection<? extends TransitiveInfoCollection> deps);
/**
* Takes the path of a Java resource and tries to determine the Java
* root relative path of the resource.
*
* <p>This is only used if the Java rule doesn't have a {@code resource_strip_prefix} attribute.
*
* @param path the root relative path of the resource.
* @return the Java root relative path of the resource of the root
* relative path of the resource if no Java root relative path can be
* determined.
*/
PathFragment getDefaultJavaResourcePath(PathFragment path);
/**
* @return a list of extra arguments to appends to the runfiles support.
*/
List<String> getExtraArguments(RuleContext ruleContext, ImmutableList<Artifact> sources);
/**
* @return main class (entry point) for the Java compiler.
*/
String getJavaBuilderMainClass();
/**
* @return An artifact representing the protobuf-format version of the
* proguard mapping, or null if the proguard version doesn't support this.
*/
Artifact getProtoMapping(RuleContext ruleContext) throws InterruptedException;
/**
* Produces the proto generated extension registry artifacts, or <tt>null</tt>
* if no registry needs to be generated for the provided <tt>ruleContext</tt>.
*/
@Nullable
GeneratedExtensionRegistryProvider createGeneratedExtensionRegistry(
RuleContext ruleContext,
JavaCommon common,
NestedSetBuilder<Artifact> filesBuilder,
JavaCompilationArtifacts.Builder javaCompilationArtifactsBuilder,
JavaRuleOutputJarsProvider.Builder javaRuleOutputJarsProviderBuilder,
JavaSourceJarsProvider.Builder javaSourceJarsProviderBuilder)
throws InterruptedException;
Artifact getObfuscatedConstantStringMap(RuleContext ruleContext) throws InterruptedException;
}