GN: Normalize the build directory path

BUG=586906
TEST=ln -s /tmp out_tmp && out/gn/gn gen //out_tmp/Release

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

Cr-Original-Commit-Position: refs/heads/master@{#376288}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 62b5ce373ce17228a3c06f3e32ff329180e89921
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 79814e6..bad4b7b 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -226,6 +226,21 @@
 }
 #endif
 
+// Expands all ./, ../, and symbolic links in the given path.
+bool NormalizePath(const base::FilePath& path, base::FilePath* out) {
+#if defined(OS_POSIX)
+  char buf[PATH_MAX];
+  if (!realpath(path.value().c_str(), buf)) {
+    return false;
+  }
+  *out = base::FilePath(buf);
+#else
+  // Do nothing on a non-POSIX system.
+  *out = path;
+#endif
+  return true;
+}
+
 }  // namespace
 
 const char Setup::kBuildArgFileName[] = "args.gn";
@@ -513,9 +528,16 @@
     root_path = dotfile_name_.DirName();
   }
 
+  base::FilePath root_path_normalized;
+  if (!NormalizePath(root_path, &root_path_normalized)) {
+    Err(Location(), "Can't normalize the root path.",
+        "I could not normalize the path \"" + FilePathToUTF8(root_path) + "\".")
+        .PrintToStdout();
+    return false;
+  }
   if (scheduler_.verbose_logging())
-    scheduler_.Log("Using source root", FilePathToUTF8(root_path));
-  build_settings_.SetRootPath(root_path);
+    scheduler_.Log("Using source root", FilePathToUTF8(root_path_normalized));
+  build_settings_.SetRootPath(root_path_normalized);
 
   return true;
 }
@@ -531,11 +553,21 @@
     return false;
   }
 
+  base::FilePath build_dir_path = build_settings_.GetFullPath(resolved);
+  base::FilePath build_dir_path_normalized;
+  if (!NormalizePath(build_dir_path, &build_dir_path_normalized)) {
+    Err(Location(), "Can't normalize the root path.",
+        "I could not normalize the path \"" + FilePathToUTF8(build_dir_path) +
+        "\".").PrintToStdout();
+    return false;
+  }
+  resolved = SourceDirForPath(build_settings_.root_path(),
+                              build_dir_path_normalized);
+
   if (scheduler_.verbose_logging())
     scheduler_.Log("Using build dir", resolved.value());
 
   if (require_exists) {
-    base::FilePath build_dir_path = build_settings_.GetFullPath(resolved);
     if (!base::PathExists(build_dir_path.Append(
             FILE_PATH_LITERAL("build.ninja")))) {
       Err(Location(), "Not a build directory.",