Skip to content

test precompiled headers #7404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
mSettings.plistOutput = std::move(path);
}

else if (std::strcmp(argv[i], "-pch") == 0)
mSettings.precompileHeader = true;

// Special Cppcheck Premium options
else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && isCppcheckPremium()) {
// valid options --premium=..
Expand Down
164 changes: 161 additions & 3 deletions externals/simplecpp/simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,13 @@ namespace simplecpp {
return invalidHashHash(loc, macroName, "Combining '\\"+ tokenA->str()+ "' and '"+ strAB.substr(tokenA->str().size()) + "' yields universal character '\\" + strAB + "'. This is undefined behavior according to C standard chapter 5.1.1.2, paragraph 4.");
}
};

std::string dump() const {
std::string ret;
for (const Token *tok = nameTokDef; sameline(nameTokDef,tok); tok = tok->next)
ret += "\n" + toString(tok->location.col) + ":" + tok->str();
return ret.substr(1);
}
private:
/** Create new token where Token::macro is set for replaced tokens */
Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced, const Token *expandedFromToken=nullptr) const {
Expand Down Expand Up @@ -3245,7 +3252,18 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
continue;

std::ifstream f;
const std::string header2 = openHeader(f,dui,sourcefile,header,systemheader);
std::string header2;
if (filenames.size() == 1) {
header2 = openHeader(f,dui,sourcefile,header + ".pch",systemheader);
if (f.is_open()) {
const std::string header2WithoutPch = header2.substr(0, header2.size() - 4);
TokenList *tokens = new TokenList(header2WithoutPch, filenames, outputList);
ret[header2WithoutPch] = tokens;
continue;
}
}
if (!f.is_open())
header2 = openHeader(f,dui,sourcefile,header,systemheader);
if (!f.is_open())
continue;
f.close();
Expand Down Expand Up @@ -3314,8 +3332,82 @@ static std::string getTimeDefine(const struct tm *timep)
return std::string("\"").append(buf).append("\"");
}

void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond)
static void loadPrecompiledHeader(simplecpp::TokenList& output,
const std::string& pch,
std::istream& f,
std::vector<std::string>& files,
std::map<std::string, simplecpp::TokenList *> &filedata,
simplecpp::MacroMap& macros)
{
simplecpp::TokenList * const macroTokens = new simplecpp::TokenList(files);
filedata[pch] = macroTokens;
enum { FILES, TOKENS, MACROS } section = FILES;
simplecpp::Location loc(files);
std::string line;
while (std::getline(f,line)) {
if (line == "files") {
section = FILES;
continue;
}
if (line == "tokens") {
section = TOKENS;
continue;
}
if (line == "[MACRO]") {
section = MACROS;
loc.fileIndex = 1;
loc.line = 1;
if (macroTokens->cback())
loc.line = macroTokens->cback()->location.line + 1;
loc.col = 1;
macroTokens->push_back(new simplecpp::Token("#", loc));
loc.col = 2;
macroTokens->push_back(new simplecpp::Token("define", loc));
continue;
}
if (section == FILES) {
std::string::size_type pos = line.find(':');
if (pos >= 1 && pos < line.size())
files.push_back(line.substr(pos+1));
continue;
}
if (section == TOKENS) {
std::string::size_type pos = 0;
while (pos < line.size() && line[pos] != ':') {
char c = line[pos++];
int value = 0;
while (pos < line.size() && std::isdigit(line[pos]))
value = value * 10 + line[pos++] - '0';
if (c == 'f')
loc.fileIndex = value;
else if (c == 'l')
loc.line = value;
else if (c == 'c')
loc.col = value;
}
if (pos + 1 < line.size() && line[pos] == ':')
output.push_back(new simplecpp::Token(line.substr(pos + 1), loc));
continue;
}
if (section == MACROS) {
const std::string::size_type pos = line.find(':');
loc.col = std::atoi(line.substr(0, pos).c_str());
macroTokens->push_back(new simplecpp::Token(line.substr(pos + 1), loc));
}
}
for (const simplecpp::Token* tok = macroTokens->cfront(); tok; tok = tok->next) {
if (tok->op == '#' && tok->next && tok->next->str() == DEFINE) {
simplecpp::Macro macro(tok, files);
if (macro.name() != "__DATE__" && macro.name() != "__TIME__")
macros.insert(std::pair<simplecpp::TokenString,simplecpp::Macro>(macro.name(), macro));
}
}
}

