Blaze exports a feature for actions with objective c source in their transitive
closure.

PiperOrigin-RevId: 165934905
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
index db757a1..e0369a1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
@@ -105,6 +105,9 @@
 
   private static final String GENERATE_LINKMAP_FEATURE_NAME = "generate_linkmap";
 
+  /** Enabled if this target has objc sources in its transitive closure. */
+  private static final String CONTAINS_OBJC = "contains_objc_sources";
+
   private static final ImmutableList<String> ACTIVATED_ACTIONS =
       ImmutableList.of(
           "objc-compile",
@@ -251,7 +254,7 @@
                 outputArchive,
                 ccToolchain,
                 fdoSupport,
-                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration))
+                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider))
             .addActionInputs(objcProvider.getObjcLibraries())
             .addActionInputs(objcProvider.getCcLibraries())
             .addActionInputs(objcProvider.get(IMPORTED_LIBRARY).toSet())
@@ -327,7 +330,7 @@
                 binaryToLink,
                 toolchain,
                 fdoSupport,
-                getFeatureConfiguration(ruleContext, toolchain, buildConfiguration))
+                getFeatureConfiguration(ruleContext, toolchain, buildConfiguration, objcProvider))
             .setMnemonic("ObjcLink")
             .addActionInputs(bazelBuiltLibraries)
             .addActionInputs(objcProvider.getCcLibraries())
@@ -426,7 +429,7 @@
         new CcLibraryHelper(
                 ruleContext,
                 semantics,
-                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration),
+                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider),
                 CcLibraryHelper.SourceCategory.CC_AND_OBJC,
                 ccToolchain,
                 fdoSupport,
@@ -472,8 +475,11 @@
     return result;
   }
 
-  private FeatureConfiguration getFeatureConfiguration(RuleContext ruleContext,
-      CcToolchainProvider ccToolchain, BuildConfiguration configuration) {
+  private FeatureConfiguration getFeatureConfiguration(
+      RuleContext ruleContext,
+      CcToolchainProvider ccToolchain,
+      BuildConfiguration configuration,
+      ObjcProvider objcProvider) {
     boolean isHost = ruleContext.getConfiguration().isHostConfiguration();
     ImmutableSet.Builder<String> activatedCrosstoolSelectables =
         ImmutableSet.<String>builder()
@@ -524,6 +530,9 @@
     if (bitcodeMode != AppleBitcodeMode.NONE) {
       activatedCrosstoolSelectables.addAll(bitcodeMode.getFeatureNames());
     }
+    if (objcProvider.is(Flag.USES_OBJC)) {
+      activatedCrosstoolSelectables.add(CONTAINS_OBJC);
+    }
 
     activatedCrosstoolSelectables.addAll(ruleContext.getFeatures());
     try {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
index a58beff..ae1c7b7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
@@ -26,6 +26,7 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FLAG;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_OBJC;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
@@ -70,8 +71,10 @@
 import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
 import com.google.devtools.build.lib.rules.cpp.CcLinkParamsInfo;
 import com.google.devtools.build.lib.rules.cpp.CppCompilationContext;
+import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
 import com.google.devtools.build.lib.util.FileType;
+import com.google.devtools.build.lib.util.FileTypeSet;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.HashSet;
@@ -523,14 +526,22 @@
         }
 
         boolean usesCpp = false;
+        boolean usesObjc = false;
         for (Artifact sourceFile :
             Iterables.concat(artifacts.getSrcs(), artifacts.getNonArcSrcs())) {
           usesCpp = usesCpp || ObjcRuleClasses.CPP_SOURCES.matches(sourceFile.getExecPath());
+          usesObjc =
+              usesObjc
+                  || FileTypeSet.of(CppFileTypes.OBJC_SOURCE, CppFileTypes.OBJCPP_SOURCE)
+                      .matches(sourceFile.getExecPath().getPathString());
         }
 
         if (usesCpp) {
           objcProvider.add(FLAG, USES_CPP);
         }
+        if (usesObjc) {
+          objcProvider.add(FLAG, USES_OBJC);
+        }
       }
 
       if (alwayslink) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
index 502e055..c5e39a4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
@@ -349,6 +349,12 @@
      */
     USES_CPP,
 
+    /**
+     * Indicates that Objective-C (or Objective-C++) is used in any source file. This affects how
+     * the linker is invoked.
+     */
+    USES_OBJC,
+
     /** Indicates that Swift dependencies are present. This affects bundling actions. */
     USES_SWIFT,
 
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
index abbae40..2028571 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
@@ -59,6 +59,24 @@
     useConfiguration(ObjcCrosstoolMode.OFF, args);
   }
 
+  @Override
+  @Test
+  public void testObjcSourcesFeatureCC() throws Exception {
+    // Features are not exported by legacy actions.
+  }
+
+  @Override
+  @Test
+  public void testObjcSourcesFeatureObjc() throws Exception {
+    // Features are not exported by legacy actions.
+  }
+
+  @Override
+  @Test
+  public void testObjcSourcesFeatureObjcPlusPlus() throws Exception {
+    // Features are not exported by legacy actions.
+  }
+
   @Test
   public void testLibFileIsCorrectForSlashInTargetName() throws Exception {
     ConfiguredTarget target =
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
index 9e2d0c0..3409176 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
@@ -1601,4 +1601,45 @@
   public void testCustomModuleMap() throws Exception {
     checkCustomModuleMap(RULE_TYPE);
   }
+
+  private boolean containsObjcFeature(String srcName) throws Exception {
+     MockObjcSupport.setup(
+        mockToolsConfig,
+        "feature {",
+        "  name: 'contains_objc_sources'",
+        "  flag_set {",
+        "    flag_group {",
+        "      flag: 'DUMMY_FLAG'",
+        "    }",
+        "    action: 'c++-compile'",
+        "  }",
+        "}");
+    createLibraryTargetWriter("//bottom:lib").setList("srcs", srcName).write();
+    createLibraryTargetWriter("//middle:lib")
+        .setList("srcs", "b.cc")
+        .setList("deps", "//bottom:lib")
+        .write();
+    createLibraryTargetWriter("//top:lib")
+        .setList("srcs", "a.cc")
+        .setList("deps", "//middle:lib")
+        .write();
+
+    CommandAction compileAction = compileAction("//top:lib", "a.o");
+    return compileAction.getArguments().contains("DUMMY_FLAG");
+  }
+
+  @Test
+  public void testObjcSourcesFeatureCC() throws Exception {
+    assertThat(containsObjcFeature("c.cc")).isFalse();
+  }
+
+  @Test
+  public void testObjcSourcesFeatureObjc() throws Exception {
+     assertThat(containsObjcFeature("c.m")).isTrue();
+  }
+
+  @Test
+  public void testObjcSourcesFeatureObjcPlusPlus() throws Exception {
+     assertThat(containsObjcFeature("c.mm")).isTrue();
+  }
 }