cmake/Source/cmGeneratorExpressionDAGChecker.cxx

225 lines
6.6 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2013-03-16 19:13:01 +02:00
#include "cmGeneratorExpressionDAGChecker.h"
2015-08-17 11:37:30 +02:00
#include "cmAlgorithms.h"
2016-10-30 18:24:19 +01:00
#include "cmGeneratorExpressionContext.h"
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorTarget.h"
2016-07-09 11:21:54 +02:00
#include "cmLocalGenerator.h"
2016-10-30 18:24:19 +01:00
#include "cmake.h"
#include <sstream>
#include <string.h>
#include <utility>
2013-03-16 19:13:01 +02:00
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
2016-07-09 11:21:54 +02:00
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)
, TransitivePropertiesOnly(false)
2015-04-27 22:25:09 +02:00
{
Initialize();
}
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
2016-07-09 11:21:54 +02:00
const std::string& target, const std::string& property,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent)
: Parent(parent)
, Target(target)
, Property(property)
, Content(content)
, Backtrace()
, TransitivePropertiesOnly(false)
2015-04-27 22:25:09 +02:00
{
Initialize();
}
2016-07-09 11:21:54 +02:00
void cmGeneratorExpressionDAGChecker::Initialize()
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* p = this->Parent;
while (p) {
2013-03-16 19:13:01 +02:00
top = p;
p = p->Parent;
2016-07-09 11:21:54 +02:00
}
2014-08-03 19:52:23 +02:00
this->CheckResult = this->CheckGraph();
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
2013-11-03 12:27:13 +02:00
2017-04-14 19:02:05 +02:00
if (CheckResult == DAG &&
(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(clang-tidy)
2014-08-03 19:52:23 +02:00
#undef TEST_TRANSITIVE_PROPERTY_METHOD
2016-07-09 11:21:54 +02:00
{
std::map<std::string, std::set<std::string> >::const_iterator it =
top->Seen.find(this->Target);
if (it != top->Seen.end()) {
const std::set<std::string>& propSet = it->second;
if (propSet.find(this->Property) != propSet.end()) {
2013-03-16 19:13:01 +02:00
this->CheckResult = ALREADY_SEEN;
return;
}
}
2016-07-09 11:21:54 +02:00
const_cast<cmGeneratorExpressionDAGChecker*>(top)
->Seen[this->Target]
.insert(this->Property);
}
2013-03-16 19:13:01 +02:00
}
cmGeneratorExpressionDAGChecker::Result
2014-08-03 19:52:23 +02:00
cmGeneratorExpressionDAGChecker::Check() const
2013-03-16 19:13:01 +02:00
{
return this->CheckResult;
}
2014-08-03 19:52:23 +02:00
void cmGeneratorExpressionDAGChecker::ReportError(
2016-07-09 11:21:54 +02:00
cmGeneratorExpressionContext* context, const std::string& expr)
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
if (this->CheckResult == DAG) {
2013-03-16 19:13:01 +02:00
return;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
context->HadError = true;
2016-07-09 11:21:54 +02:00
if (context->Quiet) {
2013-03-16 19:13:01 +02:00
return;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
if (parent && !parent->Parent) {
2015-04-27 22:25:09 +02:00
std::ostringstream e;
2013-03-16 19:13:01 +02:00
e << "Error evaluating generator expression:\n"
<< " " << expr << "\n"
2016-07-09 11:21:54 +02:00
<< "Self reference on target \"" << context->HeadTarget->GetName()
<< "\".\n";
context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
parent->Backtrace);
2013-03-16 19:13:01 +02:00
return;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
std::ostringstream e;
/* clang-format off */
2013-03-16 19:13:01 +02:00
e << "Error evaluating generator expression:\n"
<< " " << expr << "\n"
<< "Dependency loop found.";
2016-07-09 11:21:54 +02:00
/* clang-format on */
context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
context->Backtrace);
2013-03-16 19:13:01 +02:00
}
int loopStep = 1;
2016-07-09 11:21:54 +02:00
while (parent) {
2015-04-27 22:25:09 +02:00
std::ostringstream e;
2013-03-16 19:13:01 +02:00
e << "Loop step " << loopStep << "\n"
<< " "
<< (parent->Content ? parent->Content->GetOriginalExpression() : expr)
<< "\n";
2016-07-09 11:21:54 +02:00
context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
parent->Backtrace);
2013-03-16 19:13:01 +02:00
parent = parent->Parent;
++loopStep;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
}
cmGeneratorExpressionDAGChecker::Result
2014-08-03 19:52:23 +02:00
cmGeneratorExpressionDAGChecker::CheckGraph() const
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
while (parent) {
if (this->Target == parent->Target && this->Property == parent->Property) {
2013-03-16 19:13:01 +02:00
return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
}
2016-07-09 11:21:54 +02:00
parent = parent->Parent;
}
2013-03-16 19:13:01 +02:00
return DAG;
}
2013-11-03 12:27:13 +02:00
bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
{
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
while (parent) {
2013-11-03 12:27:13 +02:00
top = parent;
parent = parent->Parent;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
return top->TransitivePropertiesOnly;
}
2016-07-09 11:21:54 +02:00
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char* tgt)
2013-03-16 19:13:01 +02:00
{
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
while (parent) {
2013-03-16 19:13:01 +02:00
top = parent;
parent = parent->Parent;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
const char* prop = top->Property.c_str();
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
if (tgt) {
2013-11-03 12:27:13 +02:00
return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
return (strcmp(prop, "LINK_LIBRARIES") == 0 ||
strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0 ||
strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 ||
cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_")) ||
strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0;
2013-03-16 19:13:01 +02:00
}
2015-04-27 22:25:09 +02:00
std::string cmGeneratorExpressionDAGChecker::TopTarget() const
{
2016-07-09 11:21:54 +02:00
const cmGeneratorExpressionDAGChecker* top = this;
const cmGeneratorExpressionDAGChecker* parent = this->Parent;
while (parent) {
2015-04-27 22:25:09 +02:00
top = parent;
parent = parent->Parent;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
return top->Target;
}
2016-07-09 11:21:54 +02:00
enum TransitiveProperty
{
2014-08-03 19:52:23 +02:00
#define DEFINE_ENUM_ENTRY(NAME) NAME,
CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
#undef DEFINE_ENUM_ENTRY
2016-07-09 11:21:54 +02:00
TransitivePropertyTerminal
2014-08-03 19:52:23 +02:00
};
2013-03-16 19:13:01 +02:00
2016-07-09 11:21:54 +02:00
template <TransitiveProperty>
2016-10-30 18:24:19 +01:00
bool additionalTest(const char* const /*unused*/)
2013-11-03 12:27:13 +02:00
{
2014-08-03 19:52:23 +02:00
return false;
2013-11-03 12:27:13 +02:00
}
2016-07-09 11:21:54 +02:00
template <>
2014-08-03 19:52:23 +02:00
bool additionalTest<COMPILE_DEFINITIONS>(const char* const prop)
2013-03-16 19:13:01 +02:00
{
2014-08-03 19:52:23 +02:00
return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
2013-03-16 19:13:01 +02:00
}
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY) \
bool cmGeneratorExpressionDAGChecker::METHOD() const \
{ \
const char* const prop = this->Property.c_str(); \
if (strcmp(prop, #PROPERTY) == 0 || \
strcmp(prop, "INTERFACE_" #PROPERTY) == 0) { \
return true; \
} \
return additionalTest<PROPERTY>(prop); \
}
2014-08-03 19:52:23 +02:00
CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
#undef DEFINE_TRANSITIVE_PROPERTY_METHOD