Refactor compilation, archiving, and fully linking logic from
experimental_objc_library to make it suitable for reuse.

--
MOS_MIGRATED_REVID=135270294
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolSupport.java
new file mode 100644
index 0000000..a01e15e4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolSupport.java
@@ -0,0 +1,229 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.rules.objc;
+
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+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.TransitiveInfoProviderMap;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
+import com.google.devtools.build.lib.rules.cpp.CppLinkAction;
+import com.google.devtools.build.lib.rules.cpp.CppLinkActionBuilder;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
+import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.Collection;
+
+/**
+ * Support for rules that compile, archive, and link sources using the c++ rules backend, including
+ * the crosstool.
+ */
+public class CrosstoolSupport {
+
+  private static final String OBJC_MODULE_FEATURE_NAME = "use_objc_modules";
+  private static final Iterable<String> ACTIVATED_ACTIONS =
+      ImmutableList.of(
+          "objc-compile",
+          "objc++-compile",
+          "objc-archive",
+          "objc-fully-link",
+          "assemble",
+          "preprocess-assemble",
+          "c-compile",
+          "c++-compile");
+
+  private final RuleContext ruleContext;
+  private final ObjcVariablesExtension variablesExtension;
+  private final IntermediateArtifacts intermediateArtifacts;
+  private final CompilationSupport compilationSupport;
+  private final CompilationArtifacts compilationArtifacts;
+  private final FeatureConfiguration featureConfiguration;
+
+  /**
+   * Creates a new instance of CrosstoolSupport.
+   *
+   * @param ruleContext the RuleContext for the target in question
+   * @param objcProvider the provider to query in populating build variables for templating the
+   *     crosstool
+   * @return a CrosstoolSupport instance that can register compile and archive actions
+   */
+  public CrosstoolSupport(RuleContext ruleContext, ObjcProvider objcProvider)
+      throws InterruptedException {
+    this.ruleContext = ruleContext;
+    this.compilationArtifacts = CompilationSupport.compilationArtifacts(ruleContext);
+    this.intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext);
+    this.compilationSupport = new CompilationSupport(ruleContext);
+    this.featureConfiguration = getFeatureConfiguration(ruleContext);
+    this.variablesExtension =
+        new ObjcVariablesExtension(
+            ruleContext,
+            objcProvider,
+            compilationArtifacts,
+            ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB),
+            intermediateArtifacts,
+            ruleContext.getConfiguration());
+  }
+
+  /**
+   * Registers a {@link CppCompileAction} to build objc or objc++ source.
+   *
+   * @param common the common instance that should be queried in the construction of a compile
+   *     action
+   * @return providers that should be exported by the calling rule implementation
+   */
+  public TransitiveInfoProviderMap registerCompileActions(ObjcCommon common)
+      throws RuleErrorException, InterruptedException {
+    return createCcLibraryHelper(common).build().getProviders();
+  }
+
+  /**
+   * Registers a {@link CppCompileAction} to build objc or objc++ source as well as a {@link
+   * CppLinkAction} to archive the resulting object files.
+   *
+   * @param common the common instance that should be queried in the construction of a compile and
+   *     archive action
+   * @return providers that should be exported by the calling rule implementation
+   */
+  public TransitiveInfoProviderMap registerCompileAndArchiveActions(ObjcCommon common)
+      throws RuleErrorException, InterruptedException {
+    Artifact objList = intermediateArtifacts.archiveObjList();
+
+    // TODO(b/30783125): Signal the need for this action in the CROSSTOOL.
+    compilationSupport.registerObjFilelistAction(
+        getObjFiles(compilationArtifacts, intermediateArtifacts), objList);
+
+    return createCcLibraryHelper(common)
+        .setLinkType(LinkTargetType.OBJC_ARCHIVE)
+        .addLinkActionInput(objList)
+        .build()
+        .getProviders();
+  }
+
+  /**
+   * Registers a {@link CppLinkAction} to produce a fully linked archive.
+   *
+   * @param common the common instance that hsould be queried in the construction of a fully link
+   *     action
+   */
+  public void registerFullyLinkAction(ObjcCommon common) throws InterruptedException {
+    Artifact fullyLinkedArchive =
+        ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB);
+    PathFragment labelName = new PathFragment(ruleContext.getLabel().getName());
+    String libraryIdentifier =
+        ruleContext
+            .getPackageDirectory()
+            .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
+            .getPathString();
+    CppLinkAction fullyLinkAction =
+        new CppLinkActionBuilder(ruleContext, fullyLinkedArchive)
+            .addActionInputs(common.getObjcProvider().getObjcLibraries())
+            .addActionInputs(common.getObjcProvider().getCcLibraries())
+            .addActionInputs(common.getObjcProvider().get(IMPORTED_LIBRARY).toSet())
+            .setLinkType(LinkTargetType.OBJC_FULLY_LINKED_ARCHIVE)
+            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
+            .setLibraryIdentifier(libraryIdentifier)
+            .addVariablesExtension(variablesExtension)
+            .setFeatureConfiguration(featureConfiguration)
+            .build();
+    ruleContext.registerAction(fullyLinkAction);
+  }
+
+  private static FeatureConfiguration getFeatureConfiguration(RuleContext ruleContext) {
+    CcToolchainProvider toolchain =
+        ruleContext
+            .getPrerequisite(":cc_toolchain", Mode.TARGET)
+            .getProvider(CcToolchainProvider.class);
+
+    ImmutableList.Builder<String> activatedCrosstoolSelectables =
+        ImmutableList.<String>builder()
+            .addAll(ACTIVATED_ACTIONS)
+            .addAll(
+                ruleContext
+                    .getFragment(AppleConfiguration.class)
+                    .getBitcodeMode()
+                    .getFeatureNames())
+            // We create a module map by default to allow for swift interop.
+            .add(OBJC_MODULE_FEATURE_NAME)
+            .add(CppRuleClasses.MODULE_MAPS)
+            .add(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET)
+            .add(CppRuleClasses.DEPENDENCY_FILE)
+            .add(CppRuleClasses.INCLUDE_PATHS);
+
+    if (ruleContext.getPrerequisiteArtifact("pch", Mode.TARGET) != null) {
+      activatedCrosstoolSelectables.add("pch");
+    }
+ 
+    return toolchain.getFeatures().getFeatureConfiguration(activatedCrosstoolSelectables.build());
+  }
+
+  private CcLibraryHelper createCcLibraryHelper(ObjcCommon common) {
+    CompilationAttributes compilationAttributes =
+        CompilationAttributes.Builder.fromRuleContext(ruleContext).build();
+    PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
+    Collection<Artifact> arcSources = Sets.newHashSet(compilationArtifacts.getSrcs());
+    Collection<Artifact> nonArcSources = Sets.newHashSet(compilationArtifacts.getNonArcSrcs());
+    Collection<Artifact> privateHdrs = Sets.newHashSet(compilationArtifacts.getPrivateHdrs());
+    Collection<Artifact> publicHdrs = Sets.newHashSet(compilationAttributes.hdrs());
+    Artifact pchHdr = ruleContext.getPrerequisiteArtifact("pch", Mode.TARGET);
+    ImmutableList<Artifact> pchHdrList =
+        (pchHdr != null) ? ImmutableList.<Artifact>of(pchHdr) : ImmutableList.<Artifact>of();
+    return new CcLibraryHelper(
+            ruleContext,
+            new ObjcCppSemantics(common.getObjcProvider()),
+            featureConfiguration,
+            CcLibraryHelper.SourceCategory.CC_AND_OBJC)
+        .addSources(arcSources, ImmutableMap.of("objc_arc", ""))
+        .addSources(nonArcSources, ImmutableMap.of("no_objc_arc", ""))
+        .addSources(privateHdrs)
+        .addDefines(common.getObjcProvider().get(DEFINE))
+        .enableCompileProviders()
+        .addPublicHeaders(publicHdrs)
+        .addPublicHeaders(pchHdrList)
+        .addPrecompiledFiles(precompiledFiles)
+        .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET))
+        .addCopts(compilationSupport.getCompileRuleCopts())
+        .addIncludeDirs(common.getObjcProvider().get(INCLUDE))
+        .addCopts(ruleContext.getFragment(ObjcConfiguration.class).getCoptsForCompilationMode())
+        .addSystemIncludeDirs(common.getObjcProvider().get(INCLUDE_SYSTEM))
+        .setCppModuleMap(intermediateArtifacts.moduleMap())
+        .addVariableExtension(variablesExtension);
+  }
+
+  private static ImmutableList<Artifact> getObjFiles(
+      CompilationArtifacts compilationArtifacts, IntermediateArtifacts intermediateArtifacts) {
+    ImmutableList.Builder<Artifact> result = new ImmutableList.Builder<>();
+    for (Artifact sourceFile : compilationArtifacts.getSrcs()) {
+      result.add(intermediateArtifacts.objFile(sourceFile));
+    }
+    for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) {
+      result.add(intermediateArtifacts.objFile(nonArcSourceFile));
+    }
+    return result.build();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
index c71e3e4..eeff405 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
@@ -14,45 +14,21 @@
 
 package com.google.devtools.build.lib.rules.objc;
 
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE_SYSTEM;
 import static com.google.devtools.build.lib.rules.objc.XcodeProductType.LIBRARY_STATIC;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
 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.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
-import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
-import com.google.devtools.build.lib.rules.cpp.CppLinkAction;
-import com.google.devtools.build.lib.rules.cpp.CppLinkActionBuilder;
-import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
-import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
-import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
-import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles;
 import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
 import com.google.devtools.build.lib.syntax.Type;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.Collection;
 
 /** Implementation for experimental_objc_library. */
 public class ExperimentalObjcLibrary implements RuleConfiguredTargetFactory {
 
-  private static final String OBJC_MODULE_FEATURE_NAME = "use_objc_modules";
-  private static final Iterable<String> ACTIVATED_ACTIONS =
-      ImmutableList.of("objc-compile", "objc++-compile", "objc-archive", "objc-fully-link",
-          "assemble", "preprocess-assemble", "c-compile", "c++-compile");
-
   @Override
   public ConfiguredTarget create(RuleContext ruleContext) 
     throws InterruptedException, RuleErrorException {
@@ -71,64 +47,21 @@
 
     CompilationArtifacts compilationArtifacts =
         CompilationSupport.compilationArtifacts(ruleContext);
-    CompilationAttributes compilationAttributes =
-        CompilationAttributes.Builder.fromRuleContext(ruleContext).build();
-    PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
     CompilationSupport compilationSupport = new CompilationSupport(ruleContext);
-    IntermediateArtifacts intermediateArtifacts =
-        ObjcRuleClasses.intermediateArtifacts(ruleContext);
 
     ObjcCommon common = common(ruleContext);
-    ObjcVariablesExtension variablesExtension =
-        new ObjcVariablesExtension(
-            ruleContext,
-            common.getObjcProvider(),
-            compilationArtifacts,
-            ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB),
-            intermediateArtifacts,
-            ruleContext.getConfiguration());
 
-    FeatureConfiguration featureConfiguration = getFeatureConfiguration(ruleContext);
+    CrosstoolSupport crosstoolSupport = new CrosstoolSupport(ruleContext, common.getObjcProvider());
 
-    Collection<Artifact> arcSources = Sets.newHashSet(compilationArtifacts.getSrcs());
-    Collection<Artifact> nonArcSources = Sets.newHashSet(compilationArtifacts.getNonArcSrcs());
-    Collection<Artifact> privateHdrs = Sets.newHashSet(compilationArtifacts.getPrivateHdrs());
-    Collection<Artifact> publicHdrs = Sets.newHashSet(compilationAttributes.hdrs());
-    Artifact pchHdr = ruleContext.getPrerequisiteArtifact("pch", Mode.TARGET);
-    ImmutableList<Artifact> pchHdrList = (pchHdr != null)
-        ? ImmutableList.<Artifact>of(pchHdr)
-        : ImmutableList.<Artifact>of();
-
-    CcLibraryHelper helper =
-        new CcLibraryHelper(
-                ruleContext,
-                new ObjcCppSemantics(common.getObjcProvider()),
-                featureConfiguration,
-                CcLibraryHelper.SourceCategory.CC_AND_OBJC)
-            .addSources(arcSources, ImmutableMap.of("objc_arc", ""))
-            .addSources(nonArcSources, ImmutableMap.of("no_objc_arc", ""))
-            .addSources(privateHdrs)
-            .addDefines(common.getObjcProvider().get(DEFINE))
-            .enableCompileProviders()
-            .addPublicHeaders(publicHdrs)
-            .addPublicHeaders(pchHdrList)
-            .addPrecompiledFiles(precompiledFiles)
-            .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET))
-            .addCopts(compilationSupport.getCompileRuleCopts())
-            .addIncludeDirs(common.getObjcProvider().get(INCLUDE))
-            .addCopts(ruleContext.getFragment(ObjcConfiguration.class).getCoptsForCompilationMode())
-            .addSystemIncludeDirs(common.getObjcProvider().get(INCLUDE_SYSTEM))
-            .addVariableExtension(variablesExtension)
-            .setCppModuleMap(ObjcRuleClasses.intermediateArtifacts(ruleContext).moduleMap());
-
+    TransitiveInfoProviderMap compilationProviders;
     if (compilationArtifacts.getArchive().isPresent()) {
-      registerArchiveAction(
-          intermediateArtifacts, compilationSupport, compilationArtifacts, helper);
+      compilationProviders = crosstoolSupport.registerCompileAndArchiveActions(common);
+    } else {
+      compilationProviders = crosstoolSupport.registerCompileActions(common);
     }
