aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Sergio Campama <kaipi@google.com>2016-08-16 04:22:30 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2016-08-16 15:21:27 +0000
commitaaa58714859459d2bac3814579a74f5d56297d1b (patch)
treeffa1b3786fa64ea207a941ce93eaadf607231bd3 /src/main/java/com/google/devtools/build
parent74c075aa1864875c5529540f62bcbe3fe80fc311 (diff)
Adds proto grouping behavior so that generation and compilation actions are much smaller. This adds more granularity and helps prevent excessive compilation by minimizing the number of inputs for each action.
-- MOS_MIGRATED_REVID=130359288
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java57
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java48
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java45
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoAspect.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java41
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoProvider.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java466
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java617
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java5
9 files changed, 701 insertions, 612 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
index 4c878e648d..1d3ac278c7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
@@ -44,7 +44,6 @@ import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs;
import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
-import com.google.devtools.build.lib.rules.objc.ProtoSupport.TargetType;
import java.util.List;
import java.util.Set;
@@ -95,11 +94,28 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
ObjcProvider.Builder objcProviderBuilder = new ObjcProvider.Builder();
for (BuildConfiguration childConfig : childConfigurations) {
+ Optional<ObjcProvider> protosObjcProvider = Optional.absent();
+ ObjcConfiguration objcConfiguration = childConfig.getFragment(ObjcConfiguration.class);
+ if (objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) {
+ ProtobufSupport protoSupport =
+ new ProtobufSupport(ruleContext)
+ .registerGenerationActions()
+ .registerCompilationActions();
+
+ protosObjcProvider = Optional.of(protoSupport.getObjcProvider());
+ }
+
IntermediateArtifacts intermediateArtifacts =
ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig);
- ObjcCommon common = common(ruleContext, childConfig, intermediateArtifacts,
- nullToEmptyList(configToDepsCollectionMap.get(childConfig)),
- nullToEmptyList(configurationToNonPropagatedObjcMap.get(childConfig)));
+
+ ObjcCommon common =
+ common(
+ ruleContext,
+ childConfig,
+ intermediateArtifacts,
+ nullToEmptyList(configToDepsCollectionMap.get(childConfig)),
+ nullToEmptyList(configurationToNonPropagatedObjcMap.get(childConfig)),
+ protosObjcProvider);
ImmutableList.Builder<J2ObjcMappingFileProvider> j2ObjcMappingFileProviders =
ImmutableList.builder();
J2ObjcEntryClassProvider.Builder j2ObjcEntryClassProviderBuilder =
@@ -119,19 +135,6 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
binariesToLipo.add(intermediateArtifacts.strippedSingleArchitectureBinary());
- ObjcConfiguration objcConfiguration = childConfig.getFragment(ObjcConfiguration.class);
- if (objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) {
- ProtoSupport protoSupport =
- new ProtoSupport(ruleContext, TargetType.LINKING_TARGET).registerActions();
-
- ObjcCommon protoCommon = protoSupport.getCommon();
- new CompilationSupport(
- ruleContext,
- protoSupport.getIntermediateArtifacts(),
- new CompilationAttributes.Builder().build())
- .registerCompileAndArchiveActions(protoCommon, protoSupport.getUserHeaderSearchPaths());
- }
-
new CompilationSupport(ruleContext, childConfig)
.registerCompileAndArchiveActions(common)
.registerLinkActions(
@@ -143,7 +146,7 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
DsymOutputType.APP)
.validateAttributes();
ruleContext.assertNoErrors();
-
+
objcProviderBuilder.addTransitiveAndPropagate(common.getObjcProvider());
}
@@ -165,23 +168,17 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
return targetBuilder.build();
}
- private ObjcCommon common(RuleContext ruleContext, BuildConfiguration buildConfiguration,
+ private ObjcCommon common(
+ RuleContext ruleContext,
+ BuildConfiguration buildConfiguration,
IntermediateArtifacts intermediateArtifacts,
List<TransitiveInfoCollection> propagatedDeps,
- List<ObjcProvider> nonPropagatedObjcDeps) {
+ List<ObjcProvider> nonPropagatedObjcDeps,
+ Optional<ObjcProvider> protosObjcProvider) {
CompilationArtifacts compilationArtifacts =
CompilationSupport.compilationArtifacts(ruleContext, intermediateArtifacts);
- Optional<Artifact> protoLib;
- ObjcConfiguration objcConfiguration = buildConfiguration.getFragment(ObjcConfiguration.class);
- if (objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) {
- ProtoSupport protoSupport = new ProtoSupport(ruleContext, TargetType.LINKING_TARGET);
- protoLib = protoSupport.getCommon().getCompiledArchive();
- } else {
- protoLib = Optional.absent();
- }
-
return new ObjcCommon.Builder(ruleContext, buildConfiguration)
.setCompilationAttributes(
CompilationAttributes.Builder.fromRuleContext(ruleContext).build())
@@ -191,12 +188,12 @@ public class AppleBinary implements RuleConfiguredTargetFactory {
.addDeps(propagatedDeps)
.addDepObjcProviders(
ruleContext.getPrerequisites("bundles", Mode.TARGET, ObjcProvider.class))
+ .addDepObjcProviders(protosObjcProvider.asSet())
.addNonPropagatedDepObjcProviders(nonPropagatedObjcDeps)
.setIntermediateArtifacts(intermediateArtifacts)
.setAlwayslink(false)
// TODO(b/29152500): Enable module map generation.
.setLinkedBinary(intermediateArtifacts.strippedSingleArchitectureBinary())
- .addExtraImportLibraries(protoLib.asSet())
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
index 8579bb4966..c584268458 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
@@ -35,17 +35,14 @@ import com.google.devtools.build.lib.rules.apple.Platform;
import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs;
import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
-import com.google.devtools.build.lib.rules.objc.ProtoSupport.TargetType;
import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.LinkedBinary;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
-/**
- * Implementation for rules that link binaries.
- */
+/** Implementation for rules that link binaries. */
abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory {
/**
- * Indicates whether this binary generates an application bundle. If so, it causes the
- * {@code infoplist} attribute to be read and a bundle to be added to the files-to-build.
+ * Indicates whether this binary generates an application bundle. If so, it causes the {@code
+ * infoplist} attribute to be read and a bundle to be added to the files-to-build.
*/
enum HasReleaseBundlingSupport {
YES, NO;
@@ -77,25 +74,14 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory
throws InterruptedException, RuleErrorException {
ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
- ObjcProvider protosObjcProvider = null;
- XcodeProvider protosXcodeProvider = null;
-
+ Optional<ObjcProvider> protosObjcProvider = Optional.absent();
+ Optional<XcodeProvider> protosXcodeProvider = Optional.absent();
if (objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) {
- XcodeProvider.Builder protosXcodeProviderBuilder = new XcodeProvider.Builder();
- ProtoSupport protoSupport = new ProtoSupport(ruleContext, TargetType.LINKING_TARGET)
- .registerActions()
- .addXcodeProviderOptions(protosXcodeProviderBuilder);
-
- ObjcCommon protoCommon = protoSupport.getCommon();
- protosObjcProvider = protoCommon.getObjcProvider();
-
- new CompilationSupport(
- ruleContext,
- protoSupport.getIntermediateArtifacts(),
- new CompilationAttributes.Builder().build())
- .registerCompileAndArchiveActions(protoCommon, protoSupport.getUserHeaderSearchPaths())
- .addXcodeSettings(protosXcodeProviderBuilder, protoCommon);
- protosXcodeProvider = protosXcodeProviderBuilder.build();
+ ProtobufSupport protoSupport =
+ new ProtobufSupport(ruleContext).registerGenerationActions().registerCompilationActions();
+
+ protosObjcProvider = Optional.of(protoSupport.getObjcProvider());
+ protosXcodeProvider = Optional.of(protoSupport.getXcodeProvider());
}
ObjcCommon common = common(ruleContext, protosObjcProvider);
@@ -103,11 +89,8 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory
ObjcProvider objcProvider = common.getObjcProvider();
assertLibraryOrSources(objcProvider, ruleContext);
- XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder();
- if (protosXcodeProvider != null) {
- xcodeProviderBuilder.addPropagatedDependencies(
- ImmutableList.of(protosXcodeProvider));
- }
+ XcodeProvider.Builder xcodeProviderBuilder =
+ new XcodeProvider.Builder().addPropagatedDependencies(protosXcodeProvider.asSet());
IntermediateArtifacts intermediateArtifacts =
ObjcRuleClasses.intermediateArtifacts(ruleContext);
@@ -222,7 +205,7 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory
}
}
- private ObjcCommon common(RuleContext ruleContext, ObjcProvider protosObjcProvider) {
+ private ObjcCommon common(RuleContext ruleContext, Optional<ObjcProvider> protosObjcProvider) {
IntermediateArtifacts intermediateArtifacts =
ObjcRuleClasses.intermediateArtifacts(ruleContext);
CompilationArtifacts compilationArtifacts =
@@ -238,6 +221,7 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory
.addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET))
.addRuntimeDeps(ruleContext.getPrerequisites("runtime_deps", Mode.TARGET))
.addDeps(ruleContext.getPrerequisites("bundles", Mode.TARGET))
+ .addDepObjcProviders(protosObjcProvider.asSet())
.addNonPropagatedDepObjcProviders(
ruleContext.getPrerequisites(
"non_propagated_deps", Mode.TARGET, ObjcProvider.class))
@@ -254,10 +238,6 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory
builder.setLinkmapFile(intermediateArtifacts.linkmap());
}
- if (protosObjcProvider != null) {
- builder.addDepObjcProviders(ImmutableList.of(protosObjcProvider));
- }
-
return builder.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
index 5e22cd713c..c15c84300a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
@@ -18,6 +18,7 @@ import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STORYBOARD;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.XCDATAMODEL;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
@@ -31,11 +32,11 @@ import com.google.devtools.build.lib.analysis.RunfilesSupport;
import com.google.devtools.build.lib.analysis.actions.ExecutionRequirements;
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.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs;
import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
-import com.google.devtools.build.lib.rules.objc.ProtoSupport.TargetType;
import com.google.devtools.build.lib.rules.objc.ReleaseBundlingSupport.LinkedBinary;
import com.google.devtools.build.lib.rules.test.ExecutionInfoProvider;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
@@ -85,25 +86,14 @@ public final class IosTest implements RuleConfiguredTargetFactory {
throws InterruptedException, RuleErrorException {
ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
- ObjcProvider protosObjcProvider = null;
- XcodeProvider protosXcodeProvider = null;
+ Optional<ObjcProvider> protosObjcProvider = Optional.absent();
+ Optional<XcodeProvider> protosXcodeProvider = Optional.absent();
if (objcConfiguration.experimentalAutoTopLevelUnionObjCProtos()) {
- XcodeProvider.Builder protosXcodeProviderBuilder = new XcodeProvider.Builder();
- ProtoSupport protoSupport = new ProtoSupport(ruleContext, TargetType.LINKING_TARGET)
- .registerActions()
- .addXcodeProviderOptions(protosXcodeProviderBuilder);
-
- ObjcCommon protoCommon = protoSupport.getCommon();
- protosObjcProvider = protoCommon.getObjcProvider();
-
- new CompilationSupport(
- ruleContext,
- protoSupport.getIntermediateArtifacts(),
- new CompilationAttributes.Builder().build())
- .registerCompileAndArchiveActions(protoCommon, protoSupport.getUserHeaderSearchPaths())
- .addXcodeSettings(protosXcodeProviderBuilder, protoCommon);
- protosXcodeProvider = protosXcodeProviderBuilder.build();
+ ProtobufSupport protoSupport =
+ new ProtobufSupport(ruleContext).registerGenerationActions().registerCompilationActions();
+ protosObjcProvider = Optional.of(protoSupport.getObjcProvider());
+ protosXcodeProvider = Optional.of(protoSupport.getXcodeProvider());
}
ObjcCommon common = common(ruleContext, protosObjcProvider);
@@ -116,11 +106,9 @@ public final class IosTest implements RuleConfiguredTargetFactory {
ruleContext.ruleError(NO_MULTI_CPUS_ERROR);
}
- XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder();
- if (protosXcodeProvider != null) {
- xcodeProviderBuilder.addPropagatedDependencies(
- ImmutableList.of(protosXcodeProvider));
- }
+ XcodeProvider.Builder xcodeProviderBuilder =
+ new XcodeProvider.Builder().addPropagatedDependencies(protosXcodeProvider.asSet());
+
NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
addResourceFilesToBuild(ruleContext, common.getObjcProvider(), filesToBuild);
@@ -264,10 +252,8 @@ public final class IosTest implements RuleConfiguredTargetFactory {
}
}
- /**
- * Constructs an {@link ObjcCommon} instance based on the attributes.
- */
- private ObjcCommon common(RuleContext ruleContext, ObjcProvider protosObjcProvider) {
+ /** Constructs an {@link ObjcCommon} instance based on the attributes. */
+ private ObjcCommon common(RuleContext ruleContext, Optional<ObjcProvider> protosObjcProvider) {
CompilationArtifacts compilationArtifacts =
CompilationSupport.compilationArtifacts(ruleContext);
@@ -281,6 +267,7 @@ public final class IosTest implements RuleConfiguredTargetFactory {
.addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET))
.addRuntimeDeps(ruleContext.getPrerequisites("runtime_deps", Mode.TARGET))
.addDeps(ruleContext.getPrerequisites("bundles", Mode.TARGET))
+ .addDepObjcProviders(protosObjcProvider.asSet())
.addNonPropagatedDepObjcProviders(
ruleContext.getPrerequisites(
"non_propagated_deps", Mode.TARGET, ObjcProvider.class))
@@ -293,10 +280,6 @@ public final class IosTest implements RuleConfiguredTargetFactory {
.addDepObjcProviders(ImmutableList.of(xcTestAppProvider(ruleContext).getObjcProvider()));
}
- if (protosObjcProvider != null) {
- builder.addDepObjcProviders(ImmutableList.of(protosObjcProvider));
- }
-
// Add the memleaks library if the --ios_memleaks flag is true. The library pauses the test
// after all tests have been executed so that leaks can be run.
ObjcConfiguration config = ruleContext.getFragment(ObjcConfiguration.class);
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
index f497511959..b2d733e42f 100644
--- 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
@@ -77,7 +77,7 @@ public class ObjcProtoAspect extends NativeAspectClass implements ConfiguredAspe
ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class);
for (ProtoSourcesProvider protoProvider : protoProviders) {
- aspectObjcProtoProvider.addProtoSources(protoProvider.getTransitiveProtoSources());
+ aspectObjcProtoProvider.addProtoGroup(protoProvider.getTransitiveProtoSources());
}
// Propagate protobuf's headers and search paths so the BinaryLinkingTargetFactory subclasses
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
index dbf4d4b353..7e22ff5812 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
@@ -14,16 +14,13 @@
package com.google.devtools.build.lib.rules.objc;
-import static com.google.devtools.build.lib.rules.objc.XcodeProductType.LIBRARY_STATIC;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
-import com.google.devtools.build.lib.rules.objc.ProtoSupport.TargetType;
/**
* Implementation for the "objc_proto_library" rule.
@@ -46,43 +43,23 @@ public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
private ConfiguredTarget createProtobufTarget(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
- XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder();
-
- ProtoSupport protoSupport =
- new ProtoSupport(ruleContext, TargetType.PROTO_TARGET)
- .addXcodeProviderOptions(xcodeProviderBuilder)
- .addFilesToBuild(filesToBuild)
- .registerActions();
-
- ObjcCommon common = protoSupport.getCommon();
-
- filesToBuild.addAll(common.getCompiledArchive().asSet());
-
- new XcodeSupport(ruleContext)
- .addFilesToBuild(filesToBuild)
- .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), LIBRARY_STATIC)
- .addDependencies(
- xcodeProviderBuilder, new Attribute(ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET))
- .registerActions(xcodeProviderBuilder.build());
-
boolean experimentalAutoUnion =
ObjcRuleClasses.objcConfiguration(ruleContext).experimentalAutoTopLevelUnionObjCProtos();
- CompilationSupport compilationSupport = new CompilationSupport(ruleContext);
+ ProtobufSupport protoSupport =
+ new ProtobufSupport(ruleContext).registerGenerationActions().addFilesToBuild(filesToBuild);
- // If the experimental flag is not set, or if it's set and doesn't use the protobuf library,
- // register the compilation actions, as the output needs to be linked in the final binary.
if (!experimentalAutoUnion) {
- compilationSupport.registerCompileAndArchiveActions(common);
- } else {
- // Even though there is nothing to compile, still generate a module map based on this target
- // headers.
- compilationSupport.registerGenerateModuleMapAction(common.getCompilationArtifacts());
+ protoSupport.registerCompilationActions();
}
+ XcodeProvider xcodeProvider = protoSupport.getXcodeProvider();
+
+ new XcodeSupport(ruleContext).registerActions(xcodeProvider).addFilesToBuild(filesToBuild);
+
return ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build())
- .addProvider(XcodeProvider.class, xcodeProviderBuilder.build())
- .addProvider(ObjcProvider.class, common.getObjcProvider())
+ .addProvider(ObjcProvider.class, protoSupport.getObjcProvider())
+ .addProvider(XcodeProvider.class, xcodeProvider)
.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
index f11f8ff904..b8dd834ff0 100644
--- 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
@@ -40,27 +40,25 @@ import com.google.devtools.build.lib.vfs.PathFragment;
*/
public class ObjcProtoProvider implements TransitiveInfoProvider {
- private final NestedSet<Artifact> protoSources;
+ private final NestedSet<NestedSet<Artifact>> protoGroups;
private final NestedSet<Artifact> protobufHeaders;
private final NestedSet<PathFragment> protobufHeaderSearchPaths;
private final NestedSet<Artifact> portableProtoFilters;
private ObjcProtoProvider(
- NestedSet<Artifact> protoSources,
+ NestedSet<NestedSet<Artifact>> protoGroups,
NestedSet<Artifact> portableProtoFilters,
NestedSet<Artifact> protobufHeaders,
NestedSet<PathFragment> protobufHeaderSearchPaths) {
- this.protoSources = Preconditions.checkNotNull(protoSources);
+ this.protoGroups = Preconditions.checkNotNull(protoGroups);
this.portableProtoFilters = Preconditions.checkNotNull(portableProtoFilters);
this.protobufHeaders = Preconditions.checkNotNull(protobufHeaders);
this.protobufHeaderSearchPaths = Preconditions.checkNotNull(protobufHeaderSearchPaths);
}
- /**
- * 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 proto groups that the dependencies of this provider has seen. */
+ public NestedSet<NestedSet<Artifact>> getProtoGroups() {
+ return protoGroups;
}
/** Returns the header artifacts provided by the Protobuf library. */
@@ -85,17 +83,21 @@ public class ObjcProtoProvider implements TransitiveInfoProvider {
* several transitive dependencies.
*/
public static final class Builder {
- private final NestedSetBuilder<Artifact> protoSources = NestedSetBuilder.naiveLinkOrder();
+ private final NestedSetBuilder<NestedSet<Artifact>> protoGroups =
+ NestedSetBuilder.stableOrder();
private final NestedSetBuilder<Artifact> portableProtoFilters = NestedSetBuilder.stableOrder();
private final NestedSetBuilder<Artifact> protobufHeaders = NestedSetBuilder.stableOrder();
private final NestedSetBuilder<PathFragment> protobufHeaderSearchPaths =
NestedSetBuilder.linkOrder();
/**
- * Adds all the protos to the set of dependencies.
+ * Adds a proto group to be propagated. Each group represents a proto_library target and
+ * contains protos to be built along with their transitive dependencies. We propagate protos as
+ * groups because the grouping provides relationship information between the protos, which can
+ * be used to limit the number of inputs to each proto generation action.
*/
- public Builder addProtoSources(NestedSet<Artifact> protoSources) {
- this.protoSources.addTransitive(protoSources);
+ public Builder addProtoGroup(NestedSet<Artifact> protoGroup) {
+ this.protoGroups.add(protoGroup);
return this;
}
@@ -125,7 +127,7 @@ public class ObjcProtoProvider implements TransitiveInfoProvider {
*/
public Builder addTransitive(Iterable<ObjcProtoProvider> providers) {
for (ObjcProtoProvider provider : providers) {
- this.protoSources.addTransitive(provider.getProtoSources());
+ this.protoGroups.addTransitive(provider.getProtoGroups());
this.portableProtoFilters.addTransitive(provider.getPortableProtoFilters());
this.protobufHeaders.addTransitive(provider.getProtobufHeaders());
this.protobufHeaderSearchPaths.addTransitive(provider.getProtobufHeaderSearchPaths());
@@ -137,12 +139,12 @@ public class ObjcProtoProvider implements TransitiveInfoProvider {
* Whether this provider has any protos or filters.
*/
public boolean isEmpty() {
- return protoSources.isEmpty() && portableProtoFilters.isEmpty();
+ return protoGroups.isEmpty() && portableProtoFilters.isEmpty();
}
public ObjcProtoProvider build() {
return new ObjcProtoProvider(
- protoSources.build(),
+ protoGroups.build(),
portableProtoFilters.build(),
protobufHeaders.build(),
protobufHeaderSearchPaths.build());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java
deleted file mode 100644
index 5cfe31fbe4..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright 2015 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.common.base.CaseFormat.LOWER_UNDERSCORE;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Ordering;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
-import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
-import com.google.devtools.build.lib.cmdline.Label;
-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.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
-import com.google.devtools.build.lib.util.FileType;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.ArrayList;
-
-
-/**
- * Support for generating Objective C proto static libraries that registers actions that generate
- * the Objective C protos and validates the rules' attributes.
- *
- * This ProtoSupport class supports 2 protocol buffer compilers, named ProtocolBuffers2 and the
- * open-sourced version named protobuf. When refering to a specific library, the naming will either
- * refer to PB2 (for ProtocolBuffers2) or protobuf (the open-source version). When the context is
- * independent of the library, the naming will just refer to "proto". The selection of which proto
- * library to use depends on the presence of the 'portable_proto_filters' rule attribute.
- *
- * Keep in mind that these libraries are independent of the proto syntax used. ProtocolBuffers2
- * supports proto2 syntax, but the protobuf library supports both proto2 and proto3 syntax.
- *
- * <p>Methods on this class can be called in any order without impacting the result.
- */
-final class ProtoSupport {
- private static final PathFragment BAZEL_TOOLS_PREFIX = new PathFragment("external/bazel_tools/");
-
- /**
- * Type of target that is generating the protos. There is a distinction because when generating
- * the protos from an objc_proto_library, the attributes of the rule need to be considered, but
- * when generating from a linking target (e.g. objc_binary), the attributes don't exist, but the
- * ObjcProtoProviders need to be checked.
- */
- enum TargetType {
- /**
- * The generating rule is an objc_proto_library rule.
- */
- PROTO_TARGET,
-
- /**
- * The generating target is a linking rule, which generates, compiles and links all the protos
- * in the transitive closure of dependencies.
- */
- LINKING_TARGET,
- }
-
- private static final String UNIQUE_DIRECTORY_NAME = "_generated_protos";
-
- /**
- * List of file name segments that should be upper cased when being generated. More information
- * available in the generateProtobufFilename() method.
- */
- private static final ImmutableSet<String> UPPERCASE_SEGMENTS =
- ImmutableSet.of("url", "http", "https");
-
- private final RuleContext ruleContext;
- private final ProtoAttributes attributes;
- private final TargetType targetType;
- private final IntermediateArtifacts intermediateArtifacts;
-
- /**
- * Creates a new proto support.
- *
- * @param ruleContext context this proto library is constructed in
- * @param targetType the type of target generating the protos
- */
- public ProtoSupport(RuleContext ruleContext, TargetType targetType) {
- this.ruleContext = ruleContext;
- this.attributes = new ProtoAttributes(ruleContext);
- this.targetType = targetType;
- if (targetType != TargetType.PROTO_TARGET) {
- // Use a a prefixed version of the intermediate artifacts to avoid naming collisions, as
- // the proto compilation step happens in the same context as the linking target.
- this.intermediateArtifacts =
- new IntermediateArtifacts(
- ruleContext, "_protos", "protos", ruleContext.getConfiguration());
- } else {
- this.intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext);
- }
- }
-
- /**
- * Returns the intermediate artifacts associated with generated proto compilation.
- */
- public IntermediateArtifacts getIntermediateArtifacts() {
- return intermediateArtifacts;
- }
-
- /**
- * Registers actions required for compiling the proto files.
- *
- * @return this proto support
- */
- public ProtoSupport registerActions() {
- if (!Iterables.isEmpty(getFilteredProtoSources())) {
- registerProtoInputListFileAction();
- registerGenerateProtoFilesAction();
- }
- return this;
- }
-
- /**
- * Returns the common object for a proto specific compilation environment.
- */
- public ObjcCommon getCommon() {
- ObjcCommon.Builder commonBuilder =
- new ObjcCommon.Builder(ruleContext)
- .setIntermediateArtifacts(intermediateArtifacts)
- .setHasModuleMap()
- .setCompilationArtifacts(getCompilationArtifacts());
-
- if (targetType == TargetType.LINKING_TARGET) {
- commonBuilder.addDepObjcProviders(
- ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProvider.class));
- } else if (targetType == TargetType.PROTO_TARGET) {
- commonBuilder.addDepObjcProviders(
- ruleContext.getPrerequisites(
- ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET, ObjcProvider.class));
-
- if (experimentalAutoUnion()) {
- commonBuilder.addDirectDependencyHeaderSearchPaths(getUserHeaderSearchPaths());
- } else {
- commonBuilder.addUserHeaderSearchPaths(getUserHeaderSearchPaths());
- }
- }
- return commonBuilder.build();
- }
-
- /**
- * Adds required configuration to the XcodeProvider support class for proto compilation.
- *
- * @param xcodeProviderBuilder The builder for the XcodeProvider support class.
- * @return this proto support
- */
- public ProtoSupport addXcodeProviderOptions(XcodeProvider.Builder xcodeProviderBuilder)
- throws RuleErrorException {
- xcodeProviderBuilder
- .addUserHeaderSearchPaths(getUserHeaderSearchPaths())
- .addHeaders(getGeneratedHeaders())
- .setCompilationArtifacts(getCompilationArtifacts());
-
- if (targetType == TargetType.PROTO_TARGET) {
- xcodeProviderBuilder.addCopts(ObjcRuleClasses.objcConfiguration(ruleContext).getCopts());
- } else if (targetType == TargetType.LINKING_TARGET) {
- Label protosLabel = null;
- try {
- protosLabel = ruleContext.getLabel().getLocalTargetLabel(
- ruleContext.getLabel().getName() + "_BundledProtos");
- } catch (LabelSyntaxException e) {
- ruleContext.throwWithRuleError(e.getLocalizedMessage());
- }
- ObjcCommon protoCommon = getCommon();
- new XcodeSupport(ruleContext, intermediateArtifacts, protosLabel)
- .addXcodeSettings(xcodeProviderBuilder,
- protoCommon.getObjcProvider(),
- XcodeProductType.LIBRARY_STATIC)
- .addDependencies(xcodeProviderBuilder, new Attribute("deps", Mode.TARGET));
- }
- return this;
- }
-
- /**
- * Adds the files needed to be built by the rule.
- *
- * @param filesToBuild An aggregated set of the files to be built by the rule.
- * @return this proto support
- */
- public ProtoSupport addFilesToBuild(NestedSetBuilder<Artifact> filesToBuild) {
- filesToBuild.addAll(getGeneratedSources()).addAll(getGeneratedHeaders());
- return this;
- }
-
- /**
- * Returns the proto compilation artifacts for the current rule.
- */
- public CompilationArtifacts getCompilationArtifacts() {
- ImmutableList<Artifact> generatedSources = getGeneratedSources();
- CompilationArtifacts.Builder builder =
- new CompilationArtifacts.Builder()
- .setIntermediateArtifacts(intermediateArtifacts)
- .setPchFile(Optional.<Artifact>absent())
- .addAdditionalHdrs(getGeneratedHeaders());
-
- if (experimentalAutoUnion()) {
- if (targetType == TargetType.LINKING_TARGET) {
- builder.addNonArcSrcs(generatedSources);
- }
- } else {
- if (targetType == TargetType.PROTO_TARGET) {
- builder.addNonArcSrcs(generatedSources);
- }
- }
-
- return builder.build();
- }
-
- /**
- * Returns the include paths for the generated protos.
- */
- public ImmutableSet<PathFragment> getUserHeaderSearchPaths() {
- return ImmutableSet.of(getWorkspaceRelativeOutputDir());
- }
-
- private Iterable<Artifact> getAllProtoSources() {
- NestedSetBuilder<Artifact> protos = NestedSetBuilder.stableOrder();
-
- if (experimentalAutoUnion() && targetType == TargetType.LINKING_TARGET) {
- Iterable<ObjcProtoProvider> objcProtoProviders =
- ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
- for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
- protos.addTransitive(objcProtoProvider.getProtoSources());
- }
- }
-
- protos.addTransitive(attributes.getProtoFiles());
-
- return protos.build();
- }
-
- private Iterable<Artifact> getFilteredProtoSources() {
- // Transform the well known proto artifacts by removing the external/bazel_tools prefix if
- // present. Otherwise the comparison for filtering out the well known types is not possible.
- ImmutableSet.Builder<PathFragment> wellKnownProtoPathsBuilder = new ImmutableSet.Builder<>();
- for (Artifact wellKnownProto : attributes.getWellKnownTypeProtos()) {
- PathFragment execPath = wellKnownProto.getExecPath();
- if (execPath.startsWith(BAZEL_TOOLS_PREFIX)) {
- wellKnownProtoPathsBuilder.add(execPath.relativeTo(BAZEL_TOOLS_PREFIX));
- } else {
- wellKnownProtoPathsBuilder.add(execPath);
- }
- }
-
- ImmutableSet<PathFragment> wellKnownProtoPaths = wellKnownProtoPathsBuilder.build();
-
- // Filter out the well known types from being sent to be generated, as these protos have already
- // been generated and linked in libprotobuf.a.
- ImmutableSet.Builder<Artifact> filteredProtos = new ImmutableSet.Builder<>();
- for (Artifact proto : getAllProtoSources()) {
- if (!wellKnownProtoPaths.contains(proto.getExecPath())) {
- filteredProtos.add(proto);
- }
- }
-
- return filteredProtos.build();
- }
-
- private NestedSet<Artifact> getPortableProtoFilters() {
- NestedSetBuilder<Artifact> portableProtoFilters = NestedSetBuilder.stableOrder();
-
- if (experimentalAutoUnion() && targetType == TargetType.LINKING_TARGET) {
- Iterable<ObjcProtoProvider> objcProtoProviders =
- ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
- for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
- portableProtoFilters.addTransitive(objcProtoProvider.getPortableProtoFilters());
- }
- }
-
- portableProtoFilters.addAll(attributes.getPortableProtoFilters());
- return portableProtoFilters.build();
- }
-
- private boolean experimentalAutoUnion() {
- ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext);
- return objcConfiguration.experimentalAutoTopLevelUnionObjCProtos();
- }
-
- private void registerProtoInputListFileAction() {
- ruleContext.registerAction(
- new FileWriteAction(
- ruleContext.getActionOwner(),
- getProtoInputListFile(),
- getProtoInputListFileContents(),
- false));
- }
-
- private void registerGenerateProtoFilesAction() {
- ruleContext.registerAction(
- ObjcRuleClasses.spawnOnDarwinActionBuilder()
- .setMnemonic("GenObjcProtos")
- .addTransitiveInputs(getGenerateActionInputs())
- .addOutputs(getGenerateActionOutputs())
- .setExecutable(new PathFragment("/usr/bin/python"))
- .setCommandLine(getGenerateCommandLine())
- .build(ruleContext));
- }
-
- private Artifact getProtoInputListFile() {
- return ruleContext.getUniqueDirectoryArtifact(
- "_protos", "_proto_input_files", ruleContext.getConfiguration().getGenfilesDirectory(
- ruleContext.getRule().getRepository()));
- }
-
- private String getProtoInputListFileContents() {
- // Sort the file names to make the remote action key independent of the precise deps structure.
- // compile_protos.py will sort the input list anyway.
- Iterable<Artifact> sorted = Ordering.natural().immutableSortedCopy(getFilteredProtoSources());
- return Artifact.joinExecPaths("\n", sorted);
- }
-
- private PathFragment getWorkspaceRelativeOutputDir() {
- // Generate sources in a package-and-rule-scoped directory; adds both the
- // package-and-rule-scoped directory and the header-containing-directory to the include path
- // of dependers.
- PathFragment rootRelativeOutputDir = ruleContext.getUniqueDirectory(UNIQUE_DIRECTORY_NAME);
-
- return new PathFragment(
- ruleContext.getBinOrGenfilesDirectory().getExecPath(), rootRelativeOutputDir);
- }
-
- private ImmutableList<Artifact> getGeneratedHeaders() {
- return generatedOutputArtifacts(FileType.of(".pbobjc.h"));
- }
-
- private ImmutableList<Artifact> getGeneratedSources() {
- return generatedOutputArtifacts(FileType.of(".pbobjc.m"));
- }
-
- private NestedSet<Artifact> getGenerateActionInputs() {
- NestedSetBuilder<Artifact> inputsBuilder =
- NestedSetBuilder.<Artifact>stableOrder()
- .add(attributes.getProtoCompiler())
- .addAll(getAllProtoSources())
- .add(getProtoInputListFile())
- .addAll(attributes.getProtoCompilerSupport())
- .addTransitive(getPortableProtoFilters());
-
- return inputsBuilder.build();
- }
-
- private Iterable<Artifact> getGenerateActionOutputs() {
- return Iterables.concat(getGeneratedHeaders(), getGeneratedSources());
- }
-
- private CustomCommandLine getGenerateCommandLine() {
- return new CustomCommandLine.Builder()
- .add(attributes.getProtoCompiler().getExecPathString())
- .add("--input-file-list")
- .add(getProtoInputListFile().getExecPathString())
- .add("--output-dir")
- .add(getWorkspaceRelativeOutputDir().getSafePathString())
- .add("--force")
- .add("--proto-root-dir")
- .add(".")
- .addBeforeEachExecPath("--config", getPortableProtoFilters())
- .build();
- }
-
- private ImmutableList<Artifact> generatedOutputArtifacts(FileType newFileType) {
- ImmutableList.Builder<Artifact> builder = new ImmutableList.Builder<>();
- for (Artifact protoFile : getFilteredProtoSources()) {
- String protoFileName = FileSystemUtils.removeExtension(protoFile.getFilename());
- String generatedOutputName = generateProtobufFilename(protoFileName);
- PathFragment generatedFilePath =
- new PathFragment(
- protoFile.getRootRelativePath().getParentDirectory(),
- new PathFragment(generatedOutputName));
-
- PathFragment outputFile =
- FileSystemUtils.appendExtension(
- generatedFilePath, newFileType.getExtensions().get(0));
-
- if (outputFile != null) {
- builder.add(
- ruleContext.getUniqueDirectoryArtifact(
- UNIQUE_DIRECTORY_NAME, outputFile, ruleContext.getBinOrGenfilesDirectory()));
- }
- }
- return builder.build();
- }
-
- /**
- * Processes the case of the proto file name in the same fashion as the objective_c generator's
- * UnderscoresToCamelCase function.
- *
- * https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
- */
- private String generateProtobufFilename(String protoFilename) {
- boolean lastCharWasDigit = false;
- boolean lastCharWasUpper = false;
- boolean lastCharWasLower = false;
-
- StringBuilder currentSegment = new StringBuilder();
-
- ArrayList<String> segments = new ArrayList<>();
-
- for (int i = 0; i < protoFilename.length(); i++) {
- char currentChar = protoFilename.charAt(i);
- if (CharMatcher.javaDigit().matches(currentChar)) {
- if (!lastCharWasDigit) {
- segments.add(currentSegment.toString());
- currentSegment = new StringBuilder();
- }
- currentSegment.append(currentChar);
- lastCharWasDigit = true;
- lastCharWasUpper = false;
- lastCharWasLower = false;
- } else if (CharMatcher.javaLowerCase().matches(currentChar)) {
- if (!lastCharWasLower && !lastCharWasUpper) {
- segments.add(currentSegment.toString());
- currentSegment = new StringBuilder();
- }
- currentSegment.append(currentChar);
- lastCharWasDigit = false;
- lastCharWasUpper = false;
- lastCharWasLower = true;
- } else if (CharMatcher.javaUpperCase().matches(currentChar)) {
- if (!lastCharWasUpper) {
- segments.add(currentSegment.toString());
- currentSegment = new StringBuilder();
- }
- currentSegment.append(Character.toLowerCase(currentChar));
- lastCharWasDigit = false;
- lastCharWasUpper = true;
- lastCharWasLower = false;
- } else {
- lastCharWasDigit = false;
- lastCharWasUpper = false;
- lastCharWasLower = false;
- }
- }
-
- segments.add(currentSegment.toString());
-
- StringBuilder casedSegments = new StringBuilder();
- for (String segment : segments) {
- if (UPPERCASE_SEGMENTS.contains(segment)) {
- casedSegments.append(segment.toUpperCase());
- } else {
- casedSegments.append(LOWER_UNDERSCORE.to(UPPER_CAMEL, segment));
- }
- }
- return casedSegments.toString();
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java
new file mode 100644
index 0000000000..32118ac4fc
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java
@@ -0,0 +1,617 @@
+// 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.common.base.CaseFormat.LOWER_UNDERSCORE;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.devtools.build.lib.rules.objc.XcodeProductType.LIBRARY_STATIC;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Ordering;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
+import com.google.devtools.build.lib.cmdline.Label;
+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.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.proto.ProtoSourcesProvider;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Support for generating Objective C proto static libraries that registers actions which generate
+ * and compile the Objective C protos by using the open source protobuf library and compiler.
+ *
+ * <p>Each group represents one proto_library target depended on by objc_proto_library targets using
+ * the portable_proto_filters attribute. This group contains all the necessary protos to satisfy its
+ * internal dependencies.
+ *
+ * <p>Grouping has a first pass in which for each proto required to be built, we find the smallest
+ * group containing it, and store that information in a map. We then reverse that map into a multi
+ * map, in which the keys are the input protos and the values are the output protos to be
+ * generated/compiled with the input group as dependencies. This minimizes the number of inputs
+ * required for each generation/compilation action and the probability of regeneration when one of
+ * the proto files change, improving cache hits.
+ */
+final class ProtobufSupport {
+
+ private static final PathFragment BAZEL_TOOLS_PREFIX = new PathFragment("external/bazel_tools/");
+
+ private static final String BUNDLED_PROTOS_IDENTIFIER = "BundledProtos";
+
+ /**
+ * List of file name segments that should be upper cased when being generated. More information
+ * available in the generateProtobufFilename() method.
+ */
+ private static final ImmutableSet<String> UPPERCASE_SEGMENTS =
+ ImmutableSet.of("url", "http", "https");
+
+ private static final String UNIQUE_DIRECTORY_NAME = "_generated_protos";
+
+ private final RuleContext ruleContext;
+ private final ProtoAttributes attributes;
+
+ // Each entry of this map represents a generation action and a compilation action. The input set
+ // are dependencies of the output set. The output set is always a subset of, or the same set as,
+ // the input set. For example, given a sample entry of the inputsToOutputsMap like:
+ //
+ // {A, B, C} => {B, C}
+ //
+ // this represents:
+ // 1. A generation action in which the inputs are A, B and C, and the outputs are B.pbobjc.h,
+ // B.pbobjc.m, C.pbobjc.h and C.pbobjc.m.
+ // 2. A compilation action in which the inputs are A.pbobjc.h, B.pbobjc.h, C.pbobjc.h,
+ // B.pbobjc.m and C.pbobjc.m, while the outputs are B.pbobjc.o and C.pbobjc.o.
+ //
+ // Given that each input set appears only once, by the nature of the structure, we can safely use
+ // it as an identifier of the entry.
+ private final ImmutableSetMultimap<ImmutableSet<Artifact>, Artifact> inputsToOutputsMap;
+
+ /**
+ * Creates a new proto support for the protobuf library. This support code bundles up all the
+ * transitive protos within the groups in which they were defined. We use that information to
+ * minimize the number of inputs per generation/compilation actions by only providing what is
+ * really needed to the actions.
+ *
+ * @param ruleContext context this proto library is constructed in
+ */
+ public ProtobufSupport(RuleContext ruleContext) throws RuleErrorException {
+ this.ruleContext = ruleContext;
+ this.attributes = new ProtoAttributes(ruleContext);
+ this.inputsToOutputsMap = getInputsToOutputsMap();
+ }
+
+ /**
+ * Registers the proto generation actions. These actions generate the ObjC/CPP code to be compiled
+ * by this rule.
+ */
+ public ProtobufSupport registerGenerationActions() {
+ int actionId = 0;
+ for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) {
+ Iterable<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos);
+
+ registerGenerationAction(outputProtos, inputProtos, getUniqueBundledProtosSuffix(actionId));
+
+ IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId);
+
+ CompilationArtifacts compilationArtifacts =
+ getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos);
+
+ ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts);
+
+ new CompilationSupport(
+ ruleContext, intermediateArtifacts, new CompilationAttributes.Builder().build())
+ .registerGenerateModuleMapAction(common.getCompilationArtifacts());
+ actionId++;
+ }
+ return this;
+ }
+
+ /** Registers the actions that will compile the generated code. */
+ public ProtobufSupport registerCompilationActions() {
+ int actionId = 0;
+ Iterable<PathFragment> userHeaderSearchPaths =
+ ImmutableList.of(getWorkspaceRelativeOutputDir());
+ for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) {
+ ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos);
+
+ IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId);
+
+ CompilationArtifacts compilationArtifacts =
+ getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos);
+
+ ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts);
+
+ new CompilationSupport(
+ ruleContext, intermediateArtifacts, new CompilationAttributes.Builder().build())
+ .registerCompileAndArchiveActions(common, userHeaderSearchPaths);
+
+ actionId++;
+ }
+ return this;
+ }
+
+ /** Adds the generated files to the set of files to be output when this rule is built. */
+ public ProtobufSupport addFilesToBuild(NestedSetBuilder<Artifact> filesToBuild) {
+ for (ImmutableSet<Artifact> inputProtoFiles : inputsToOutputsMap.keySet()) {
+ ImmutableSet<Artifact> outputProtoFiles = inputsToOutputsMap.get(inputProtoFiles);
+ Iterable<Artifact> generatedSources = getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.m");
+ Iterable<Artifact> generatedHeaders = getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.h");
+
+ filesToBuild.addAll(generatedSources).addAll(generatedHeaders);
+ }
+
+ if (!ObjcRuleClasses.objcConfiguration(ruleContext).experimentalAutoTopLevelUnionObjCProtos()) {
+ int actionId = 0;
+ for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) {
+ ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos);
+ IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId);
+
+ CompilationArtifacts compilationArtifacts =
+ getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos);
+
+ ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts);
+ filesToBuild.addAll(common.getCompiledArchive().asSet());
+ actionId++;
+ }
+ }
+
+ return this;
+ }
+
+ /** Returns the ObjcProvider for this target. */
+ public ObjcProvider getObjcProvider() {
+ Iterable<PathFragment> userHeaderSearchPaths =
+ ImmutableList.of(getWorkspaceRelativeOutputDir());
+ ObjcCommon.Builder commonBuilder = new ObjcCommon.Builder(ruleContext);
+
+ int actionId = 0;
+ for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) {
+ ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos);
+ IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId);
+
+ CompilationArtifacts compilationArtifacts =
+ getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos);
+
+ ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts);
+ commonBuilder.addDepObjcProviders(ImmutableSet.of(common.getObjcProvider()));
+ actionId++;
+ }
+
+ if (ObjcRuleClasses.objcConfiguration(ruleContext).experimentalAutoTopLevelUnionObjCProtos()) {
+ commonBuilder.addDirectDependencyHeaderSearchPaths(userHeaderSearchPaths);
+ } else {
+ commonBuilder.addUserHeaderSearchPaths(userHeaderSearchPaths);
+ }
+
+ return commonBuilder.build().getObjcProvider();
+ }
+
+ /** Returns the XcodeProvider for this target. */
+ public XcodeProvider getXcodeProvider() throws RuleErrorException {
+ XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder();
+ IntermediateArtifacts intermediateArtifacts =
+ ObjcRuleClasses.intermediateArtifacts(ruleContext);
+ new XcodeSupport(ruleContext, intermediateArtifacts, getXcodeLabel(getBundledProtosSuffix()))
+ .addXcodeSettings(xcodeProviderBuilder, getObjcProvider(), LIBRARY_STATIC);
+
+ int actionId = 0;
+ for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) {
+ ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos);
+ IntermediateArtifacts bundleIntermediateArtifacts = getUniqueIntermediateArtifacts(actionId);
+
+ CompilationArtifacts compilationArtifacts =
+ getCompilationArtifacts(bundleIntermediateArtifacts, inputProtos, outputProtos);
+
+ ObjcCommon common = getCommon(bundleIntermediateArtifacts, compilationArtifacts);
+
+ XcodeProvider bundleProvider =
+ getBundleXcodeProvider(
+ common, bundleIntermediateArtifacts, getUniqueBundledProtosSuffix(actionId));
+ xcodeProviderBuilder.addPropagatedDependencies(ImmutableSet.of(bundleProvider));
+ actionId++;
+ }
+
+ return xcodeProviderBuilder.build();
+ }
+
+ private NestedSet<Artifact> getPortableProtoFilters() {
+ Iterable<ObjcProtoProvider> objcProtoProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
+
+ NestedSetBuilder<Artifact> portableProtoFilters = NestedSetBuilder.stableOrder();
+ for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
+ portableProtoFilters.addTransitive(objcProtoProvider.getPortableProtoFilters());
+ }
+ portableProtoFilters.addAll(attributes.getPortableProtoFilters());
+ return portableProtoFilters.build();
+ }
+
+ private NestedSet<Artifact> getProtobufHeaders() {
+ Iterable<ObjcProtoProvider> objcProtoProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
+
+ NestedSetBuilder<Artifact> protobufHeaders = NestedSetBuilder.stableOrder();
+ for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
+ protobufHeaders.addTransitive(objcProtoProvider.getProtobufHeaders());
+ }
+ return protobufHeaders.build();
+ }
+
+ private NestedSet<PathFragment> getProtobufHeaderSearchPaths() {
+ Iterable<ObjcProtoProvider> objcProtoProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
+
+ NestedSetBuilder<PathFragment> protobufHeaderSearchPaths = NestedSetBuilder.stableOrder();
+ for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
+ protobufHeaderSearchPaths.addTransitive(objcProtoProvider.getProtobufHeaderSearchPaths());
+ }
+ return protobufHeaderSearchPaths.build();
+ }
+
+ private ImmutableSetMultimap<ImmutableSet<Artifact>, Artifact> getInputsToOutputsMap()
+ throws RuleErrorException {
+ Iterable<ObjcProtoProvider> objcProtoProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class);
+ Iterable<ProtoSourcesProvider> protoProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class);
+
+ ImmutableList.Builder<NestedSet<Artifact>> protoSets =
+ new ImmutableList.Builder<NestedSet<Artifact>>();
+
+ // Traverse all the dependencies ObjcProtoProviders and ProtoSourcesProviders to aggregate
+ // all the transitive groups of proto.
+ for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) {
+ protoSets.addAll(objcProtoProvider.getProtoGroups());
+ }
+ for (ProtoSourcesProvider protoProvider : protoProviders) {
+ protoSets.add(protoProvider.getTransitiveProtoSources());
+ }
+
+ HashMap<Artifact, ImmutableSet<Artifact>> protoToGroupMap =
+ new HashMap<Artifact, ImmutableSet<Artifact>>();
+
+ // For each proto in each proto group, store the smallest group in which it is contained. This
+ // group will be considered the smallest input group with which the proto can be generated.
+ for (NestedSet<Artifact> nestedProtoSet : protoSets.build()) {
+ ImmutableSet<Artifact> protoSet = ImmutableSet.copyOf(nestedProtoSet.toSet());
+ for (Artifact proto : protoSet) {
+ // If the proto is well known, don't store it as we don't need to generate it; it comes
+ // generated with the runtime library.
+ if (isProtoWellKnown(proto)) {
+ continue;
+ }
+ if (!protoToGroupMap.containsKey(proto)
+ || protoToGroupMap.get(proto).size() > protoSet.size()) {
+ protoToGroupMap.put(proto, protoSet);
+ }
+ }
+ }
+
+ // Now that we have the smallest proto inputs groups for each proto to be generated, we reverse
+ // that map into a multimap to take advantage of the fact that multiple protos can be generated
+ // with the same inputs, to avoid having multiple generation actions with the same inputs and
+ // different ouputs. This only applies for the generation actions, as the compilation actions
+ // compile one generated file at a time.
+ // It's OK to use ImmutableSet<Artifact> as the key, since Artifact caches it's hashCode, and
+ // ImmutableSet calculates it's hashCode in O(n).
+ ImmutableSetMultimap.Builder<ImmutableSet<Artifact>, Artifact> inputsToOutputsMapBuilder =
+ ImmutableSetMultimap.builder();
+
+ for (Artifact proto : protoToGroupMap.keySet()) {
+ inputsToOutputsMapBuilder.put(protoToGroupMap.get(proto), proto);
+ }
+ return inputsToOutputsMapBuilder.build();
+ }
+
+ private XcodeProvider getBundleXcodeProvider(
+ ObjcCommon common, IntermediateArtifacts intermediateArtifacts, String labelSuffix)
+ throws RuleErrorException {
+ Iterable<PathFragment> userHeaderSearchPaths =
+ ImmutableList.of(getWorkspaceRelativeOutputDir());
+
+ XcodeProvider.Builder xcodeProviderBuilder =
+ new XcodeProvider.Builder()
+ .addUserHeaderSearchPaths(userHeaderSearchPaths)
+ .setCompilationArtifacts(common.getCompilationArtifacts().get());
+
+ XcodeSupport xcodeSupport =
+ new XcodeSupport(ruleContext, intermediateArtifacts, getXcodeLabel(labelSuffix))
+ .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), LIBRARY_STATIC);
+ if (isLinkingTarget()) {
+ xcodeProviderBuilder
+ .addHeaders(getProtobufHeaders())
+ .addUserHeaderSearchPaths(getProtobufHeaderSearchPaths());
+ } else {
+ xcodeSupport.addDependencies(
+ xcodeProviderBuilder, new Attribute(ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET));
+ }
+
+ return xcodeProviderBuilder.build();
+ }
+
+ private String getBundledProtosSuffix() {
+ return "_" + BUNDLED_PROTOS_IDENTIFIER;
+ }
+
+ private String getUniqueBundledProtosPrefix(int actionId) {
+ return BUNDLED_PROTOS_IDENTIFIER + "_" + actionId;
+ }
+
+ private String getUniqueBundledProtosSuffix(int actionId) {
+ return getBundledProtosSuffix() + "_" + actionId;
+ }
+
+ private Label getXcodeLabel(String suffix) throws RuleErrorException {
+ Label xcodeLabel = null;
+ try {
+ xcodeLabel =
+ ruleContext.getLabel().getLocalTargetLabel(ruleContext.getLabel().getName() + suffix);
+ } catch (LabelSyntaxException e) {
+ ruleContext.throwWithRuleError(e.getLocalizedMessage());
+ }
+ return xcodeLabel;
+ }
+
+ private IntermediateArtifacts getUniqueIntermediateArtifacts(int actionId) {
+ return new IntermediateArtifacts(
+ ruleContext,
+ getUniqueBundledProtosSuffix(actionId),
+ getUniqueBundledProtosPrefix(actionId),
+ ruleContext.getConfiguration());
+ }
+
+ private ObjcCommon getCommon(
+ IntermediateArtifacts intermediateArtifacts, CompilationArtifacts compilationArtifacts) {
+ ObjcCommon.Builder commonBuilder =
+ new ObjcCommon.Builder(ruleContext)
+ .setIntermediateArtifacts(intermediateArtifacts)
+ .setHasModuleMap()
+ .setCompilationArtifacts(compilationArtifacts);
+ if (isLinkingTarget()) {
+ commonBuilder.addUserHeaderSearchPaths(getProtobufHeaderSearchPaths());
+ } else {
+ commonBuilder.addDepObjcProviders(
+ ruleContext.getPrerequisites(
+ ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET, ObjcProvider.class));
+ }
+ return commonBuilder.build();
+ }
+
+ private CompilationArtifacts getCompilationArtifacts(
+ IntermediateArtifacts intermediateArtifacts,
+ Iterable<Artifact> inputProtoFiles,
+ Iterable<Artifact> outputProtoFiles) {
+ // Filter the well known protos from the set of headers. We don't generate the headers for them
+ // as they are part of the runtime library.
+ Iterable<Artifact> filteredInputProtos = filterWellKnownProtos(inputProtoFiles);
+
+ CompilationArtifacts.Builder compilationArtifacts =
+ new CompilationArtifacts.Builder()
+ .setIntermediateArtifacts(intermediateArtifacts)
+ .setPchFile(Optional.<Artifact>absent())
+ .addAdditionalHdrs(getGeneratedProtoOutputs(filteredInputProtos, ".pbobjc.h"))
+ .addAdditionalHdrs(getProtobufHeaders());
+
+ boolean experimentalAutoUnion =
+ ObjcRuleClasses.objcConfiguration(ruleContext).experimentalAutoTopLevelUnionObjCProtos();
+
+ if (!experimentalAutoUnion || isLinkingTarget()) {
+ compilationArtifacts.addNonArcSrcs(getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.m"));
+ }
+
+ return compilationArtifacts.build();
+ }
+
+ private void registerGenerationAction(
+ Iterable<Artifact> outputProtos, Iterable<Artifact> inputProtos, String protoFileSuffix) {
+ Artifact protoInputsFile = getProtoInputsFile(protoFileSuffix);
+
+ ruleContext.registerAction(
+ new FileWriteAction(
+ ruleContext.getActionOwner(),
+ protoInputsFile,
+ getProtoInputsFileContents(outputProtos),
+ false));
+
+ ruleContext.registerAction(
+ ObjcRuleClasses.spawnOnDarwinActionBuilder()
+ .setMnemonic("GenObjcBundledProtos")
+ .addInput(attributes.getProtoCompiler())
+ .addInputs(attributes.getProtoCompilerSupport())
+ .addTransitiveInputs(getPortableProtoFilters())
+ .addInput(protoInputsFile)
+ .addInputs(inputProtos)
+ .addOutputs(getGeneratedProtoOutputs(outputProtos, ".pbobjc.h"))
+ .addOutputs(getGeneratedProtoOutputs(outputProtos, ".pbobjc.m"))
+ .setExecutable(new PathFragment("/usr/bin/python"))
+ .setCommandLine(getGenerationCommandLine(protoInputsFile))
+ .build(ruleContext));
+ }
+
+ private Artifact getProtoInputsFile(String suffix) {
+ return ruleContext.getUniqueDirectoryArtifact(
+ "_protos",
+ "_proto_input_files" + suffix,
+ ruleContext.getConfiguration().getGenfilesDirectory());
+ }
+
+ private String getProtoInputsFileContents(Iterable<Artifact> outputProtos) {
+ // Sort the file names to make the remote action key independent of the precise deps structure.
+ // compile_protos.py will sort the input list anyway.
+ Iterable<Artifact> sorted = Ordering.natural().immutableSortedCopy(outputProtos);
+ return Artifact.joinExecPaths("\n", sorted);
+ }
+
+ private CustomCommandLine getGenerationCommandLine(Artifact protoInputsFile) {
+ return new CustomCommandLine.Builder()
+ .add(attributes.getProtoCompiler().getExecPathString())
+ .add("--input-file-list")
+ .add(protoInputsFile.getExecPathString())
+ .add("--output-dir")
+ .add(getWorkspaceRelativeOutputDir().getSafePathString())
+ .add("--force")
+ .add("--proto-root-dir")
+ .add(".")
+ .addBeforeEachExecPath("--config", getPortableProtoFilters())
+ .build();
+ }
+
+ private PathFragment getWorkspaceRelativeOutputDir() {
+ // Generate sources in a package-and-rule-scoped directory; adds both the
+ // package-and-rule-scoped directory and the header-containing-directory to the include path
+ // of dependers.
+ PathFragment rootRelativeOutputDir = ruleContext.getUniqueDirectory(UNIQUE_DIRECTORY_NAME);
+
+ return new PathFragment(
+ ruleContext.getBinOrGenfilesDirectory().getExecPath(), rootRelativeOutputDir);
+ }
+
+ private Iterable<Artifact> getGeneratedProtoOutputs(
+ Iterable<Artifact> outputProtos, String extension) {
+ ImmutableList.Builder<Artifact> builder = new ImmutableList.Builder<>();
+ for (Artifact protoFile : outputProtos) {
+ String protoFileName = FileSystemUtils.removeExtension(protoFile.getFilename());
+ String generatedOutputName = getProtobufFilename(protoFileName);
+
+ PathFragment generatedFilePath =
+ new PathFragment(
+ protoFile.getRootRelativePath().getParentDirectory(),
+ new PathFragment(generatedOutputName));
+
+ PathFragment outputFile = FileSystemUtils.appendExtension(generatedFilePath, extension);
+
+ if (outputFile != null) {
+ builder.add(
+ ruleContext.getUniqueDirectoryArtifact(
+ UNIQUE_DIRECTORY_NAME, outputFile, ruleContext.getBinOrGenfilesDirectory()));
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Processes the case of the proto file name in the same fashion as the objective_c generator's
+ * UnderscoresToCamelCase function.
+ *
+ * <p>https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+ */
+ private String getProtobufFilename(String protoFilename) {
+ boolean lastCharWasDigit = false;
+ boolean lastCharWasUpper = false;
+ boolean lastCharWasLower = false;
+
+ StringBuilder currentSegment = new StringBuilder();
+
+ ArrayList<String> segments = new ArrayList<>();
+
+ for (int i = 0; i < protoFilename.length(); i++) {
+ char currentChar = protoFilename.charAt(i);
+ if (CharMatcher.javaDigit().matches(currentChar)) {
+ if (!lastCharWasDigit) {
+ segments.add(currentSegment.toString());
+ currentSegment = new StringBuilder();
+ }
+ currentSegment.append(currentChar);
+ lastCharWasDigit = true;
+ lastCharWasUpper = false;
+ lastCharWasLower = false;
+ } else if (CharMatcher.javaLowerCase().matches(currentChar)) {
+ if (!lastCharWasLower && !lastCharWasUpper) {
+ segments.add(currentSegment.toString());
+ currentSegment = new StringBuilder();
+ }
+ currentSegment.append(currentChar);
+ lastCharWasDigit = false;
+ lastCharWasUpper = false;
+ lastCharWasLower = true;
+ } else if (CharMatcher.javaUpperCase().matches(currentChar)) {
+ if (!lastCharWasUpper) {
+ segments.add(currentSegment.toString());
+ currentSegment = new StringBuilder();
+ }
+ currentSegment.append(Character.toLowerCase(currentChar));
+ lastCharWasDigit = false;
+ lastCharWasUpper = true;
+ lastCharWasLower = false;
+ } else {
+ lastCharWasDigit = false;
+ lastCharWasUpper = false;
+ lastCharWasLower = false;
+ }
+ }
+
+ segments.add(currentSegment.toString());
+
+ StringBuilder casedSegments = new StringBuilder();
+ for (String segment : segments) {
+ if (UPPERCASE_SEGMENTS.contains(segment)) {
+ casedSegments.append(segment.toUpperCase());
+ } else {
+ casedSegments.append(LOWER_UNDERSCORE.to(UPPER_CAMEL, segment));
+ }
+ }
+ return casedSegments.toString();
+ }
+
+ private ImmutableSet<Artifact> filterWellKnownProtos(Iterable<Artifact> protoFiles) {
+ // Since well known protos are already linked in the runtime library, we have to filter them
+ // so they don't get generated again.
+ ImmutableSet.Builder<Artifact> filteredProtos = new ImmutableSet.Builder<Artifact>();
+ for (Artifact protoFile : protoFiles) {
+ if (!isProtoWellKnown(protoFile)) {
+ filteredProtos.add(protoFile);
+ }
+ }
+ return filteredProtos.build();
+ }
+
+ private ImmutableSet<PathFragment> getWellKnownProtoPaths(RuleContext ruleContext) {
+ ImmutableSet.Builder<PathFragment> wellKnownProtoPathsBuilder = new ImmutableSet.Builder<>();
+ Iterable<Artifact> wellKnownProtoFiles =
+ ruleContext
+ .getPrerequisiteArtifacts(ObjcRuleClasses.PROTOBUF_WELL_KNOWN_TYPES, Mode.HOST)
+ .list();
+ for (Artifact wellKnownProtoFile : wellKnownProtoFiles) {
+ PathFragment execPath = wellKnownProtoFile.getExecPath();
+ if (execPath.startsWith(BAZEL_TOOLS_PREFIX)) {
+ wellKnownProtoPathsBuilder.add(execPath.relativeTo(BAZEL_TOOLS_PREFIX));
+ } else {
+ wellKnownProtoPathsBuilder.add(execPath);
+ }
+ }
+ return wellKnownProtoPathsBuilder.build();
+ }
+
+ private boolean isProtoWellKnown(Artifact protoFile) {
+ return getWellKnownProtoPaths(ruleContext).contains(protoFile.getExecPath());
+ }
+
+ private boolean isLinkingTarget() {
+ return !ruleContext
+ .attributes()
+ .isAttributeValueExplicitlySpecified(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java
index 49aa2697be..f67ebf7b91 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java
@@ -1,4 +1,4 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
+// 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.
@@ -66,8 +66,7 @@ final class ProtocolBuffers2Support {
/**
* Register the proto generation actions. These actions generate the ObjC/CPP code to be compiled
- * by this rule, and also generates the Xcode project call the protoc compiler to generate
- * ObjC/CPP code.
+ * by this rule.
*/
public ProtocolBuffers2Support registerGenerationActions() throws InterruptedException {
ruleContext.registerAction(