diff options
author | 2015-06-18 17:56:11 +0000 | |
---|---|---|
committer | 2015-06-19 11:04:17 +0000 | |
commit | ca4e13ac57d5c4c44cc4e4618522799cfde96ab3 (patch) | |
tree | 0d66f3ab4195c8aee1c0ca95bf7b91619cb1ebd0 | |
parent | ad26d68e108b92e529c9f91c5ac812451660af4d (diff) |
Move J2ObjCLibrary and supporting classes to Bazel, and enable J2ObJC in Bazel.
--
MOS_MIGRATED_REVID=96324830
10 files changed, 554 insertions, 8 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index dabf2fe27c..dfbcc4244a 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -80,6 +80,8 @@ import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader; import com.google.devtools.build.lib.rules.cpp.CppOptions; import com.google.devtools.build.lib.rules.genquery.GenQueryRule; +import com.google.devtools.build.lib.rules.java.J2ObjcCommandLineOptions; +import com.google.devtools.build.lib.rules.java.J2ObjcConfiguration; import com.google.devtools.build.lib.rules.java.JavaConfiguration; import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader; import com.google.devtools.build.lib.rules.java.JavaCpuSupplier; @@ -88,13 +90,13 @@ import com.google.devtools.build.lib.rules.java.JavaOptions; import com.google.devtools.build.lib.rules.java.JavaToolchainRule; import com.google.devtools.build.lib.rules.java.Jvm; import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader; +import com.google.devtools.build.lib.rules.objc.BazelJ2ObjcLibraryRule; import com.google.devtools.build.lib.rules.objc.ExperimentalIosTestRule; import com.google.devtools.build.lib.rules.objc.IosApplicationRule; import com.google.devtools.build.lib.rules.objc.IosDeviceRule; import com.google.devtools.build.lib.rules.objc.IosExtensionBinaryRule; import com.google.devtools.build.lib.rules.objc.IosExtensionRule; -import com.google.devtools.build.lib.rules.objc.J2ObjcCommandLineOptions; -import com.google.devtools.build.lib.rules.objc.J2ObjcConfiguration; +import com.google.devtools.build.lib.rules.objc.J2ObjcLibraryBaseRule; import com.google.devtools.build.lib.rules.objc.ObjcBinaryRule; import com.google.devtools.build.lib.rules.objc.ObjcBuildInfoFactory; import com.google.devtools.build.lib.rules.objc.ObjcBundleLibraryRule; @@ -329,6 +331,8 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new IosApplicationRule()); builder.addRuleDefinition(new IosExtensionBinaryRule()); builder.addRuleDefinition(new IosExtensionRule()); + builder.addRuleDefinition(new J2ObjcLibraryBaseRule()); + builder.addRuleDefinition(new BazelJ2ObjcLibraryRule()); builder.addRuleDefinition(new BazelExtraActionRule()); builder.addRuleDefinition(new BazelActionListenerRule()); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java index acc91733ac..6e7f85a8a9 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java @@ -25,6 +25,10 @@ import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.JavaRule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; +import com.google.devtools.build.lib.rules.java.J2ObjcConfiguration; +import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; +import com.google.devtools.build.lib.rules.java.JavaConfiguration; import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider; /** @@ -35,6 +39,8 @@ public final class BazelJavaLibraryRule implements RuleDefinition { public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) { return builder + .requiresConfigurationFragments( + JavaConfiguration.class, CppConfiguration.class, J2ObjcConfiguration.class) /* <!-- #BLAZE_RULE(java_library).IMPLICIT_OUTPUTS --> <ul> <li><code>lib<var>name</var>.jar</code>: A Java archive containing the class files.</li> @@ -144,6 +150,7 @@ public final class BazelJavaLibraryRule implements RuleDefinition { .add(attr("exported_plugins", LABEL_LIST).cfg(HOST).allowedRuleClasses("java_plugin") .legacyAllowAnyFileType()) .advertiseProvider(JavaSourceInfoProvider.class) + .advertiseProvider(JavaCompilationArgsProvider.class) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/J2ObjcCommandLineOptions.java index 7d1f88b4d4..6c09c84dd7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcCommandLineOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/J2ObjcCommandLineOptions.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.devtools.build.lib.rules.objc; +package com.google.devtools.build.lib.rules.java; import com.google.common.collect.Multimap; import com.google.devtools.build.lib.analysis.config.FragmentOptions; @@ -23,15 +23,17 @@ import com.google.devtools.common.options.Option; import java.util.List; /** - * Command-line Options for J2ObjC translation of Java source code to ObjC. + * Command-line options for J2ObjC translation of Java source code to ObjC. + * These command line options are used by Java rules that can be transpiled + * (specifically, J2ObjCAspects thereof). */ public class J2ObjcCommandLineOptions extends FragmentOptions { @Option(name = "j2objc_translation_flags", converter = Converters.CommaSeparatedOptionListConverter.class, allowMultiple = true, defaultValue = "", - category = "undocumented", - help = "Specifies the translation flags for the J2ObjC transpiler." + category = "flags", + help = "Additional options to pass to the J2ObjC tool." ) public List<String> translationFlags; diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/J2ObjcConfiguration.java index afb3038169..9a24e446a0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/J2ObjcConfiguration.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.devtools.build.lib.rules.objc; +package com.google.devtools.build.lib.rules.java; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; @@ -28,7 +28,9 @@ import java.util.Collections; import java.util.Set; /** - * A J2ObjC transpiler configuration containing J2ObjC translation flags. + * A J2ObjC transpiler configuration fragment containing J2ObjC translation flags. + * This configuration fragment is used by Java rules that can be transpiled + * (specifically, J2ObjCAspects thereof). */ public class J2ObjcConfiguration extends Fragment { /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java index 8db95eb81e..dc195c78ae 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; /** * A base rule for building the java_import rule. @@ -36,6 +37,8 @@ public class JavaImportBaseRule implements RuleDefinition { @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder + .requiresConfigurationFragments(JavaConfiguration.class, CppConfiguration.class, + J2ObjcConfiguration.class) .add(attr(":host_jdk", LABEL) .cfg(HOST) .value(JavaSemantics.HOST_JDK)) @@ -71,6 +74,7 @@ public class JavaImportBaseRule implements RuleDefinition { .add(attr("constraints", STRING_LIST) .orderIndependent() .nonconfigurable("used in Attribute.validityPredicate implementations (loading time)")) + .advertiseProvider(JavaSourceInfoProvider.class) .advertiseProvider(JavaCompilationArgsProvider.class) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcLibraryRule.java new file mode 100644 index 0000000000..a976b688a4 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcLibraryRule.java @@ -0,0 +1,55 @@ +// Copyright 2015 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.attr; +import static com.google.devtools.build.lib.packages.Type.LABEL_LIST; + +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; + +/** + * Concrete implementation of J2ObjCLibraryBaseRule. + */ +public class BazelJ2ObjcLibraryRule implements RuleDefinition { + + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE(j2objc_library).ATTRIBUTE(deps) --> + A list of <code>j2objc_library</code>, <code>java_library</code> + and <code>java_import</code> targets that contain + Java files to be transpiled to Objective-C. + ${SYNOPSIS} + <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/ + .add(attr("deps", LABEL_LIST) + .aspect(J2ObjcAspect.class) + .direct_compile_time_input() + .allowedRuleClasses("j2objc_library", "java_library", "java_import") + .allowedFileTypes()) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("j2objc_library") + .factoryClass(J2ObjcLibrary.class) + .ancestors(J2ObjcLibraryBaseRule.class) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java index 4a7bb7f401..1f346ed7a7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java @@ -56,6 +56,7 @@ import com.google.devtools.build.lib.analysis.config.CompilationMode; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.cpp.LinkerInputs; +import com.google.devtools.build.lib.rules.java.J2ObjcConfiguration; import com.google.devtools.build.lib.rules.objc.ObjcCommon.CompilationAttributes; import com.google.devtools.build.lib.rules.objc.XcodeProvider.Builder; import com.google.devtools.build.lib.shell.ShellUtils; 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 new file mode 100644 index 0000000000..99bdfb4e22 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java @@ -0,0 +1,282 @@ +// Copyright 2015 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.Type.LABEL; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +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.analysis.TransitiveInfoCollection; +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.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.packages.AspectDefinition; +import com.google.devtools.build.lib.packages.Type; +import com.google.devtools.build.lib.rules.java.J2ObjcConfiguration; +import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; +import com.google.devtools.build.lib.rules.java.JavaCompilationHelper; +import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider; +import com.google.devtools.build.lib.rules.java.Jvm; +import com.google.devtools.build.lib.rules.objc.J2ObjcSource.SourceType; +import com.google.devtools.build.lib.syntax.Label; +import com.google.devtools.build.lib.syntax.Label.SyntaxException; +import com.google.devtools.build.lib.util.FileType; +import com.google.devtools.build.lib.vfs.PathFragment; + +import java.util.List; + +/** + * J2ObjC transpilation aspect for Java rules. + */ +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); + } + + @Override + public AspectDefinition getDefinition() { + return addAttributeAspects(new AspectDefinition.Builder("J2ObjCAspect")) + .requireProvider(JavaSourceInfoProvider.class) + .requireProvider(JavaCompilationArgsProvider.class) + .add(attr("$j2objc", LABEL).cfg(HOST).exec() + .value(parseLabel("//tools/j2objc:j2objc_deploy.jar"))) + .add(attr("$j2objc_wrapper", LABEL) + .allowedFileTypes(FileType.of(".py")) + .cfg(HOST) + .exec() + .singleArtifact() + .value(parseLabel("//tools/j2objc:j2objc_wrapper"))) + .build(); + } + + private static Label parseLabel(String from) { + try { + return Label.parseAbsolute(from); + } catch (SyntaxException e) { + throw new IllegalArgumentException(from); + } + } + + @Override + public Aspect create(ConfiguredTarget base, RuleContext ruleContext) { + Aspect.Builder builder = new Aspect.Builder(); + + JavaCompilationArgsProvider compilationArgsProvider = + base.getProvider(JavaCompilationArgsProvider.class); + JavaSourceInfoProvider sourceInfoProvider = + base.getProvider(JavaSourceInfoProvider.class); + + ImmutableSet<Artifact> javaInputFiles = ImmutableSet.<Artifact>builder() + .addAll(sourceInfoProvider.getSourceFiles()) + .addAll(sourceInfoProvider.getSourceJars()) + .addAll(sourceInfoProvider.getSourceJarsForJarFiles()) + .build(); + + NestedSetBuilder<Artifact> depsHeaderMappingsBuilder = NestedSetBuilder.stableOrder(); + NestedSetBuilder<Artifact> depsClassMappingsBuilder = NestedSetBuilder.stableOrder(); + NestedSetBuilder<Artifact> depsDependencyMappingsBuilder = NestedSetBuilder.stableOrder(); + + for (J2ObjcMappingFileProvider provider : getJ2ObjCMappings(ruleContext)) { + depsHeaderMappingsBuilder.addTransitive(provider.getHeaderMappingFiles()); + depsClassMappingsBuilder.addTransitive(provider.getClassMappingFiles()); + depsDependencyMappingsBuilder.addTransitive(provider.getDependencyMappingFiles()); + } + + NestedSet<Artifact> depsHeaderMappings = depsHeaderMappingsBuilder.build(); + NestedSet<Artifact> depsClassMappings = depsClassMappingsBuilder.build(); + NestedSet<Artifact> depsDependencyMappings = depsDependencyMappingsBuilder.build(); + + J2ObjcSrcsProvider.Builder srcsBuilder = new J2ObjcSrcsProvider.Builder(); + J2ObjcMappingFileProvider j2ObjcMappingFileProvider; + + if (!javaInputFiles.isEmpty()) { + J2ObjcSource j2ObjcSource = buildJ2ObjcSource(ruleContext, javaInputFiles); + + createJ2ObjcTranspilationAction(ruleContext, depsHeaderMappings, depsClassMappings, + javaInputFiles, compilationArgsProvider, j2ObjcSource); + + // J2ObjC merges all input header mapping files into the output header mapping file, so we + // only need to export the output header mapping file here. + NestedSet<Artifact> headerMappingFiles = NestedSetBuilder.<Artifact>stableOrder() + .add(j2ObjcOutputHeaderMappingFile(ruleContext)) + .build(); + NestedSet<Artifact> dependencyMappingFiles = NestedSetBuilder.<Artifact>stableOrder() + .add(j2ObjcOutputDependencyMappingFile(ruleContext)) + .addTransitive(depsDependencyMappings) + .build(); + + srcsBuilder.addSource(j2ObjcSource); + j2ObjcMappingFileProvider = new J2ObjcMappingFileProvider( + headerMappingFiles, depsClassMappings, dependencyMappingFiles); + } else { + j2ObjcMappingFileProvider = new J2ObjcMappingFileProvider( + depsHeaderMappings, depsClassMappings, depsDependencyMappings); + } + + for (J2ObjcSrcsProvider provider : + ruleContext.getPrerequisites("exports", Mode.TARGET, J2ObjcSrcsProvider.class)) { + srcsBuilder.addTransitive(provider); + } + + srcsBuilder.addTransitiveFromDeps(ruleContext); + + return builder + .addProvider(J2ObjcSrcsProvider.class, srcsBuilder.build()) + .addProvider(J2ObjcMappingFileProvider.class, j2ObjcMappingFileProvider) + .build(); + } + + private static void createJ2ObjcTranspilationAction( + RuleContext ruleContext, + NestedSet<Artifact> depsHeaderMappingFiles, + NestedSet<Artifact> depsClassMappingFiles, + Iterable<Artifact> sources, + JavaCompilationArgsProvider compArgsProvider, + J2ObjcSource j2ObjcSource) { + CustomCommandLine.Builder argBuilder = CustomCommandLine.builder(); + PathFragment javaExecutable = ruleContext.getHostConfiguration().getFragment(Jvm.class) + .getJavaExecutable(); + argBuilder.add("--java").add(javaExecutable.getPathString()); + + Artifact j2ObjcDeployJar = ruleContext.getPrerequisiteArtifact("$j2objc", Mode.HOST); + argBuilder.addExecPath("--j2objc", j2ObjcDeployJar); + + argBuilder.add("--main_class").add("com.google.devtools.j2objc.J2ObjC"); + argBuilder.addJoinExecPaths("--translated_source_files", ",", j2ObjcSource.getObjcSrcs()); + argBuilder.add("--objc_file_path").addPath(j2ObjcSource.getObjcFilePath()); + + Artifact outputDependencyMappingFile = j2ObjcOutputDependencyMappingFile(ruleContext); + argBuilder.addExecPath("--output_dependency_mapping_file", outputDependencyMappingFile); + + Iterable<String> translationFlags = ruleContext + .getFragment(J2ObjcConfiguration.class) + .getTranslationFlags(); + argBuilder.add(translationFlags); + + if (!depsHeaderMappingFiles.isEmpty()) { + argBuilder.addJoinExecPaths("--header-mapping", ",", depsHeaderMappingFiles); + } + + Artifact outputHeaderMappingFile = j2ObjcOutputHeaderMappingFile(ruleContext); + argBuilder.addExecPath("--output-header-mapping", outputHeaderMappingFile); + + if (!depsClassMappingFiles.isEmpty()) { + argBuilder.addJoinExecPaths("--mapping", ",", depsClassMappingFiles); + } + + argBuilder.add("-d").addPath(j2ObjcSource.getObjcFilePath()); + + // In J2ObjC, the jars you pass as dependencies must be precisely the same as the + // jars used to transpile those dependencies--we cannot use ijars here. + NestedSet<Artifact> compileTimeJars = + compArgsProvider.getRecursiveJavaCompilationArgs().getRuntimeJars(); + if (!compileTimeJars.isEmpty()) { + argBuilder.addJoinExecPaths("-classpath", ":", compileTimeJars); + } + + argBuilder.addExecPaths(sources); + + SpawnAction.Builder builder = new SpawnAction.Builder() + .setMnemonic("TranspilingJ2objc") + .setExecutable(ruleContext.getPrerequisiteArtifact("$j2objc_wrapper", Mode.HOST)) + .addInput(ruleContext.getPrerequisiteArtifact("$j2objc_wrapper", Mode.HOST)) + .addInput(j2ObjcDeployJar) + .addInputs(sources) + .addTransitiveInputs(compileTimeJars) + .addInputs(JavaCompilationHelper.getHostJavabaseInputs(ruleContext)) + .addTransitiveInputs(depsHeaderMappingFiles) + .addTransitiveInputs(depsClassMappingFiles) + .setCommandLine(argBuilder.build()) + .addOutputs(j2ObjcSource.getObjcSrcs()) + .addOutputs(j2ObjcSource.getObjcHdrs()) + .addOutput(outputHeaderMappingFile) + .addOutput(outputDependencyMappingFile); + + ruleContext.registerAction(builder.build(ruleContext)); + } + + private static List<? extends J2ObjcMappingFileProvider> getJ2ObjCMappings(RuleContext context) { + ImmutableList.Builder<J2ObjcMappingFileProvider> mappingFileProviderBuilder = + new ImmutableList.Builder<>(); + addJ2ObjCMappingsForAttribute(mappingFileProviderBuilder, context, "deps"); + addJ2ObjCMappingsForAttribute(mappingFileProviderBuilder, context, "runtime_deps"); + addJ2ObjCMappingsForAttribute(mappingFileProviderBuilder, context, "exports"); + return mappingFileProviderBuilder.build(); + } + + private static void addJ2ObjCMappingsForAttribute( + ImmutableList.Builder<J2ObjcMappingFileProvider> builder, RuleContext context, + String attributeName) { + if (context.attributes().has(attributeName, Type.LABEL_LIST)) { + for (TransitiveInfoCollection dependencyInfoDatum : + context.getPrerequisites(attributeName, Mode.TARGET)) { + J2ObjcMappingFileProvider provider = + dependencyInfoDatum.getProvider(J2ObjcMappingFileProvider.class); + if (provider != null) { + builder.add(provider); + } + } + } + } + + private static Artifact j2ObjcOutputHeaderMappingFile(RuleContext ruleContext) { + return ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".mapping.j2objc"); + } + + private static Artifact j2ObjcOutputDependencyMappingFile(RuleContext ruleContext) { + return ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".dependency_mapping.j2objc"); + } + + private J2ObjcSource buildJ2ObjcSource(RuleContext ruleContext, + Iterable<Artifact> javaInputSourceFiles) { + PathFragment objcFileRootRelativePath = ruleContext.getUniqueDirectory("_j2objc"); + PathFragment objcFilePath = ruleContext + .getConfiguration() + .getBinFragment() + .getRelative(objcFileRootRelativePath); + Iterable<Artifact> objcSrcs = getOutputObjcFiles(ruleContext, javaInputSourceFiles, + objcFileRootRelativePath, ".m"); + Iterable<Artifact> objcHdrs = getOutputObjcFiles(ruleContext, javaInputSourceFiles, + objcFileRootRelativePath, ".h"); + return new J2ObjcSource(ruleContext.getRule().getLabel(), objcSrcs, objcHdrs, objcFilePath, + SourceType.JAVA); + } + + private Iterable<Artifact> getOutputObjcFiles(RuleContext ruleContext, + Iterable<Artifact> javaSrcs, PathFragment objcFileRootRelativePath, String suffix) { + ImmutableList.Builder<Artifact> objcSources = ImmutableList.builder(); + + for (Artifact javaSrc : javaSrcs) { + objcSources.add(ruleContext.getRelatedArtifact( + objcFileRootRelativePath.getRelative(javaSrc.getExecPath()), suffix)); + } + + return objcSources.build(); + } +} 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 new file mode 100644 index 0000000000..e2224a8378 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java @@ -0,0 +1,110 @@ +// Copyright 2015 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.collect.nestedset.Order.STABLE_ORDER; + +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.RuleConfiguredTargetBuilder; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.packages.Type; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.java.J2ObjcConfiguration; +import com.google.devtools.build.lib.vfs.PathFragment; + +import java.util.List; + +/** + * Implementation for the "j2objc_library" rule, which exports ObjC source files translated from + * Java source files in java_library rules to dependent objc_binary rules for compilation and + * linking into the final application bundle. See {@link J2ObjcLibraryBaseRule} for details. + */ +public class J2ObjcLibrary implements RuleConfiguredTargetFactory { + + public static final String NO_ENTRY_CLASS_ERROR_MSG = + "Entry classes must be specified when flag --compilationMode=opt is on in order to" + + " perform J2ObjC dead code stripping."; + + @Override + public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { + checkAttributes(ruleContext); + + if (ruleContext.hasErrors()) { + return null; + } + + J2ObjcSrcsProvider j2ObjcSrcsProvider = new J2ObjcSrcsProvider.Builder() + .addTransitiveFromDeps(ruleContext) + .addEntryClasses(ruleContext.attributes().get("entry_classes", Type.STRING_LIST)) + .build(); + + ObjcProvider.Builder objcProvider = new ObjcProvider.Builder() + .addTransitiveAndPropagate(ruleContext.getPrerequisite( + "$jre_emul_lib", Mode.TARGET, ObjcProvider.class)) + .addTransitiveAndPropagate(ruleContext.getPrerequisites( + "deps", Mode.TARGET, ObjcProvider.class)); + + if (j2ObjcSrcsProvider.hasProtos()) { + if (ruleContext.attributes().has("$protobuf_lib", Type.LABEL)) { + objcProvider.addTransitiveAndPropagate(ruleContext.getPrerequisite( + "$protobuf_lib", Mode.TARGET, ObjcProvider.class)); + } 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."); + } + } + + for (J2ObjcSource j2objcSource : j2ObjcSrcsProvider.getSrcs()) { + objcProvider.addAll(ObjcProvider.HEADER, j2objcSource.getObjcHdrs()); + objcProvider.add(ObjcProvider.INCLUDE, j2objcSource.getObjcFilePath()); + objcProvider.add(ObjcProvider.INCLUDE, new PathFragment( + j2objcSource.getObjcFilePath(), + ruleContext.getConfiguration().getGenfilesFragment())); + } + + return new RuleConfiguredTargetBuilder(ruleContext) + .setFilesToBuild(NestedSetBuilder.<Artifact>emptySet(STABLE_ORDER)) + .add(RunfilesProvider.class, RunfilesProvider.EMPTY) + .addProvider(J2ObjcSrcsProvider.class, j2ObjcSrcsProvider) + .addProvider( + J2ObjcMappingFileProvider.class, ObjcRuleClasses.j2ObjcMappingFileProvider(ruleContext)) + .addProvider(ObjcProvider.class, objcProvider.build()) + .build(); + } + + private static void checkAttributes(RuleContext ruleContext) { + checkAttributes(ruleContext, "deps"); + checkAttributes(ruleContext, "exports"); + } + + private static void checkAttributes(RuleContext ruleContext, String attributeName) { + if (!ruleContext.attributes().has(attributeName, Type.LABEL_LIST)) { + return; + } + + List<String> entryClasses = ruleContext.attributes().get("entry_classes", Type.STRING_LIST); + J2ObjcConfiguration j2objcConfiguration = ruleContext.getFragment(J2ObjcConfiguration.class); + if (j2objcConfiguration.removeDeadCode() && (entryClasses == null || entryClasses.isEmpty())) { + ruleContext.attributeError("entry_classes", NO_ENTRY_CLASS_ERROR_MSG); + } + } +} 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 new file mode 100644 index 0000000000..5842402ad0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java @@ -0,0 +1,79 @@ +// Copyright 2015 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.attr; +import static com.google.devtools.build.lib.packages.Type.LABEL; +import static com.google.devtools.build.lib.packages.Type.STRING_LIST; + +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; + +/** + * Abstract rule definition for j2objc_library. + */ +public class J2ObjcLibraryBaseRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + // TODO(rduan): Add support for package prefixes. + return builder + /* <!-- #BLAZE_RULE(j2objc_library).ATTRIBUTE(entry_classes) --> + The list of Java classes whose translated ObjC counterparts will be referenced directly + by user ObjC code. This attibute is required if flag <code>--j2objc_dead_code_removal + </code> is on. The Java classes should be specified in their canonical names as defined by + <a href="http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.7">the Java + Language Specification.</a> + ${SYNOPSIS} + When flag <code>--j2objc_dead_code_removal</code> is specified, the list of entry classes + will be collected transitively and used as entry points to perform dead code analysis. + Unused classes will then be removed from the final ObjC app bundle. + <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/ + .add(attr("entry_classes", STRING_LIST)) + .add(attr("$jre_emul_jar", LABEL) + .value(env.getLabel("//third_party/java_src/j2objc/jre_emul:libjre_emul.jar"))) + .add(attr("$jre_emul_lib", LABEL) + .value(env.getLabel("//third_party/java_src/j2objc/jre_emul:jre_emul_lib"))) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("$j2objc_library_base") + .type(RuleClassType.ABSTRACT) + .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.CoptsRule.class) + .build(); + } +} + +// TODO(mthvedt): Add support and examples for open-source users. +/*<!-- #BLAZE_RULE (NAME = j2objc_library, TYPE = LIBRARY, FAMILY = Objective-C) --> + +${ATTRIBUTE_SIGNATURE} + +<p>This rule uses <a href="https://github.com/google/j2objc">J2ObjC</a> +to translate Java source files to Objective-C, which then can be used used as dependencies of +<code>objc_library</code> and <code>objc_binary</code> rules. More information about J2ObjC +can be found <a href="http://j2objc.org">here</a>. +</p> + + +${ATTRIBUTE_DEFINITION} + +<!-- #END_BLAZE_RULE -->*/ |