--
PiperOrigin-RevId: 150019356
MOS_MIGRATED_REVID=150019356
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 23e1e7d..7843d31 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -819,6 +819,7 @@
"rules/java/ProguardSpecProvider.java",
"rules/java/ProtoJavaApiInfoAspectProvider.java",
"rules/java/ProtoJavaApiInfoProvider.java",
+ "rules/java/proto/ActionReuser.java",
"rules/java/proto/JavaCompilationArgsAspectProvider.java",
"rules/java/proto/JavaLiteProtoAspect.java",
"rules/java/proto/JavaLiteProtoLibrary.java",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/ProtoJavaApiInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/ProtoJavaApiInfoProvider.java
index b43c112..e76072a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/ProtoJavaApiInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/ProtoJavaApiInfoProvider.java
@@ -14,11 +14,13 @@
package com.google.devtools.build.lib.rules.java;
import com.google.auto.value.AutoValue;
+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.TransitiveInfoProvider;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import java.util.Map;
+import javax.annotation.Nullable;
/**
* An object that provides information about API versions used by a proto library.
@@ -37,6 +39,12 @@
JavaCompilationArgs javaCompilationArgs1,
JavaCompilationArgs javaCompilationArgsMutable,
JavaCompilationArgs javaCompilationArgsImmutable,
+ Artifact sourceJar1,
+ Artifact sourceJarMutable,
+ Artifact sourceJarImmutable,
+ ImmutableList<JavaCompilationArgsProvider> protoRuntime1,
+ ImmutableList<JavaCompilationArgsProvider> protoRuntimeMutable,
+ ImmutableList<JavaCompilationArgsProvider> protoRuntimeImmutable,
Map<Artifact, Artifact> compileTimeJarToRuntimeJar,
boolean mixedApiVersions,
int apiVersion,
@@ -53,6 +61,12 @@
javaCompilationArgs1,
javaCompilationArgsMutable,
javaCompilationArgsImmutable,
+ sourceJar1,
+ sourceJarMutable,
+ sourceJarImmutable,
+ protoRuntime1,
+ protoRuntimeMutable,
+ protoRuntimeImmutable,
mixedApiVersions,
apiVersion,
supportsProto1,
@@ -114,6 +128,32 @@
*/
public abstract JavaCompilationArgs getJavaCompilationArgsImmutable();
+ // The following 3 fields are the -src.jar artifact created by proto_library. If a certain
+ // proto_library does not produce some artifact, it'll be null. This can happen for example when
+ // there are no srcs, or when a certain combination of attributes results in "mutable" not being
+ // produced.
+ @Nullable
+ public abstract Artifact sourceJar1();
+
+ @Nullable
+ public abstract Artifact sourceJarMutable();
+
+ @Nullable
+ public abstract Artifact sourceJarImmutable();
+
+ // The following 3 fields are the jars that proto_library got from the proto runtime, including
+ // Stubby. Different flavors can have different runtimes. If a certain proto_library does not
+ // produce some artifact, it'll be null. This can happen for example when a certain combination of
+ // attributes results in "mutable" not being produced.
+ @Nullable
+ public abstract ImmutableList<JavaCompilationArgsProvider> getProtoRuntime1();
+
+ @Nullable
+ public abstract ImmutableList<JavaCompilationArgsProvider> getProtoRuntimeMutable();
+
+ @Nullable
+ public abstract ImmutableList<JavaCompilationArgsProvider> getProtoRuntimeImmutable();
+
/**
* Returns true if the transitive closure contains libraries with API versions other than the one
* specified in this target. Building in mixed mode will add implicit deps for all the api_version
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/ActionReuser.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/ActionReuser.java
new file mode 100644
index 0000000..64913ad
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/ActionReuser.java
@@ -0,0 +1,123 @@
+// Copyright 2017 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.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Iterables.isEmpty;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode.TARGET;
+import static com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType.BOTH;
+import static com.google.devtools.build.lib.rules.java.proto.JavaProtoLibraryTransitiveFilesToBuildProvider.GET_JARS;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredAspect;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleContext;
+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.java.JavaCompilationArgs;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
+import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
+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.java.ProtoJavaApiInfoProvider;
+import com.google.devtools.build.lib.rules.proto.ProtoConfiguration;
+
+public class ActionReuser {
+
+ /**
+ * If the underlying proto_library rule already registers the compile actions we need, just reuse
+ * them. This will preserve memory.
+ *
+ * <p>TODO(b/36191931): Delete when it's time.
+ */
+ public static boolean reuseExistingActions(
+ ConfiguredTarget base, RuleContext ruleContext, ConfiguredAspect.Builder aspect) {
+ if (!ruleContext
+ .getConfiguration()
+ .getFragment(ProtoConfiguration.class)
+ .reuseJavaCompileActionsFromProtoLibrary()) {
+ return false;
+ }
+
+ ProtoJavaApiInfoProvider javaApi = base.getProvider(ProtoJavaApiInfoProvider.class);
+ if (javaApi == null) {
+ return false;
+ }
+
+ JavaCompilationArgs directJars = javaApi.getJavaCompilationArgsImmutable();
+ if (isEmpty(directJars.getCompileTimeJars()) || javaApi.sourceJarImmutable() == null) {
+ return false;
+ }
+
+ JavaCompilationArgs transitiveJars =
+ JavaCompilationArgs.builder()
+ .addTransitiveArgs(javaApi.getTransitiveJavaCompilationArgsImmutable(), BOTH)
+ .addTransitiveDependencies(javaApi.getProtoRuntimeImmutable(), true /* recursive */)
+ .addTransitiveArgs(directJars, BOTH)
+ .build();
+
+ Artifact outputJar = getOnlyElement(directJars.getRuntimeJars());
+ Artifact compileTimeJar = getOnlyElement(directJars.getCompileTimeJars());
+ Artifact sourceJar = checkNotNull(javaApi.sourceJarImmutable());
+
+ JavaCompilationArgsProvider compilationArgsProvider =
+ JavaCompilationArgsProvider.create(
+ directJars,
+ transitiveJars,
+ NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+ NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER));
+
+ JavaSkylarkApiProvider.Builder skylarkApiProvider =
+ JavaSkylarkApiProvider.builder()
+ .setRuleOutputJarsProvider(
+ createOutputJarProvider(outputJar, compileTimeJar, sourceJar))
+ .setSourceJarsProvider(createSrcJarProvider(sourceJar))
+ .setCompilationArgsProvider(compilationArgsProvider);
+
+ NestedSet<Artifact> transitiveOutputJars =
+ NestedSetBuilder.fromNestedSets(
+ transform(
+ ruleContext.getPrerequisites(
+ "deps", TARGET, JavaProtoLibraryTransitiveFilesToBuildProvider.class),
+ GET_JARS))
+ .add(outputJar)
+ .build();
+
+ aspect
+ .addSkylarkTransitiveInfo(
+ JavaSkylarkApiProvider.PROTO_NAME.getLegacyId(), skylarkApiProvider.build())
+ .addProviders(
+ new JavaProtoLibraryTransitiveFilesToBuildProvider(transitiveOutputJars),
+ new JavaCompilationArgsAspectProvider(compilationArgsProvider));
+ return true;
+ }
+
+ private static JavaRuleOutputJarsProvider createOutputJarProvider(
+ Artifact outputJar, Artifact compileTimeJar, Artifact sourceJar) {
+ return JavaRuleOutputJarsProvider.builder()
+ .addOutputJar(outputJar, compileTimeJar, ImmutableList.of(sourceJar))
+ .build();
+ }
+
+ private static JavaSourceJarsProvider createSrcJarProvider(Artifact sourceJar) {
+ return JavaSourceJarsProvider.create(
+ NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+ NestedSetBuilder.<Artifact>stableOrder().add(sourceJar).build());
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
index e2ba1bd..36be8ab 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
@@ -114,6 +114,9 @@
checkNotNull(base.getProvider(ProtoSupportDataProvider.class)).getSupportData();
Impl impl = new Impl(ruleContext, supportData, javaSemantics, rpcSupport);
+ if (impl.shouldGenerateCode() && ActionReuser.reuseExistingActions(base, ruleContext, aspect)) {
+ return aspect.build();
+ }
impl.addProviders(aspect);
return aspect.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoConfiguration.java
index 64a202d..3203f53 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoConfiguration.java
@@ -110,6 +110,17 @@
)
public StrictDepsMode strictProtoDeps;
+ @Option(
+ name = "reuseJavaCompileActionsFromProtoLibrary",
+ defaultValue = "false",
+ category = "experimental",
+ help =
+ "When true, a java_proto_library that wraps a proto_library with java_api_version!=0"
+ + "will reuse its actions. This saves memory and prevents duplicate jars from "
+ + "appearing on a Java compilation's classpath"
+ )
+ public boolean reuseJavaCompileActionsFromProtoLibrary;
+
@Override
public FragmentOptions getHost(boolean fallback) {
Options host = (Options) super.getHost(fallback);
@@ -121,6 +132,7 @@
host.protoToolchainForJavaLite = protoToolchainForJavaLite;
host.protoToolchainForCc = protoToolchainForCc;
host.strictProtoDeps = strictProtoDeps;
+ host.reuseJavaCompileActionsFromProtoLibrary = reuseJavaCompileActionsFromProtoLibrary;
return host;
}
}
@@ -153,6 +165,7 @@
private final Label protoToolchainForJavaLite;
private final Label protoToolchainForCc;
private final StrictDepsMode strictProtoDeps;
+ private final boolean reuseJavaCompileActionsFromProtoLibrary;
public ProtoConfiguration(Options options) {
this.experimentalProtoExtraActions = options.experimentalProtoExtraActions;
@@ -162,6 +175,7 @@
this.protoToolchainForJavaLite = options.protoToolchainForJavaLite;
this.protoToolchainForCc = options.protoToolchainForCc;
this.strictProtoDeps = options.strictProtoDeps;
+ this.reuseJavaCompileActionsFromProtoLibrary = options.reuseJavaCompileActionsFromProtoLibrary;
}
public ImmutableList<String> protocOpts() {
@@ -196,4 +210,8 @@
public StrictDepsMode strictProtoDeps() {
return strictProtoDeps;
}
+
+ public boolean reuseJavaCompileActionsFromProtoLibrary() {
+ return reuseJavaCompileActionsFromProtoLibrary;
+ }
}