ENH: Improve new error/warning message generation

- Add cmListFileBacktrace to record stack traces
  - Move main IssueMessage method to the cmake class instance
    (make the backtrace an explicit argument)
  - Change cmMakefile::IssueMessage to construct a backtrace
    and call the cmake instance version
  - Record a backtrace at the point a target is created
    (useful later for messages issued by generators)
This commit is contained in:
Brad King 2008-03-13 13:48:57 -04:00
parent 73df9a5cd4
commit f7f03347a6
8 changed files with 155 additions and 91 deletions

View File

@ -268,3 +268,18 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
return false;
}
//----------------------------------------------------------------------------
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;
}

View File

@ -57,11 +57,15 @@ struct cmListFileContext
long Line;
};
std::ostream& operator<<(std::ostream&, cmListFileContext const&);
struct cmListFileFunction: public cmListFileContext
{
std::vector<cmListFileArgument> Arguments;
};
class cmListFileBacktrace: public std::vector<cmListFileContext> {};
struct cmListFile
{
cmListFile()

View File

@ -35,8 +35,6 @@
#include "cmake.h"
#include <stdlib.h> // required for atoi
#include "cmDocumentationFormatterText.h"
#include <cmsys/RegularExpression.hxx>
#include <cmsys/auto_ptr.hxx>
@ -287,108 +285,51 @@ bool cmMakefile::CommandExists(const char* name) const
void cmMakefile::IssueMessage(cmake::MessageType t,
std::string const& text) const
{
cmOStringStream msg;
bool isError = false;
// Construct the message header.
if(t == cmake::FATAL_ERROR)
// Collect context information.
cmListFileBacktrace backtrace;
if(!this->CallStack.empty())
{
isError = true;
msg << "CMake Error:";
}
else if(t == cmake::INTERNAL_ERROR)
{
isError = true;
msg << "CMake Internal Error, please report a bug: ";
}
else
{
msg << "CMake Warning";
if(t == cmake::AUTHOR_WARNING)
if((t == cmake::FATAL_ERROR) || (t == cmake::INTERNAL_ERROR))
{
if(this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"))
{
return;
}
msg << "(dev)";
this->CallStack.back().Status->SetNestedError(true);
}
msg << ":";
}
// 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;
this->GetBacktrace(backtrace);
}
else if(!this->ListFileStack.empty())
{
// We are processing the project but are not currently executing a
// command. Add whatever context information we have.
if(this->LocalGenerator->GetParent())
cmListFileContext lfc;
lfc.FilePath = this->ListFileStack.back();
lfc.Line = 0;
if(!this->GetCMakeInstance()->GetIsInTryCompile())
{
msg << " in directory "
<< this->LocalGenerator->Convert(this->GetCurrentDirectory(),
cmLocalGenerator::HOME);
}
else if(this->GetCMakeInstance()->GetIsInTryCompile())
{
msg << " in directory " << this->GetCurrentDirectory();
}
else
{
msg << " in top-level directory";
lfc.FilePath = this->LocalGenerator->Convert(lfc.FilePath.c_str(),
cmLocalGenerator::HOME);
}
backtrace.push_back(lfc);
}
// Add the message text.
{
msg << " {\n";
cmDocumentationFormatterText formatter;
formatter.SetIndent(" ");
formatter.PrintFormatted(msg, text.c_str());
msg << "}";
}
// Issue the message.
this->GetCMakeInstance()->IssueMessage(t, text, backtrace);
}
// Add the rest of the context.
if(i != this->CallStack.rend())
//----------------------------------------------------------------------------
bool cmMakefile::GetBacktrace(cmListFileBacktrace& backtrace) const
{
if(this->CallStack.empty())
{
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";
return false;
}
else
for(CallStackType::const_reverse_iterator i = this->CallStack.rbegin();
i != this->CallStack.rend(); ++i)
{
msg << "\n";
}
// Output the message.
if(isError)
{
cmSystemTools::SetErrorOccured();
cmSystemTools::Message(msg.str().c_str(), "Error");
}
else
{
cmSystemTools::Message(msg.str().c_str(), "Warning");
cmListFileContext lfc = *(*i).Context;
lfc.FilePath = this->LocalGenerator->Convert(lfc.FilePath.c_str(),
cmLocalGenerator::HOME);
backtrace.push_back(lfc);
}
return true;
}
//----------------------------------------------------------------------------
@ -1647,12 +1588,11 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName,
cmTarget*
cmMakefile::AddNewTarget(cmTarget::TargetType type, const char* name)
{
cmTargets::iterator it;
cmTarget target;
cmTargets::iterator it =
this->Targets.insert(cmTargets::value_type(name, cmTarget())).first;
cmTarget& target = it->second;
target.SetType(type, name);
target.SetMakefile(this);
it=this->Targets.insert(
cmTargets::value_type(target.GetName(), target)).first;
this->LocalGenerator->GetGlobalGenerator()->AddTarget(*it);
return &it->second;
}

View File

@ -606,6 +606,11 @@ public:
*/
std::string GetListFileStack();
/**
* Get the current context backtrace.
*/
bool GetBacktrace(cmListFileBacktrace& backtrace) const;
/**
* Get the vector of files created by this makefile
*/

View File

@ -21,6 +21,7 @@
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmComputeLinkInformation.h"
#include "cmListFileCache.h"
#include <map>
#include <set>
#include <queue>
@ -43,6 +44,9 @@ public:
typedef cmTarget::SourceFileFlags SourceFileFlags;
std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap;
bool SourceFileFlagsConstructed;
// The backtrace when the target was created.
cmListFileBacktrace Backtrace;
};
//----------------------------------------------------------------------------
@ -719,6 +723,15 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault(property.c_str(), 0);
}
}
// Save the backtrace of target construction.
this->Makefile->GetBacktrace(this->Internal->Backtrace);
}
//----------------------------------------------------------------------------
cmListFileBacktrace const& cmTarget::GetBacktrace() const
{
return this->Internal->Backtrace;
}
//----------------------------------------------------------------------------

View File

@ -25,6 +25,7 @@ class cmMakefile;
class cmSourceFile;
class cmGlobalGenerator;
class cmComputeLinkInformation;
class cmListFileBacktrace;
struct cmTargetLinkInformationMap:
public std::map<cmStdString, cmComputeLinkInformation*>
@ -374,6 +375,9 @@ public:
/** Return whether this target is an executable Bundle on Apple. */
bool IsAppBundleOnApple();
/** Get a backtrace from the creation of the target. */
cmListFileBacktrace const& GetBacktrace() const;
private:
/**
* A list of direct dependencies. Use in conjunction with DependencyMap.

View File

@ -28,6 +28,7 @@
#include "cmSourceFile.h"
#include "cmVersion.h"
#include "cmTest.h"
#include "cmDocumentationFormatterText.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
@ -4108,3 +4109,80 @@ int cmake::VisualStudioLinkNonIncremental(std::vector<std::string>& args,
}
return 0;
}
//----------------------------------------------------------------------------
void cmake::IssueMessage(cmake::MessageType t, std::string const& text,
cmListFileBacktrace const& backtrace)
{
cmOStringStream msg;
bool isError = false;
// Construct the message header.
if(t == cmake::FATAL_ERROR)
{
isError = true;
msg << "CMake Error";
}
else if(t == cmake::INTERNAL_ERROR)
{
isError = true;
msg << "CMake Internal Error (please report a bug)";
}
else
{
msg << "CMake Warning";
if(t == cmake::AUTHOR_WARNING)
{
// Allow suppression of these warnings.
cmCacheManager::CacheIterator it = this->CacheManager
->GetCacheIterator("CMAKE_SUPPRESS_DEVELOPER_WARNINGS");
if(!it.IsAtEnd() && it.GetValueAsBool())
{
return;
}
msg << " (dev)";
}
}
// Add the immediate context.
cmListFileBacktrace::const_iterator i = backtrace.begin();
if(i != backtrace.end())
{
cmListFileContext const& lfc = *i;
msg << (lfc.Line? " at ": " in ") << lfc;
++i;
}
// Add the message text.
{
msg << ":\n";
cmDocumentationFormatterText formatter;
formatter.SetIndent(" ");
formatter.PrintFormatted(msg, text.c_str());
}
// Add the rest of the context.
if(i != backtrace.end())
{
msg << "Call Stack (most recent call first):\n";
while(i != backtrace.end())
{
cmListFileContext const& lfc = *i;
msg << " " << lfc << "\n";
++i;
}
}
// Add a terminating blank line.
msg << "\n";
// Output the message.
if(isError)
{
cmSystemTools::SetErrorOccured();
cmSystemTools::Message(msg.str().c_str(), "Error");
}
else
{
cmSystemTools::Message(msg.str().c_str(), "Warning");
}
}

View File

@ -54,6 +54,7 @@ class cmFileTimeComparison;
class cmExternalMakefileProjectGenerator;
class cmDocumentationSection;
class cmPolicies;
class cmListFileBacktrace;
class cmake
{
@ -349,6 +350,10 @@ class cmake
{
this->SuppressDevWarnings = v;
}
/** Display a message to the user. */
void IssueMessage(cmake::MessageType t, std::string const& text,
cmListFileBacktrace const& backtrace);
protected:
void InitializeProperties();
int HandleDeleteCacheVariables(const char* var);