summaryrefslogtreecommitdiffstats
path: root/Source/cmMakefile.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2008-03-07 13:40:36 (GMT)
committerBrad King <brad.king@kitware.com>2008-03-07 13:40:36 (GMT)
commit680104a490250f7b56b67aa3cbb7c113d997e93c (patch)
tree52af6beb6a876f03a1205c050ad8295e338ca573 /Source/cmMakefile.cxx
parent41a59e211ef6b0c9c839545661579934ce9415c1 (diff)
downloadCMake-680104a490250f7b56b67aa3cbb7c113d997e93c.zip
CMake-680104a490250f7b56b67aa3cbb7c113d997e93c.tar.gz
CMake-680104a490250f7b56b67aa3cbb7c113d997e93c.tar.bz2
ENH: New format for warning and error messages
- Add cmMakefile methods IssueError and IssueWarning - Maintain an explicit call stack in cmMakefile - Include context/call-stack info in messages - Nested errors now unwind the call stack - Use new mechanism for policy warnings and errors - Improve policy error message - Include cmExecutionStatus pointer in call stack so that errors deeper in the C++ stack under a command invocation will become errors for the command
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r--Source/cmMakefile.cxx212
1 files changed, 163 insertions, 49 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index df93dc0..a3c3846 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -280,6 +280,134 @@ bool cmMakefile::CommandExists(const char* name) const
return this->GetCMakeInstance()->CommandExists(name);
}
+//----------------------------------------------------------------------------
+// Helper function to print a block of text with every line following
+// a given prefix.
+void cmMakefilePrintPrefixed(std::ostream& os, const char* prefix,
+ std::string const& msg)
+{
+ bool newline = true;
+ for(const char* c = msg.c_str(); *c; ++c)
+ {
+ if(newline)
+ {
+ os << prefix;
+ newline = false;
+ }
+ os << *c;
+ if(*c == '\n')
+ {
+ newline = true;
+ }
+ }
+ if(!newline)
+ {
+ os << "\n";
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmMakefile::IssueError(std::string const& msg) const
+{
+ this->IssueMessage(msg, true);
+}
+
+//----------------------------------------------------------------------------
+void cmMakefile::IssueWarning(std::string const& msg) const
+{
+ this->IssueMessage(msg, false);
+}
+
+//----------------------------------------------------------------------------
+void cmMakefile::IssueMessage(std::string const& text, bool isError) const
+{
+ cmOStringStream msg;
+
+ // Construct the message header.
+ if(isError)
+ {
+ msg << "CMake Error:";
+ }
+ else
+ {
+ msg << "CMake Warning:";
+ }
+
+ // Add the immediate context.
+ CallStackType::const_reverse_iterator i = this->CallStack.rbegin();
+ if(i != this->CallStack.rend())
+ {
+ if(isError)
+ {
+ i->Status->SetNestedError(true);
+ }
+ cmListFileContext const& lfc = *i->Context;
+ msg
+ << " at "
+ << this->LocalGenerator->Convert(lfc.FilePath.c_str(),
+ cmLocalGenerator::HOME)
+ << ":" << lfc.Line << " " << lfc.Name;
+ ++i;
+ }
+
+ // Add the message text.
+ msg << " {\n";
+ cmMakefilePrintPrefixed(msg, " ", text);
+ msg << "}";
+
+ // Add the rest of the context.
+ if(i != this->CallStack.rend())
+ {
+ msg << " with call stack {\n";
+ while(i != this->CallStack.rend())
+ {
+ cmListFileContext const& lfc = *i->Context;
+ msg << " "
+ << this->LocalGenerator->Convert(lfc.FilePath.c_str(),
+ cmLocalGenerator::HOME)
+ << ":" << lfc.Line << " " << lfc.Name << "\n";
+ ++i;
+ }
+ msg << "}\n";
+ }
+ else
+ {
+ msg << "\n";
+ }
+
+ // Output the message.
+ if(isError)
+ {
+ cmSystemTools::SetErrorOccured();
+ cmSystemTools::Message(msg.str().c_str(), "Error");
+ }
+ else
+ {
+ cmSystemTools::Message(msg.str().c_str(), "Warning");
+ }
+}
+
+//----------------------------------------------------------------------------
+// Helper class to make sure the call stack is valid.
+class cmMakefileCall
+{
+public:
+ cmMakefileCall(cmMakefile* mf,
+ cmListFileContext const& lfc,
+ cmExecutionStatus& status): Makefile(mf)
+ {
+ cmMakefile::CallStackEntry entry = {&lfc, &status};
+ this->Makefile->CallStack.push_back(entry);
+ }
+ ~cmMakefileCall()
+ {
+ this->Makefile->CallStack.pop_back();
+ }
+private:
+ cmMakefile* Makefile;
+};
+
+//----------------------------------------------------------------------------
bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
cmExecutionStatus &status)
{
@@ -294,34 +422,30 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
std::string name = lff.Name;
- // execute the command
- cmCommand *rm =
- this->GetCMakeInstance()->GetCommand(name.c_str());
- if(rm)
- {
- // const char* versionValue
- // = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
- // int major = 0;
- // int minor = 0;
- // if ( versionValue )
- // {
- // sscanf(versionValue, "%d.%d", &major, &minor);
- // }
- cmCommand* usedCommand = rm->Clone();
- usedCommand->SetMakefile(this);
- bool keepCommand = false;
- if(usedCommand->GetEnabled() && !cmSystemTools::GetFatalErrorOccured() &&
- (!this->GetCMakeInstance()->GetScriptMode() ||
- usedCommand->IsScriptable()))
- {
- if(!usedCommand->InvokeInitialPass(lff.Arguments,status))
+ // Place this call on the call stack.
+ cmMakefileCall stack_manager(this, lff, status);
+ static_cast<void>(stack_manager);
+
+ // Lookup the command prototype.
+ if(cmCommand* proto = this->GetCMakeInstance()->GetCommand(name.c_str()))
+ {
+ // Clone the prototype.
+ cmsys::auto_ptr<cmCommand> pcmd(proto->Clone());
+ pcmd->SetMakefile(this);
+
+ // Decide whether to invoke the command.
+ if(pcmd->GetEnabled() && !cmSystemTools::GetFatalErrorOccured() &&
+ (!this->GetCMakeInstance()->GetScriptMode() || pcmd->IsScriptable()))
+ {
+ // Try invoking the command.
+ if(!pcmd->InvokeInitialPass(lff.Arguments,status) ||
+ status.GetNestedError())
{
- cmOStringStream error;
- error << "Error in cmake code at\n"
- << lff.FilePath << ":" << lff.Line << ":\n"
- << usedCommand->GetError() << std::endl
- << " Called from: " << this->GetListFileStack().c_str();
- cmSystemTools::Error(error.str().c_str());
+ if(!status.GetNestedError())
+ {
+ // The command invocation requested that we report an error.
+ this->IssueError(pcmd->GetError());
+ }
result = false;
if ( this->GetCMakeInstance()->GetScriptMode() )
{
@@ -331,38 +455,28 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
else
{
// use the command
- keepCommand = true;
- this->UsedCommands.push_back(usedCommand);
+ this->UsedCommands.push_back(pcmd.release());
}
}
else if ( this->GetCMakeInstance()->GetScriptMode()
- && !usedCommand->IsScriptable() )
+ && !pcmd->IsScriptable() )
{
- cmOStringStream error;
- error << "Error in cmake code at\n"
- << lff.FilePath << ":" << lff.Line << ":\n"
- << "Command " << usedCommand->GetName()
- << "() is not scriptable" << std::endl;
- cmSystemTools::Error(error.str().c_str());
+ std::string error = "Command ";
+ error += pcmd->GetName();
+ error += "() is not scriptable";
+ this->IssueError(error);
result = false;
cmSystemTools::SetFatalErrorOccured();
}
- // if the Cloned command was not used
- // then delete it
- if(!keepCommand)
- {
- delete usedCommand;
- }
}
else
{
if(!cmSystemTools::GetFatalErrorOccured())
{
- cmOStringStream error;
- error << "Error in cmake code at\n"
- << lff.FilePath << ":" << lff.Line << ":\n"
- << "Unknown CMake command \"" << lff.Name.c_str() << "\".";
- cmSystemTools::Error(error.str().c_str());
+ std::string error = "Unknown CMake command \"";
+ error += lff.Name;
+ error += "\".";
+ this->IssueError(error);
result = false;
cmSystemTools::SetFatalErrorOccured();
}
@@ -3152,8 +3266,8 @@ bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
switch (this->GetPolicyStatus(cmPolicies::CMP_0002))
{
case cmPolicies::WARN:
- msg = this->GetPolicies()->
- GetPolicyWarning(cmPolicies::CMP_0002);
+ this->IssueWarning(this->GetPolicies()->
+ GetPolicyWarning(cmPolicies::CMP_0002));
case cmPolicies::OLD:
return true;
case cmPolicies::REQUIRED_IF_USED: