From ca2921b11ce6024a570ff080d3d15c669f4becc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Str=C3=B6mb=C3=A4ck?= Date: Mon, 11 Jan 2016 11:14:49 +0100 Subject: [PATCH] Added checks for precompiled header usage. --- .gitignore | 2 ++ src/cmdline.cpp | 1 + src/compile.cpp | 12 +++++++++++- src/includes.cpp | 47 ++++++++++++++++++++++++++++++++++++++++------- src/includes.h | 7 +++++-- todo.org | 1 - 6 files changed, 59 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index bd253b2..51db656 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ mymake *.exe *.lib +*.pch +*.gch diff --git a/src/cmdline.cpp b/src/cmdline.cpp index d469d46..c3b4e0c 100644 --- a/src/cmdline.cpp +++ b/src/cmdline.cpp @@ -178,6 +178,7 @@ bool CmdLine::parseOption(char opt) { break; case 'a': state = sArguments; + execute = tYes; break; case 'e': execute = (state == sNegate) ? tNo : tYes; diff --git a/src/compile.cpp b/src/compile.cpp index 17aa6e6..883c1f2 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -45,7 +45,8 @@ namespace compile { String outputName = config.getStr("output"); // Compile pre-compiled header first. - addFile(q, config.getStr("pch"), true); + String pchStr = config.getStr("pch"); + addFile(q, pchStr, true); // Add initial files. addFiles(q, config.getArray("input")); @@ -73,6 +74,15 @@ namespace compile { // Add all other files we need. IncludeInfo info = includes.info(now); + + // Check so that any pch file is included first. + if (!pchStr.empty() && pchStr != info.firstInclude) { + PLN("ERROR: Precompiled header " << pchStr << " must be included first in each implementation file."); + PLN("This is not the case for " << now.makeRelative(wd) << "."); + PLN("You need to use '#include \"" << pchStr << "\"' (exactly like that), and use 'include=./'."); + return false; + } + for (set::const_iterator i = info.includes.begin(); i != info.includes.end(); ++i) { DEBUG(now << " depends on " << *i, VERBOSE); addFile(q, *i); diff --git a/src/includes.cpp b/src/includes.cpp index 6c53e35..41f1797 100644 --- a/src/includes.cpp +++ b/src/includes.cpp @@ -14,6 +14,8 @@ Timestamp IncludeInfo::lastModified() const { ostream &operator <<(ostream &to, const IncludeInfo &i) { to << i.file << ": "; + if (!i.firstInclude.empty()) + to << "(first: " << i.firstInclude << ") "; join(to, i.includes); return to; } @@ -47,8 +49,7 @@ IncludeInfo Includes::info(const Path &file) { } // We need to update the cache... - IncludeInfo r(file); - r.includes = recursiveIncludesIn(file); + IncludeInfo r = recursiveIncludesIn(file); cache[file] = Info(r, Timestamp()); @@ -69,17 +70,23 @@ Path Includes::resolveInclude(const Path &fromFile, const String &src) const { throw IncludeError("The include " + src + " in file " + toS(fromFile) + " was not found!"); } -set Includes::recursiveIncludesIn(const Path &file) { - set result; +IncludeInfo Includes::recursiveIncludesIn(const Path &file) { + bool first = true; + IncludeInfo result(file); PathQueue to; to.push(file); while (to.any()) { Path now = to.pop(); - result << now; + result.includes << now; - includesIn(now, to); + if (first) { + includesIn(now, to, &result.firstInclude); + first = false; + } else { + includesIn(now, to, null); + } } return result; @@ -108,18 +115,38 @@ static bool isInclude(const String &line, String &out) { return true; } -void Includes::includesIn(const Path &file, PathQueue &to) { +static bool isBlank(const String &line) { + for (nat i = 0; i < line.size(); i++) { + switch (line[i]) { + case ' ': + case '\t': + case '\r': + break; + default: + return false; + } + } + return true; +} + +void Includes::includesIn(const Path &file, PathQueue &to, String *firstInclude) { ifstream in(toS(file).c_str()); + bool first = true; String include; String line; while (getline(in, line)) { if (isInclude(line, include)) { try { + if (first && firstInclude) + *firstInclude = include; to << resolveInclude(file, include); } catch (const IncludeError &e) { WARNING(e.what()); } + first = false; + } else if (!isBlank(line)) { + first = false; } } } @@ -163,6 +190,11 @@ void Includes::load(const Path &from) { cache[path] = Info(path, time); current = &cache[path]; + } else if (type == '>') { + if (!current) + return; + + getline(src, current->info.firstInclude); } else if (type == '-') { if (!current) return; @@ -185,6 +217,7 @@ void Includes::save(const Path &to) const { const Info &info = i->second; dest << "+" << info.lastModified.time << ' ' << info.info.file << endl; + dest << ">" << info.info.firstInclude << endl; for (set::const_iterator i = info.info.includes.begin(); i != info.info.includes.end(); ++i) { dest << "-" << *i << endl; diff --git a/src/includes.h b/src/includes.h index dd5f09b..8f6e98f 100644 --- a/src/includes.h +++ b/src/includes.h @@ -27,6 +27,9 @@ class IncludeInfo { // The file itself. Path file; + // The first included file (if any). + String firstInclude; + // All files included from this file. set includes; @@ -83,9 +86,9 @@ class Includes { InfoMap cache; // Find includes in file, and all files included from there. - set recursiveIncludesIn(const Path &file); + IncludeInfo recursiveIncludesIn(const Path &file); // Find includes in file. - void includesIn(const Path &file, PathQueue &to); + void includesIn(const Path &file, PathQueue &to, String *firstInclude); }; diff --git a/todo.org b/todo.org index d222620..579c256 100644 --- a/todo.org +++ b/todo.org @@ -2,7 +2,6 @@ Move constants used with Config into string constants somewhere. - We should check so that precompiled headers are always included first in every .cpp-file.