Absolute path fixes for gn.

To avoid collisions object files and other build ouput is now prefixed
with ABS_PATH and the full path of the input file.
E.g. /some/path/foo.cc maps to //out/obj/ABS_PATH/some/path/foo.o

In addition there are several fixes for absolute paths on Windows:
The drive letter colon is skipped when parsing labels.
Transform C:\ to /C:\ where needed.

BUG=445454
NOPRESUBMIT=true

Review URL: https://codereview.chromium.org/857163002

Cr-Commit-Position: refs/heads/master@{#315531}
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index 89e8a30..7495b05c 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -520,6 +520,22 @@
 
 std::string MakeRelativePath(const std::string& input,
                              const std::string& dest) {
+#if defined(OS_WIN)
+  // Make sure that absolute |input| path starts with a slash if |dest| path
+  // does. Otherwise skipping common prefixes won't work properly. Ensure the
+  // same for |dest| path too.
+  if (IsPathAbsolute(input) && !IsSlash(input[0]) && IsSlash(dest[0])) {
+    std::string corrected_input(1, dest[0]);
+    corrected_input.append(input);
+    return MakeRelativePath(corrected_input, dest);
+  }
+  if (IsPathAbsolute(dest) && !IsSlash(dest[0]) && IsSlash(input[0])) {
+    std::string corrected_dest(1, input[0]);
+    corrected_dest.append(dest);
+    return MakeRelativePath(input, corrected_dest);
+  }
+#endif
+
   std::string ret;
 
   // Skip the common prefixes of the source and dest as long as they end in
@@ -732,6 +748,19 @@
       size_t build_dir_size = build_dir.size();
       result.value().append(&source_dir.value()[build_dir_size],
                             source_dir.value().size() - build_dir_size);
+    } else {
+      result.value().append("ABS_PATH");
+#if defined(OS_WIN)
+      // Windows absolute path contains ':' after drive letter. Remove it to
+      // avoid inserting ':' in the middle of path (eg. "ABS_PATH/C:/").
+      std::string src_dir_value = source_dir.value();
+      const auto colon_pos = src_dir_value.find(':');
+      if (colon_pos != std::string::npos)
+        src_dir_value.erase(src_dir_value.begin() + colon_pos);
+#else
+      const std::string& src_dir_value = source_dir.value();
+#endif
+      result.value().append(src_dir_value);
     }
   }
   return result;