-    registerFullyLinkAction(ruleContext, common, variablesExtension, featureConfiguration);
-
-    CcLibraryHelper.Info info = helper.build();
-
+    
+    crosstoolSupport.registerFullyLinkAction(common);
+    
     NestedSetBuilder<Artifact> filesToBuild =
         NestedSetBuilder.<Artifact>stableOrder().addAll(common.getCompiledArchive().asSet());
 
@@ -150,80 +83,12 @@
 
     return ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build())
         .addProvider(ObjcProvider.class, common.getObjcProvider())
-        .addProviders(info.getProviders())
+        .addProviders(compilationProviders)
         .addProvider(ObjcProvider.class, common.getObjcProvider())
         .addProvider(XcodeProvider.class, xcodeProviderBuilder.build())
         .build();
   }
 
-  private static FeatureConfiguration getFeatureConfiguration(RuleContext ruleContext) {
-    CcToolchainProvider toolchain =
-        ruleContext
-            .getPrerequisite(":cc_toolchain", Mode.TARGET)
-            .getProvider(CcToolchainProvider.class);
-
-    ImmutableList.Builder<String> activatedCrosstoolSelectables =
-        ImmutableList.<String>builder().addAll(ACTIVATED_ACTIONS);
-
-    if (ruleContext.getPrerequisiteArtifact("pch", Mode.TARGET) != null) {
-      activatedCrosstoolSelectables.add("pch");
-    }
-
-    activatedCrosstoolSelectables.addAll(
-        ruleContext.getFragment(AppleConfiguration.class).getBitcodeMode().getFeatureNames());
-
-    // We create a module map by default to allow for swift interop.
-    activatedCrosstoolSelectables.add(OBJC_MODULE_FEATURE_NAME);
-    activatedCrosstoolSelectables.add(CppRuleClasses.MODULE_MAPS);
-    activatedCrosstoolSelectables.add(CppRuleClasses.COMPILE_ACTION_FLAGS_IN_FLAG_SET);
-    activatedCrosstoolSelectables.add(CppRuleClasses.DEPENDENCY_FILE);
-    activatedCrosstoolSelectables.add(CppRuleClasses.INCLUDE_PATHS);
-
-    return toolchain.getFeatures().getFeatureConfiguration(activatedCrosstoolSelectables.build());
-  }
-
-  private static void registerArchiveAction(
-      IntermediateArtifacts intermediateArtifacts,
-      CompilationSupport compilationSupport,
-      CompilationArtifacts compilationArtifacts,
-      CcLibraryHelper helper) {
-    Artifact objList = intermediateArtifacts.archiveObjList();
-
-    // TODO(b/30783125): Signal the need for this action in the CROSSTOOL.
-    compilationSupport.registerObjFilelistAction(
-        getObjFiles(compilationArtifacts, intermediateArtifacts), objList);
-
-    helper.setLinkType(LinkTargetType.OBJC_ARCHIVE).addLinkActionInput(objList);
-  }
-
-  private static void registerFullyLinkAction(
-      RuleContext ruleContext,
-      ObjcCommon common,
-      VariablesExtension variablesExtension,
-      FeatureConfiguration featureConfiguration)
-      throws InterruptedException {
-    Artifact fullyLinkedArchive =
-        ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB);
-    PathFragment labelName = new PathFragment(ruleContext.getLabel().getName());
-    String libraryIdentifier =
-        ruleContext
-            .getPackageDirectory()
-            .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
-            .getPathString();
-    CppLinkAction fullyLinkAction =
-        new CppLinkActionBuilder(ruleContext, fullyLinkedArchive)
-            .addActionInputs(common.getObjcProvider().getObjcLibraries())
-            .addActionInputs(common.getObjcProvider().getCcLibraries())
-            .addActionInputs(common.getObjcProvider().get(IMPORTED_LIBRARY).toSet())
-            .setLinkType(LinkTargetType.OBJC_FULLY_LINKED_ARCHIVE)
-            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-            .setLibraryIdentifier(libraryIdentifier)
-            .addVariablesExtension(variablesExtension)
-            .setFeatureConfiguration(featureConfiguration)
-            .build();
-    ruleContext.registerAction(fullyLinkAction);
-  }
-
   /** Throws errors or warnings for bad attribute state. */
   private static void validateAttributes(RuleContext ruleContext) {
     for (String copt : ObjcCommon.getNonCrosstoolCopts(ruleContext)) {
@@ -254,18 +119,4 @@
         .setHasModuleMap()
         .build();
   }
-  
-  private static ImmutableList<Artifact> getObjFiles(
-      CompilationArtifacts compilationArtifacts, IntermediateArtifacts intermediateArtifacts) {
-    ImmutableList.Builder<Artifact> result = new ImmutableList.Builder<>();
-    for (Artifact sourceFile : compilationArtifacts.getSrcs()) {
-      Artifact objFile = intermediateArtifacts.objFile(sourceFile);
-      result.add(objFile);
-    }
-    for (Artifact nonArcSourceFile : compilationArtifacts.getNonArcSrcs()) {
-      Artifact objFile = intermediateArtifacts.objFile(nonArcSourceFile);
-      result.add(objFile);
-    }
-    return result.build();
-  }
 }