diff options
author | Brad King <brad.king@kitware.com> | 2008-03-07 13:40:36 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-03-07 13:40:36 (GMT) |
commit | 680104a490250f7b56b67aa3cbb7c113d997e93c (patch) | |
tree | 52af6beb6a876f03a1205c050ad8295e338ca573 /Source/cmMakefile.cxx | |
parent | 41a59e211ef6b0c9c839545661579934ce9415c1 (diff) | |
download | CMake-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.cxx | 212 |
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: |