static void simplecppPreprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond, simplecpp::MacroMap& macros)
{
using namespace simplecpp;

#ifdef SIMPLECPP_WINDOWS
if (dui.clearIncludeCache)
nonExistingFilesCache.clear();
Expand Down Expand Up @@ -3347,7 +3439,6 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
std::vector<std::string> dummy;

const bool hasInclude = isCpp17OrLater(dui);
MacroMap macros;
for (std::list<std::string>::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) {
const std::string &macrostr = *it;
const std::string::size_type eq = macrostr.find('=');
Expand Down Expand Up @@ -3534,6 +3625,13 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
if (header2.empty()) {
// try to load file..
std::ifstream f;
if (output.empty()) {
header2 = openHeader(f, dui, rawtok->location.file(), header + ".pch", systemheader);
if (f.is_open()) {
loadPrecompiledHeader(output, header + ".pch", f, files, filedata, macros);
continue;
}
}
header2 = openHeader(f, dui, rawtok->location.file(), header, systemheader);
if (f.is_open()) {
f.close();
Expand Down Expand Up @@ -3792,6 +3890,66 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
}
}

void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond)
{
MacroMap macroMap;
simplecppPreprocess(output,
rawtokens,
files,
filedata,
dui,
outputList,
macroUsage,
ifCond,
macroMap);
}


std::string simplecpp::precompileHeader(const TokenList &rawtokens, std::vector<std::string> &files, const DUI &dui, OutputList *outputList)
{
std::map<std::string, TokenList*> filedata;
simplecpp::TokenList output(files);
std::list<simplecpp::MacroUsage> macroUsage;
std::list<simplecpp::IfCond> ifCond;
simplecpp::MacroMap macroMap;
simplecppPreprocess(output,
rawtokens,
files,
filedata,
dui,
outputList,
&macroUsage,
&ifCond,
macroMap);

std::string ret;
ret = "files\n";
for (size_t i = 0; i < files.size(); ++i)
ret += toString(i) + ":" + files[i] + "\n";
ret += "tokens\n";
unsigned int fileIndex = 0;
unsigned int line = 0;
unsigned int col = 0;
for (const simplecpp::Token *tok = output.cfront(); tok; tok = tok->next) {
if (tok->location.fileIndex != fileIndex) {
fileIndex = tok->location.fileIndex;
ret += "f" + toString(fileIndex);
}
if (tok->location.line != line) {
line = tok->location.line;
ret += "l" + toString(line);
}
if (tok->location.col != col) {
col = tok->location.col;
ret += "c" + toString(col);
}
ret += ":" + tok->str() + "\n";
}
for (simplecpp::MacroMap::const_iterator it = macroMap.begin(); it != macroMap.end(); ++it)
ret += "[MACRO]\n" + it->second.dump() + "\n";
return ret;
}

void simplecpp::cleanup(std::map<std::string, TokenList*> &filedata)
{
for (std::map<std::string, TokenList*>::iterator it = filedata.begin(); it != filedata.end(); ++it)
Expand Down
10 changes: 10 additions & 0 deletions externals/simplecpp/simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,16 @@ namespace simplecpp {
*/
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, TokenList*> &filedata, const DUI &dui, OutputList *outputList = nullptr, std::list<MacroUsage> *macroUsage = nullptr, std::list<IfCond> *ifCond = nullptr);

/**
* Precompile header
* @param rawtokens Raw tokenlist for top sourcefile
* @param files internal data of simplecpp
* @param dui defines, undefs, and include paths
* @param outputList output: list that will receive output messages
* @return precompiled header data
*/
SIMPLECPP_LIB std::string precompileHeader(const TokenList &rawtokens, std::vector<std::string> &files, const DUI &dui, OutputList *outputList = nullptr);

/**
* Deallocate data
*/
Expand Down
9 changes: 9 additions & 0 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,15 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
return mLogger->exitcode();
}

if (mSettings.precompileHeader) {
std::ofstream fout(file.spath() + ".pch");
if (fout.is_open()) {
const simplecpp::DUI& dui = Preprocessor::createDUI(mSettings, "", file.spath());
fout << simplecpp::precompileHeader(tokens1, files, dui, &outputList);
return mLogger->exitcode();
}
}

Preprocessor preprocessor(mSettings, mErrorLogger);

if (!preprocessor.loadFiles(tokens1, files))
Expand Down
2 changes: 1 addition & 1 deletion lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ static void splitcfg(const std::string &cfg, std::list<std::string> &defines, co
}
}

static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cfg, const std::string &filename)
simplecpp::DUI Preprocessor::createDUI(const Settings &mSettings, const std::string &cfg, const std::string &filename)
{
// TODO: make it possible to specify platform-dependent sizes
simplecpp::DUI dui;
Expand Down
2 changes: 2 additions & 0 deletions lib/preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {

static void setPlatformInfo(simplecpp::TokenList &tokens, const Settings& settings);

static simplecpp::DUI createDUI(const Settings &mSettings, const std::string &cfg, const std::string &filename);

simplecpp::TokenList preprocess(const simplecpp::TokenList &tokens1, const std::string &cfg, std::vector<std::string> &files, bool throwError = false);

std::string getcode(const simplecpp::TokenList &tokens1, const std::string &cfg, std::vector<std::string> &files, bool writeLocations);
Expand Down
3 changes: 3 additions & 0 deletions lib/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
/** Is checker id enabled by premiumArgs */
bool isPremiumEnabled(const char id[]) const;

/** @brief Precompile a header file into a .pch file */
bool precompileHeader{};

/** @brief Using -E for debugging purposes */
bool preprocessOnly{};

Expand Down
Loading