diff options
author | 2016-12-01 02:28:42 +0000 | |
---|---|---|
committer | 2016-12-01 10:17:56 +0000 | |
commit | 8e589dc314bec537da7946272b03100bbd915a0a (patch) | |
tree | fed7ba85be897be1cbb33376ca805e034051c2d1 /src/main/java/com/google/devtools/build/lib/rules/cpp | |
parent | 3e8a15267e9c7fffb6a65ee63e4dd6ec10e522d5 (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')
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; + } +} |