089fe1c13d
While porting boost to use these features, the generation step took too long (several minutes before I stopped it). The reason was that the boost libraries form a large interdependent mesh. The libraries list their dependencies in their INTERFACE such as: $<LINKED:boost::core>;$<LINKED:boost::config>;$<LINKED:boost::mpl> As boost::core already depends on the boost::config libraries, that expression has no impact on the end-content, as it is removed after the generation step. There is no DAG issue though, so the generator expression evaluation would fully evaluate them. In the case of the config library, it also depends on the core library, so all depends are followed through that again, despite the fact that they've just been evaluated. After this patch, the evaluation skips libraries if they have already been seen via depends or directly in the content. This patch keeps track of targets whose INTERFACE has been consumed already. The INCLUDE_DIRECTORIES and COMPILE_DEFINITIONS properties are whitelisted because repeated content will be stripped out later during generation. For other properties now and in the future, that may not be the case.
170 lines
5.4 KiB
C++
170 lines
5.4 KiB
C++
/*============================================================================
|
|
CMake - Cross Platform Makefile Generator
|
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
|
|
|
Distributed under the OSI-approved BSD License (the "License");
|
|
see accompanying file Copyright.txt for details.
|
|
|
|
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 "cmGeneratorExpressionDAGChecker.h"
|
|
|
|
#include "cmMakefile.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
|
|
const cmListFileBacktrace &backtrace,
|
|
const std::string &target,
|
|
const std::string &property,
|
|
const GeneratorExpressionContent *content,
|
|
cmGeneratorExpressionDAGChecker *parent)
|
|
: Parent(parent), Target(target), Property(property),
|
|
Content(content), Backtrace(backtrace)
|
|
{
|
|
const cmGeneratorExpressionDAGChecker *top = this;
|
|
const cmGeneratorExpressionDAGChecker *p = this->Parent;
|
|
while (p)
|
|
{
|
|
top = p;
|
|
p = p->Parent;
|
|
}
|
|
this->CheckResult = this->checkGraph();
|
|
|
|
if (CheckResult == DAG && (top->Property == "INCLUDE_DIRECTORIES"
|
|
|| top->Property == "COMPILE_DEFINITIONS") )
|
|
{
|
|
std::map<cmStdString, std::set<cmStdString> >::const_iterator it
|
|
= top->Seen.find(target);
|
|
if (it != top->Seen.end())
|
|
{
|
|
const std::set<cmStdString> &propSet = it->second;
|
|
const std::set<cmStdString>::const_iterator i = propSet.find(property);
|
|
if (i != propSet.end())
|
|
{
|
|
this->CheckResult = ALREADY_SEEN;
|
|
return;
|
|
}
|
|
}
|
|
const_cast<cmGeneratorExpressionDAGChecker *>(top)
|
|
->Seen[target].insert(property);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGeneratorExpressionDAGChecker::Result
|
|
cmGeneratorExpressionDAGChecker::check() const
|
|
{
|
|
return this->CheckResult;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGeneratorExpressionDAGChecker::reportError(
|
|
cmGeneratorExpressionContext *context,
|
|
const std::string &expr)
|
|
{
|
|
if (this->CheckResult == DAG)
|
|
{
|
|
return;
|
|
}
|
|
|
|
context->HadError = true;
|
|
if (context->Quiet)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const cmGeneratorExpressionDAGChecker *parent = this->Parent;
|
|
|
|
if (parent && !parent->Parent)
|
|
{
|
|
cmOStringStream e;
|
|
e << "Error evaluating generator expression:\n"
|
|
<< " " << expr << "\n"
|
|
<< "Self reference on target \""
|
|
<< context->HeadTarget->GetName() << "\".\n";
|
|
context->Makefile->GetCMakeInstance()
|
|
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
|
|
parent->Backtrace);
|
|
return;
|
|
}
|
|
|
|
{
|
|
cmOStringStream e;
|
|
e << "Error evaluating generator expression:\n"
|
|
<< " " << expr << "\n"
|
|
<< "Dependency loop found.";
|
|
context->Makefile->GetCMakeInstance()
|
|
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
|
|
context->Backtrace);
|
|
}
|
|
|
|
int loopStep = 1;
|
|
while (parent)
|
|
{
|
|
cmOStringStream e;
|
|
e << "Loop step " << loopStep << "\n"
|
|
<< " "
|
|
<< (parent->Content ? parent->Content->GetOriginalExpression() : expr)
|
|
<< "\n";
|
|
context->Makefile->GetCMakeInstance()
|
|
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
|
|
parent->Backtrace);
|
|
parent = parent->Parent;
|
|
++loopStep;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGeneratorExpressionDAGChecker::Result
|
|
cmGeneratorExpressionDAGChecker::checkGraph() const
|
|
{
|
|
const cmGeneratorExpressionDAGChecker *parent = this->Parent;
|
|
while (parent)
|
|
{
|
|
if (this->Target == parent->Target && this->Property == parent->Property)
|
|
{
|
|
return parent->Parent ? CYCLIC_REFERENCE : SELF_REFERENCE;
|
|
}
|
|
parent = parent->Parent;
|
|
}
|
|
return DAG;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries()
|
|
{
|
|
const cmGeneratorExpressionDAGChecker *top = this;
|
|
const cmGeneratorExpressionDAGChecker *parent = this->Parent;
|
|
while (parent)
|
|
{
|
|
top = parent;
|
|
parent = parent->Parent;
|
|
}
|
|
|
|
const char *prop = top->Property.c_str();
|
|
return (strcmp(prop, "LINK_LIBRARIES") == 0
|
|
|| strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0
|
|
|| strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0
|
|
|| strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 26) == 0
|
|
|| strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 35) == 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories()
|
|
{
|
|
const char *prop = this->Property.c_str();
|
|
return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0
|
|
|| strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions()
|
|
{
|
|
const char *prop = this->Property.c_str();
|
|
return (strcmp(prop, "COMPILE_DEFINITIONS") == 0
|
|
|| strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0 );
|
|
}
|