deps_nodes->reserve(deps.ins_.size());
for (vector<StringPiece>::iterator i = deps.ins_.begin();
i != deps.ins_.end(); ++i) {
- if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, err))
+ unsigned int slash_bits;
+ if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, err,
+ &slash_bits))
return false;
- deps_nodes->push_back(state_->GetNode(*i));
+ deps_nodes->push_back(state_->GetNode(*i, slash_bits));
}
if (disk_interface_->RemoveFile(depfile) < 0) {
ASSERT_EQ("cc oo.h.in", command_runner_.commands_ran_[0]);
}
+#ifdef _WIN32
+TEST_F(BuildTest, DepFileCanonicalize) {
+ string err;
+ int orig_edges = state_.edges_.size();
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cc\n command = cc $in\n depfile = $out.d\n"
+"build gen/stuff/foo.o: cc foo.c\n"));
+ Edge* edge = state_.edges_.back();
+
+ fs_.Create("foo.c", "");
+ GetNode("bar.h")->MarkDirty(); // Mark bar.h as missing.
+ // Note, different slashes from manifest.
+ fs_.Create("gen/stuff/foo.o.d", "gen\\stuff\\foo.o: blah.h bar.h\n");
+ EXPECT_TRUE(builder_.AddTarget("gen/stuff/foo.o", &err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, fs_.files_read_.size());
+ EXPECT_EQ("gen/stuff/foo.o.d", fs_.files_read_[0]);
+
+ // Expect three new edges: one generating foo.o, and two more from
+ // loading the depfile.
+ ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size());
+ // Expect our edge to now have three inputs: foo.c and two headers.
+ ASSERT_EQ(3u, edge->inputs_.size());
+
+ // Expect the command line we generate to only use the original input.
+ ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
+}
+#endif
+
TEST_F(BuildTest, Phony) {
string err;
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
for (int j = 0; j < 5; ++j) {
const int kNumRepetitions = 2000000;
int64_t start = GetTimeMillis();
+ unsigned int slash_bits;
for (int i = 0; i < kNumRepetitions; ++i) {
- CanonicalizePath(buf, &len, &err);
+ CanonicalizePath(buf, &len, &err, &slash_bits);
}
int delta = (int)(GetTimeMillis() - start);
times.push_back(delta);
return false;
}
+ unsigned int unused;
+ if (!CanonicalizePath(const_cast<char*>(depfile.out_.str_),
+ &depfile.out_.len_, err, &unused))
+ return false;
+
// Check that this depfile matches the edge's output.
Node* first_output = edge->outputs_[0];
StringPiece opath = StringPiece(first_output->path());
// Add all its in-edges.
for (vector<StringPiece>::iterator i = depfile.ins_.begin();
i != depfile.ins_.end(); ++i, ++implicit_dep) {
- if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, err))
+ unsigned int slash_bits;
+ if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, err,
+ &slash_bits))
return false;
- Node* node = state_->GetNode(*i);
+ Node* node = state_->GetNode(*i, slash_bits);
*implicit_dep = node;
node->AddOutEdge(edge);
CreatePhonyInEdge(node);
size_t len = input.size();
strncpy(copy, input.c_str(), input.size() + 1);
string err;
- if (!CanonicalizePath(copy, &len, &err))
+ unsigned int slash_bits;
+ if (!CanonicalizePath(copy, &len, &err, &slash_bits))
Warning("couldn't canonicalize '%s': %s\n", input.c_str(), err.c_str());
StringPiece partially_fixed(copy, len);
do {
string path = eval.Evaluate(env_);
string path_err;
- if (!CanonicalizePath(&path, &path_err))
+ unsigned int slash_bits; // Unused because this only does lookup.
+ if (!CanonicalizePath(&path, &path_err, &slash_bits))
return lexer_.Error(path_err, err);
if (!state_->AddDefault(path, &path_err))
return lexer_.Error(path_err, err);
/// Returns true if the manifest was rebuilt.
bool NinjaMain::RebuildManifest(const char* input_file, string* err) {
string path = input_file;
- if (!CanonicalizePath(&path, err))
+ unsigned int slash_bits; // Unused because this path is only used for lookup.
+ if (!CanonicalizePath(&path, err, &slash_bits))
return false;
Node* node = state_.LookupNode(path);
if (!node)
Node* NinjaMain::CollectTarget(const char* cpath, string* err) {
string path = cpath;
- if (!CanonicalizePath(&path, err))
+ unsigned int slash_bits; // Unused because this path is only used for lookup.
+ if (!CanonicalizePath(&path, err, &slash_bits))
return NULL;
// Special syntax: "foo.cc^" means "the first output of foo.cc".
fprintf(stderr, "\n");
}
-bool CanonicalizePath(string* path, string* err) {
- unsigned int unused;
- return CanonicalizePath(path, err, &unused);
-}
-
bool CanonicalizePath(string* path, string* err, unsigned int* slash_bits) {
METRIC_RECORD("canonicalize str");
size_t len = path->size();
return true;
}
-bool CanonicalizePath(char* path, size_t* len, string* err) {
- unsigned int unused;
- return CanonicalizePath(path, len, err, &unused);
-}
-
unsigned int ShiftOverBit(int offset, unsigned int bits) {
// e.g. for |offset| == 2:
// | ... 9 8 7 6 5 4 3 2 1 0 |
void Error(const char* msg, ...);
/// Canonicalize a path like "foo/../bar.h" into just "bar.h".
-bool CanonicalizePath(string* path, string* err);
-
-bool CanonicalizePath(char* path, size_t* len, string* err);
-
/// |slash_bits| has bits set starting from lowest for a backslash that was
/// normalized to a forward slash. (only used on Windows)
bool CanonicalizePath(string* path, string* err, unsigned int* slash_bits);
#include "test.h"
+namespace {
+
+bool CanonicalizePath(string* path, string* err) {
+ unsigned int unused;
+ return ::CanonicalizePath(path, err, &unused);
+}
+
+} // namespace
+
TEST(CanonicalizePath, PathSamples) {
string path;
string err;
string path;
string err;
size_t len;
+ unsigned int unused;
path = "foo/. bar/.";
len = strlen("foo/."); // Canonicalize only the part before the space.
- EXPECT_TRUE(CanonicalizePath(&path[0], &len, &err));
+ EXPECT_TRUE(CanonicalizePath(&path[0], &len, &err, &unused));
EXPECT_EQ(strlen("foo"), len);
EXPECT_EQ("foo/. bar/.", string(path));
path = "foo/../file bar/.";
len = strlen("foo/../file");
- EXPECT_TRUE(CanonicalizePath(&path[0], &len, &err));
+ EXPECT_TRUE(CanonicalizePath(&path[0], &len, &err, &unused));
EXPECT_EQ(strlen("file"), len);
EXPECT_EQ("file ./file bar/.", string(path));
}