diff options
4 files changed, 211 insertions, 3 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java index 36bb1ea586..25e9fe0749 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java @@ -179,7 +179,7 @@ public class ObjcCommandLineOptions extends FragmentOptions { + " and system libraries." ) public boolean prioritizeStaticLibs; - + @Option( name = "objc_debug_with_GLIBCXX", defaultValue = "true", @@ -200,7 +200,17 @@ public class ObjcCommandLineOptions extends FragmentOptions { + "build." ) public Label extraEntitlements; - + + @Option( + name = "experimental_auto_top_level_union_objc_protos", + defaultValue = "false", + category = "flags", + help = + "Specifies whether to use the experimental proto generation scheme, in which they are all " + + "generated and linked into the final linking target." + ) + public boolean experimentalAutoTopLevelUnionObjCProtos; + @VisibleForTesting static final String DEFAULT_MINIMUM_IOS = "7.0"; @Override diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java index ec85472ae8..f8ed4411e2 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java @@ -74,6 +74,7 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { private final boolean useAbsolutePathsForActions; private final boolean prioritizeStaticLibs; private final boolean debugWithGlibcxx; + private final boolean experimentalAutoTopLevelUnionObjCProtos; @Nullable private final Label extraEntitlements; ObjcConfiguration(ObjcCommandLineOptions objcOptions, BuildConfiguration.Options options, @@ -100,6 +101,8 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { this.prioritizeStaticLibs = objcOptions.prioritizeStaticLibs; this.debugWithGlibcxx = objcOptions.debugWithGlibcxx; this.extraEntitlements = objcOptions.extraEntitlements; + this.experimentalAutoTopLevelUnionObjCProtos = + objcOptions.experimentalAutoTopLevelUnionObjCProtos; } /** @@ -255,7 +258,7 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { public String getSigningCertName() { return this.signingCertName; } - + /** * Returns true if the linker invocation should contain static library includes before framework * and system library includes. @@ -271,4 +274,12 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { public Label getExtraEntitlements() { return extraEntitlements; } + + /** + * Whether the experimental feature of only generating proto sources at the linking target is + * enabled or not. + */ + public boolean experimentalAutoTopLevelUnionObjCProtos() { + return experimentalAutoTopLevelUnionObjCProtos; + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoAspect.java new file mode 100644 index 0000000000..cf102da124 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoAspect.java @@ -0,0 +1,87 @@ +// 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.objc; + +import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; + +import com.google.devtools.build.lib.analysis.ConfiguredAspect; +import com.google.devtools.build.lib.analysis.ConfiguredNativeAspectFactory; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.packages.AspectDefinition; +import com.google.devtools.build.lib.packages.AspectParameters; +import com.google.devtools.build.lib.rules.proto.ProtoSourcesProvider; + +/** + * Aspect that gathers the proto dependencies of the attached rule target, and propagates the proto + * values of its dependencies through the ObjcProtoProvider. + */ +public class ObjcProtoAspect implements ConfiguredNativeAspectFactory { + public static final String NAME = "ObjcProtoAspect"; + + @Override + public AspectDefinition getDefinition(AspectParameters aspectParameters) { + return new AspectDefinition.Builder(NAME) + .attributeAspect("deps", ObjcProtoAspect.class) + .requiresConfigurationFragments(ObjcConfiguration.class) + .build(); + } + + @Override + public ConfiguredAspect create( + ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) + throws InterruptedException { + ConfiguredAspect.Builder aspectBuilder = new ConfiguredAspect.Builder(NAME, ruleContext); + ObjcConfiguration objcConfiguration = ruleContext.getFragment(ObjcConfiguration.class); + + if (!objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) { + // Only process the aspect if the experimental flag is set. + return aspectBuilder.build(); + } + + ObjcProtoProvider.Builder aspectObjcProtoProvider = new ObjcProtoProvider.Builder(); + + Iterable<ObjcProtoProvider> depObjcProtoProviders = + ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class); + aspectObjcProtoProvider.addTransitive(depObjcProtoProviders); + + // If the rule has the portable_proto_filters, it must be an objc_proto_library configured + // to use the third party protobuf library, in contrast with the PB2 internal library. Only + // the third party library is enabled to propagate the protos with this aspect. + if (ruleContext + .attributes() + .has(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, LABEL_LIST)) { + aspectObjcProtoProvider.addPortableProtoFilters( + PrerequisiteArtifacts.nestedSet( + ruleContext, ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, Mode.HOST)); + + // Gather up all the dependency protos depended by this target. + Iterable<ProtoSourcesProvider> protoProviders = + ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class); + + for (ProtoSourcesProvider protoProvider : protoProviders) { + aspectObjcProtoProvider.addProtoSources(protoProvider.getTransitiveProtoSources()); + } + } + + // Only add the provider if it has any values, otherwise skip it. + if (!aspectObjcProtoProvider.isEmpty()) { + aspectBuilder.addProvider(ObjcProtoProvider.class, aspectObjcProtoProvider.build()); + } + return aspectBuilder.build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoProvider.java new file mode 100644 index 0000000000..d1ed2b9aea --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoProvider.java @@ -0,0 +1,100 @@ +// 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.objc; + +import com.google.common.base.Preconditions; +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.collect.nestedset.NestedSetBuilder; + +/** + * A provider that provides all protos and portable proto filters information in the transitive + * closure of its dependencies that are needed for generating and compiling only one version of + * proto files. + */ +public class ObjcProtoProvider implements TransitiveInfoProvider { + + private final NestedSet<Artifact> protoSources; + private final NestedSet<Artifact> portableProtoFilters; + + private ObjcProtoProvider( + NestedSet<Artifact> protoSources, NestedSet<Artifact> portableProtoFilters) { + this.protoSources = Preconditions.checkNotNull(protoSources); + this.portableProtoFilters = Preconditions.checkNotNull(portableProtoFilters); + } + + /** + * Returns the set of all the protos that the dependencies of this provider has seen. + */ + public NestedSet<Artifact> getProtoSources() { + return protoSources; + } + + /** + * Returns the set of all the associated filters to the collected protos. + */ + public NestedSet<Artifact> getPortableProtoFilters() { + return portableProtoFilters; + } + + /** + * A builder for this context with an API that is optimized for collecting information from + * several transitive dependencies. + */ + public static final class Builder { + private final NestedSetBuilder<Artifact> protoSources = NestedSetBuilder.linkOrder(); + private final NestedSetBuilder<Artifact> portableProtoFilters = NestedSetBuilder.linkOrder(); + + /** + * Adds all the protos to the set of dependencies. + */ + public Builder addProtoSources(NestedSet<Artifact> protoSources) { + this.protoSources.addTransitive(protoSources); + return this; + } + + /** + * Adds all the proto filters to the set of dependencies. + */ + public Builder addPortableProtoFilters(Iterable<Artifact> protoFilters) { + this.portableProtoFilters.addAll(protoFilters); + return this; + } + + /** + * Add all protos and filters from providers, and propagate them to any (transitive) dependers + * on this ObjcProtoProvider. + */ + public Builder addTransitive(Iterable<ObjcProtoProvider> providers) { + for (ObjcProtoProvider provider : providers) { + this.protoSources.addTransitive(provider.getProtoSources()); + this.portableProtoFilters.addTransitive(provider.getPortableProtoFilters()); + } + return this; + } + + /** + * Whether this provider has any protos or filters. + */ + public boolean isEmpty() { + return protoSources.isEmpty() && portableProtoFilters.isEmpty(); + } + + public ObjcProtoProvider build() { + return new ObjcProtoProvider(protoSources.build(), portableProtoFilters.build()); + } + } +} |