Add a way to select non-default Xcode toolchain

* Adds a flag --xcode_toolchain which sets TOOLCHAINS env variable for xcrun.
* Updates swift_library to work with this flag when selecting Swift runtime location.
* By default the flag has a null value and is not set in env.

--
MOS_MIGRATED_REVID=135033093
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
index 5d2830a..3d71ca5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
@@ -227,6 +227,17 @@
     }
   }
 
+  @Option(
+    name = "xcode_toolchain",
+    defaultValue = "null",
+    category = "flags",
+    help = "The identifier of an Xcode toolchain to use for builds. Currently only the toolchains "
+           + "that ship with Xcode are supported. For example, in addition to the default toolchain"
+           + " Xcode 8 has 'com.apple.dt.toolchain.Swift_2_3' which can be used for building legacy"
+           + " Swift code."
+  )
+  public String xcodeToolchain;
+
   @Option(name = "apple_bitcode",
       converter = AppleBitcodeMode.Converter.class,
       // TODO(blaze-team): Default to embedded_markers when fully implemented.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
index 59a6fc1..e0d2427 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
@@ -84,6 +84,7 @@
   private final ImmutableList<String> tvosCpus;
   private final AppleBitcodeMode bitcodeMode;
   private final Label xcodeConfigLabel;
+  @Nullable private final String xcodeToolchain;
   @Nullable private final Label defaultProvisioningProfileLabel;
   private final boolean disableNativeSwiftRules;
 
@@ -127,6 +128,7 @@
     this.xcodeConfigLabel =
         Preconditions.checkNotNull(appleOptions.xcodeVersionConfig, "xcodeConfigLabel");
     this.defaultProvisioningProfileLabel = appleOptions.defaultProvisioningProfile;
+    this.xcodeToolchain = appleOptions.xcodeToolchain;
     this.disableNativeSwiftRules = appleOptions.disableNativeSwiftRules;
   }
 
@@ -519,6 +521,17 @@
     return Joiner.on('-').join(components);
   }
 
+  /** Returns the identifier for an Xcode toolchain to use with tools. */
+  @SkylarkCallable(
+    name = "xcode_toolchain",
+    doc = "Identifier for the custom Xcode toolchain to use in build or None if not specified",
+    allowReturnNones = true,
+    structField = true
+  )
+  public String getXcodeToolchain() {
+    return xcodeToolchain;
+  }
+
   /**
    * Whether the native Swift support should be disabled. Used to deprecate said functionality.
    */
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 fa16aaf..8136e83 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
@@ -1445,9 +1445,22 @@
     }
 
     if (objcProvider.is(USES_SWIFT)) {
-      commandLine
-          .add("-L")
-          .add(AppleToolchain.swiftLibDir(appleConfiguration.getSingleArchPlatform()));
+      // Check if there's a swift library path already. If that's not the case - fall back to
+      // the default one. This is for backwards compatibility with Swift native rules.
+      // TODO(b/30281236): Remove when native Swift is deprecated.
+      boolean swiftLibDirSet = false;
+      for (String arg : objcProvider.get(ObjcProvider.LINKOPT)) {
+        if (arg.startsWith("-L") && arg.contains("usr/lib/swift")) {
+          swiftLibDirSet = true;
+          break;
+        }
+      }
+
+      if (!swiftLibDirSet) {
+        commandLine
+            .add("-L")
+            .add(AppleToolchain.swiftLibDir(appleConfiguration.getSingleArchPlatform()));
+      }
     }
 
     for (String linkopt : attributes.linkopts()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
index 009b3fd..4cf8e62 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
@@ -1058,13 +1058,21 @@
       return;
     }
 
-    CustomCommandLine.Builder commandLine =
-        CustomCommandLine.builder()
-            .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath())
-            .add("Frameworks")
-            .add("--platform")
-            .add(platform.getLowerCaseNameInPlist())
-            .addExecPath("--scan-executable", combinedArchBinary);
+    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
+
+    CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
+    if (appleConfiguration.getXcodeToolchain() != null) {
+      commandLine.add("--toolchain").add(appleConfiguration.getXcodeToolchain());
+    }
+
+    commandLine
+        .add("--output_zip_path")
+        .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath())
+        .add("--bundle_path")
+        .add("Frameworks")
+        .add("--platform")
+        .add(platform.getLowerCaseNameInPlist())
+        .addExecPath("--scan-executable", combinedArchBinary);
 
     ruleContext.registerAction(
         ObjcRuleClasses.spawnAppleEnvActionBuilder(ruleContext, platform)
@@ -1082,13 +1090,21 @@
       return;
     }
 
