Call GetCanonicalPath only if needed to avoid FS overhead (#494)

diff --git a/crosstool/cc_toolchain_config.bzl b/crosstool/cc_toolchain_config.bzl
index 8002332..ec2ce1b 100644
--- a/crosstool/cc_toolchain_config.bzl
+++ b/crosstool/cc_toolchain_config.bzl
@@ -1432,6 +1432,24 @@
                 ],
             ),
         ],
+        env_sets = [
+            env_set(
+                actions = [
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.objc_compile,
+                    ACTION_NAMES.objcpp_compile,
+                ],
+                env_entries = [
+                    env_entry(
+                        key = "COVERAGE_PREFIX_MAP_USE_ABSOLUTE_CWD_PATH",
+                        value = "1",
+                    ),
+                ],
+            ),
+        ],
         requires = [feature_set(features = ["coverage"])],
     )
 
diff --git a/crosstool/wrapped_clang.cc b/crosstool/wrapped_clang.cc
index a5076b3..895baaf 100644
--- a/crosstool/wrapped_clang.cc
+++ b/crosstool/wrapped_clang.cc
@@ -256,12 +256,14 @@
 
 void ProcessArgument(const std::string arg, const std::string developer_dir,
                      const std::string sdk_root, const std::string cwd,
+                     const std::string canonical_cwd,
                      std::string &linked_binary, std::string &dsym_path,
                      bool &strip_debug_symbols, std::string toolchain_path,
                      std::function<void(const std::string &)> consumer);
 
 bool ProcessResponseFile(const std::string arg, const std::string developer_dir,
                          const std::string sdk_root, const std::string cwd,
+                         const std::string canonical_cwd,
                          std::string &linked_binary, std::string &dsym_path,
                          bool &strip_debug_symbols, std::string toolchain_path,
                          std::function<void(const std::string &)> consumer) {
@@ -277,7 +279,7 @@
     // Arguments in response files might be quoted/escaped, so we need to
     // unescape them ourselves.
     ProcessArgument(Unescape(arg_from_file), developer_dir, sdk_root, cwd,
-                    linked_binary, dsym_path, strip_debug_symbols,
+                    canonical_cwd, linked_binary, dsym_path, strip_debug_symbols,
                     toolchain_path, consumer);
   }
 
@@ -360,14 +362,15 @@
 
 void ProcessArgument(const std::string arg, const std::string developer_dir,
                      const std::string sdk_root, const std::string cwd,
+                     const std::string canonical_cwd,
                      std::string &linked_binary, std::string &dsym_path,
                      bool &strip_debug_symbols, std::string toolchain_path,
                      std::function<void(const std::string &)> consumer) {
   auto new_arg = arg;
   if (arg[0] == '@') {
-    if (ProcessResponseFile(arg, developer_dir, sdk_root, cwd, linked_binary,
-                            dsym_path, strip_debug_symbols, toolchain_path,
-                            consumer)) {
+    if (ProcessResponseFile(arg, developer_dir, sdk_root, cwd, canonical_cwd,
+                            linked_binary, dsym_path, strip_debug_symbols,
+                            toolchain_path, consumer)) {
       return;
     }
   }
@@ -384,7 +387,9 @@
   }
 
   FindAndReplace("__BAZEL_EXECUTION_ROOT__", cwd, &new_arg);
-  FindAndReplace("__BAZEL_EXECUTION_ROOT_CANONICAL__", GetCanonicalPath(cwd), &new_arg);
+  if (!canonical_cwd.empty()) { // empty if coverage_prefix_map_absolute_sources_non_hermetic_private_feature not requested
+    FindAndReplace("__BAZEL_EXECUTION_ROOT_CANONICAL__", canonical_cwd, &new_arg);
+  }
   FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__", developer_dir, &new_arg);
   FindAndReplace("__BAZEL_XCODE_SDKROOT__", sdk_root, &new_arg);
   if (!toolchain_path.empty()) {
@@ -440,6 +445,11 @@
   bool strip_debug_symbols = false;
 
   const std::string cwd = GetCurrentDirectory();
+  std::string canonical_cwd = "";
+  if (getenv("COVERAGE_PREFIX_MAP_USE_ABSOLUTE_CWD_PATH")) {
+    canonical_cwd = GetCanonicalPath(cwd);
+  }
+
   std::vector<std::string> invocation_args = {"/usr/bin/xcrun", tool_name};
   std::vector<std::string> processed_args = {};
 
@@ -449,8 +459,8 @@
   for (int i = 1; i < argc; i++) {
     std::string arg(argv[i]);
 
-    ProcessArgument(arg, developer_dir, sdk_root, cwd, linked_binary, dsym_path,
-                    strip_debug_symbols, toolchain_path, consumer);
+    ProcessArgument(arg, developer_dir, sdk_root, cwd, canonical_cwd, linked_binary,
+                    dsym_path, strip_debug_symbols, toolchain_path, consumer);
   }
 
   char *modulemap = getenv("APPLE_SUPPORT_MODULEMAP");