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:
parent
73df9a5cd4
commit
f7f03347a6
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue