Converts wrapped_clang from a bash script to a C++ source file which is compiled as part of bazel's repository bootstrap. This should make crosstool's clang invocations faster. An added benefit of this is that wrapped_clang.cc supports the "DSYM_HINT" flags specified through the CROSSTOOL, so with this change, apple_binary gets support for the --apple_generate_dsym flag.

The dSYM generation issue has been flagged multiple times:
https://github.com/bazelbuild/bazel/issues/4312
https://github.com/bazelbuild/bazel/issues/3940
https://github.com/bazelbuild/bazel/issues/3372

RELNOTES: apple_binary can now generate dSYM outputs with the --apple_generate_dsym=true flag.
PiperOrigin-RevId: 184688215
diff --git a/src/test/shell/bazel/apple/bazel_apple_test.sh b/src/test/shell/bazel/apple/bazel_apple_test.sh
index f3e0ae3..d90d6f0 100755
--- a/src/test/shell/bazel/apple/bazel_apple_test.sh
+++ b/src/test/shell/bazel/apple/bazel_apple_test.sh
@@ -347,4 +347,33 @@
   assert_contains "IOS UNKNOWN" bazel-genfiles/a/ioso
 }
 
+function test_apple_binary_dsym_builds() {
+  rm -rf package
+  mkdir -p package
+  cat > package/BUILD <<EOF
+apple_binary(
+    name = "main_binary",
+    deps = [":main_lib"],
+    platform_type = "ios",
+    minimum_os_version = "10.0",
+)
+objc_library(
+    name = "main_lib",
+    srcs = ["main.m"],
+)
+EOF
+  cat > package/main.m <<EOF
+int main() {
+  return 0;
+}
+EOF
+
+  bazel build --verbose_failures //package:main_binary \
+      --apple_crosstool_transition \
+      --ios_multi_cpus=i386,x86_64 \
+      --xcode_version=$XCODE_VERSION \
+      --apple_generate_dsym=true \
+      || fail "should build apple_binary with dSYMs"
+}
+
 run_suite "apple_tests"
diff --git a/src/test/shell/bazel/remote_execution_test.sh b/src/test/shell/bazel/remote_execution_test.sh
index 87ad193..dff2504 100755
--- a/src/test/shell/bazel/remote_execution_test.sh
+++ b/src/test/shell/bazel/remote_execution_test.sh
@@ -96,6 +96,13 @@
 }
 
 function test_cc_test() {
+  if [[ "$PLATFORM" == "darwin" ]]; then
+    # TODO(b/37355380): This test is disabled due to RemoteWorker not supporting
+    # setting SDKROOT and DEVELOPER_DIR appropriately, as is required of
+    # action executors in order to select the appropriate Xcode toolchain.
+    return 0
+  fi
+
   mkdir -p a
   cat > a/BUILD <<EOF
 package(default_visibility = ["//visibility:public"])
diff --git a/tools/cpp/osx_cc_configure.bzl b/tools/cpp/osx_cc_configure.bzl
index 1c75c6e..8dd837b 100644
--- a/tools/cpp/osx_cc_configure.bzl
+++ b/tools/cpp/osx_cc_configure.bzl
@@ -73,17 +73,40 @@
         Label("@bazel_tools//tools/osx/crosstool:wrapped_ar.tpl"),
         "wrapped_ar")
     repository_ctx.symlink(
-        Label("@bazel_tools//tools/osx/crosstool:wrapped_clang.tpl"),
-        "wrapped_clang")
-    repository_ctx.symlink(
-        Label("@bazel_tools//tools/osx/crosstool:wrapped_clang_pp.tpl"),
-        "wrapped_clang_pp")
-    repository_ctx.symlink(
         Label("@bazel_tools//tools/osx/crosstool:BUILD.tpl"),
         "BUILD")
     repository_ctx.symlink(
         Label("@bazel_tools//tools/osx/crosstool:osx_archs.bzl"),
         "osx_archs.bzl")
