diff options
author | 2015-09-18 17:09:02 +0000 | |
---|---|---|
committer | 2015-09-21 08:59:14 +0000 | |
commit | f081184097239243b436f96774b63b010d5e021f (patch) | |
tree | 3c145b4d0bae5768a0ea4935e838dced3f78d7f9 /src/main/java/com/google/devtools | |
parent | ee26ee1c5b4a10ca6bb401e0dafaea0026de4ab9 (diff) |
Enable j2objc_library proto aspect for Bazel. Note that the remote j2objc workspace hasn't been set up yet.
RELNOTES: j2objc_library on Bazel now transpiles transitive proto_library dependencies. (Note that java_* rules in Bazel do not yet support protos; currently they ignore proto dependencies.)
--
MOS_MIGRATED_REVID=103392720
Diffstat (limited to 'src/main/java/com/google/devtools')
6 files changed, 295 insertions, 15 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java index 58d79c60fd..f23d62dcbe 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java @@ -128,6 +128,8 @@ public class BazelJavaRuleClasses { "genproto", // TODO(bazel-team): we should filter using providers instead (skylark rule). "java_import", "java_library", + // There is no Java protoc for Bazel--yet. This is here for the benefit of J2 protos. + "proto_library", "sh_binary", "sh_library"); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java new file mode 100644 index 0000000000..fa976a159c --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java @@ -0,0 +1,179 @@ +// Copyright 2014 Google Inc. 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.rules.objc.J2ObjcSource.SourceType; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.Aspect; +import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; +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.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.AspectDefinition; +import com.google.devtools.build.lib.packages.AspectParameters; +import com.google.devtools.build.lib.rules.proto.ProtoCommon; +import com.google.devtools.build.lib.rules.proto.ProtoSourcesProvider; +import com.google.devtools.build.lib.syntax.Label; + +/** + * J2ObjC aspect for the proto_library rule. + * + * <p>J2ObjC proto is different from other proto languages in that it needs to implement both the + * Java API and the Objective-C API. The Java API implementation is needed for compatibility with + * ObjC code translated by J2ObjC from Java. The Objective-C API is also required for compatibility + * with hand-written ObjC code. As an example, for an accessor of a int field called int_value in + * message Foo, both the Java API version (getIntValue) and the ObjC version (intValue) are needed. + * + * <p>On the whole, the dependency chain looks like: objc_binary -> objc_library -> j2objc_library + * -> java_library -> proto_library. The jars containing compiled Java protos provided by + * proto_library are needed in the classpath for J2ObjC transpilation in java_library, but they + * themselves are not transpiled or exported to objc_* rules. Instead, the J2ObjC protos generated + * by this class and provided by proto_library will be exported all the way to objc_binary for ObjC + * compilation and linking into the final application bundle. + */ +public abstract class AbstractJ2ObjcProtoAspect implements ConfiguredAspectFactory { + public static final String NAME = "J2ObjcProtoAspect"; + + public AspectDefinition getDefinition() { + AspectDefinition.Builder builder = new AspectDefinition.Builder("J2ObjcProtoAspect") + .requireProvider(ProtoSourcesProvider.class) + .attributeAspect("deps", getClass()) + .attributeAspect("exports", getClass()) + .attributeAspect("runtime_deps", getClass()); + return addAdditionalAttributes(builder).build(); + } + + protected abstract AspectDefinition.Builder addAdditionalAttributes( + AspectDefinition.Builder builder); + + protected static Label parseLabel(String from) { + try { + return Label.parseAbsolute(from); + } catch (LabelSyntaxException e) { + throw new IllegalArgumentException(from); + } + } + + protected abstract boolean checkShouldCreateAspect(RuleContext ruleContext); + + @Override + public Aspect create(ConfiguredTarget base, RuleContext ruleContext, + AspectParameters parameters) { + if (!checkShouldCreateAspect(ruleContext)) { + return new Aspect.Builder(NAME).build(); + } + + ProtoSourcesProvider protoSourcesProvider = base.getProvider(ProtoSourcesProvider.class); + ImmutableList<Artifact> protoSources = protoSourcesProvider.getProtoSources(); + NestedSet<Artifact> transitiveImports = protoSourcesProvider.getTransitiveImports(); + + J2ObjcSrcsProvider.Builder srcsBuilder = new J2ObjcSrcsProvider.Builder(); + Iterable<Artifact> headerMappingFiles; + Iterable<Artifact> classMappingFiles; + + if (protoSources.isEmpty()) { + headerMappingFiles = ImmutableList.of(); + classMappingFiles = ImmutableList.of(); + } else { + J2ObjcSource j2ObjcSource = j2ObjcSource(ruleContext, protoSources); + headerMappingFiles = headerMappingFiles(ruleContext, protoSources); + classMappingFiles = classMappingFiles(ruleContext, protoSources); + srcsBuilder.addSource(j2ObjcSource); + + createActions(base, ruleContext, protoSources, transitiveImports, + headerMappingFiles, classMappingFiles, j2ObjcSource); + } + + J2ObjcSrcsProvider j2objcSrcsProvider = srcsBuilder + .addTransitiveJ2ObjcSrcs(ruleContext, "deps") + .build(); + NestedSet<Artifact> j2ObjcTransitiveHeaderMappingFiles = j2ObjcTransitiveHeaderMappingFiles( + ruleContext, headerMappingFiles); + NestedSet<Artifact> j2ObjcTransitiveClassMappingFiles = j2ObjcTransitiveClassMappingFiles( + ruleContext, classMappingFiles); + + return new Aspect.Builder(NAME) + .addProvider(J2ObjcSrcsProvider.class, j2objcSrcsProvider) + .addProvider( + J2ObjcMappingFileProvider.class, + new J2ObjcMappingFileProvider( + j2ObjcTransitiveHeaderMappingFiles, + j2ObjcTransitiveClassMappingFiles, + NestedSetBuilder.<Artifact>stableOrder().build())) + .build(); + } + + protected abstract void createActions(ConfiguredTarget base, RuleContext ruleContext, + Iterable<Artifact> protoSources, NestedSet<Artifact> transitiveProtoSources, + Iterable<Artifact> headerMappingFiles, Iterable<Artifact> classMappingFiles, + J2ObjcSource j2ObjcSource); + + protected abstract boolean checkShouldCreateSources(RuleContext ruleContext); + + private J2ObjcSource j2ObjcSource(RuleContext ruleContext, + ImmutableList<Artifact> protoSources) { + Iterable<Artifact> generatedSourceFiles = checkShouldCreateSources(ruleContext) + ? ProtoCommon.getGeneratedOutputs(ruleContext, protoSources, ".j2objc.pb.m") + : ImmutableList.<Artifact>of(); + + return new J2ObjcSource( + ruleContext.getTarget().getLabel(), + generatedSourceFiles, + ProtoCommon.getGeneratedOutputs(ruleContext, protoSources, ".j2objc.pb.h"), + ruleContext.getConfiguration().getGenfilesDirectory().getExecPath(), + SourceType.PROTO); + } + + private static Iterable<Artifact> headerMappingFiles(RuleContext ruleContext, + ImmutableList<Artifact> protoSources) { + return ProtoCommon.getGeneratedOutputs(ruleContext, protoSources, ".j2objc.mapping"); + } + + private static Iterable<Artifact> classMappingFiles(RuleContext ruleContext, + ImmutableList<Artifact> protoSources) { + return ProtoCommon.getGeneratedOutputs(ruleContext, protoSources, ".clsmap.properties"); + } + + private static NestedSet<Artifact> j2ObjcTransitiveHeaderMappingFiles(RuleContext ruleContext, + Iterable<Artifact> headerMappingFiles) { + NestedSetBuilder<Artifact> mappingFileBuilder = NestedSetBuilder.stableOrder(); + mappingFileBuilder.addAll(headerMappingFiles); + + for (J2ObjcMappingFileProvider provider : + ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcMappingFileProvider.class)) { + mappingFileBuilder.addTransitive(provider.getHeaderMappingFiles()); + } + + return mappingFileBuilder.build(); + } + + private static NestedSet<Artifact> j2ObjcTransitiveClassMappingFiles(RuleContext ruleContext, + Iterable<Artifact> classMappingFiles) { + NestedSetBuilder<Artifact> mappingFileBuilder = NestedSetBuilder.stableOrder(); + mappingFileBuilder.addAll(classMappingFiles); + + for (J2ObjcMappingFileProvider provider : + ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcMappingFileProvider.class)) { + mappingFileBuilder.addTransitive(provider.getClassMappingFiles()); + } + + return mappingFileBuilder.build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java new file mode 100644 index 0000000000..1103aee7ff --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcProtoAspect.java @@ -0,0 +1,103 @@ +// Copyright 2014 Google Inc. 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.Attribute.ConfigurationTransition.HOST; +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LABEL; + +import com.google.common.collect.ImmutableMap; +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.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.packages.AspectDefinition; +import com.google.devtools.build.lib.vfs.PathFragment; + +/** + * An aspect that transpiles .proto dependencies using the J2ObjC proto plugin, + * //tools/objc:compile_protos and //tools/objc:proto_support. N.B.: These two tools + * have not yet been released into open-source. + */ +public class BazelJ2ObjcProtoAspect extends AbstractJ2ObjcProtoAspect { + + @Override + protected AspectDefinition.Builder addAdditionalAttributes(AspectDefinition.Builder builder) { + return builder + .add(attr("$protoc_darwin", LABEL) + .cfg(HOST) + .exec() + .value(parseLabel("//tools/objc:compile_protos"))) + .add(attr("$protoc_support_darwin", LABEL) + .cfg(HOST) + .exec() + .value(parseLabel("//tools/objc:proto_support"))) + .add(attr("$j2objc_plugin", LABEL) + .cfg(HOST) + .exec() + .value(parseLabel( + "//third_party/java/j2objc:proto_plugin"))); + } + + @Override + protected boolean checkShouldCreateAspect(RuleContext ruleContext) { + return true; + } + + protected void createActions(ConfiguredTarget base, RuleContext ruleContext, + Iterable<Artifact> protoSources, NestedSet<Artifact> transitiveProtoSources, + Iterable<Artifact> headerMappingFiles, Iterable<Artifact> classMappingFiles, + J2ObjcSource j2ObjcSource) { + String genDir = ruleContext.getConfiguration().getGenfilesDirectory().getExecPathString(); + Artifact compiler = ruleContext.getPrerequisiteArtifact( + "$protoc_darwin", Mode.HOST); + Artifact j2objcPlugin = ruleContext.getPrerequisiteArtifact("$j2objc_plugin", Mode.HOST); + + ruleContext.registerAction(new SpawnAction.Builder() + .setMnemonic("TranslatingJ2ObjcProtos") + .addInput(compiler) + .addInput(j2objcPlugin) + .addInputs(ruleContext.getPrerequisiteArtifacts( + "$protoc_support_darwin", Mode.HOST).list()) + .addInputs(protoSources) + .addTransitiveInputs(transitiveProtoSources) + .addOutputs(j2ObjcSource.getObjcSrcs()) + .addOutputs(j2ObjcSource.getObjcHdrs()) + .addOutputs(headerMappingFiles) + .addOutputs(classMappingFiles) + .setExecutable(new PathFragment("/usr/bin/python")) + .setCommandLine(new CustomCommandLine.Builder() + .add(compiler.getPath().toString()) + .add("-w") + .add(compiler.getRoot().getPath().toString()) + .add("--generate-j2objc") + .add("--generator-param=file_dir_mapping") + .add("--generator-param=generate_class_mappings") + .add("--j2objc-plugin=" + j2objcPlugin.getExecPathString()) + .add("--output-dir=" + genDir) + .addExecPaths(protoSources) + .build()) + .setExecutionInfo(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "")) + .build(ruleContext)); + } + + @Override + protected boolean checkShouldCreateSources(RuleContext ruleContext) { + return true; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java index 0b15f5dbf3..48ed58fb0e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java @@ -59,9 +59,9 @@ public class J2ObjcAspect implements ConfiguredAspectFactory { * Adds the attribute aspect args to the given AspectDefinition.Builder. */ protected AspectDefinition.Builder addAttributeAspects(AspectDefinition.Builder builder) { - return builder.attributeAspect("deps", J2ObjcAspect.class) - .attributeAspect("exports", J2ObjcAspect.class) - .attributeAspect("runtime_deps", J2ObjcAspect.class); + return builder.attributeAspect("deps", J2ObjcAspect.class, BazelJ2ObjcProtoAspect.class) + .attributeAspect("exports", J2ObjcAspect.class, BazelJ2ObjcProtoAspect.class) + .attributeAspect("runtime_deps", J2ObjcAspect.class, BazelJ2ObjcProtoAspect.class); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java index bb88b2f539..88a66c4138 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java @@ -72,18 +72,12 @@ public class J2ObjcLibrary implements RuleConfiguredTargetFactory { .addDependencies(xcodeProviderBuilder, new Attribute("deps", Mode.TARGET)); if (j2ObjcSrcsProvider.hasProtos()) { - if (ruleContext.attributes().has("$protobuf_lib", BuildType.LABEL)) { - objcProviderBuilder.addTransitiveAndPropagate( - ruleContext.getPrerequisite("$protobuf_lib", Mode.TARGET, ObjcProvider.class)); - xcodeSupport.addDependencies( - xcodeProviderBuilder, new Attribute("$protobuf_lib", Mode.TARGET)); - } else { - // In theory no Bazel rule should ever provide protos, because they're not supported yet. - // If we reach here, it's a programming error, not a rule error. - throw new IllegalStateException( - "Found protos in the dependencies of rule " + ruleContext.getLabel() + ", " - + "but protos are not supported in Bazel."); - } + // Public J2 in Bazel provides no protobuf_lib, and if OSS users try to sneakily use + // undocumented functionality to reach here, the below code will error. + objcProviderBuilder.addTransitiveAndPropagate( + ruleContext.getPrerequisite("$protobuf_lib", Mode.TARGET, ObjcProvider.class)); + xcodeSupport.addDependencies( + xcodeProviderBuilder, new Attribute("$protobuf_lib", Mode.TARGET)); } for (J2ObjcSource j2objcSource : j2ObjcSrcsProvider.getSrcs()) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java index a0825f6d5f..9bcfcea3d0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java @@ -47,6 +47,8 @@ public class J2ObjcLibraryBaseRule implements RuleDefinition { .add(attr("entry_classes", STRING_LIST)) .add(attr("$jre_emul_lib", LABEL) .value(env.getLabel("//third_party/java/j2objc:jre_emul_lib"))) + .add(attr("$protobuf_lib", LABEL) + .value(env.getLabel("//third_party/java/j2objc:proto_runtime"))) .build(); } |