libtool wrapper script to isolate the unfortunate hacks we must make to get around apple's buggy libtool tool

--
MOS_MIGRATED_REVID=123024674
diff --git a/src/BUILD b/src/BUILD
index de25d30..6604f6f 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -74,6 +74,7 @@
 OSX_DUMMY_TARGETS = [
     "src/tools/xcode/actoolwrapper/actoolwrapper",
     "src/tools/xcode/ibtoolwrapper/ibtoolwrapper",
+    "src/tools/xcode/libtool/libtool",
     "src/tools/xcode/momcwrapper/momcwrapper",
     "src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper",
     "src/tools/xcode/environment/environment_plist",
@@ -100,6 +101,7 @@
     srcs = [
         "//src/tools/xcode/actoolwrapper:actoolwrapper",
         "//src/tools/xcode/ibtoolwrapper:ibtoolwrapper",
+        "//src/tools/xcode/libtool:libtool",
         "//src/tools/xcode/momcwrapper:momcwrapper",
         "//src/tools/xcode/swiftstdlibtoolwrapper:swiftstdlibtoolwrapper",
         "//src/tools/xcode/environment:environment_plist",
@@ -295,6 +297,7 @@
         "//src/tools/xcode/actoolwrapper:srcs",
         "//src/tools/xcode/environment:srcs",
         "//src/tools/xcode/ibtoolwrapper:srcs",
+        "//src/tools/xcode/libtool:srcs",
         "//src/tools/xcode/momcwrapper:srcs",
         "//src/tools/xcode/realpath:srcs",
         "//src/tools/xcode/stdredirect:srcs",
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 72cfe3c..48d31f5 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
@@ -405,6 +405,7 @@
     builder.addRuleDefinition(new ObjcRuleClasses.CompileDependencyRule());
     builder.addRuleDefinition(new ObjcRuleClasses.ResourceToolsRule());
     builder.addRuleDefinition(new ObjcRuleClasses.XcrunRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.LibtoolRule());
     builder.addRuleDefinition(new ObjcRuleClasses.IpaRule());
     builder.addRuleDefinition(new ObjcRuleClasses.ReleaseBundlingToolsRule());
     builder.addRuleDefinition(new ObjcRuleClasses.WatchExtensionBundleRule());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
index 9ba7bb1..80b056e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AbstractJ2ObjcProtoAspect.java
@@ -90,6 +90,9 @@
         .add(attr("$xcrunwrapper", LABEL).cfg(HOST).exec()
             .value(Label.parseAbsoluteUnchecked(
                 toolsRepository + "//tools/objc:xcrunwrapper")))
+        .add(attr(ObjcRuleClasses.LIBTOOL_ATTRIBUTE, LABEL).cfg(HOST).exec()
+              .value(Label.parseAbsoluteUnchecked(
+                toolsRepository + "//tools/objc:libtool")))
         .add(attr(":xcode_config", LABEL)
             .allowedRuleClasses("xcode_config")
             .checkConstraints()
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 882faeb..3fff5d5 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
@@ -38,7 +38,6 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.COMPILABLE_SRCS_TYPE;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.DSYMUTIL;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.HEADERS;
-import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.LIBTOOL;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.NON_ARC_SRCS_TYPE;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.PRECOMPILED_SRCS_TYPE;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SRCS_TYPE;
@@ -143,7 +142,14 @@
    * Returns the location of the xcrunwrapper tool.
    */
   public static final FilesToRunProvider xcrunwrapper(RuleContext ruleContext) {
-   return ruleContext.getExecutablePrerequisite("$xcrunwrapper", Mode.HOST);
+    return ruleContext.getExecutablePrerequisite("$xcrunwrapper", Mode.HOST);
+  }
+
+  /**
+   * Returns the location of the libtool tool.
+   */
+  public static final FilesToRunProvider libtool(RuleContext ruleContext) {
+    return ruleContext.getExecutablePrerequisite(ObjcRuleClasses.LIBTOOL_ATTRIBUTE, Mode.HOST);
   }
 
   /**
@@ -719,9 +725,8 @@
     actions.add(ObjcRuleClasses.spawnAppleEnvActionBuilder(
             ruleContext, appleConfiguration.getIosCpuPlatform())
         .setMnemonic("ObjcLink")
-        .setExecutable(xcrunwrapper(ruleContext))
+        .setExecutable(libtool(ruleContext))
         .setCommandLine(new CustomCommandLine.Builder()
-            .add(LIBTOOL)
             .add("-static")
             .add("-filelist").add(objList.getExecPathString())
             .add("-arch_only").add(appleConfiguration.getIosCpu())
@@ -750,9 +755,8 @@
     ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(
             ruleContext, appleConfiguration.getIosCpuPlatform())
         .setMnemonic("ObjcLink")
-        .setExecutable(xcrunwrapper(ruleContext))
+        .setExecutable(libtool(ruleContext))
         .setCommandLine(new CustomCommandLine.Builder()
-            .add(LIBTOOL)
             .add("-static")
             .add("-arch_only").add(appleConfiguration.getIosCpu())
             .add("-syslibroot").add(AppleToolchain.sdkDir())
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
index 99bf436..895312c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcAspect.java
@@ -115,6 +115,9 @@
         .add(attr("$xcrunwrapper", LABEL).cfg(HOST).exec()
             .value(Label.parseAbsoluteUnchecked(
                 toolsRepository + "//tools/objc:xcrunwrapper")))
+        .add(attr(ObjcRuleClasses.LIBTOOL_ATTRIBUTE, LABEL).cfg(HOST).exec()
+              .value(Label.parseAbsoluteUnchecked(
+                toolsRepository + "//tools/objc:libtool")))
         .add(attr(":xcode_config", LABEL)
             .allowedRuleClasses("xcode_config")
             .checkConstraints()
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
index ec91db8..2cb9f9c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
@@ -154,7 +154,8 @@
     return RuleDefinition.Metadata.builder()
         .name("objc_proto_library")
         .factoryClass(ObjcProtoLibrary.class)
-        .ancestors(BaseRuleClasses.RuleBase.class, ObjcRuleClasses.XcrunRule.class)
+        .ancestors(BaseRuleClasses.RuleBase.class, ObjcRuleClasses.LibtoolRule.class,
+            ObjcRuleClasses.XcrunRule.class)
         .build();
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
index bad5520..48981fb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
@@ -61,10 +61,15 @@
  * Shared rule classes and associated utility code for Objective-C rules.
  */
 public class ObjcRuleClasses {
+
+  /**
+   * Name of the attribute used for implicit dependency on the libtool wrapper.
+   */
+  public static final String LIBTOOL_ATTRIBUTE = "$libtool";
+
   static final String CLANG = "clang";
   static final String CLANG_PLUSPLUS = "clang++";
   static final String SWIFT = "swift";
-  static final String LIBTOOL = "libtool";
   static final String DSYMUTIL = "dsymutil";
   static final String LIPO = "lipo";
   static final String STRIP = "strip";
@@ -746,12 +751,34 @@
               BaseRuleClasses.RuleBase.class,
               CompileDependencyRule.class,
               CoptsRule.class,
+              LibtoolRule.class,
               XcrunRule.class)
           .build();
     }
   }
 
   /**
+   * Common attributes for {@code objc_*} rules that need to call libtool.
+   */
+  public static class LibtoolRule implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+      return builder
+          .add(attr(LIBTOOL_ATTRIBUTE, LABEL).cfg(HOST).exec()
+              .value(env.getToolsLabel("//tools/objc:libtool")))
+          .build();
+    }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_libtool_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(XcrunRule.class)
+          .build();
+    }
+  }
+
+  /**
    * Common attributes for {@code objc_*} rules that can optionally be set to {@code alwayslink}.
    */
   public static class AlwaysLinkRule implements RuleDefinition {
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD
index 2b3578a..4f5663e 100644
--- a/src/test/shell/bazel/BUILD
+++ b/src/test/shell/bazel/BUILD
@@ -24,6 +24,7 @@
             "//src/tools/xcode/actoolwrapper",
             "//src/tools/xcode/environment:environment_plist",
             "//src/tools/xcode/ibtoolwrapper",
+            "//src/tools/xcode/libtool",
             "//src/tools/xcode/momcwrapper",
             "//src/tools/xcode/realpath",
             "//src/tools/xcode/stdredirect:StdRedirect.dylib",
diff --git a/src/tools/xcode/libtool/BUILD b/src/tools/xcode/libtool/BUILD
new file mode 100644
index 0000000..1d7fb58
--- /dev/null
+++ b/src/tools/xcode/libtool/BUILD
@@ -0,0 +1,14 @@
+package(default_visibility = ["//src:__subpackages__"])
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+)
+
+sh_binary(
+    name = "libtool",
+    srcs = ["libtool.sh"],
+    data = [
+        "//src/tools/xcode/xcrunwrapper",
+    ],
+)
diff --git a/src/tools/xcode/libtool/README b/src/tools/xcode/libtool/README
new file mode 100644
index 0000000..7b81753
--- /dev/null
+++ b/src/tools/xcode/libtool/README
@@ -0,0 +1,9 @@
+libtool.sh runs the command passed to it using "xcrun libtool".
+
+It creates symbolic links for all input files with a content-hash appended
+to their original name (foo.o becomes foo_{md5sum}.o). This is to circumvent
+a bug in the original tool that arises when two input files have the same
+base name (even if they are in different directories).
+
+xcrun only runs on Darwin, so libtool.sh only runs on Darwin.
+
diff --git a/src/tools/xcode/libtool/libtool.sh b/src/tools/xcode/libtool/libtool.sh
new file mode 100755
index 0000000..c72f229
--- /dev/null
+++ b/src/tools/xcode/libtool/libtool.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# 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.
+#
+# libtool.sh runs the command passed to it using "xcrunwrapper libtool".
+#
+# It creates symbolic links for all input files with a content-hash appended
+# to their original name (foo.o becomes foo_{md5sum}.o). This is to circumvent
+# a bug in the original tool that arises when two input files have the same
+# base name (even if they are in different directories).
+
+set -eu
+
+MY_LOCATION=${MY_LOCATION:-"$0.runfiles/bazel_tools/tools/objc"}
+WRAPPER="${MY_LOCATION}/xcrunwrapper.sh"
+
+# TODO(b/28347228): When all callers of "xcrunwrapper libtool" are migrated to
+# using this script, move the symlinking behavior to this script.
+"${WRAPPER}" libtool "$@"
diff --git a/tools/objc/BUILD b/tools/objc/BUILD
index 1fa4628..149a9bb 100644
--- a/tools/objc/BUILD
+++ b/tools/objc/BUILD
@@ -64,6 +64,14 @@
 )
 
 sh_binary(
+    name = "libtool",
+    srcs = [":libtool.sh"],
+    data = [
+        ":xcrunwrapper",
+    ],
+)
+
+sh_binary(
     name = "actoolwrapper",
     srcs = [":actoolwrapper.sh"],
     data = [