// 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 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.ConfiguredTarget;
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.RunfilesProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider;
import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore;
import com.google.devtools.build.lib.rules.cpp.CppCompilationContext;
import com.google.devtools.build.lib.rules.cpp.LinkerInput;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
/**
* Implementation for the java_library rule.
*/
public class JavaLibrary implements RuleConfiguredTargetFactory {
private final JavaSemantics semantics;
protected JavaLibrary(JavaSemantics semantics) {
this.semantics = semantics;
}
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
JavaCommon common = new JavaCommon(ruleContext, semantics);
RuleConfiguredTargetBuilder builder =
init(ruleContext, common, false /* includeGeneratedExtensionRegistry */);
return builder != null ? builder.build() : null;
}
final RuleConfiguredTargetBuilder init(
RuleContext ruleContext, final JavaCommon common, boolean includeGeneratedExtensionRegistry)
throws InterruptedException {
JavaTargetAttributes.Builder attributesBuilder = common.initCommon();
// Collect the transitive dependencies.
JavaCompilationHelper helper = new JavaCompilationHelper(
ruleContext, semantics, common.getJavacOpts(), attributesBuilder);
helper.addLibrariesToAttributes(common.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY));
if (ruleContext.hasErrors()) {
return null;
}
semantics.checkRule(ruleContext, common);
JavaCompilationArtifacts.Builder javaArtifactsBuilder = new JavaCompilationArtifacts.Builder();
if (ruleContext.hasErrors()) {
common.setJavaCompilationArtifacts(JavaCompilationArtifacts.EMPTY);
return null;
}
JavaConfiguration javaConfig = ruleContext.getFragment(JavaConfiguration.class);
NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.stableOrder();
JavaTargetAttributes attributes = helper.getAttributes();
if (attributes.hasMessages()) {
helper.setTranslations(
semantics.translate(ruleContext, javaConfig, attributes.getMessages()));
}
ruleContext.checkSrcsSamePackage(true);
Artifact jar = null;
Artifact srcJar = ruleContext.getImplicitOutputArtifact(
JavaSemantics.JAVA_LIBRARY_SOURCE_JAR);
NestedSet<Artifact> transitiveSourceJars = common.collectTransitiveSourceJars(srcJar);
JavaSourceJarsProvider.Builder sourceJarsProviderBuilder =
JavaSourceJarsProvider.builder()
.addSourceJar(srcJar)
.addAllTransitiveSourceJars(transitiveSourceJars);
Artifact classJar = ruleContext.getImplicitOutputArtifact(
JavaSemantics.JAVA_LIBRARY_CLASS_JAR);
if (attributes.hasSources() || attributes.hasResources()) {
// We only want to add a jar to the classpath of a dependent rule if it has content.
javaArtifactsBuilder.addRuntimeJar(classJar);
jar = classJar;
}
filesBuilder.add(classJar);
Artifact manifestProtoOutput = helper.createManifestProtoOutput(classJar);
// The gensrc jar is created only if the target uses annotation processing.
// Otherwise, it is null, and the source jar action will not depend on the compile action.
Artifact genSourceJar = null;
Artifact genClassJar = null;
if (helper.usesAnnotationProcessing()) {
genClassJar = helper.createGenJar(classJar);
genSourceJar = helper.createGensrcJar(classJar);
helper.createGenJarAction(classJar, manifestProtoOutput, genClassJar);
}
Artifact outputDepsProto = helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder);
helper.createCompileActionWithInstrumentation(classJar, manifestProtoOutput, genSourceJar,
outputDepsProto, javaArtifactsBuilder);
helper.createSourceJarAction(srcJar, genSourceJar);
Artifact iJar = null;
if (attributes.hasSources() && jar != null) {
iJar = helper.createCompileTimeJarAction(jar, javaArtifactsBuilder);
}
JavaRuleOutputJarsProvider.Builder ruleOutputJarsProviderBuilder =
JavaRuleOutputJarsProvider.builder()
.addOutputJar(classJar, iJar, ImmutableList.of(srcJar))
.setJdeps(outputDepsProto);
GeneratedExtensionRegistryProvider generatedExtensionRegistryProvider = null;
if (includeGeneratedExtensionRegistry) {
generatedExtensionRegistryProvider =
semantics.createGeneratedExtensionRegistry(
ruleContext,
common,
filesBuilder,
javaArtifactsBuilder,
ruleOutputJarsProviderBuilder,
sourceJarsProviderBuilder);
}
boolean neverLink = JavaCommon.isNeverLink(ruleContext);
JavaCompilationArtifacts javaArtifacts = javaArtifactsBuilder.build();
common.setJavaCompilationArtifacts(javaArtifacts);
common.setClassPathFragment(
new ClasspathConfiguredFragment(
javaArtifacts, attributes, neverLink, helper.getBootclasspathOrDefault()));
CppCompilationContext transitiveCppDeps = common.collectTransitiveCppDeps();
// If sources are empty, treat this library as a forwarding node for dependencies.
JavaCompilationArgs javaCompilationArgs =
common.collectJavaCompilationArgs(false, neverLink, false);
JavaCompilationArgs recursiveJavaCompilationArgs =
common.collectJavaCompilationArgs(true, neverLink, false);
NestedSet<Artifact> compileTimeJavaDepArtifacts = common.collectCompileTimeDependencyArtifacts(
javaArtifacts.getCompileTimeDependencyArtifact());
NestedSet<Artifact> runTimeJavaDepArtifacts = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
NestedSet<LinkerInput> transitiveJavaNativeLibraries =
common.collectTransitiveJavaNativeLibraries();
CcLinkParamsStore ccLinkParamsStore = new CcLinkParamsStore() {
@Override
protected void collect(CcLinkParams.Builder builder, boolean linkingStatically,
boolean linkShared) {
builder.addTransitiveTargets(common.targetsTreatedAsDeps(ClasspathType.BOTH),
JavaCcLinkParamsProvider.TO_LINK_PARAMS, CcLinkParamsProvider.TO_LINK_PARAMS);
}
};
ProtoJavaApiInfoAspectProvider.Builder protoAspectBuilder =
ProtoJavaApiInfoAspectProvider.builder();
for (TransitiveInfoCollection dep : common.getDependencies()) {
ProtoJavaApiInfoAspectProvider protoProvider =
JavaProvider.getProvider(ProtoJavaApiInfoAspectProvider.class, dep);
if (protoProvider != null) {
protoAspectBuilder.addTransitive(protoProvider);
}
}
RuleConfiguredTargetBuilder builder =
new RuleConfiguredTargetBuilder(ruleContext);
semantics.addProviders(
ruleContext, common, ImmutableList.<String>of(), classJar, srcJar,
genClassJar, genSourceJar, ImmutableMap.<Artifact, Artifact>of(),
filesBuilder, builder);
if (generatedExtensionRegistryProvider != null) {
builder.add(GeneratedExtensionRegistryProvider.class, generatedExtensionRegistryProvider);
}
JavaCompilationArgsProvider compilationArgsProvider =
JavaCompilationArgsProvider.create(
javaCompilationArgs, recursiveJavaCompilationArgs,
compileTimeJavaDepArtifacts, runTimeJavaDepArtifacts);
JavaSourceJarsProvider sourceJarsProvider = sourceJarsProviderBuilder.build();
JavaRuleOutputJarsProvider ruleOutputJarsProvider = ruleOutputJarsProviderBuilder.build();
JavaSkylarkApiProvider.Builder skylarkApiProvider =
JavaSkylarkApiProvider.builder()
.setRuleOutputJarsProvider(ruleOutputJarsProvider)
.setSourceJarsProvider(sourceJarsProvider)
.setCompilationArgsProvider(compilationArgsProvider);
NestedSet<Artifact> filesToBuild = filesBuilder.build();
common.addTransitiveInfoProviders(builder, skylarkApiProvider, filesToBuild, classJar);
common.addGenJarsProvider(builder, skylarkApiProvider, genClassJar, genSourceJar);
NestedSet<Artifact> proguardSpecs = new ProguardLibrary(ruleContext).collectProguardSpecs();
CcLinkParamsProvider ccLinkParamsProvider = new CcLinkParamsProvider(ccLinkParamsStore);
JavaProvider javaProvider = JavaProvider.Builder.create()
.addProvider(JavaCompilationArgsProvider.class, compilationArgsProvider)
.addProvider(JavaSourceJarsProvider.class, sourceJarsProvider)
.addProvider(ProtoJavaApiInfoAspectProvider.class, protoAspectBuilder.build())
.addProvider(JavaRuleOutputJarsProvider.class, ruleOutputJarsProvider)
// java_library doesn't need to return JavaRunfilesProvider
.build();
builder
.addSkylarkTransitiveInfo(JavaSkylarkApiProvider.NAME, skylarkApiProvider.build())
.addProvider(ruleOutputJarsProvider)
.addProvider(new JavaRuntimeJarProvider(javaArtifacts.getRuntimeJars()))
.addProvider(
RunfilesProvider.simple(
JavaCommon.getRunfiles(ruleContext, semantics, javaArtifacts, neverLink)))
.setFilesToBuild(filesToBuild)
.addProvider(new JavaNeverlinkInfoProvider(neverLink))
.addProvider(transitiveCppDeps)
.addProvider(JavaCompilationArgsProvider.class, compilationArgsProvider)
.addProvider(javaProvider)
.addProvider(ccLinkParamsProvider)
.addNativeDeclaredProvider(ccLinkParamsProvider)
.addNativeDeclaredProvider(javaProvider)
.addProvider(new JavaNativeLibraryProvider(transitiveJavaNativeLibraries))
.addProvider(JavaSourceInfoProvider.fromJavaTargetAttributes(attributes, semantics))
// TODO(bazel-team): this should only happen for java_plugin
.addProvider(JavaCommon.getTransitivePlugins(ruleContext))
.addProvider(new ProguardSpecProvider(proguardSpecs))
.addOutputGroup(JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, transitiveSourceJars)
.addOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL, proguardSpecs);
if (ruleContext.hasErrors()) {
return null;
}
return builder;
}
}