blob: 8f917c3fe72691e60d7684478088943f8ac6788b [file] [log] [blame]
// Copyright 2016 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.proto;
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.rules.java.JavaRuleClasses.HOST_JAVA_RUNTIME_ATTRIBUTE_NAME;
import static com.google.devtools.build.lib.rules.java.proto.JplCcLinkParams.createCcLinkingInfo;
import static com.google.devtools.build.lib.rules.java.proto.StrictDepsUtils.createNonStrictCompilationArgsProvider;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
import com.google.devtools.build.lib.analysis.PlatformConfiguration;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.config.HostTransition;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.AspectDefinition;
import com.google.devtools.build.lib.packages.AspectParameters;
import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault;
import com.google.devtools.build.lib.packages.NativeAspectClass;
import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaInfo;
import com.google.devtools.build.lib.rules.java.JavaRuleClasses;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaSkylarkApiProvider;
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.Exports;
import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.Services;
import com.google.devtools.build.lib.rules.proto.ProtoConfiguration;
import com.google.devtools.build.lib.rules.proto.ProtoInfo;
import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainProvider;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
/** An Aspect which JavaLiteProtoLibrary injects to build Java Lite protos. */
public class JavaLiteProtoAspect extends NativeAspectClass implements ConfiguredAspectFactory {
public static LabelLateBoundDefault<?> getProtoToolchainLabel(String defaultValue) {
return LabelLateBoundDefault.fromTargetConfiguration(
ProtoConfiguration.class,
Label.parseAbsoluteUnchecked(defaultValue),
(rule, attributes, protoConfig) -> protoConfig.protoToolchainForJavaLite());
}
private final JavaSemantics javaSemantics;
private final String defaultProtoToolchainLabel;
private final Label hostJdkAttribute;
private final Label javaToolchainAttribute;
public JavaLiteProtoAspect(
JavaSemantics javaSemantics,
String defaultProtoToolchainLabel,
RuleDefinitionEnvironment env) {
this.javaSemantics = javaSemantics;
this.defaultProtoToolchainLabel = defaultProtoToolchainLabel;
this.hostJdkAttribute = JavaSemantics.hostJdkAttribute(env);
this.javaToolchainAttribute = JavaSemantics.javaToolchainAttribute(env);
}
@Override
public ConfiguredAspect create(
ConfiguredTargetAndData ctadBase,
RuleContext ruleContext,
AspectParameters parameters,
String toolsRepository)
throws InterruptedException, ActionConflictException {
ConfiguredAspect.Builder aspect = new ConfiguredAspect.Builder(this, parameters, ruleContext);
ProtoInfo protoInfo = ctadBase.getConfiguredTarget().get(ProtoInfo.PROVIDER);
JavaProtoAspectCommon aspectCommon =
JavaProtoAspectCommon.getLiteInstance(ruleContext, javaSemantics);
Impl impl = new Impl(ruleContext, protoInfo, aspectCommon);
impl.addProviders(aspect);
return aspect.build();
}
@Override
public AspectDefinition getDefinition(AspectParameters aspectParameters) {
AspectDefinition.Builder result =
new AspectDefinition.Builder(this)
.propagateAlongAttribute("deps")
.propagateAlongAttribute("exports")
.requiresConfigurationFragments(
JavaConfiguration.class, ProtoConfiguration.class, PlatformConfiguration.class)
.requireSkylarkProviders(ProtoInfo.PROVIDER.id())
.advertiseProvider(JavaProtoLibraryAspectProvider.class)
.advertiseProvider(
ImmutableList.of(SkylarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey())))
.advertiseProvider(ImmutableList.of(JavaSkylarkApiProvider.SKYLARK_NAME))
.add(
attr(JavaProtoAspectCommon.LITE_PROTO_TOOLCHAIN_ATTR, LABEL)
.mandatoryNativeProviders(
ImmutableList.<Class<? extends TransitiveInfoProvider>>of(
ProtoLangToolchainProvider.class))
.value(getProtoToolchainLabel(defaultProtoToolchainLabel)))
.add(
attr(HOST_JAVA_RUNTIME_ATTRIBUTE_NAME, LABEL)
.cfg(HostTransition.createFactory())
.value(hostJdkAttribute)
.mandatoryProviders(ToolchainInfo.PROVIDER.id()))
.add(
attr(JavaRuleClasses.JAVA_TOOLCHAIN_ATTRIBUTE_NAME, LABEL)
.useOutputLicenses()
.value(javaToolchainAttribute)
.mandatoryProviders(ToolchainInfo.PROVIDER.id()));
return result.build();
}
private static class Impl {
private final RuleContext ruleContext;
private final ProtoInfo protoInfo;
/**
* Compilation-args from all dependencies, merged together. This is typically the input to a
* Java compilation action.
*/
private final JavaCompilationArgsProvider dependencyCompilationArgs;
// Compilation-args from all exports, merged together.
private final JavaCompilationArgsProvider exportsCompilationArgs;
private final JavaProtoAspectCommon aspectCommon;
private final Iterable<JavaProtoLibraryAspectProvider> javaProtoLibraryAspectProviders;
Impl(RuleContext ruleContext, ProtoInfo protoInfo, JavaProtoAspectCommon aspectCommon) {
this.ruleContext = ruleContext;
this.protoInfo = protoInfo;
this.aspectCommon = aspectCommon;
this.javaProtoLibraryAspectProviders =
ruleContext.getPrerequisites(
"deps", RuleConfiguredTarget.Mode.TARGET, JavaProtoLibraryAspectProvider.class);
dependencyCompilationArgs =
JavaCompilationArgsProvider.merge(
ruleContext.getPrerequisites(
"deps", RuleConfiguredTarget.Mode.TARGET, JavaCompilationArgsProvider.class));
this.exportsCompilationArgs =
JavaCompilationArgsProvider.merge(
ruleContext.getPrerequisites(
"exports", RuleConfiguredTarget.Mode.TARGET, JavaCompilationArgsProvider.class));
}
void addProviders(ConfiguredAspect.Builder aspect) throws InterruptedException {
JavaInfo.Builder javaInfo = JavaInfo.Builder.create();
// Represents the result of compiling the code generated for this proto, including all of its
// dependencies.
JavaCompilationArgsProvider generatedCompilationArgsProvider;
// The jars that this proto and its dependencies produce. Used to roll-up jars up to the
// java_proto_library, to be put into filesToBuild.
NestedSetBuilder<Artifact> transitiveOutputJars = NestedSetBuilder.stableOrder();
for (JavaProtoLibraryAspectProvider provider : javaProtoLibraryAspectProviders) {
transitiveOutputJars.addTransitive(provider.getJars());
}
if (!protoInfo.getDirectProtoSources().isEmpty()) {
Artifact sourceJar = aspectCommon.getSourceJarArtifact();
createProtoCompileAction(sourceJar);
Artifact outputJar = aspectCommon.getOutputJarArtifact();
generatedCompilationArgsProvider =
aspectCommon.createJavaCompileAction(
"java_lite_proto_library", sourceJar, outputJar, dependencyCompilationArgs);
transitiveOutputJars.add(outputJar);
Artifact compileTimeJar =
generatedCompilationArgsProvider.getDirectCompileTimeJars().getSingleton();
// TODO(carmi): Expose to native rules
JavaRuleOutputJarsProvider ruleOutputJarsProvider =
JavaRuleOutputJarsProvider.builder()
.addOutputJar(
outputJar,
compileTimeJar,
null /* manifestProto */,
ImmutableList.of(sourceJar))
.build();
JavaSourceJarsProvider sourceJarsProvider =
JavaSourceJarsProvider.create(
NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
ImmutableList.of(sourceJar));
aspect.addProvider(ruleOutputJarsProvider).addProvider(sourceJarsProvider);
javaInfo.addProvider(JavaRuleOutputJarsProvider.class, ruleOutputJarsProvider);
javaInfo.addProvider(JavaSourceJarsProvider.class, sourceJarsProvider);
} else {
// No sources - this proto_library is an alias library, which exports its dependencies.
// Simply propagate the compilation-args from its dependencies.
generatedCompilationArgsProvider = dependencyCompilationArgs;
aspect.addProvider(JavaRuleOutputJarsProvider.EMPTY);
javaInfo.addProvider(JavaRuleOutputJarsProvider.class, JavaRuleOutputJarsProvider.EMPTY);
}
generatedCompilationArgsProvider =
JavaCompilationArgsProvider.merge(
ImmutableList.of(generatedCompilationArgsProvider, exportsCompilationArgs));
aspect.addProvider(generatedCompilationArgsProvider);
javaInfo.addProvider(JavaCompilationArgsProvider.class, generatedCompilationArgsProvider);
aspect.addNativeDeclaredProvider(
createCcLinkingInfo(ruleContext, aspectCommon.getProtoRuntimeDeps()));
JavaSkylarkApiProvider skylarkApiProvider = JavaSkylarkApiProvider.fromRuleContext();
aspect
.addSkylarkTransitiveInfo(JavaSkylarkApiProvider.NAME, skylarkApiProvider)
.addNativeDeclaredProvider(javaInfo.build())
.addProvider(
new JavaProtoLibraryAspectProvider(
transitiveOutputJars.build(),
createNonStrictCompilationArgsProvider(
javaProtoLibraryAspectProviders,
generatedCompilationArgsProvider,
aspectCommon.getProtoRuntimeDeps())));
}
private void createProtoCompileAction(Artifact sourceJar) throws InterruptedException {
ProtoCompileActionBuilder.registerActions(
ruleContext,
ImmutableList.of(
new ProtoCompileActionBuilder.ToolchainInvocation(
"javalite",
aspectCommon.getProtoToolchainProvider(),
sourceJar.getExecPathString())),
protoInfo,
ruleContext.getLabel(),
ImmutableList.of(sourceJar),
"JavaLite",
Exports.USE,
Services.ALLOW);
}
}
}