[C++] Regenerate ninja file when $(wildcard) is changed
diff --git a/fileutil.cc b/fileutil.cc
index 4c87e9c..11f8f6d 100644
--- a/fileutil.cc
+++ b/fileutil.cc
@@ -123,9 +123,7 @@
class GlobCache {
public:
~GlobCache() {
- for (auto& p : cache_) {
- delete p.second;
- }
+ Clear();
}
void Get(const char* pat, vector<string>** files) {
@@ -147,13 +145,33 @@
*files = p.first->second;
}
+ const unordered_map<string, vector<string>*>& GetAll() const {
+ return cache_;
+ }
+
+ void Clear() {
+ for (auto& p : cache_) {
+ delete p.second;
+ }
+ cache_.clear();
+ }
+
private:
unordered_map<string, vector<string>*> cache_;
};
+static GlobCache g_gc;
+
} // namespace
void Glob(const char* pat, vector<string>** files) {
- static GlobCache gc;
- gc.Get(pat, files);
+ g_gc.Get(pat, files);
+}
+
+const unordered_map<string, vector<string>*>& GetAllGlobCache() {
+ return g_gc.GetAll();
+}
+
+void ClearGlobCache() {
+ g_gc.Clear();
}
diff --git a/fileutil.h b/fileutil.h
index 96659d9..b282603 100644
--- a/fileutil.h
+++ b/fileutil.h
@@ -17,6 +17,7 @@
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include "string_piece.h"
@@ -33,4 +34,8 @@
void Glob(const char* pat, vector<string>** files);
+const unordered_map<string, vector<string>*>& GetAllGlobCache();
+
+void ClearGlobCache();
+
#endif // FILEUTIL_H_
diff --git a/main.cc b/main.cc
index e8eafa1..c45e7a1 100644
--- a/main.cc
+++ b/main.cc
@@ -227,6 +227,7 @@
fprintf(stderr, "No need to regenerate ninja file\n");
return 0;
}
+ ClearGlobCache();
}
time_t start_time;
diff --git a/ninja.cc b/ninja.cc
index 636e867..cbf8b4f 100644
--- a/ninja.cc
+++ b/ninja.cc
@@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <algorithm>
#include <map>
#include <memory>
#include <string>
@@ -663,6 +664,48 @@
fclose(fp);
}
+ void GetCommonPrefixDir(const vector<string>& files, string* o) {
+ for (const string& file : files) {
+ size_t l = min(file.size(), o->size());
+ for (size_t i = 0; i < l; i++) {
+ if (file[i] != (*o)[i]) {
+ size_t index = o->rfind('/', i);
+ if (index == string::npos)
+ index = 0;
+ o->resize(index);
+ break;
+ }
+ }
+ }
+ }
+
+ void GetReadDirs(const string& pat,
+ const vector<string>& files,
+ unordered_set<string>* dirs) {
+ string prefix_dir = Dirname(pat).as_string();
+ size_t index = prefix_dir.find_first_of("?*[\\");
+ if (index != string::npos) {
+ index = prefix_dir.rfind('/', index);
+ if (index == string::npos) {
+ prefix_dir = "";
+ } else {
+ prefix_dir = prefix_dir.substr(0, index);
+ }
+ }
+
+ GetCommonPrefixDir(files, &prefix_dir);
+ if (prefix_dir.empty())
+ prefix_dir = ".";
+ dirs->insert(prefix_dir);
+ for (const string& file : files) {
+ StringPiece dir = Dirname(file);
+ while (dir != prefix_dir) {
+ dirs->insert(dir.as_string());
+ dir = Dirname(dir);
+ }
+ }
+ }
+
void GenerateStamp() {
FILE* fp = fopen(GetStampFilename().c_str(), "wb");
@@ -682,6 +725,23 @@
DumpString(fp, p.second);
}
+ const unordered_map<string, vector<string>*>& globs = GetAllGlobCache();
+ DumpInt(fp, globs.size());
+ for (const auto& p : globs) {
+ DumpString(fp, p.first);
+ const vector<string>& files = *p.second;
+ unordered_set<string> dirs;
+ GetReadDirs(p.first, files, &dirs);
+ DumpInt(fp, dirs.size());
+ for (const string& dir : dirs) {
+ DumpString(fp, dir);
+ }
+ DumpInt(fp, files.size());
+ for (const string& file : files) {
+ DumpString(fp, file);
+ }
+ }
+
fclose(fp);
}
@@ -723,8 +783,8 @@
time_t gen_time = LoadInt(fp);
string s, s2;
- int l = LoadInt(fp);
- for (int i = 0; i < l; i++) {
+ int num_files = LoadInt(fp);
+ for (int i = 0; i < num_files; i++) {
LoadString(fp, &s);
if (gen_time < GetTimestamp(s)) {
fprintf(stderr, "%s was modified, regenerating...\n", s.c_str());
@@ -732,8 +792,8 @@
}
}
- l = LoadInt(fp);
- for (int i = 0; i < l; i++) {
+ int num_envs = LoadInt(fp);
+ for (int i = 0; i < num_envs; i++) {
LoadString(fp, &s);
StringPiece val(getenv(s.c_str()));
LoadString(fp, &s2);
@@ -745,5 +805,42 @@
}
}
+ int num_globs = LoadInt(fp);
+ string pat;
+ for (int i = 0; i < num_globs; i++) {
+ LoadString(fp, &pat);
+ bool needs_reglob = false;
+ int num_dirs = LoadInt(fp);
+ for (int j = 0; j < num_dirs; j++) {
+ LoadString(fp, &s);
+ needs_reglob |= gen_time < GetTimestamp(s);
+ }
+
+ int num_files = LoadInt(fp);
+ if (needs_reglob) {
+ vector<string>* files;
+ Glob(pat.c_str(), &files);
+ sort(files->begin(), files->end());
+ bool needs_regen = files->size() != static_cast<size_t>(num_files);
+ if (!needs_regen) {
+ for (int j = 0; j < num_files; j++) {
+ LoadString(fp, &s);
+ if ((*files)[j] != s) {
+ needs_regen = true;
+ break;
+ }
+ }
+ }
+ if (needs_regen) {
+ fprintf(stderr, "wildcard(%s) was changed, regenerating...\n",
+ pat.c_str());
+ return true;
+ }
+ } else {
+ for (int j = 0; j < num_files; j++)
+ LoadString(fp, &s);
+ }
+ }
+
return false;
}