-    CustomCommandLine.Builder commandLine =
-        CustomCommandLine.builder()
-            .addPath(intermediateArtifacts.swiftSupportZip().getExecPath())
-            .add("SwiftSupport/" + platform.getLowerCaseNameInPlist())
-            .add("--platform")
-            .add(platform.getLowerCaseNameInPlist())
-            .addExecPath("--scan-executable", combinedArchBinary);
+    AppleConfiguration configuration = ruleContext.getFragment(AppleConfiguration.class);
+
+    CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
+    if (configuration.getXcodeToolchain() != null) {
+      commandLine.add("--toolchain").add(configuration.getXcodeToolchain());
+    }
+
+    commandLine
+        .add("--output_zip_path")
+        .addPath(intermediateArtifacts.swiftSupportZip().getExecPath())
+        .add("--bundle_path")
+        .add("SwiftSupport/" + platform.getLowerCaseNameInPlist())
+        .add("--platform")
+        .add(platform.getLowerCaseNameInPlist())
+        .addExecPath("--scan-executable", combinedArchBinary);
 
     ruleContext.registerAction(
         ObjcRuleClasses.spawnAppleEnvActionBuilder(ruleContext, platform)
diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh b/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh
index 7197cdc..d4f2f4f 100755
--- a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh
+++ b/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh
@@ -17,7 +17,9 @@
 # swiftstdlibtoolwrapper runs swift-stdlib-tool and zips up the output.
 # This script only runs on darwin and you must have Xcode installed.
 #
-# $1 OUTZIP - the path to place the output zip file.
+# --output_zip_path - the path to place the output zip file.
+# --bundle_path - the path inside of the archive to where libs will be copied.
+# --toolchain - toolchain identifier to use with xcrun.
 
 set -eu
 
@@ -25,15 +27,50 @@
 REALPATH="${MY_LOCATION}/realpath"
 WRAPPER="${MY_LOCATION}/xcrunwrapper.sh"
 
-OUTZIP=$("${REALPATH}" "$1")
-PATH_INSIDE_ZIP="$2"
-shift 2
+TOOL_ARGS=()
+while [[ $# -gt 0 ]]; do
+  ARG="$1"
+  shift
+  case "${ARG}" in
+    --output_zip_path)
+      ARG="$1"
+      shift
+      OUTZIP=$("${REALPATH}" "${ARG}")
+      ;;
+    --bundle_path)
+      ARG="$1"
+      shift
+      PATH_INSIDE_ZIP="$ARG"
+      ;;
+    --toolchain)
+      ARG="$1"
+      shift
+      TOOLCHAIN=${ARG}
+      ;;
+    # Remaining args are swift-stdlib-tool args
+    *)
+     TOOL_ARGS+=("$ARG")
+     ;;
+    esac
+done
+
+
 TEMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/swiftstdlibtoolZippingOutput.XXXXXX")
 trap "rm -rf \"$TEMPDIR\"" EXIT
 
 FULLPATH="$TEMPDIR/$PATH_INSIDE_ZIP"
 
-$WRAPPER swift-stdlib-tool --copy --verbose --destination "$FULLPATH" "$@"
+XCRUN_ARGS=()
+
+if [ -n "${TOOLCHAIN:-}" ]; then
+  XCRUN_ARGS+=(--toolchain "$TOOLCHAIN")
+fi
+
+XCRUN_ARGS+=(swift-stdlib-tool --copy --verbose )
+XCRUN_ARGS+=(--destination "$FULLPATH")
+XCRUN_ARGS+=( "${TOOL_ARGS[@]}" )
+
+$WRAPPER "${XCRUN_ARGS[@]}"
 
 # Need to push/pop tempdir so it isn't the current working directory
 # when we remove it via the EXIT trap.
diff --git a/tools/build_defs/apple/swift.bzl b/tools/build_defs/apple/swift.bzl
index 9b49668..3cc22fe 100644
--- a/tools/build_defs/apple/swift.bzl
+++ b/tools/build_defs/apple/swift.bzl
@@ -78,6 +78,39 @@
   """Returns a module name for the given rule context."""
   return ctx.label.package.lstrip("//").replace("/", "_") + "_" + ctx.label.name
 
+def _swift_lib_dir(ctx):
+  """Returns the location of swift runtime directory to link against."""
+  # TODO(dmishe): Expose this template from native code.
+  developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"
+  platform_str = ctx.fragments.apple.single_arch_platform.name_in_plist.lower()
+
+  toolchain_name = "XcodeDefault"
+  if hasattr(ctx.fragments.apple, "xcode_toolchain"):
+    toolchain = ctx.fragments.apple.xcode_toolchain
+
+    # We cannot use non Xcode-packaged toolchains, and the only one non-default
+    # toolchain known to exist (as of Xcode 8.1) is this one.
+    # TODO(b/29338444): Write an integration test when Xcode 8 is available.
+    if toolchain == "com.apple.dt.toolchain.Swift_2_3":
+      toolchain_name = "Swift_2.3"
+
+  return "{0}/Toolchains/{1}.xctoolchain/usr/lib/swift/{2}".format(
+      developer_dir, toolchain_name, platform_str)
+
+def _swift_linkopts(ctx):
+  """Returns additional linker arguments for the given rule context."""
+  return set(["-L" + _swift_lib_dir(ctx)])
+
+def _swift_xcrun_args(ctx):
+  """Returns additional arguments that should be passed to xcrun."""
+  # TODO(dmishe): Remove this check when xcode_toolchain is available by default
+  args = []
+  if hasattr(ctx.fragments.apple, "xcode_toolchain"):
+    if ctx.fragments.apple.xcode_toolchain:
+      args += ["--toolchain", ctx.fragments.apple.xcode_toolchain]
+
+  return args
+
 def _swift_library_impl(ctx):
   """Implementation for swift_library Skylark rule."""
   # TODO(b/29772303): Assert xcode version.
@@ -202,7 +235,7 @@
       # https://llvm.org/bugs/show_bug.cgi?id=19501
       + ["-fmodule-map-file=%s" % x.path for x in objc_module_maps])
 
-  args = [
+  args = _swift_xcrun_args(ctx) + [
       "swiftc",
       "-emit-object",
       "-emit-module-path",
@@ -253,7 +286,8 @@
       library=set([output_lib] + dep_libs),
       header=set([output_header]),
       providers=objc_providers,
-      uses_swift=True)
+      linkopt=_swift_linkopts(ctx),
+      uses_swift=True,)
 
   return struct(
       swift=struct(