+
+    wrapped_clang_src_path = str(repository_ctx.path(
+        Label("@bazel_tools//tools/osx/crosstool:wrapped_clang.cc")))
+    xcrun_result = repository_ctx.execute(["env", "-i", "xcrun", "clang", "-std=c++11", "-lc++",
+                                           "-o", "wrapped_clang", wrapped_clang_src_path], 30)
+    if (xcrun_result.return_code == 0):
+      repository_ctx.symlink("wrapped_clang", "wrapped_clang_pp")
+    else:
+      # If for some reason wrapped_clang couldn't be built, fall back to
+      # using the bash scripts that don't support dSYM generation. This is to
+      # avoid completely breaking a build. This should be removed after a whole
+      # release cycle to keep from increasing code maintenance, if we haven't
+      # received any issues as requested below.
+      error_msg = (
+          "return code {code}, stderr: {err}, stdout: {out}").format(
+              code=xcrun_result.return_code,
+              err=xcrun_result.stderr,
+              out=xcrun_result.stdout)
+      print("wrapped_clang failed to generate. This shouldn't cause " +
+            "problems, but please file an issue at " +
+            "https://github.com/bazelbuild/bazel/issues with the following:\n" +
+            error_msg)
+      repository_ctx.symlink(
+          Label("@bazel_tools//tools/osx/crosstool:wrapped_clang.tpl"),
+          "wrapped_clang")
+      repository_ctx.symlink(
+          Label("@bazel_tools//tools/osx/crosstool:wrapped_clang_pp.tpl"),
+          "wrapped_clang_pp")
+
     escaped_include_paths = _get_escaped_xcode_cxx_inc_directories(repository_ctx, cc, xcode_toolchains)
     escaped_cxx_include_directories = []
     for path in escaped_include_paths:
