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;
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc
index d398366..9f874ebd 100644
--- a/tools/gn/filesystem_utils_unittest.cc
+++ b/tools/gn/filesystem_utils_unittest.cc
@@ -505,6 +505,22 @@
EXPECT_EQ("two/obj/foo/bar/",
GetOutputDirForSourceDirAsOutputFile(
&other_settings, SourceDir("//foo/bar/")).value());
+
+ // Absolute source path
+ EXPECT_EQ("//out/Debug/obj/ABS_PATH/abs/",
+ GetOutputDirForSourceDir(
+ &default_settings, SourceDir("/abs")).value());
+ EXPECT_EQ("obj/ABS_PATH/abs/",
+ GetOutputDirForSourceDirAsOutputFile(
+ &default_settings, SourceDir("/abs")).value());
+#if defined(OS_WIN)
+ EXPECT_EQ("//out/Debug/obj/ABS_PATH/C/abs/",
+ GetOutputDirForSourceDir(
+ &default_settings, SourceDir("/C:/abs")).value());
+ EXPECT_EQ("obj/ABS_PATH/C/abs/",
+ GetOutputDirForSourceDirAsOutputFile(
+ &default_settings, SourceDir("/C:/abs")).value());
+#endif
}
TEST(FilesystemUtils, GetGenDirForSourceDir) {
diff --git a/tools/gn/function_get_path_info_unittest.cc b/tools/gn/function_get_path_info_unittest.cc
index 855e217..306c57e 100644
--- a/tools/gn/function_get_path_info_unittest.cc
+++ b/tools/gn/function_get_path_info_unittest.cc
@@ -95,8 +95,12 @@
EXPECT_EQ("//out/Debug/obj/src/foo", Call(".", "out_dir"));
EXPECT_EQ("//out/Debug/obj/src/foo", Call("bar", "out_dir"));
EXPECT_EQ("//out/Debug/obj/foo", Call("//foo/bar.txt", "out_dir"));
- // System paths go into the root obj directory.
- EXPECT_EQ("//out/Debug/obj", Call("/foo/bar.txt", "out_dir"));
+ // System paths go into the ABS_PATH obj directory.
+ EXPECT_EQ("//out/Debug/obj/ABS_PATH/foo", Call("/foo/bar.txt", "out_dir"));
+#if defined(OS_WIN)
+ EXPECT_EQ("//out/Debug/obj/ABS_PATH/C/foo",
+ Call("/C:/foo/bar.txt", "out_dir"));
+#endif
}
// Note build dir is "//out/Debug/".
diff --git a/tools/gn/label.cc b/tools/gn/label.cc
index 095128d..89cd335 100644
--- a/tools/gn/label.cc
+++ b/tools/gn/label.cc
@@ -5,7 +5,9 @@
#include "tools/gn/label.h"
#include "base/logging.h"
+#include "base/strings/string_util.h"
#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/value.h"
@@ -93,8 +95,23 @@
Err* err) {
// To workaround the problem that StringPiece operator[] doesn't return a ref.
const char* input_str = input.data();
-
- size_t path_separator = input.find_first_of(":(");
+ size_t offset = 0;
+#if defined(OS_WIN)
+ if (IsPathAbsolute(input)) {
+ if (input[0] != '/') {
+ *err = Err(original_value, "Bad absolute path.",
+ "Absolute paths must be of the form /C:\\ but this is \"" +
+ input.as_string() + "\".");
+ return false;
+ }
+ if (input.size() > 3 && input[2] == ':' && IsSlash(input[3]) &&
+ IsAsciiAlpha(input[1])) {
+ // Skip over the drive letter colon.
+ offset = 3;
+ }
+ }
+#endif
+ size_t path_separator = input.find_first_of(":(", offset);
base::StringPiece location_piece;
base::StringPiece name_piece;
base::StringPiece toolchain_piece;
diff --git a/tools/gn/label_pattern.cc b/tools/gn/label_pattern.cc
index 396a9b73..4b31174 100644
--- a/tools/gn/label_pattern.cc
+++ b/tools/gn/label_pattern.cc
@@ -4,6 +4,7 @@
#include "tools/gn/label_pattern.h"
+#include "base/strings/string_util.h"
#include "tools/gn/err.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/value.h"
@@ -121,7 +122,23 @@
// Extract path and name.
base::StringPiece path;
base::StringPiece name;
- size_t colon = str.find(':');
+ size_t offset = 0;
+#if defined(OS_WIN)
+ if (IsPathAbsolute(str)) {
+ if (str[0] != '/') {
+ *err = Err(value, "Bad absolute path.",
+ "Absolute paths must be of the form /C:\\ but this is \"" +
+ str.as_string() + "\".");
+ return LabelPattern();
+ }
+ if (str.size() > 3 && str[2] == ':' && IsSlash(str[3]) &&
+ IsAsciiAlpha(str[1])) {
+ // Skip over the drive letter colon.
+ offset = 3;
+ }
+ }
+#endif
+ size_t colon = str.find(':', offset);
if (colon == std::string::npos) {
path = base::StringPiece(str);
} else {
diff --git a/tools/gn/label_unittest.cc b/tools/gn/label_unittest.cc
index 02c658a..9fea812 100644
--- a/tools/gn/label_unittest.cc
+++ b/tools/gn/label_unittest.cc
@@ -33,6 +33,11 @@
// Absolute paths.
{ "//chrome/", "/chrome:bar", true , "/chrome/", "bar", "//t/", "d" },
{ "//chrome/", "/chrome/:bar", true, "/chrome/", "bar", "//t/", "d" },
+#if defined(OS_WIN)
+ { "//chrome/", "/C:/chrome:bar", true , "/C:/chrome/", "bar", "//t/", "d" },
+ { "//chrome/", "/C:/chrome/:bar", true, "/C:/chrome/", "bar", "//t/", "d" },
+ { "//chrome/", "C:/chrome:bar", false, "", "", "", "" },
+#endif
// Refers to root dir.
{ "//chrome/", "//:bar", true, "//", "bar", "//t/", "d" },
// Implicit directory
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 9f6c745..8798b4d8 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -82,8 +82,15 @@
p.as_string()).value());
NormalizePath(&absolute);
if (!MakeAbsolutePathRelativeIfPossible(source_root, absolute,
- &ret.value_))
- ret.value_ = absolute;
+ &ret.value_)) {
+#if defined(OS_WIN)
+ // On Windows we'll accept "C:\foo" as an absolute path, which we want
+ // to convert to "/C:..." here.
+ if (absolute[0] != '/')
+ ret.value_ = "/";
+#endif
+ ret.value_.append(absolute.data(), absolute.size());
+ }
return ret;
}
@@ -134,8 +141,14 @@
FilePathToUTF8(Resolve(UTF8ToFilePath(source_root)).AppendASCII(
p.as_string()).value());
NormalizePath(&absolute);
- if (!MakeAbsolutePathRelativeIfPossible(source_root, absolute, &ret.value_))
- ret.value_ = absolute;
+ if (!MakeAbsolutePathRelativeIfPossible(source_root, absolute,
+ &ret.value_)) {
+#if defined(OS_WIN)
+ if (absolute[0] != '/') // See the file case for why we do this check.
+ ret.value_ = "/";
+#endif
+ ret.value_.append(absolute.data(), absolute.size());
+ }
if (!EndsWithSlash(ret.value_))
ret.value_.push_back('/');
return ret;
diff --git a/tools/gn/substitution_writer_unittest.cc b/tools/gn/substitution_writer_unittest.cc
index b59475b..f5dcb78 100644
--- a/tools/gn/substitution_writer_unittest.cc
+++ b/tools/gn/substitution_writer_unittest.cc
@@ -161,7 +161,12 @@
EXPECT_EQ("/baz.txt", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE));
EXPECT_EQ("/.", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_DIR));
EXPECT_EQ("gen", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
- EXPECT_EQ("obj", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
+ EXPECT_EQ("obj/ABS_PATH",
+ GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
+#if defined(OS_WIN)
+ EXPECT_EQ("obj/ABS_PATH/C",
+ GetRelSubst("/C:/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
+#endif
EXPECT_EQ(".",
GetRelSubst("//baz.txt", SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR));