aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar Sergio Campama <kaipi@google.com>2016-08-10 20:26:34 +0000
committerGravatar Yue Gan <yueg@google.com>2016-08-11 09:15:10 +0000
commitf3ec5975023362a05a8d01a7e7e22a4d9bcad60a (patch)
treebe557a5d406d0ff1cbe64d164fec7dc8c92cd484 /src/main/java
parentcf00c82a394e5a392a55c058ed01483d2e39c3db (diff)
Refactors out ProtocolBuffers2 related code into it's own class. This is the first step into integrating the grouping behavior for proto targets using the new library.
There's no change in functionality, only restructuring of code. -- MOS_MIGRATED_REVID=129903574
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java45
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtoAttributes.java220
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtoSupport.java318
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java260
4 files changed, 524 insertions, 319 deletions
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 344d5d3f14..dbf4d4b353 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
@@ -32,20 +32,28 @@ public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
@Override
public ConfiguredTarget create(final RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
- XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder();
+
+ ProtoAttributes attributes = new ProtoAttributes(ruleContext);
+ attributes.validate();
+
+ if (attributes.hasPortableProtoFilters()) {
+ return createProtobufTarget(ruleContext);
+ } else {
+ return createProtocolBuffers2Target(ruleContext);
+ }
+ }
+
+ 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)
- .validate()
.addXcodeProviderOptions(xcodeProviderBuilder)
.addFilesToBuild(filesToBuild)
.registerActions();
- if (ruleContext.hasErrors()) {
- return null;
- }
-
ObjcCommon common = protoSupport.getCommon();
filesToBuild.addAll(common.getCompiledArchive().asSet());
@@ -57,8 +65,6 @@ public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
xcodeProviderBuilder, new Attribute(ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET))
.registerActions(xcodeProviderBuilder.build());
- boolean usesProtobufLibrary = protoSupport.usesProtobufLibrary();
-
boolean experimentalAutoUnion =
ObjcRuleClasses.objcConfiguration(ruleContext).experimentalAutoTopLevelUnionObjCProtos();
@@ -66,7 +72,7 @@ public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
// 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 || !usesProtobufLibrary) {
+ if (!experimentalAutoUnion) {
compilationSupport.registerCompileAndArchiveActions(common);
} else {
// Even though there is nothing to compile, still generate a module map based on this target
@@ -79,4 +85,25 @@ public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
.addProvider(ObjcProvider.class, common.getObjcProvider())
.build();
}
+
+ private ConfiguredTarget createProtocolBuffers2Target(RuleContext ruleContext)
+ throws InterruptedException, RuleErrorException {
+ NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
+
+ ProtocolBuffers2Support protoSupport =
+ new ProtocolBuffers2Support(ruleContext)
+ .registerGenerationActions()
+ .registerCompilationActions()
+ .addFilesToBuild(filesToBuild);
+
+ XcodeProvider xcodeProvider = protoSupport.getXcodeProvider();
+
+ new XcodeSupport(ruleContext).registerActions(xcodeProvider).addFilesToBuild(filesToBuild);
+
+ return ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build())
+ .addProvider(ObjcProvider.class, protoSupport.getObjcProvider())
+ .addProvider(XcodeProvider.class, xcodeProvider)
+ .build();
+ }
+
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoAttributes.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoAttributes.java
new file mode 100644
index 0000000000..bc7e8bdc7a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtoAttributes.java
@@ -0,0 +1,220 @@
+// 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.devtools.build.lib.packages.BuildType.LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+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.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.syntax.Type;
+import com.google.devtools.build.lib.util.FileType;
+
+/** Common rule attributes used by an objc_proto_library. */
+final class ProtoAttributes {
+ @VisibleForTesting
+ static final String FILES_DEPRECATED_WARNING =
+ "Using files and filegroups in objc_proto_library is deprecated";
+
+ @VisibleForTesting
+ static final String NO_PROTOS_ERROR =
+ "no protos to compile - a non-empty deps attribute is required";
+
+ @VisibleForTesting
+ static final String PORTABLE_PROTO_FILTERS_NOT_EXCLUSIVE_ERROR =
+ "The portable_proto_filters attribute is incompatible with the options_file, output_cpp, "
+ + "per_proto_includes and use_objc_header_names attributes.";
+
+ @VisibleForTesting
+ static final String PORTABLE_PROTO_FILTERS_EMPTY_ERROR =
+ "The portable_proto_filters attribute can't be empty";
+
+ private final RuleContext ruleContext;
+
+ /**
+ * Creates a new ProtoAttributes object that wraps over objc_proto_library's attributes.
+ *
+ * @param ruleContext context of the objc_proto_library to wrap
+ */
+ ProtoAttributes(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ }
+
+ /**
+ * Validates the proto attributes for this target.
+ *
+ * <ul>
+ * <li>Validates that there are protos specified to be compiled.
+ * <li>Validates that, when enabling the open source protobuf library, the options for the PB2 are
+ * not specified also.
+ * <li>Validates that, when enabling the open source protobuf library, the rule specifies at least
+ * one portable proto filter file.
+ * </ul>
+ */
+ public void validate() throws RuleErrorException {
+
+ if (getProtoFiles().isEmpty()) {
+ ruleContext.throwWithRuleError(NO_PROTOS_ERROR);
+ }
+
+ PrerequisiteArtifacts prerequisiteArtifacts =
+ ruleContext.getPrerequisiteArtifacts("deps", Mode.TARGET);
+ ImmutableList<Artifact> protos = prerequisiteArtifacts.filter(FileType.of(".proto")).list();
+ if (!protos.isEmpty()) {
+ ruleContext.attributeWarning("deps", FILES_DEPRECATED_WARNING);
+ }
+
+ if (ruleContext
+ .attributes()
+ .isAttributeValueExplicitlySpecified(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR)) {
+ if (getPortableProtoFilters().isEmpty()) {
+ ruleContext.throwWithRuleError(PORTABLE_PROTO_FILTERS_EMPTY_ERROR);
+ }
+
+ if (outputsCpp()
+ || usesObjcHeaderNames()
+ || needsPerProtoIncludes()
+ || getOptionsFile().isPresent()) {
+ ruleContext.throwWithRuleError(PORTABLE_PROTO_FILTERS_NOT_EXCLUSIVE_ERROR);
+ }
+ } else {
+ if (outputsCpp()) {
+ ruleContext.ruleWarning(
+ "The output_cpp attribute has been deprecated. Please "
+ + "refer to b/29342376 for information on possible alternatives.");
+ }
+ if (!usesObjcHeaderNames()) {
+ ruleContext.ruleWarning(
+ "As part of the migration process, it is recommended to enable "
+ + "use_objc_header_names. Please refer to b/29368416 for more information.");
+ }
+ }
+ }
+
+ /** Returns whether the generated files should be C++ or Objective C. */
+ boolean outputsCpp() {
+ if (ruleContext.attributes().has(ObjcProtoLibraryRule.OUTPUT_CPP_ATTR, Type.BOOLEAN)) {
+ return ruleContext.attributes().get(ObjcProtoLibraryRule.OUTPUT_CPP_ATTR, Type.BOOLEAN);
+ }
+ return false;
+ }
+
+ /** Returns whether the generated header files should have be of type pb.h or pbobjc.h. */
+ boolean usesObjcHeaderNames() {
+ if (ruleContext
+ .attributes()
+ .has(ObjcProtoLibraryRule.USE_OBJC_HEADER_NAMES_ATTR, Type.BOOLEAN)) {
+ return ruleContext
+ .attributes()
+ .get(ObjcProtoLibraryRule.USE_OBJC_HEADER_NAMES_ATTR, Type.BOOLEAN);
+ }
+ return false;
+ }
+
+ /** Returns whether the includes should include each of the proto generated headers. */
+ boolean needsPerProtoIncludes() {
+ if (ruleContext.attributes().has(ObjcProtoLibraryRule.PER_PROTO_INCLUDES_ATTR, Type.BOOLEAN)) {
+ return ruleContext
+ .attributes()
+ .get(ObjcProtoLibraryRule.PER_PROTO_INCLUDES_ATTR, Type.BOOLEAN);
+ }
+ return false;
+ }
+
+ /** Returns whether to use the protobuf library instead of the PB2 library. */
+ boolean hasPortableProtoFilters() {
+ return ruleContext
+ .attributes()
+ .isAttributeValueExplicitlySpecified(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR);
+ }
+
+ /** Returns the list of portable proto filters. */
+ ImmutableList<Artifact> getPortableProtoFilters() {
+ if (ruleContext
+ .attributes()
+ .has(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, LABEL_LIST)) {
+ return ruleContext
+ .getPrerequisiteArtifacts(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, Mode.HOST)
+ .list();
+ }
+ return ImmutableList.of();
+ }
+
+ /** Returns the list of well known type protos. */
+ ImmutableList<Artifact> getWellKnownTypeProtos() {
+ return ruleContext
+ .getPrerequisiteArtifacts(ObjcRuleClasses.PROTOBUF_WELL_KNOWN_TYPES, Mode.HOST)
+ .list();
+ }
+
+ /** Returns the options file, or {@link Optional#absent} if it was not specified. */
+ Optional<Artifact> getOptionsFile() {
+ if (ruleContext.attributes().has(ObjcProtoLibraryRule.OPTIONS_FILE_ATTR, LABEL)) {
+ return Optional.fromNullable(
+ ruleContext.getPrerequisiteArtifact(ObjcProtoLibraryRule.OPTIONS_FILE_ATTR, Mode.HOST));
+ }
+ return Optional.absent();
+ }
+
+ /** Returns the list of proto files to compile. */
+ NestedSet<Artifact> getProtoFiles() {
+ return NestedSetBuilder.<Artifact>stableOrder()
+ .addAll(getProtoDepsFiles())
+ .addTransitive(getProtoDepsSources())
+ .build();
+ }
+
+ /** Returns the proto compiler to be used. */
+ Artifact getProtoCompiler() {
+ return ruleContext.getPrerequisiteArtifact(ObjcRuleClasses.PROTO_COMPILER_ATTR, Mode.HOST);
+ }
+
+ /** Returns the list of files needed by the proto compiler. */
+ Iterable<Artifact> getProtoCompilerSupport() {
+ return ruleContext
+ .getPrerequisiteArtifacts(ObjcRuleClasses.PROTO_COMPILER_SUPPORT_ATTR, Mode.HOST)
+ .list();
+ }
+
+ /** Returns the sets of proto files that were added using proto_library dependencies. */
+ private NestedSet<Artifact> getProtoDepsSources() {
+ NestedSetBuilder<Artifact> artifacts = NestedSetBuilder.stableOrder();
+ Iterable<ProtoSourcesProvider> providers =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class);
+ for (ProtoSourcesProvider provider : providers) {
+ artifacts.addTransitive(provider.getTransitiveProtoSources());
+ }
+ return artifacts.build();
+ }
+
+ /**
+ * Returns the list of proto files that were added directly into the deps attributes. This way of
+ * specifying the protos is deprecated, and displays a warning when the target does so.
+ */
+ private ImmutableList<Artifact> getProtoDepsFiles() {
+ PrerequisiteArtifacts prerequisiteArtifacts =
+ ruleContext.getPrerequisiteArtifacts("deps", Mode.TARGET);
+ return prerequisiteArtifacts.filter(FileType.of(".proto")).list();
+ }
+}
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
index 7863b1c4ca..bcfc5e31ca 100644
--- 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
@@ -16,19 +16,14 @@ 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.packages.BuildType.LABEL;
-import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
-import com.google.common.base.Function;
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.PrerequisiteArtifacts;
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;
@@ -38,15 +33,11 @@ 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.syntax.Type;
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;
-import javax.annotation.Nullable;
/**
* Support for generating Objective C proto static libraries that registers actions that generate
@@ -66,14 +57,6 @@ import javax.annotation.Nullable;
final class ProtoSupport {
private static final PathFragment BAZEL_TOOLS_PREFIX = new PathFragment("external/bazel_tools/");
- private static final Function<Artifact, PathFragment> PARENT_PATHFRAGMENT =
- new Function<Artifact, PathFragment>() {
- @Override
- public PathFragment apply(Artifact input) {
- return input.getExecPath().getParentDirectory();
- }
- };
-
/**
* 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
@@ -93,23 +76,6 @@ final class ProtoSupport {
LINKING_TARGET,
}
- @VisibleForTesting
- static final String NO_PROTOS_ERROR =
- "no protos to compile - a non-empty deps attribute is required";
-
- @VisibleForTesting
- static final String FILES_DEPRECATED_WARNING =
- "Using files and filegroups in objc_proto_library is deprecated";
-
- @VisibleForTesting
- static final String PORTABLE_PROTO_FILTERS_NOT_EXCLUSIVE_ERROR =
- "The portable_proto_filters attribute is incompatible with the options_file, output_cpp, "
- + "per_proto_includes and use_objc_header_names attributes.";
-
- @VisibleForTesting
- static final String PORTABLE_PROTO_FILTERS_EMPTY_ERROR =
- "The portable_proto_filters attribute can't be empty";
-
private static final String UNIQUE_DIRECTORY_NAME = "_generated_protos";
/**
@@ -120,7 +86,7 @@ final class ProtoSupport {
ImmutableSet.of("url", "http", "https");
private final RuleContext ruleContext;
- private final Attributes attributes;
+ private final ProtoAttributes attributes;
private final TargetType targetType;
private final IntermediateArtifacts intermediateArtifacts;
@@ -132,7 +98,7 @@ final class ProtoSupport {
*/
public ProtoSupport(RuleContext ruleContext, TargetType targetType) {
this.ruleContext = ruleContext;
- this.attributes = new Attributes(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
@@ -146,47 +112,6 @@ final class ProtoSupport {
}
/**
- * Validates proto support.
- * <ul>
- * <li>Validates that there are protos specified to be compiled.
- * <li>Validates that, when enabling the open source protobuf library, the options for the PB2
- * are not specified also.
- * <li>Validates that, when enabling the open source protobuf library, the rule specifies at least
- * one portable proto filter file.
- * </ul>
- *
- * @return this proto support
- */
- public ProtoSupport validate() {
- if (attributes.getProtoFiles().isEmpty()) {
- ruleContext.ruleError(NO_PROTOS_ERROR);
- }
-
- if (usesProtobufLibrary()) {
- if (attributes.getPortableProtoFilters().isEmpty()) {
- ruleContext.ruleError(PORTABLE_PROTO_FILTERS_EMPTY_ERROR);
- }
-
- if (attributes.outputsCpp()
- || attributes.usesObjcHeaderNames()
- || attributes.needsPerProtoIncludes()
- || attributes.getOptionsFile() != null) {
- ruleContext.ruleError(PORTABLE_PROTO_FILTERS_NOT_EXCLUSIVE_ERROR);
- }
- } else {
- if (attributes.outputsCpp()) {
- ruleContext.ruleWarning("The output_cpp attribute has been deprecated. Please "
- + "refer to b/29342376 for information on possible alternatives.");
- }
- if (!attributes.usesObjcHeaderNames()) {
- ruleContext.ruleWarning("As part of the migration process, it is recommended to enable "
- + "use_objc_header_names. Please refer to b/29368416 for more information.");
- }
- }
- return this;
- }
-
- /**
* Returns the intermediate artifacts associated with generated proto compilation.
*/
public IntermediateArtifacts getIntermediateArtifacts() {
@@ -224,7 +149,7 @@ final class ProtoSupport {
ruleContext.getPrerequisites(
ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET, ObjcProvider.class));
- if (usesProtobufLibrary() && experimentalAutoUnion()) {
+ if (experimentalAutoUnion()) {
commonBuilder.addDirectDependencyHeaderSearchPaths(getUserHeaderSearchPaths());
} else {
commonBuilder.addUserHeaderSearchPaths(getUserHeaderSearchPaths());
@@ -288,13 +213,8 @@ final class ProtoSupport {
.setPchFile(Optional.<Artifact>absent())
.addAdditionalHdrs(getGeneratedHeaders());
- if (targetType == TargetType.PROTO_TARGET && !usesProtobufLibrary()) {
- builder.addAdditionalHdrs(generatedSources);
- }
-
if (experimentalAutoUnion()) {
- if ((targetType == TargetType.PROTO_TARGET && !usesProtobufLibrary())
- || targetType == TargetType.LINKING_TARGET) {
+ if (targetType == TargetType.LINKING_TARGET) {
builder.addNonArcSrcs(generatedSources);
}
} else {
@@ -310,28 +230,7 @@ final class ProtoSupport {
* Returns the include paths for the generated protos.
*/
public ImmutableSet<PathFragment> getUserHeaderSearchPaths() {
- PathFragment workspaceRelativeOutputDir = getWorkspaceRelativeOutputDir();
-
- ImmutableSet.Builder<PathFragment> searchPathEntriesBuilder =
- new ImmutableSet.Builder<PathFragment>().add(workspaceRelativeOutputDir);
-
- if (attributes.needsPerProtoIncludes()) {
- PathFragment generatedProtoDir =
- new PathFragment(workspaceRelativeOutputDir, ruleContext.getLabel().getPackageFragment());
-
- searchPathEntriesBuilder
- .add(generatedProtoDir)
- .addAll(Iterables.transform(getGeneratedHeaders(), PARENT_PATHFRAGMENT));
- }
-
- return searchPathEntriesBuilder.build();
- }
-
- /**
- * Returns whether the rule is configured to use the protobuf library.
- */
- public boolean usesProtobufLibrary() {
- return attributes.hasPortableProtoFilters() || targetType == TargetType.LINKING_TARGET;
+ return ImmutableSet.of(getWorkspaceRelativeOutputDir());
}
private Iterable<Artifact> getAllProtoSources() {
@@ -440,16 +339,11 @@ final class ProtoSupport {
}
private ImmutableList<Artifact> getGeneratedHeaders() {
- boolean useObjcName = attributes.usesObjcHeaderNames() || usesProtobufLibrary();
- return generatedOutputArtifacts(FileType.of(".pb" + (useObjcName ? "objc.h" : ".h")));
+ return generatedOutputArtifacts(FileType.of(".pbobjc.h"));
}
private ImmutableList<Artifact> getGeneratedSources() {
- return generatedOutputArtifacts(
- FileType.of(
- ".pb"
- + (usesProtobufLibrary() ? "objc" : "")
- + (attributes.outputsCpp() ? ".cc" : ".m")));
+ return generatedOutputArtifacts(FileType.of(".pbobjc.m"));
}
private NestedSet<Artifact> getGenerateActionInputs() {
@@ -461,11 +355,6 @@ final class ProtoSupport {
.addAll(attributes.getProtoCompilerSupport())
.addTransitive(getPortableProtoFilters());
- Artifact optionsFile = attributes.getOptionsFile();
- if (optionsFile != null) {
- inputsBuilder.add(optionsFile);
- }
-
return inputsBuilder.build();
}
@@ -474,41 +363,6 @@ final class ProtoSupport {
}
private CustomCommandLine getGenerateCommandLine() {
- if (usesProtobufLibrary()) {
- return getProtobufCommandLine();
- } else {
- return getPb2CommandLine();
- }
- }
-
- private CustomCommandLine getPb2CommandLine() {
- CustomCommandLine.Builder commandLineBuilder =
- new CustomCommandLine.Builder()
- .add(attributes.getProtoCompiler().getExecPathString())
- .add("--input-file-list")
- .add(getProtoInputListFile().getExecPathString())
- .add("--output-dir")
- .add(getWorkspaceRelativeOutputDir().getSafePathString())
- .add("--working-dir")
- .add(".");
-
- if (attributes.getOptionsFile() != null) {
- commandLineBuilder
- .add("--compiler-options-path")
- .add(attributes.getOptionsFile().getExecPathString());
- }
-
- if (attributes.outputsCpp()) {
- commandLineBuilder.add("--generate-cpp");
- }
-
- if (attributes.usesObjcHeaderNames()) {
- commandLineBuilder.add("--use-objc-header-names");
- }
- return commandLineBuilder.build();
- }
-
- private CustomCommandLine getProtobufCommandLine() {
return new CustomCommandLine.Builder()
.add(attributes.getProtoCompiler().getExecPathString())
.add("--input-file-list")
@@ -526,17 +380,7 @@ final class ProtoSupport {
ImmutableList.Builder<Artifact> builder = new ImmutableList.Builder<>();
for (Artifact protoFile : getFilteredProtoSources()) {
String protoFileName = FileSystemUtils.removeExtension(protoFile.getFilename());
- String generatedOutputName;
- if (attributes.outputsCpp()) {
- generatedOutputName = protoFileName;
- } else if (usesProtobufLibrary()) {
- // The protobuf library generates filenames with some slight modifications.
- generatedOutputName = generateProtobufFilename(protoFileName);
- } else {
- String lowerUnderscoreBaseName = protoFileName.replace('-', '_').toLowerCase();
- generatedOutputName = LOWER_UNDERSCORE.to(UPPER_CAMEL, lowerUnderscoreBaseName);
- }
-
+ String generatedOutputName = generateProtobufFilename(protoFileName);
PathFragment generatedFilePath =
new PathFragment(
protoFile.getRootRelativePath().getParentDirectory(),
@@ -618,150 +462,4 @@ final class ProtoSupport {
}
return casedSegments.toString();
}
-
- /**
- * Common rule attributes used by an Objective C proto library.
- */
- private static class Attributes {
- private final RuleContext ruleContext;
-
- private Attributes(RuleContext ruleContext) {
- this.ruleContext = ruleContext;
- }
-
- /**
- * Returns whether the generated files should be C++ or Objective C.
- */
- boolean outputsCpp() {
- if (ruleContext.attributes().has(ObjcProtoLibraryRule.OUTPUT_CPP_ATTR, Type.BOOLEAN)) {
- return ruleContext.attributes().get(ObjcProtoLibraryRule.OUTPUT_CPP_ATTR, Type.BOOLEAN);
- }
- return false;
- }
-
- /**
- * Returns whether the generated header files should have be of type pb.h or pbobjc.h.
- */
- boolean usesObjcHeaderNames() {
- if (ruleContext
- .attributes()
- .has(ObjcProtoLibraryRule.USE_OBJC_HEADER_NAMES_ATTR, Type.BOOLEAN)) {
- return ruleContext
- .attributes()
- .get(ObjcProtoLibraryRule.USE_OBJC_HEADER_NAMES_ATTR, Type.BOOLEAN);
- }
- return false;
- }
-
- /**
- * Returns whether the includes should include each of the proto generated headers.
- */
- boolean needsPerProtoIncludes() {
- if (ruleContext
- .attributes()
- .has(ObjcProtoLibraryRule.PER_PROTO_INCLUDES_ATTR, Type.BOOLEAN)) {
- return ruleContext
- .attributes()
- .get(ObjcProtoLibraryRule.PER_PROTO_INCLUDES_ATTR, Type.BOOLEAN);
- }
- return false;
- }
-
- /**
- * Returns whether to use the protobuf library instead of the PB2 library.
- */
- boolean hasPortableProtoFilters() {
- return ruleContext
- .attributes()
- .isAttributeValueExplicitlySpecified(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR);
- }
-
- /**
- * Returns the list of portable proto filters.
- */
- ImmutableList<Artifact> getPortableProtoFilters() {
- if (ruleContext
- .attributes()
- .has(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, LABEL_LIST)) {
- return ruleContext
- .getPrerequisiteArtifacts(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR, Mode.HOST)
- .list();
- }
- return ImmutableList.of();
- }
-
- /**
- * Returns the list of well known type protos.
- */
- ImmutableList<Artifact> getWellKnownTypeProtos() {
- return ruleContext
- .getPrerequisiteArtifacts(ObjcRuleClasses.PROTOBUF_WELL_KNOWN_TYPES, Mode.HOST)
- .list();
- }
-
- /**
- * Returns the options file, or null if it was not specified.
- */
- @Nullable
- Artifact getOptionsFile() {
- if (ruleContext.attributes().has(ObjcProtoLibraryRule.OPTIONS_FILE_ATTR, LABEL)) {
- return ruleContext.getPrerequisiteArtifact(
- ObjcProtoLibraryRule.OPTIONS_FILE_ATTR, Mode.HOST);
- }
- return null;
- }
-
- /**
- * Returns the proto compiler to be used.
- */
- Artifact getProtoCompiler() {
- return ruleContext.getPrerequisiteArtifact(ObjcRuleClasses.PROTO_COMPILER_ATTR, Mode.HOST);
- }
-
- /**
- * Returns the list of files needed by the proto compiler.
- */
- ImmutableList<Artifact> getProtoCompilerSupport() {
- return ruleContext
- .getPrerequisiteArtifacts(ObjcRuleClasses.PROTO_COMPILER_SUPPORT_ATTR, Mode.HOST)
- .list();
- }
-
- /**
- * Returns the list of proto files to compile.
- */
- NestedSet<Artifact> getProtoFiles() {
- return NestedSetBuilder.<Artifact>stableOrder()
- .addAll(getProtoDepsFiles())
- .addTransitive(getProtoDepsSources())
- .build();
- }
-
- /**
- * Returns the list of proto files that were added directly into the deps attributes. This way
- * of specifying the protos is deprecated, and displays a warning when the target does so.
- */
- private ImmutableList<Artifact> getProtoDepsFiles() {
- PrerequisiteArtifacts prerequisiteArtifacts =
- ruleContext.getPrerequisiteArtifacts("deps", Mode.TARGET);
- ImmutableList<Artifact> protos = prerequisiteArtifacts.filter(FileType.of(".proto")).list();
- if (!protos.isEmpty()) {
- ruleContext.attributeWarning("deps", FILES_DEPRECATED_WARNING);
- }
- return protos;
- }
-
- /**
- * Returns the list of proto files that were added using proto_library dependencies.
- */
- private NestedSet<Artifact> getProtoDepsSources() {
- NestedSetBuilder<Artifact> artifacts = NestedSetBuilder.stableOrder();
- Iterable<ProtoSourcesProvider> providers =
- ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class);
- for (ProtoSourcesProvider provider : providers) {
- artifacts.addTransitive(provider.getTransitiveProtoSources());
- }
- return artifacts.build();
- }
- }
}
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
new file mode 100644
index 0000000000..49aa2697be
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtocolBuffers2Support.java
@@ -0,0 +1,260 @@
+// 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 static com.google.devtools.build.lib.rules.objc.XcodeProductType.LIBRARY_STATIC;
+
+import com.google.common.base.Function;
+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.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * Support for generating Objective C proto static libraries that registers actions which generate
+ * and compile the Objective C protos by using the deprecated ProtocolBuffers2 library and compiler.
+ *
+ * <p>Methods on this class can be called in any order without impacting the result.
+ */
+final class ProtocolBuffers2Support {
+
+ private static final String UNIQUE_DIRECTORY_NAME = "_generated_protos";
+
+ private static final Function<Artifact, PathFragment> PARENT_PATHFRAGMENT =
+ new Function<Artifact, PathFragment>() {
+ @Override
+ public PathFragment apply(Artifact input) {
+ return input.getExecPath().getParentDirectory();
+ }
+ };
+
+ private final RuleContext ruleContext;
+ private final ProtoAttributes attributes;
+
+ /**
+ * Creates a new proto support for the ProtocolBuffers2 library.
+ *
+ * @param ruleContext context this proto library is constructed in
+ */
+ public ProtocolBuffers2Support(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ this.attributes = new ProtoAttributes(ruleContext);
+ }
+
+ /**
+ * 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.
+ */
+ public ProtocolBuffers2Support registerGenerationActions() throws InterruptedException {
+ ruleContext.registerAction(
+ new FileWriteAction(
+ ruleContext.getActionOwner(),
+ getProtoInputsFile(),
+ getProtoInputsFileContents(attributes.getProtoFiles()),
+ false));
+
+ ruleContext.registerAction(
+ ObjcRuleClasses.spawnOnDarwinActionBuilder()
+ .setMnemonic("GenObjcPB2Protos")
+ .addInput(attributes.getProtoCompiler())
+ .addInputs(attributes.getProtoCompilerSupport())
+ .addInput(getProtoInputsFile())
+ .addInputs(attributes.getProtoFiles())
+ .addInputs(attributes.getOptionsFile().asSet())
+ .addOutputs(getGeneratedProtoOutputs(getHeaderExtension()))
+ .addOutputs(getGeneratedProtoOutputs(getSourceExtension()))
+ .setExecutable(new PathFragment("/usr/bin/python"))
+ .setCommandLine(getGenerationCommandLine())
+ .build(ruleContext));
+ return this;
+ }
+
+ /** Registers the actions that will compile the generated code. */
+ public ProtocolBuffers2Support registerCompilationActions() {
+ new CompilationSupport(ruleContext)
+ .registerCompileAndArchiveActions(getCommon())
+ .registerGenerateModuleMapAction(Optional.of(getCompilationArtifacts()));
+ return this;
+ }
+
+ /** Adds the generated files to the set of files to be output when this rule is built. */
+ public ProtocolBuffers2Support addFilesToBuild(NestedSetBuilder<Artifact> filesToBuild)
+ throws InterruptedException {
+ filesToBuild
+ .addAll(getGeneratedProtoOutputs(getHeaderExtension()))
+ .addAll(getGeneratedProtoOutputs(getSourceExtension()))
+ .addAll(getCompilationArtifacts().getArchive().asSet());
+ return this;
+ }
+
+ /** Returns the ObjcProvider for this target. */
+ public ObjcProvider getObjcProvider() {
+ return getCommon().getObjcProvider();
+ }
+
+ /** Returns the XcodeProvider for this target. */
+ public XcodeProvider getXcodeProvider() {
+ XcodeProvider.Builder xcodeProviderBuilder =
+ new XcodeProvider.Builder()
+ .addUserHeaderSearchPaths(getUserHeaderSearchPaths())
+ .setCompilationArtifacts(getCompilationArtifacts());
+
+ new XcodeSupport(ruleContext)
+ .addXcodeSettings(xcodeProviderBuilder, getCommon().getObjcProvider(), LIBRARY_STATIC)
+ .addDependencies(
+ xcodeProviderBuilder, new Attribute(ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET));
+
+ return xcodeProviderBuilder.build();
+ }
+
+ private String getHeaderExtension() {
+ return ".pb" + (attributes.usesObjcHeaderNames() ? "objc.h" : ".h");
+ }
+
+ private String getSourceExtension() {
+ return ".pb" + (attributes.outputsCpp() ? ".cc" : ".m");
+ }
+
+ private ObjcCommon getCommon() {
+ return new ObjcCommon.Builder(ruleContext)
+ .setIntermediateArtifacts(new IntermediateArtifacts(ruleContext, ""))
+ .setHasModuleMap()
+ .setCompilationArtifacts(getCompilationArtifacts())
+ .addUserHeaderSearchPaths(getUserHeaderSearchPaths())
+ .addDepObjcProviders(
+ ruleContext.getPrerequisites(
+ ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET, ObjcProvider.class))
+ .build();
+ }
+
+ private CompilationArtifacts getCompilationArtifacts() {
+ Iterable<Artifact> generatedSources = getGeneratedProtoOutputs(getSourceExtension());
+ return new CompilationArtifacts.Builder()
+ .setIntermediateArtifacts(new IntermediateArtifacts(ruleContext, ""))
+ .setPchFile(Optional.<Artifact>absent())
+ .addAdditionalHdrs(getGeneratedProtoOutputs(getHeaderExtension()))
+ .addAdditionalHdrs(generatedSources)
+ .addNonArcSrcs(generatedSources)
+ .build();
+ }
+
+ private Artifact getProtoInputsFile() {
+ return ruleContext.getUniqueDirectoryArtifact(
+ "_protos", "_proto_input_files", 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() {
+ CustomCommandLine.Builder commandLineBuilder =
+ new CustomCommandLine.Builder()
+ .add(attributes.getProtoCompiler().getExecPathString())
+ .add("--input-file-list")
+ .add(getProtoInputsFile().getExecPathString())
+ .add("--output-dir")
+ .add(getWorkspaceRelativeOutputDir().getSafePathString())
+ .add("--working-dir")
+ .add(".");
+
+ if (attributes.getOptionsFile().isPresent()) {
+ commandLineBuilder
+ .add("--compiler-options-path")
+ .add(attributes.getOptionsFile().get().getExecPathString());
+ }
+
+ if (attributes.outputsCpp()) {
+ commandLineBuilder.add("--generate-cpp");
+ }
+
+ if (attributes.usesObjcHeaderNames()) {
+ commandLineBuilder.add("--use-objc-header-names");
+ }
+ return commandLineBuilder.build();
+ }
+
+ public ImmutableSet<PathFragment> getUserHeaderSearchPaths() {
+ ImmutableSet.Builder<PathFragment> searchPathEntriesBuilder =
+ new ImmutableSet.Builder<PathFragment>().add(getWorkspaceRelativeOutputDir());
+
+ if (attributes.needsPerProtoIncludes()) {
+ PathFragment generatedProtoDir =
+ new PathFragment(
+ getWorkspaceRelativeOutputDir(), ruleContext.getLabel().getPackageFragment());
+
+ searchPathEntriesBuilder
+ .add(generatedProtoDir)
+ .addAll(
+ Iterables.transform(
+ getGeneratedProtoOutputs(getHeaderExtension()), PARENT_PATHFRAGMENT));
+ }
+
+ return searchPathEntriesBuilder.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(String extension) {
+ ImmutableList.Builder<Artifact> builder = new ImmutableList.Builder<>();
+ for (Artifact protoFile : attributes.getProtoFiles()) {
+ String protoFileName = FileSystemUtils.removeExtension(protoFile.getFilename());
+ String generatedOutputName;
+ if (attributes.outputsCpp()) {
+ generatedOutputName = protoFileName;
+ } else {
+ String lowerUnderscoreBaseName = protoFileName.replace('-', '_').toLowerCase();
+ generatedOutputName = LOWER_UNDERSCORE.to(UPPER_CAMEL, lowerUnderscoreBaseName);
+ }
+
+ 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();
+ }
+}