diff --git a/tools/osx/crosstool/CROSSTOOL.tpl b/tools/osx/crosstool/CROSSTOOL.tpl
index 79861cd..af544e9 100644
--- a/tools/osx/crosstool/CROSSTOOL.tpl
+++ b/tools/osx/crosstool/CROSSTOOL.tpl
@@ -203,6 +203,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -1806,6 +1829,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -3425,6 +3471,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -5047,6 +5116,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -6696,6 +6788,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -8315,6 +8430,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -9922,6 +10060,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -11532,6 +11693,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -13169,6 +13353,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
@@ -14779,6 +14986,29 @@
     }
   }
   feature {
+    name: "generate_dsym_file"
+    flag_set {
+      action: "c-compile"
+      action: "c++-compile"
+      action: "objc-compile"
+      action: "objc++-compile"
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "-g"
+      }
+    }
+    flag_set {
+      action: "objc-executable"
+      action: "objc++-executable"
+      flag_group {
+        flag: "DSYM_HINT_LINKED_BINARY=%{linked_binary}"
+        flag: "DSYM_HINT_DSYM_PATH=%{dsym_path}"
+        flag: "DSYM_HINT_DSYM_BUNDLE_ZIP=%{dsym_bundle_zip}"
+      }
+    }
+  }
+  feature {
     name: "contains_objc_source"
     flag_set {
       action: "c++-link-interface-dynamic-library"
diff --git a/tools/osx/crosstool/wrapped_clang.cc b/tools/osx/crosstool/wrapped_clang.cc
new file mode 100644
index 0000000..0f92db9
--- /dev/null
+++ b/tools/osx/crosstool/wrapped_clang.cc
@@ -0,0 +1,268 @@
+// Copyright 2017 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.
+//
+// wrapped_clang.cc: Pass args to 'xcrun clang' and zip dsym files.
+//
+// wrapped_clang passes its args to clang, but also supports a separate set of
+// invocations to generate dSYM files.  If "DSYM_HINT" flags are passed in, they
+// are used to construct that separate set of invocations (instead of being
+// passed to clang).
+// The following "DSYM_HINT" flags control dsym generation.  If any one if these
+// are passed in, then they all must be passed in.
+// "DSYM_HINT_LINKED_BINARY": Workspace-relative path to binary output of the
+//    link action generating the dsym file.
+// "DSYM_HINT_DSYM_PATH": Workspace-relative path to dSYM directory.
+// "DSYM_HINT_DSYM_BUNDLE_ZIP": Workspace-relative path to dSYM zip.
+//
+// Likewise, this wrapper also contains a workaround for a bug in ld that causes
+// flaky builds when using Bitcode symbol maps. ld allows the
+// -bitcode_symbol_map to be either a directory (into which the file will be
+// written) or a file, but the return value of the call to ::stat is never
+// checked so examining the S_ISDIR bit of the struct afterwards returns
+// true/false randomly depending on what data happened to be in memory at the
+// time it was called:
+// https://github.com/michaelweiser/ld64/blob/9c3700b64ed03e2d55ba094176bf6a172bf2bc6b/src/ld/Options.cpp#L3261
+// To address this, we prepend a special "BITCODE_TOUCH_SYMBOL_MAP=" flag to the
+// symbol map filename and touch it before passing it along to clang, forcing
+// the file to exist.
+
+#include <libgen.h>
+#include <spawn.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <cerrno>
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+extern char **environ;
+
+namespace {
+
+// Returns the base name of the given filepath. For example, given
+// /foo/bar/baz.txt, returns 'baz.txt'.
+const char *Basename(const char *filepath) {
+  const char *base = strrchr(filepath, '/');
+  return base ? (base + 1) : filepath;
+}
+
+// Converts an array of string arguments to char *arguments.
+// The first arg is reduced to its basename as per execve conventions.
+// Note that the lifetime of the char* arguments in the returned array
+// are controlled by the lifetime of the strings in args.
+std::vector<const char *> ConvertToCArgs(const std::vector<std::string> &args) {
+  std::vector<const char *> c_args;
+  c_args.push_back(Basename(args[0].c_str()));
+  for (int i = 1; i < args.size(); i++) {
+    c_args.push_back(args[i].c_str());
+  }
+  c_args.push_back(nullptr);
+  return c_args;
+}
+
+// Turn our current process into a new process. Avoids fork overhead.
+// Never returns.
+void ExecProcess(const std::vector<std::string> &args) {
+  std::vector<const char *> exec_argv = ConvertToCArgs(args);
+  execv(args[0].c_str(), const_cast<char **>(exec_argv.data()));
+  std::cerr << "Error executing child process.'" <<  args[0] << "'. "
+            << strerror(errno) << "\n";
+  abort();
+}
+
+// Spawns a subprocess for given arguments args. The first argument is used
+// for the executable path.
+void RunSubProcess(const std::vector<std::string> &args) {
+  std::vector<const char *> exec_argv = ConvertToCArgs(args);
+  pid_t pid;
+  int status = posix_spawn(&pid, args[0].c_str(), NULL, NULL,
+                           const_cast<char **>(exec_argv.data()), environ);
+  if (status == 0) {
+    int wait_status;
+    do {
+      wait_status = waitpid(pid, &status, 0);
+    } while ((wait_status == -1) && (errno == EINTR));
+    if (wait_status < 0) {
+      std::cerr << "Error waiting on child process '" <<  args[0] << "'. "
+                << strerror(errno) << "\n";
+      abort();
+    }
+    if (WEXITSTATUS(status) != 0) {
+      std::cerr << "Error in child process '" <<  args[0] << "'. "
+                << WEXITSTATUS(status) << "\n";
+      abort();
+    }
+  } else {
+    std::cerr << "Error forking process '" <<  args[0] << "'. "
+              << strerror(status) << "\n";
+    abort();
+  }
+}
+
+// Splits txt using whitespace delimiter, pushing each substring into strs.
+void SplitAndAdd(const std::string &txt, std::vector<std::string> &strs) {
+  for (std::istringstream stream(txt); !stream.eof();) {
+    std::string substring;
+    stream >> substring;
+    if (!substring.empty()) {
+      strs.push_back(substring);
+    }
+  }
+}
+
+// Finds and replaces all instances of oldsub with newsub, in-place on str.
+void FindAndReplace(const std::string &oldsub, const std::string &newsub,
+                    std::string *str) {
+  int start = 0;
+  while ((start = str->find(oldsub, start)) != std::string::npos) {
+    str->replace(start, oldsub.length(), newsub);
+    start += newsub.length();
+  }
+}
+
+// If arg is of the classic flag form "foo=bar", and flagname is 'foo', sets
+// str to point to a new std::string 'bar' and returns true.
+// Otherwise, returns false.
+bool SetArgIfFlagPresent(const std::string &arg, const std::string &flagname,
+                         std::string *str) {
+  std::string prefix_string = flagname + "=";
+  if (arg.compare(0, prefix_string.length(), prefix_string) == 0) {
+    *str = arg.substr(prefix_string.length());
+    return true;
+  }
+  return false;
+}
+
+// Returns the DEVELOPER_DIR environment variable in the current process
+// environment. Aborts if this variable is unset.
+std::string GetMandatoryEnvVar(const std::string &var_name) {
+  char *env_value = getenv(var_name.c_str());
+  if (env_value == nullptr) {
+    std::cerr << "Error: " << var_name << " not set.\n";
+    abort();
+  }
+  return env_value;
+}
+
+}  // namespace
+
+int main(int argc, char *argv[]) {
+  std::string tool_name;
+
+  std::string binary_name = Basename(argv[0]);
+  if (binary_name == "wrapped_clang_pp") {
+    tool_name = "clang++";
+  } else if (binary_name == "wrapped_clang") {
+    tool_name = "clang";
+  } else {
+    std::cerr << "Binary must either be named 'wrapped_clang' or "
+                 "'wrapped_clang_pp', not "
+              << binary_name << "\n";
+    abort();
+  }
+
+  std::string developer_dir = GetMandatoryEnvVar("DEVELOPER_DIR");
+  std::string sdk_root = GetMandatoryEnvVar("SDKROOT");
+
+  std::vector<std::string> processed_args = {"/usr/bin/xcrun", tool_name};
+
+  std::string linked_binary, dsym_path, dsym_bundle_zip, bitcode_symbol_map;
+  for (int i = 1; i < argc; i++) {
+    std::string arg(argv[i]);
+
+    if (SetArgIfFlagPresent(arg, "DSYM_HINT_LINKED_BINARY", &linked_binary)) {
+      continue;
+    }
+    if (SetArgIfFlagPresent(arg, "DSYM_HINT_DSYM_PATH", &dsym_path)) {
+      continue;
+    }
+    if (SetArgIfFlagPresent(arg, "DSYM_HINT_DSYM_BUNDLE_ZIP",
+                            &dsym_bundle_zip)) {
+      continue;
+    }
+    if (SetArgIfFlagPresent(arg, "BITCODE_TOUCH_SYMBOL_MAP",
+                            &bitcode_symbol_map)) {
+      // Touch bitcode_symbol_map.
+      std::ofstream bitcode_symbol_map_file(bitcode_symbol_map);
+      arg = bitcode_symbol_map;
+    }
+    FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__", developer_dir, &arg);
+    FindAndReplace("__BAZEL_XCODE_SDKROOT__", sdk_root, &arg);
+    SplitAndAdd(arg, processed_args);
+  }
+
+  // Check to see if we should postprocess with dsymutil.
+  bool postprocess = false;
+  if ((!linked_binary.empty()) || (!dsym_path.empty()) ||
+      (!dsym_bundle_zip.empty())) {
+    if ((linked_binary.empty()) || (dsym_path.empty()) ||
+        (dsym_bundle_zip.empty())) {
+      const char *missing_dsym_flag;
+      if (linked_binary.empty()) {
+        missing_dsym_flag = "DSYM_HINT_LINKED_BINARY";
+      } else if (dsym_path.empty()) {
+        missing_dsym_flag = "DSYM_HINT_DSYM_PATH";
+      } else {
+        missing_dsym_flag = "DSYM_HINT_DSYM_BUNDLE_ZIP";
+      }
+      std::cerr << "Error in clang wrapper: If any dsym "
+              "hint is defined, then "
+           << missing_dsym_flag << " must be defined\n";
+      abort();
+    } else {
+      postprocess = true;
+    }
+  }
+
+  if (!postprocess) {
+    ExecProcess(processed_args);
+    std::cerr << "ExecProcess should not return. Please fix!\n";
+    abort();
+  }
+
+  RunSubProcess(processed_args);
+
+  std::vector<std::string> dsymutil_args = {"/usr/bin/xcrun", "dsymutil",
+                                            linked_binary, "-o", dsym_path};
+
+  RunSubProcess(dsymutil_args);
+
+  std::unique_ptr<char, decltype(std::free) *> cwd{getcwd(nullptr, 0),
+                                                   std::free};
+  if (cwd == nullptr) {
+    std::cerr << "Error determining current working directory\n";
+    abort();
+  }
+  std::vector<std::string> zip_args = {
+      "/usr/bin/zip", "-q", "-r",
+      std::string(cwd.get()) + "/" + dsym_bundle_zip, "."};
+  if (chdir(dsym_path.c_str()) < 0) {
+    std::cerr << "Error changing directory to '" << dsym_path << "'\n";
+    abort();
+  }
+
+  ExecProcess(zip_args);
+
+  std::cerr << "Should never get to end of wrapped_clang. Please fix!\n";
+  abort();
+  return 0;
+}