CMake/Source/cmListFileCache.cxx

521 lines
16 KiB
C++
Raw Normal View History

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
2002-01-21 23:30:43 +03:00
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
2002-01-21 23:30:43 +03:00
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmListFileCache.h"
#include "cmListFileLexer.h"
#include "cmMakefile.h"
#include "cmOutputConverter.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
#include <cmsys/RegularExpression.hxx>
struct cmListFileParser
{
cmListFileParser(cmListFile* lf, cmMakefile* mf, const char* filename);
~cmListFileParser();
bool ParseFile();
bool ParseFunction(const char* name, long line);
bool AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim);
cmListFile* ListFile;
cmMakefile* Makefile;
const char* FileName;
cmListFileLexer* Lexer;
cmListFileFunction Function;
enum
{
SeparationOkay,
SeparationWarning,
SeparationError
} Separation;
};
cmListFileParser::cmListFileParser(cmListFile* lf, cmMakefile* mf,
const char* filename)
: ListFile(lf)
, Makefile(mf)
, FileName(filename)
, Lexer(cmListFileLexer_New())
{
}
cmListFileParser::~cmListFileParser()
{
cmListFileLexer_Delete(this->Lexer);
}
bool cmListFileParser::ParseFile()
{
// Open the file.
cmListFileLexer_BOM bom;
if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) {
cmSystemTools::Error("cmListFileCache: error can not open file ",
this->FileName);
return false;
}
// Verify the Byte-Order-Mark, if any.
if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) {
cmListFileLexer_SetFileName(this->Lexer, 0, 0);
std::ostringstream m;
m << "File\n " << this->FileName << "\n"
<< "starts with a Byte-Order-Mark that is not UTF-8.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str());
return false;
}
// Use a simple recursive-descent parser to process the token
// stream.
bool haveNewline = true;
while (cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) {
if (token->type == cmListFileLexer_Token_Space) {
} else if (token->type == cmListFileLexer_Token_Newline) {
haveNewline = true;
} else if (token->type == cmListFileLexer_Token_CommentBracket) {
haveNewline = false;
} else if (token->type == cmListFileLexer_Token_Identifier) {
if (haveNewline) {
haveNewline = false;
if (this->ParseFunction(token->text, token->line)) {
this->ListFile->Functions.push_back(this->Function);
} else {
return false;
}
} else {
std::ostringstream error;
error << "Error in cmake code at\n"
<< this->FileName << ":" << token->line << ":\n"
<< "Parse error. Expected a newline, got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
cmSystemTools::Error(error.str().c_str());
return false;
}
} else {
std::ostringstream error;
error << "Error in cmake code at\n"
<< this->FileName << ":" << token->line << ":\n"
<< "Parse error. Expected a command name, got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
cmSystemTools::Error(error.str().c_str());
return false;
}
}
return true;
}
bool cmListFile::ParseFile(const char* filename, bool topLevel, cmMakefile* mf)
{
if (!cmSystemTools::FileExists(filename) ||
cmSystemTools::FileIsDirectory(filename)) {
return false;
}
bool parseError = false;
{
cmListFileParser parser(this, mf, filename);
parseError = !parser.ParseFile();
}
// do we need a cmake_policy(VERSION call?
if (topLevel) {
bool hasVersion = false;
// search for the right policy command
for (std::vector<cmListFileFunction>::iterator i = this->Functions.begin();
i != this->Functions.end(); ++i) {
if (cmSystemTools::LowerCase(i->Name) == "cmake_minimum_required") {
hasVersion = true;
break;
}
}
// if no policy command is found this is an error if they use any
// non advanced functions or a lot of functions
if (!hasVersion) {
bool isProblem = true;
if (this->Functions.size() < 30) {
// the list of simple commands DO NOT ADD TO THIS LIST!!!!!
// these commands must have backwards compatibility forever and
// and that is a lot longer than your tiny mind can comprehend mortal
std::set<std::string> allowedCommands;
allowedCommands.insert("project");
allowedCommands.insert("set");
allowedCommands.insert("if");
allowedCommands.insert("endif");
allowedCommands.insert("else");
allowedCommands.insert("elseif");
allowedCommands.insert("add_executable");
allowedCommands.insert("add_library");
allowedCommands.insert("target_link_libraries");
allowedCommands.insert("option");
allowedCommands.insert("message");
isProblem = false;
for (std::vector<cmListFileFunction>::iterator i =
this->Functions.begin();
i != this->Functions.end(); ++i) {
std::string name = cmSystemTools::LowerCase(i->Name);
if (allowedCommands.find(name) == allowedCommands.end()) {
2008-03-20 17:46:24 +03:00
isProblem = true;
break;
}
}
}
if (isProblem) {
// Tell the top level cmMakefile to diagnose
// this violation of CMP0000.
mf->SetCheckCMP0000(true);
// Implicitly set the version for the user.
mf->SetPolicyVersion("2.4");
}
}
bool hasProject = false;
// search for a project command
for (std::vector<cmListFileFunction>::iterator i = this->Functions.begin();
i != this->Functions.end(); ++i) {
if (cmSystemTools::LowerCase(i->Name) == "project") {
hasProject = true;
break;
}
}
// if no project command is found, add one
if (!hasProject) {
cmListFileFunction project;
2006-03-15 19:02:08 +03:00
project.Name = "PROJECT";
cmListFileArgument prj("Project", cmListFileArgument::Unquoted, 0);
2006-03-15 19:02:08 +03:00
project.Arguments.push_back(prj);
this->Functions.insert(this->Functions.begin(), project);
}
}
return !parseError;
}
2002-09-19 22:34:15 +04:00
bool cmListFileParser::ParseFunction(const char* name, long line)
{
// Ininitialize a new function call.
this->Function = cmListFileFunction();
this->Function.Name = name;
this->Function.Line = line;
// Command name has already been parsed. Read the left paren.
cmListFileLexer_Token* token;
while ((token = cmListFileLexer_Scan(this->Lexer)) &&
token->type == cmListFileLexer_Token_Space) {
}
if (!token) {
std::ostringstream error;
/* clang-format off */
error << "Error in cmake code at\n" << this->FileName << ":"
<< cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
<< "Parse error. Function missing opening \"(\".";
/* clang-format on */
cmSystemTools::Error(error.str().c_str());
return false;
}
if (token->type != cmListFileLexer_Token_ParenLeft) {
std::ostringstream error;
error << "Error in cmake code at\n"
<< this->FileName << ":"
<< cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
<< "Parse error. Expected \"(\", got "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
cmSystemTools::Error(error.str().c_str());
return false;
}
// Arguments.
unsigned long lastLine;
unsigned long parenDepth = 0;
this->Separation = SeparationOkay;
while ((lastLine = cmListFileLexer_GetCurrentLine(this->Lexer),
token = cmListFileLexer_Scan(this->Lexer))) {
if (token->type == cmListFileLexer_Token_Space ||
token->type == cmListFileLexer_Token_Newline) {
this->Separation = SeparationOkay;
continue;
}
if (token->type == cmListFileLexer_Token_ParenLeft) {
parenDepth++;
this->Separation = SeparationOkay;
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
} else if (token->type == cmListFileLexer_Token_ParenRight) {
if (parenDepth == 0) {
return true;
}
parenDepth--;
this->Separation = SeparationOkay;
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_Identifier ||
token->type == cmListFileLexer_Token_ArgumentUnquoted) {
if (!this->AddArgument(token, cmListFileArgument::Unquoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_ArgumentQuoted) {
if (!this->AddArgument(token, cmListFileArgument::Quoted)) {
return false;
}
this->Separation = SeparationWarning;
} else if (token->type == cmListFileLexer_Token_ArgumentBracket) {
if (!this->AddArgument(token, cmListFileArgument::Bracket)) {
return false;
}
this->Separation = SeparationError;
} else if (token->type == cmListFileLexer_Token_CommentBracket) {
this->Separation = SeparationError;
} else {
// Error.
std::ostringstream error;
error << "Error in cmake code at\n"
<< this->FileName << ":"
<< cmListFileLexer_GetCurrentLine(this->Lexer) << ":\n"
<< "Parse error. Function missing ending \")\". "
<< "Instead found "
<< cmListFileLexer_GetTypeAsString(this->Lexer, token->type)
<< " with text \"" << token->text << "\".";
cmSystemTools::Error(error.str().c_str());
return false;
}
}
std::ostringstream error;
error << "Error in cmake code at\n"
<< this->FileName << ":" << lastLine << ":\n"
<< "Parse error. Function missing ending \")\". "
<< "End of file reached.";
cmSystemTools::Error(error.str().c_str());
return false;
}
bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim)
{
cmListFileArgument a(token->text, delim, token->line);
this->Function.Arguments.push_back(a);
if (this->Separation == SeparationOkay) {
return true;
}
bool isError = (this->Separation == SeparationError ||
delim == cmListFileArgument::Bracket);
std::ostringstream m;
/* clang-format off */
m << "Syntax " << (isError? "Error":"Warning") << " in cmake code at\n"
<< " " << this->FileName << ":" << token->line << ":"
<< token->column << "\n"
<< "Argument not separated from preceding token by whitespace.";
/* clang-format on */
if (isError) {
this->Makefile->IssueMessage(cmake::FATAL_ERROR, m.str());
return false;
} else {
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, m.str());
return true;
}
}
struct cmListFileBacktrace::Entry : public cmListFileContext
{
Entry(cmListFileContext const& lfc, Entry* up)
: cmListFileContext(lfc)
, Up(up)
, RefCount(0)
{
if (this->Up) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
this->Up->Ref();
cmState: Avoid accumulating snapshot storage for backtraces Changes during post-3.3/pre-3.4 development refactored storage of most configure-time information, including variable bindings and function scopes. All scopes (even short-lived) were kept persistently for possible future debugging features, causing huge accumulated memory usage. This was mostly addressed by commit v3.4.1~4^2 (cmState: Avoid accumulating snapshot storage for short-lived scopes, 2015-11-24). Since then we still keep short-lived scopes when they are needed for a backtrace. This is because since commit v3.4.0-rc1~378^2 (cmListFileBacktrace: Implement in terms of cmState::Snapshot, 2015-05-29) backtraces have been lightweight objects that simply point into the snapshot tree. While the intention of this approach was to avoid duplicating the call stack file path strings, the cost turned out to be holding on to the entire call stack worth of scope snapshots, which is much worse. Furthermore, since commit v3.4.0-rc2~1^2 (cmIfCommand: Issue CMP0054 warning with appropriate context, 2015-10-20) all conditions used in `if()` commands hold a backtrace for use in diagnostic messages. Even though the backtrace is short-lived it still causes the scope snapshot to be kept. This means that code like function(foo) if(0) endif() endfunction() foreach(i RANGE 1000000) foo() endforeach() accumulates storage for the function call scope snapshots. Fix this by partially reverting commit v3.4.0-rc1~378^2 and saving the entire call stack during cmListFileBacktrace construction. This way we can avoid keeping short-lived scope snapshot storage in all cases.
2016-04-13 00:07:08 +03:00
}
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
~Entry()
{
if (this->Up) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
this->Up->Unref();
}
}
void Ref() { ++this->RefCount; }
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
void Unref()
{
if (--this->RefCount == 0) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
delete this;
}
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
Entry* Up;
unsigned int RefCount;
};
cmState: Avoid accumulating snapshot storage for backtraces Changes during post-3.3/pre-3.4 development refactored storage of most configure-time information, including variable bindings and function scopes. All scopes (even short-lived) were kept persistently for possible future debugging features, causing huge accumulated memory usage. This was mostly addressed by commit v3.4.1~4^2 (cmState: Avoid accumulating snapshot storage for short-lived scopes, 2015-11-24). Since then we still keep short-lived scopes when they are needed for a backtrace. This is because since commit v3.4.0-rc1~378^2 (cmListFileBacktrace: Implement in terms of cmState::Snapshot, 2015-05-29) backtraces have been lightweight objects that simply point into the snapshot tree. While the intention of this approach was to avoid duplicating the call stack file path strings, the cost turned out to be holding on to the entire call stack worth of scope snapshots, which is much worse. Furthermore, since commit v3.4.0-rc2~1^2 (cmIfCommand: Issue CMP0054 warning with appropriate context, 2015-10-20) all conditions used in `if()` commands hold a backtrace for use in diagnostic messages. Even though the backtrace is short-lived it still causes the scope snapshot to be kept. This means that code like function(foo) if(0) endif() endfunction() foreach(i RANGE 1000000) foo() endforeach() accumulates storage for the function call scope snapshots. Fix this by partially reverting commit v3.4.0-rc1~378^2 and saving the entire call stack during cmListFileBacktrace construction. This way we can avoid keeping short-lived scope snapshot storage in all cases.
2016-04-13 00:07:08 +03:00
cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom, Entry* up,
cmListFileContext const& lfc)
: Bottom(bottom)
, Cur(new Entry(lfc, up))
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
assert(this->Bottom.IsValid());
this->Cur->Ref();
}
cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom, Entry* cur)
: Bottom(bottom)
, Cur(cur)
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
if (this->Cur) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
assert(this->Bottom.IsValid());
this->Cur->Ref();
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
}
cmListFileBacktrace::cmListFileBacktrace()
: Bottom()
, Cur(0)
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
}
cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot snapshot)
: Bottom(snapshot.GetCallStackBottom())
, Cur(0)
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
}
cmListFileBacktrace::cmListFileBacktrace(cmListFileBacktrace const& r)
: Bottom(r.Bottom)
, Cur(r.Cur)
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
if (this->Cur) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
assert(this->Bottom.IsValid());
this->Cur->Ref();
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
}
cmState: Avoid accumulating snapshot storage for backtraces Changes during post-3.3/pre-3.4 development refactored storage of most configure-time information, including variable bindings and function scopes. All scopes (even short-lived) were kept persistently for possible future debugging features, causing huge accumulated memory usage. This was mostly addressed by commit v3.4.1~4^2 (cmState: Avoid accumulating snapshot storage for short-lived scopes, 2015-11-24). Since then we still keep short-lived scopes when they are needed for a backtrace. This is because since commit v3.4.0-rc1~378^2 (cmListFileBacktrace: Implement in terms of cmState::Snapshot, 2015-05-29) backtraces have been lightweight objects that simply point into the snapshot tree. While the intention of this approach was to avoid duplicating the call stack file path strings, the cost turned out to be holding on to the entire call stack worth of scope snapshots, which is much worse. Furthermore, since commit v3.4.0-rc2~1^2 (cmIfCommand: Issue CMP0054 warning with appropriate context, 2015-10-20) all conditions used in `if()` commands hold a backtrace for use in diagnostic messages. Even though the backtrace is short-lived it still causes the scope snapshot to be kept. This means that code like function(foo) if(0) endif() endfunction() foreach(i RANGE 1000000) foo() endforeach() accumulates storage for the function call scope snapshots. Fix this by partially reverting commit v3.4.0-rc1~378^2 and saving the entire call stack during cmListFileBacktrace construction. This way we can avoid keeping short-lived scope snapshot storage in all cases.
2016-04-13 00:07:08 +03:00
cmListFileBacktrace& cmListFileBacktrace::operator=(
cmListFileBacktrace const& r)
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
cmListFileBacktrace tmp(r);
std::swap(this->Cur, tmp.Cur);
std::swap(this->Bottom, tmp.Bottom);
return *this;
}
cmListFileBacktrace::~cmListFileBacktrace()
{
if (this->Cur) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
this->Cur->Unref();
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
}
cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
// We are entering a file-level scope but have not yet reached
// any specific line or command invocation within it. This context
// is useful to print when it is at the top but otherwise can be
// skipped during call stack printing.
cmListFileContext lfc;
lfc.FilePath = file;
return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
}
cmListFileBacktrace cmListFileBacktrace::Push(
cmListFileContext const& lfc) const
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
{
return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
}
cmListFileBacktrace cmListFileBacktrace::Pop() const
{
assert(this->Cur);
return cmListFileBacktrace(this->Bottom, this->Cur->Up);
}
cmListFileContext const& cmListFileBacktrace::Top() const
{
if (this->Cur) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
return *this->Cur;
} else {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
static cmListFileContext const empty;
return empty;
}
}
2015-07-09 23:26:51 +03:00
void cmListFileBacktrace::PrintTitle(std::ostream& out) const
{
if (!this->Cur) {
return;
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
cmOutputConverter converter(this->Bottom);
cmListFileContext lfc = *this->Cur;
if (!this->Bottom.GetState()->GetIsInTryCompile()) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
}
out << (lfc.Line ? " at " : " in ") << lfc;
}
2015-07-09 23:26:51 +03:00
void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
{
if (!this->Cur || !this->Cur->Up) {
return;
}
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
bool first = true;
cmOutputConverter converter(this->Bottom);
for (Entry* i = this->Cur->Up; i; i = i->Up) {
if (i->Name.empty()) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
// Skip this whole-file scope. When we get here we already will
// have printed a more-specific context within the file.
continue;
}
if (first) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
first = false;
out << "Call Stack (most recent call first):\n";
}
cmState: Avoid accumulating snapshot storage for backtraces Changes during post-3.3/pre-3.4 development refactored storage of most configure-time information, including variable bindings and function scopes. All scopes (even short-lived) were kept persistently for possible future debugging features, causing huge accumulated memory usage. This was mostly addressed by commit v3.4.1~4^2 (cmState: Avoid accumulating snapshot storage for short-lived scopes, 2015-11-24). Since then we still keep short-lived scopes when they are needed for a backtrace. This is because since commit v3.4.0-rc1~378^2 (cmListFileBacktrace: Implement in terms of cmState::Snapshot, 2015-05-29) backtraces have been lightweight objects that simply point into the snapshot tree. While the intention of this approach was to avoid duplicating the call stack file path strings, the cost turned out to be holding on to the entire call stack worth of scope snapshots, which is much worse. Furthermore, since commit v3.4.0-rc2~1^2 (cmIfCommand: Issue CMP0054 warning with appropriate context, 2015-10-20) all conditions used in `if()` commands hold a backtrace for use in diagnostic messages. Even though the backtrace is short-lived it still causes the scope snapshot to be kept. This means that code like function(foo) if(0) endif() endfunction() foreach(i RANGE 1000000) foo() endforeach() accumulates storage for the function call scope snapshots. Fix this by partially reverting commit v3.4.0-rc1~378^2 and saving the entire call stack during cmListFileBacktrace construction. This way we can avoid keeping short-lived scope snapshot storage in all cases.
2016-04-13 00:07:08 +03:00
cmListFileContext lfc = *i;
if (!this->Bottom.GetState()->GetIsInTryCompile()) {
cmListFileBacktrace: Refactor storage to provide efficient value semantics Since commit v3.4.0-rc1~321^2~2 (Genex: Store a backtrace, not a pointer to one, 2015-07-08) we treat cmListFileBacktrace instances as lightweight values. This was true at the time only because the backtrace information was kept in the cmState snapshot hierarchy. However, that forced us to accumulate a lot of otherwise short-lived snapshots just to have the backtrace fields available for reference by cmListFileBacktrace instances. Recent refactoring made backtrace instances independent of the snapshot hierarchy to avoid accumulating short-lived snapshots. This came at the cost of making backtrace values heavy again, leading to lots of string coying and slower execution. Fix this by refactoring cmListFileBacktrace to provide value semantics with efficient shared storage underneath. Teach cmMakefile to maintain its call stack using an instance of cmListFileBacktrace. This approach allows the current backtrace to be efficiently saved whenever it is needed. Also teach cmListFileBacktrace the notion of a file-level scope. This is useful for messages about the whole file (e.g. during parsing) that are not specific to any line within it. Push the CMakeLists.txt scope for each directory and never pop it. This ensures that we always have some context information and simplifies cmMakefile::IssueMessage. Push/pop a file-level scope as each included file is processed. This supersedes cmParseFileScope and improves diagnostic message context information in a few places. Fix the corresponding test cases to expect the improved output.
2016-04-14 18:24:08 +03:00
lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
}
out << " " << lfc << "\n";
}
}
std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
{
os << lfc.FilePath;
if (lfc.Line) {
os << ":" << lfc.Line;
if (!lfc.Name.empty()) {
os << " (" << lfc.Name << ")";
}
}
return os;
}
bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
if (lhs.Line != rhs.Line) {
return lhs.Line < rhs.Line;
}
return lhs.FilePath < rhs.FilePath;
}
bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath;
}
bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs)
{
return !(lhs == rhs);
}