cmake/Source/cmGeneratorExpressionDAGChecker.cxx

255 lines
7.5 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"
2020-02-01 23:06:01 +01:00
#include <cstring>
#include <sstream>
#include <utility>
2020-08-30 11:54:41 +02:00
#include <cm/string_view>
#include <cmext/string_view>
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"
2019-11-11 23:01:05 +01:00
#include "cmMessageType.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2016-10-30 18:24:19 +01:00
#include "cmake.h"
2013-03-16 19:13:01 +02:00
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
2019-11-11 23:01:05 +01:00
cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
std::string property, const GeneratorExpressionContent* content,
2016-07-09 11:21:54 +02:00
cmGeneratorExpressionDAGChecker* parent)
: Parent(parent)
, Target(target)
2019-11-11 23:01:05 +01:00
, Property(std::move(property))
2016-07-09 11:21:54 +02:00
, Content(content)
2019-11-11 23:01:05 +01:00
, Backtrace(std::move(backtrace))
2016-07-09 11:21:54 +02:00
, TransitivePropertiesOnly(false)
2015-04-27 22:25:09 +02:00
{
2021-09-14 00:13:48 +02:00
this->Initialize();
2015-04-27 22:25:09 +02:00
}
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
2019-11-11 23:01:05 +01:00
cmGeneratorTarget const* target, std::string property,
2016-07-09 11:21:54 +02:00
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* parent)
: Parent(parent)
, Target(target)
2019-11-11 23:01:05 +01:00
, Property(std::move(property))
2016-07-09 11:21:54 +02:00
, Content(content)
, Backtrace()
, TransitivePropertiesOnly(false)
2015-04-27 22:25:09 +02:00
{
2021-09-14 00:13:48 +02:00
this->Initialize();
2015-04-27 22:25:09 +02:00
}
2016-07-09 11:21:54 +02:00
void cmGeneratorExpressionDAGChecker::Initialize()
2013-03-16 19:13:01 +02:00
{
2020-08-30 11:54:41 +02:00
const auto* top = this->Top();
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
2021-09-14 00:13:48 +02:00
if (this->CheckResult == DAG &&
2017-04-14 19:02:05 +02:00
(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
2019-11-11 23:01:05 +01:00
TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(*)
2014-08-03 19:52:23 +02:00
#undef TEST_TRANSITIVE_PROPERTY_METHOD
2016-07-09 11:21:54 +02:00
{
2020-02-01 23:06:01 +01:00
auto it = top->Seen.find(this->Target);
2016-07-09 11:21:54 +02:00
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;
}
}
2020-02-01 23:06:01 +01:00
top->Seen[this->Target].insert(this->Property);
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::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";
2019-11-11 23:01:05 +01:00
context->LG->GetCMakeInstance()->IssueMessage(MessageType::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 */
2019-11-11 23:01:05 +01:00
context->LG->GetCMakeInstance()->IssueMessage(MessageType::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";
2019-11-11 23:01:05 +01:00
context->LG->GetCMakeInstance()->IssueMessage(MessageType::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;
}
2020-08-30 11:54:41 +02:00
bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
2013-11-03 12:27:13 +02:00
{
2020-08-30 11:54:41 +02:00
return this->Top()->TransitivePropertiesOnly;
}
2013-11-03 12:27:13 +02:00
2020-08-30 11:54:41 +02:00
bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
{
return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
2013-11-03 12:27:13 +02:00
}
2020-08-30 11:54:41 +02:00
bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
2019-11-11 23:01:05 +01:00
{
2020-08-30 11:54:41 +02:00
return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
2019-11-11 23:01:05 +01:00
}
2021-09-14 00:13:48 +02:00
bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
{
cm::string_view property(this->Top()->Property);
return property == "INCLUDE_DIRECTORIES"_s ||
property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
}
2020-08-30 11:54:41 +02:00
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
2018-08-09 18:06:22 +02:00
{
2020-08-30 11:54:41 +02:00
cm::string_view property(this->Top()->Property);
return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
2022-08-04 22:12:04 +02:00
property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s;
2020-08-30 11:54:41 +02:00
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
{
cm::string_view property(this->Top()->Property);
2018-08-09 18:06:22 +02:00
2020-08-30 11:54:41 +02:00
return property == "LINK_OPTIONS"_s;
2018-08-09 18:06:22 +02:00
}
2018-10-28 12:09:07 +01:00
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
2022-08-04 22:12:04 +02:00
cmGeneratorTarget const* tgt, ForGenex genex) const
2013-03-16 19:13:01 +02:00
{
2020-08-30 11:54:41 +02:00
const auto* top = this->Top();
2013-03-16 19:13:01 +02:00
2020-08-30 11:54:41 +02:00
cm::string_view prop(top->Property);
2013-11-03 12:27:13 +02:00
2016-07-09 11:21:54 +02:00
if (tgt) {
2020-08-30 11:54:41 +02:00
return top->Target == tgt && prop == "LINK_LIBRARIES"_s;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
2022-08-04 22:12:04 +02:00
auto result = prop == "LINK_LIBRARIES"_s ||
prop == "INTERFACE_LINK_LIBRARIES"_s ||
prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s ||
2022-03-29 21:10:50 +02:00
prop == "LINK_INTERFACE_LIBRARIES"_s ||
2020-08-30 11:54:41 +02:00
prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s ||
cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
2022-03-29 21:10:50 +02:00
cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_");
2022-08-04 22:12:04 +02:00
return genex == ForGenex::LINK_LIBRARY || genex == ForGenex::LINK_GROUP
? result
: (result || prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s);
2013-03-16 19:13:01 +02:00
}
2020-08-30 11:54:41 +02:00
cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top()
const
2015-04-27 22:25:09 +02:00
{
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
}
2020-08-30 11:54:41 +02:00
return top;
}
cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
{
return this->Top()->Target;
2015-04-27 22:25:09 +02:00
}
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