aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/objc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/objc')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/BazelJ2ObjcLibraryRule.java55
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java282
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcCommandLineOptions.java48
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java128
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java110
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibraryBaseRule.java79
7 files changed, 527 insertions, 176 deletions
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/J2ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcCommandLineOptions.java
deleted file mode 100644
index 7d1f88b4d4..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcCommandLineOptions.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 com.google.common.collect.Multimap;
-import com.google.devtools.build.lib.analysis.config.FragmentOptions;
-import com.google.devtools.build.lib.syntax.Label;
-import com.google.devtools.common.options.Converters;
-import com.google.devtools.common.options.Option;
-
-import java.util.List;
-
-/**
- * Command-line Options for J2ObjC translation of Java source code to ObjC.
- */
-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."
- )
- public List<String> translationFlags;
-
- @Option(name = "j2objc_dead_code_removal",
- defaultValue = "false",
- category = "undocumented",
- help = "Whether to perform J2ObjC dead code removal to strip unused code from the final app "
- + "bundle."
- )
- public boolean removeDeadCode;
-
- @Override
- public void addAllLabels(Multimap<String, Label> labelMap) {}
-}
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/objc/J2ObjcConfiguration.java
deleted file mode 100644
index afb3038169..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcConfiguration.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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 com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
-import com.google.devtools.build.lib.analysis.config.BuildOptions;
-import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
-import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
-import com.google.devtools.build.lib.analysis.config.FragmentOptions;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
-
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * A J2ObjC transpiler configuration containing J2ObjC translation flags.
- */
-public class J2ObjcConfiguration extends Fragment {
- /**
- * Always-on flags for J2ObjC translation. These flags will always be used for invoking the J2ObjC
- * transpiler. See https://github.com/google/j2objc/wiki/j2objc for flag documentation.
- */
- private static final Set<String> J2OBJC_ALWAYS_ON_TRANSLATION_FLAGS = ImmutableSet.of(
- "-encoding",
- "UTF-8",
- "--doc-comments",
- "--extract-unsequenced",
- "--final-methods-as-functions",
- "--hide-private-members",
- "--segmented-headers",
- "-XcombineJars");
-
- /**
- * Allowed flags for J2ObjC translation. See https://github.com/google/j2objc/wiki/j2objc for flag
- * documentation.
- */
- static final Set<String> J2OBJC_BLACKLISTED_TRANSLATION_FLAGS =
- ImmutableSet.of("--prefixes", "--prefix", "-x");
-
- static final String INVALID_TRANSLATION_FLAGS_MSG_TEMPLATE =
- "J2Objc translation flags: %s not supported. Unsupported flags are: %s";
-
- /**
- * Configuration loader for {@link J2ObjcConfiguration}.
- */
- public static class Loader implements ConfigurationFragmentFactory {
- @Override
- public Fragment create(ConfigurationEnvironment env, BuildOptions buildOptions) {
- return new J2ObjcConfiguration(buildOptions.get(J2ObjcCommandLineOptions.class));
- }
-
- @Override
- public Class<? extends Fragment> creates() {
- return J2ObjcConfiguration.class;
- }
-
- @Override
- public ImmutableSet<Class<? extends FragmentOptions>> requiredOptions() {
- return ImmutableSet.<Class<? extends FragmentOptions>>of(J2ObjcCommandLineOptions.class);
- }
- }
-
- private final Set<String> translationFlags;
- private final boolean removeDeadCode;
-
- J2ObjcConfiguration(J2ObjcCommandLineOptions j2ObjcOptions) {
- this.removeDeadCode = j2ObjcOptions.removeDeadCode;
- this.translationFlags = ImmutableSet.<String>builder()
- .addAll(j2ObjcOptions.translationFlags)
- .addAll(J2OBJC_ALWAYS_ON_TRANSLATION_FLAGS)
- .build();
- }
-
- /**
- * Returns the translation flags used to invoke the J2ObjC transpiler. The returned flags contain
- * both the always-on flags from {@link #J2OBJC_ALWAYS_ON_TRANSLATION_FLAGS} and user-specified
- * flags from {@link J2ObjcCommandLineOptions}. The set of valid flags can be found at
- * {@link #J2OBJC_BLACKLISTED_TRANSLATION_FLAGS}.
- */
- public Iterable<String> getTranslationFlags() {
- return translationFlags;
- }
-
- /**
- * Returns whether to perform J2ObjC dead code removal. If true, the list of entry classes will be
- * collected transitively throuh "entry_classes" attribute on j2objc_library and used as entry
- * points to perform dead code analysis. Unused classes will then be removed from the final ObjC
- * app bundle.
- */
- public boolean removeDeadCode() {
- return removeDeadCode;
- }
-
- @Override
- public String getName() {
- return "J2ObjC";
- }
-
- @Override
- public String cacheKey() {
- return Joiner.on(" ").join(translationFlags) + "-" + String.valueOf(removeDeadCode);
- }
-
- @Override
- public void reportInvalidOptions(EventHandler reporter, BuildOptions buildOptions) {
- if (!Collections.disjoint(translationFlags, J2OBJC_BLACKLISTED_TRANSLATION_FLAGS)) {
- String errorMsg = String.format(INVALID_TRANSLATION_FLAGS_MSG_TEMPLATE,
- Joiner.on(",").join(translationFlags),
- Joiner.on(",").join(J2OBJC_BLACKLISTED_TRANSLATION_FLAGS));
- reporter.handle(Event.error(errorMsg));
- }
- }
-}
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 -->*/