aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/cpp
diff options
context:
space:
mode:
authorGravatar Carmi Grushko <carmi@google.com>2016-12-01 02:28:42 +0000
committerGravatar Irina Iancu <elenairina@google.com>2016-12-01 10:17:56 +0000
commit8e589dc314bec537da7946272b03100bbd915a0a (patch)
treefed7ba85be897be1cbb33376ca805e034051c2d1 /src/main/java/com/google/devtools/build/lib/rules/cpp
parent3e8a15267e9c7fffb6a65ee63e4dd6ec10e522d5 (diff)
Initial commit of cc_proto_library.
RELNOTES: cc_proto_library generates C++ code from proto_library rules. -- MOS_MIGRATED_REVID=140680034
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/cpp')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/BUILD65
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java307
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java81
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryFilesToBuilderProvider.java33
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryOutputGroupProvider.java34
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryRule.java109
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/ProtoCcHeaderProvider.java44
10 files changed, 683 insertions, 5 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
index 1c8578ae16..76df2a1954 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
@@ -7,7 +7,10 @@ package(
java_library(
name = "cpp",
- srcs = glob(["**/*.java"]),
+ srcs = glob([
+ "*.java",
+ "transitions/*.java",
+ ]),
deps = [
"//src/main/java/com/google/devtools/build/lib:build-base",
"//src/main/java/com/google/devtools/build/lib:collect",
@@ -15,6 +18,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib:events",
"//src/main/java/com/google/devtools/build/lib:io",
"//src/main/java/com/google/devtools/build/lib:packages-internal",
+ "//src/main/java/com/google/devtools/build/lib:proto-rules",
"//src/main/java/com/google/devtools/build/lib:shell",
"//src/main/java/com/google/devtools/build/lib:skylarkinterface",
"//src/main/java/com/google/devtools/build/lib:util",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
index dbed5de2e7..133ce4540a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
@@ -869,7 +869,7 @@ public final class CcLibraryHelper {
Preconditions.checkState(
// 'cc_inc_library' rules do not compile, and thus are not affected by LIPO.
ruleContext.getRule().getRuleClass().equals("cc_inc_library")
- || ruleContext.getRule().isAttrDefined(":lipo_context_collector", BuildType.LABEL));
+ || ruleContext.isAttrDefined(":lipo_context_collector", BuildType.LABEL));
if (checkDepsGenerateCpp) {
for (LanguageDependentFragment dep :
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index f5e0ab5f39..4213adcc5c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.rules.cpp;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -34,7 +36,6 @@ import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
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.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleErrorConsumer;
import com.google.devtools.build.lib.rules.cpp.CcLinkParams.Linkstamp;
import com.google.devtools.build.lib.rules.cpp.CppCompilationContext.Builder;
@@ -247,7 +248,7 @@ public class CppHelper {
* if there is no such attribute (this is currently not an error).
*/
@Nullable public static CcToolchainProvider getToolchain(RuleContext ruleContext) {
- if (ruleContext.attributes().getAttributeDefinition(":cc_toolchain") == null) {
+ if (!ruleContext.isAttrDefined(":cc_toolchain", LABEL)) {
// TODO(bazel-team): Report an error or throw an exception in this case.
return null;
}
@@ -384,7 +385,7 @@ public class CppHelper {
scannableBuilder.addTransitive(dep.getTransitiveIncludeScannables());
}
- if (ruleContext.attributes().has("malloc", BuildType.LABEL)) {
+ if (ruleContext.attributes().has("malloc", LABEL)) {
TransitiveInfoCollection malloc = mallocForTarget(ruleContext);
TransitiveLipoInfoProvider provider = malloc.getProvider(TransitiveLipoInfoProvider.class);
if (provider != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/BUILD b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/BUILD
new file mode 100644
index 0000000000..e81fe72905
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/BUILD
@@ -0,0 +1,65 @@
+package(
+ default_visibility = ["//src:__subpackages__"],
+)
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_library(
+ name = "CcProtoLibrary",
+ srcs = [
+ "CcProtoAspect.java",
+ "CcProtoLibrary.java",
+ "CcProtoLibraryRule.java",
+ ],
+ deps = [
+ ":CcProtoLibraryFilesToBuilderProvider",
+ ":CcProtoLibraryOutputGroupProvider",
+ ":ProtoCcHeaderProvider",
+ "//src/main/java/com/google/devtools/build/lib:build-base",
+ "//src/main/java/com/google/devtools/build/lib:collect",
+ "//src/main/java/com/google/devtools/build/lib:concurrent",
+ "//src/main/java/com/google/devtools/build/lib:packages-internal",
+ "//src/main/java/com/google/devtools/build/lib:proto-rules",
+ "//src/main/java/com/google/devtools/build/lib:vfs",
+ "//src/main/java/com/google/devtools/build/lib/actions",
+ "//src/main/java/com/google/devtools/build/lib/rules/cpp",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
+
+java_library(
+ name = "CcProtoLibraryFilesToBuilderProvider",
+ srcs = ["CcProtoLibraryFilesToBuilderProvider.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:collect",
+ "//src/main/java/com/google/devtools/build/lib:concurrent",
+ "//src/main/java/com/google/devtools/build/lib:transitive-info-provider",
+ "//src/main/java/com/google/devtools/build/lib/actions",
+ ],
+)
+
+java_library(
+ name = "CcProtoLibraryOutputGroupProvider",
+ srcs = ["CcProtoLibraryOutputGroupProvider.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:collect",
+ "//src/main/java/com/google/devtools/build/lib:concurrent",
+ "//src/main/java/com/google/devtools/build/lib:transitive-info-provider",
+ "//src/main/java/com/google/devtools/build/lib/actions",
+ "//third_party:guava",
+ ],
+)
+
+java_library(
+ name = "ProtoCcHeaderProvider",
+ srcs = ["ProtoCcHeaderProvider.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:collect",
+ "//src/main/java/com/google/devtools/build/lib:transitive-info-provider",
+ "//src/main/java/com/google/devtools/build/lib/actions",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
new file mode 100644
index 0000000000..65e3c7664b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
@@ -0,0 +1,307 @@
+// 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.cpp.proto;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode.TARGET;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredAspect;
+import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
+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.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.AspectDefinition;
+import com.google.devtools.build.lib.packages.AspectParameters;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.AttributeMap;
+import com.google.devtools.build.lib.packages.NativeAspectClass;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
+import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppHelper;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.rules.cpp.CppSemantics;
+import com.google.devtools.build.lib.rules.proto.ProtoCommon;
+import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder;
+import com.google.devtools.build.lib.rules.proto.ProtoCompileActionBuilder.ToolchainInvocation;
+import com.google.devtools.build.lib.rules.proto.ProtoConfiguration;
+import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainProvider;
+import com.google.devtools.build.lib.rules.proto.ProtoSourceFileBlacklist;
+import com.google.devtools.build.lib.rules.proto.ProtoSupportDataProvider;
+import com.google.devtools.build.lib.rules.proto.SupportData;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/** Part of the implementation of cc_proto_library. */
+public class CcProtoAspect extends NativeAspectClass implements ConfiguredAspectFactory {
+
+ private static final String PROTO_TOOLCHAIN_ATTR = ":aspect_cc_proto_toolchain";
+
+ private static final Attribute.LateBoundLabel<BuildConfiguration> PROTO_TOOLCHAIN_LABEL =
+ new Attribute.LateBoundLabel<BuildConfiguration>(
+ "@com_google_protobuf_cc//:cc_toolchain", ProtoConfiguration.class) {
+ @Override
+ public Label resolve(Rule rule, AttributeMap attributes, BuildConfiguration configuration) {
+ return configuration.getFragment(ProtoConfiguration.class).protoToolchainForCc();
+ }
+ };
+
+ private final CppSemantics cppSemantics;
+ private final Attribute.LateBoundLabel<BuildConfiguration> ccToolchainAttrValue;
+
+ public CcProtoAspect(
+ CppSemantics cppSemantics,
+ Attribute.LateBoundLabel<BuildConfiguration> ccToolchainAttrValue) {
+ this.cppSemantics = cppSemantics;
+ this.ccToolchainAttrValue = ccToolchainAttrValue;
+ }
+
+ @Override
+ public ConfiguredAspect create(
+ ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters)
+ throws InterruptedException {
+ // Get SupportData, which is provided by the proto_library rule we attach to.
+ SupportData supportData =
+ checkNotNull(base.getProvider(ProtoSupportDataProvider.class)).getSupportData();
+
+ try {
+ ConfiguredAspect.Builder result = new ConfiguredAspect.Builder(this, parameters, ruleContext);
+ new Impl(ruleContext, supportData, cppSemantics).addProviders(result);
+ return result.build();
+ } catch (RuleErrorException e) {
+ ruleContext.ruleError(e.getMessage());
+ return null;
+ }
+ }
+
+ @Override
+ public AspectDefinition getDefinition(AspectParameters aspectParameters) {
+ AspectDefinition.Builder result =
+ new AspectDefinition.Builder(this)
+ .attributeAspect("deps", this)
+ .requiresConfigurationFragments(CppConfiguration.class, ProtoConfiguration.class)
+ .requireProviders(ProtoSupportDataProvider.class)
+ .add(
+ attr(PROTO_TOOLCHAIN_ATTR, LABEL)
+ .mandatoryNativeProviders(
+ ImmutableList.<Class<? extends TransitiveInfoProvider>>of(
+ ProtoLangToolchainProvider.class))
+ .value(PROTO_TOOLCHAIN_LABEL))
+ .add(attr(":cc_toolchain", LABEL).value(ccToolchainAttrValue))
+ .add(
+ attr(":lipo_context_collector", LABEL)
+ .cfg(CppRuleClasses.LipoTransition.LIPO_COLLECTOR)
+ .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR)
+ .skipPrereqValidatorCheck());
+
+ return result.build();
+ }
+
+ private static class Impl {
+
+ private final TransitiveInfoProviderMap ccLibraryProviders;
+ private final ProtoCcHeaderProvider headerProvider;
+ private final ImmutableMap<String, NestedSet<Artifact>> outputGroups;
+
+ private final RuleContext ruleContext;
+ private final SupportData supportData;
+ private final CppSemantics cppSemantics;
+ private final NestedSetBuilder<Artifact> filesBuilder;
+
+ Impl(RuleContext ruleContext, SupportData supportData, CppSemantics cppSemantics)
+ throws RuleErrorException, InterruptedException {
+ this.ruleContext = ruleContext;
+ this.supportData = supportData;
+ this.cppSemantics = cppSemantics;
+ FeatureConfiguration featureConfiguration = getFeatureConfiguration(supportData);
+
+ CcLibraryHelper helper = initializeCcLibraryHelper(featureConfiguration);
+ helper.addDeps(ruleContext.getPrerequisites("deps", TARGET));
+
+ // Compute and register files generated by this proto library.
+ Collection<Artifact> outputs = new ArrayList<>();
+ if (areSrcsBlacklisted()) {
+ registerBlacklistedSrcs(supportData, helper);
+ headerProvider = null;
+ } else if (supportData.hasProtoSources()) {
+ Collection<Artifact> headers = getHeaders(supportData);
+ Collection<Artifact> sources = getSources(supportData);
+ outputs.addAll(headers);
+ outputs.addAll(sources);
+
+ helper.addSources(sources);
+ helper.addPublicHeaders(headers);
+
+ NestedSetBuilder<Artifact> publicHeaderPaths = NestedSetBuilder.stableOrder();
+ publicHeaderPaths.addAll(headers);
+ headerProvider = new ProtoCcHeaderProvider(publicHeaderPaths.build(), true);
+ } else {
+ // If this proto_library doesn't have sources, it provides the combined headers of all its
+ // direct dependencies. Thus, if a direct dependency does have sources, the generated files
+ // are also provided by this library. If a direct dependency does not have sources, it will
+ // do the same thing, so that effectively this library looks through all source-less
+ // proto_libraries and provides all generated headers of the proto_libraries with sources
+ // that it depends on.
+ //
+ // Similar, if a proto_library, does not have sources, it forwards the information whether
+ // its transitive dependencies generated .pb.h files. If one of them doesn't, this
+ // proto_library pretends to not generate them either.
+ boolean hasDepWithoutPbH = false;
+ NestedSetBuilder<Artifact> transitiveHeaders = NestedSetBuilder.stableOrder();
+ for (ProtoCcHeaderProvider headerProvider :
+ ruleContext.getPrerequisites("deps", TARGET, ProtoCcHeaderProvider.class)) {
+ helper.addPublicTextualHeaders(headerProvider.getHeaders());
+ transitiveHeaders.addTransitive(headerProvider.getHeaders());
+ hasDepWithoutPbH = hasDepWithoutPbH || !headerProvider.getGeneratesPbH();
+ }
+ headerProvider = new ProtoCcHeaderProvider(transitiveHeaders.build(), !hasDepWithoutPbH);
+ }
+
+ filesBuilder = NestedSetBuilder.stableOrder();
+ filesBuilder.addAll(outputs);
+ createProtoCompileAction(supportData, outputs);
+
+ CcLibraryHelper.Info info = helper.build();
+ ccLibraryProviders = info.getProviders();
+ outputGroups = info.getOutputGroups();
+ info.addLinkingOutputsTo(filesBuilder);
+ }
+
+ private boolean areSrcsBlacklisted() {
+ return !new ProtoSourceFileBlacklist(
+ ruleContext, getProtoToolchainProvider().blacklistedProtos())
+ .checkSrcs(supportData.getDirectProtoSources(), "cc_proto_library");
+ }
+
+ private FeatureConfiguration getFeatureConfiguration(SupportData supportData) {
+ ImmutableSet.Builder<String> requestedFeatures = new ImmutableSet.Builder<>();
+ ImmutableSet.Builder<String> unsupportedFeatures = new ImmutableSet.Builder<>();
+ unsupportedFeatures.add(CppRuleClasses.PARSE_HEADERS);
+ unsupportedFeatures.add(CppRuleClasses.LAYERING_CHECK);
+ if (!areSrcsBlacklisted() && supportData.hasProtoSources()) {
+ requestedFeatures.add(CppRuleClasses.HEADER_MODULES);
+ } else {
+ unsupportedFeatures.add(CppRuleClasses.HEADER_MODULES);
+ }
+ FeatureConfiguration featureConfiguration =
+ CcCommon.configureFeatures(
+ ruleContext,
+ requestedFeatures.build(),
+ unsupportedFeatures.build(),
+ CcLibraryHelper.SourceCategory.CC,
+ CppHelper.getToolchain(
+ ruleContext, ruleContext.getPrerequisite(":cc_toolchain", TARGET)));
+ return featureConfiguration;
+ }
+
+ private CcLibraryHelper initializeCcLibraryHelper(FeatureConfiguration featureConfiguration) {
+ CcLibraryHelper helper = new CcLibraryHelper(ruleContext, cppSemantics, featureConfiguration);
+ helper.enableCcSpecificLinkParamsProvider();
+ helper.enableCcNativeLibrariesProvider();
+ // TODO(dougk): Configure output artifact with action_config
+ // once proto compile action is configurable from the crosstool.
+ if (!ruleContext.getFragment(CppConfiguration.class).supportsDynamicLinker()) {
+ helper.setCreateDynamicLibrary(false);
+ }
+ TransitiveInfoCollection runtime = getProtoToolchainProvider().runtime();
+ if (runtime != null) {
+ helper.addDeps(ImmutableList.of(runtime));
+ }
+ return helper;
+ }
+
+ private Collection<Artifact> getHeaders(SupportData supportData) {
+ return ProtoCommon.getGeneratedOutputs(
+ ruleContext, supportData.getDirectProtoSources(), ".pb.h");
+ }
+
+ private Collection<Artifact> getSources(SupportData supportData) {
+ return ProtoCommon.getGeneratedOutputs(
+ ruleContext, supportData.getDirectProtoSources(), ".pb.cc");
+ }
+
+ private void registerBlacklistedSrcs(SupportData supportData, CcLibraryHelper helper) {
+ // Hack: This is a proto_library for descriptor.proto or similar.
+ //
+ // The headers of those libraries are precomputed . They are also explicitly part of normal
+ // cc_library rules that export them in their 'hdrs' attribute, and compile them as header
+ // module if requested.
+ //
+ // The sole purpose of a proto_library with blacklisted srcs is so other proto_library rules
+ // can import them from a protocol buffer, as proto_library rules can only depend on other
+ // proto library rules.
+ ImmutableList.Builder<PathFragment> headers = new ImmutableList.Builder<>();
+ for (Artifact source : supportData.getDirectProtoSources()) {
+ headers.add(FileSystemUtils.replaceExtension(source.getRootRelativePath(), ".pb.h"));
+ headers.add(FileSystemUtils.replaceExtension(source.getRootRelativePath(), ".proto.h"));
+ }
+ // We add the header to the proto_library's module map as additional (textual) header for
+ // two reasons:
+ // 1. The header will be exported via a normal cc_library, and a header must only be exported
+ // non-textually from one library.
+ // 2. We want to allow proto_library rules that depend on the bootstrap-hack proto_library
+ // to be layering-checked; we need to provide a module map for the layering check to work.
+ helper.addAdditionalExportedHeaders(headers.build());
+ }
+
+ private void createProtoCompileAction(SupportData supportData, Collection<Artifact> outputs) {
+ String genfilesPath = ruleContext.getConfiguration().getGenfilesFragment().getPathString();
+
+ ImmutableList.Builder<ToolchainInvocation> invocations = ImmutableList.builder();
+ invocations.add(
+ new ToolchainInvocation("C++", checkNotNull(getProtoToolchainProvider()), genfilesPath));
+ ProtoCompileActionBuilder.registerActions(
+ ruleContext,
+ invocations.build(),
+ supportData.getDirectProtoSources(),
+ supportData.getTransitiveImports(),
+ supportData.getProtosInDirectDeps(),
+ outputs,
+ "C++",
+ true /* allowServices */);
+ }
+
+ private ProtoLangToolchainProvider getProtoToolchainProvider() {
+ return ruleContext.getPrerequisite(
+ PROTO_TOOLCHAIN_ATTR, TARGET, ProtoLangToolchainProvider.class);
+ }
+
+ public void addProviders(ConfiguredAspect.Builder builder) {
+ builder.addProviders(ccLibraryProviders);
+ builder.addProvider(new CcProtoLibraryFilesToBuilderProvider(filesBuilder.build()));
+ builder.addProvider(new CcProtoLibraryOutputGroupProvider(outputGroups));
+ if (headerProvider != null) {
+ builder.addProvider(headerProvider);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
new file mode 100644
index 0000000000..b92501be5c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
@@ -0,0 +1,81 @@
+// 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.cpp.proto;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode.TARGET;
+
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+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.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.rules.cpp.CcExecutionDynamicLibrariesProvider;
+import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider;
+import com.google.devtools.build.lib.rules.cpp.CcNativeLibraryProvider;
+import com.google.devtools.build.lib.rules.cpp.CcSkylarkApiProvider;
+import com.google.devtools.build.lib.rules.cpp.CcSpecificLinkParamsProvider;
+
+/** Part of the implementation of cc_proto_library. */
+public class CcProtoLibrary implements RuleConfiguredTargetFactory {
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext)
+ throws InterruptedException, RuleErrorException {
+
+ if (ruleContext.getPrerequisites("deps", TARGET).size() != 1) {
+ ruleContext.throwWithAttributeError(
+ "deps",
+ "'deps' attribute must contain exactly one label "
+ + "(we didn't name it 'dep' for consistency). "
+ + "The main use-case for multiple deps is to create a rule that contains several "
+ + "other targets. This makes dependency bloat more likely. It also makes it harder"
+ + "to remove unused deps.");
+ }
+
+ TransitiveInfoCollection dep = checkNotNull(ruleContext.getPrerequisite("deps", TARGET));
+
+ RuleConfiguredTargetBuilder result =
+ new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(
+ dep.getProvider(CcProtoLibraryFilesToBuilderProvider.class).filesBuilder)
+ .addProvider(
+ RunfilesProvider.class, RunfilesProvider.withData(Runfiles.EMPTY, Runfiles.EMPTY));
+
+ addProviderIfNotNull(result, dep.getProvider(CcLinkParamsProvider.class));
+ addProviderIfNotNull(result, dep.getProvider(CcNativeLibraryProvider.class));
+ addProviderIfNotNull(result, dep.getProvider(CcExecutionDynamicLibrariesProvider.class));
+ addProviderIfNotNull(result, dep.getProvider(CcSpecificLinkParamsProvider.class));
+ addProviderIfNotNull(result, dep.getProvider(ProtoCcHeaderProvider.class));
+
+ result.addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider());
+
+ CcProtoLibraryOutputGroupProvider outputGroups =
+ dep.getProvider(CcProtoLibraryOutputGroupProvider.class);
+ if (outputGroups != null) {
+ result.addOutputGroups(outputGroups.outputGroups);
+ }
+ return result.build();
+ }
+
+ private void addProviderIfNotNull(
+ RuleConfiguredTargetBuilder result, TransitiveInfoProvider provider) {
+ if (provider != null) {
+ result.addProvider(provider);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryFilesToBuilderProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryFilesToBuilderProvider.java
new file mode 100644
index 0000000000..8170cd470d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryFilesToBuilderProvider.java
@@ -0,0 +1,33 @@
+// 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.cpp.proto;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety;
+
+/**
+ * Used by CcProtoAspect to propagate files-to-build to CcProtoLibrary, where it is exposed via
+ * setFilesToBuild().
+ */
+@ThreadSafety.Immutable
+final class CcProtoLibraryFilesToBuilderProvider implements TransitiveInfoProvider {
+ final NestedSet<Artifact> filesBuilder;
+
+ CcProtoLibraryFilesToBuilderProvider(NestedSet<Artifact> filesBuilder) {
+ this.filesBuilder = filesBuilder;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryOutputGroupProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryOutputGroupProvider.java
new file mode 100644
index 0000000000..49fe3ece15
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryOutputGroupProvider.java
@@ -0,0 +1,34 @@
+// 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.cpp.proto;
+
+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.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety;
+
+/**
+ * Used by CcProtoAspect to propagate output groups to CcProtoLibrary, where it is exposed via
+ * setOutputGroups().
+ */
+@ThreadSafety.Immutable
+final class CcProtoLibraryOutputGroupProvider implements TransitiveInfoProvider {
+ final ImmutableMap<String, NestedSet<Artifact>> outputGroups;
+
+ CcProtoLibraryOutputGroupProvider(ImmutableMap<String, NestedSet<Artifact>> outputGroups) {
+ this.outputGroups = outputGroups;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryRule.java
new file mode 100644
index 0000000000..f41b49c24a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibraryRule.java
@@ -0,0 +1,109 @@
+// 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.cpp.proto;
+
+import static com.google.devtools.build.lib.packages.Aspect.INJECTING_RULE_KIND_PARAMETER_KEY;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+
+import com.google.common.base.Function;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.AspectParameters;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import javax.annotation.Nullable;
+
+/** Declaration part of cc_proto_library. */
+public class CcProtoLibraryRule implements RuleDefinition {
+
+ private static final Function<Rule, AspectParameters> ASPECT_PARAMETERS =
+ new Function<Rule, AspectParameters>() {
+ @Nullable
+ @Override
+ public AspectParameters apply(@Nullable Rule rule) {
+ return new AspectParameters.Builder()
+ .addAttribute(INJECTING_RULE_KIND_PARAMETER_KEY, "cc_proto_library")
+ .build();
+ }
+ };
+
+ private final CcProtoAspect ccProtoAspect;
+
+ public CcProtoLibraryRule(CcProtoAspect ccProtoAspect) {
+ this.ccProtoAspect = ccProtoAspect;
+ }
+
+ @Override
+ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ // This rule isn't ready for use yet.
+ .setUndocumented()
+ /* <!-- #BLAZE_RULE(cc_proto_library).ATTRIBUTE(deps) -->
+ The list of <a href="protocol-buffer.html#proto_library"><code>proto_library</code></a>
+ rules to generate C++ code for.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .override(
+ attr("deps", LABEL_LIST)
+ .allowedRuleClasses("proto_library")
+ .allowedFileTypes()
+ .aspect(ccProtoAspect, ASPECT_PARAMETERS))
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name("cc_proto_library")
+ .factoryClass(CcProtoLibrary.class)
+ .ancestors(BaseRuleClasses.RuleBase.class)
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = cc_proto_library, TYPE = LIBRARY, FAMILY = C / C++) -->
+
+<p>
+<code>cc_proto_library</code> generates C++ code from <code>.proto</code> files.
+</p>
+
+<p>
+<code>deps</code> must point to <a href="protocol-buffer.html#proto_library"><code>proto_library
+</code></a> rules.
+</p>
+
+<p>
+Example:
+</p>
+
+<pre class="code">
+cc_library(
+ name = "lib",
+ deps = [":foo_cc_proto"],
+)
+
+cc_proto_library(
+ name = "foo_cc_proto",
+ deps = [":foo_proto"],
+)
+
+proto_library(
+ name = "foo_proto",
+)
+</pre>
+
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/ProtoCcHeaderProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/ProtoCcHeaderProvider.java
new file mode 100644
index 0000000000..5bf13de92e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/ProtoCcHeaderProvider.java
@@ -0,0 +1,44 @@
+// 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.cpp.proto;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+
+/** Provides information about generated C++ headers of dependencies. */
+public final class ProtoCcHeaderProvider implements TransitiveInfoProvider {
+ private final NestedSet<Artifact> headers;
+ private final boolean generatesPbH;
+
+ public ProtoCcHeaderProvider(NestedSet<Artifact> headers, boolean generatesPbH) {
+ this.headers = headers;
+ this.generatesPbH = generatesPbH;
+ }
+
+ /**
+ * @return the headers of the proto library for C++.
+ * <p>Normally these are the headers generated by the proto compiler for C++; only in case of
+ * a proto_library with blacklisted srcs will these be files from the source tree.
+ */
+ public NestedSet<Artifact> getHeaders() {
+ return headers;
+ }
+
+ /** @return true, if this proto library generates .pb.h files. */
+ public boolean getGeneratesPbH() {
+ return generatesPbH;
+ }
+}