123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmGeneratorExpressionDAGChecker.h"
- #include "cmAlgorithms.h"
- #include "cmGeneratorExpressionContext.h"
- #include "cmGeneratorExpressionEvaluator.h"
- #include "cmGeneratorTarget.h"
- #include "cmLocalGenerator.h"
- #include "cmake.h"
- #include <sstream>
- #include <string.h>
- #include <utility>
- 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)
- , TransitivePropertiesOnly(false)
- {
- Initialize();
- }
- cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
- const std::string& target, const std::string& property,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* parent)
- : Parent(parent)
- , Target(target)
- , Property(property)
- , Content(content)
- , Backtrace()
- , TransitivePropertiesOnly(false)
- {
- Initialize();
- }
- void cmGeneratorExpressionDAGChecker::Initialize()
- {
- const cmGeneratorExpressionDAGChecker* top = this;
- const cmGeneratorExpressionDAGChecker* p = this->Parent;
- while (p) {
- top = p;
- p = p->Parent;
- }
- this->CheckResult = this->CheckGraph();
- #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
- if (CheckResult == DAG &&
- (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
- TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(clang-tidy)
- #undef TEST_TRANSITIVE_PROPERTY_METHOD
- {
- 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()) {
- this->CheckResult = ALREADY_SEEN;
- return;
- }
- }
- const_cast<cmGeneratorExpressionDAGChecker*>(top)
- ->Seen[this->Target]
- .insert(this->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) {
- std::ostringstream e;
- e << "Error evaluating generator expression:\n"
- << " " << expr << "\n"
- << "Self reference on target \"" << context->HeadTarget->GetName()
- << "\".\n";
- context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
- parent->Backtrace);
- return;
- }
- {
- std::ostringstream e;
- /* clang-format off */
- e << "Error evaluating generator expression:\n"
- << " " << expr << "\n"
- << "Dependency loop found.";
- /* clang-format on */
- context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
- context->Backtrace);
- }
- int loopStep = 1;
- while (parent) {
- std::ostringstream e;
- e << "Loop step " << loopStep << "\n"
- << " "
- << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
- << "\n";
- context->LG->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.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 == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
- }
- parent = parent->Parent;
- }
- return DAG;
- }
- bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
- {
- const cmGeneratorExpressionDAGChecker* top = this;
- const cmGeneratorExpressionDAGChecker* parent = this->Parent;
- while (parent) {
- top = parent;
- parent = parent->Parent;
- }
- return top->TransitivePropertiesOnly;
- }
- bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char* tgt)
- {
- const cmGeneratorExpressionDAGChecker* top = this;
- const cmGeneratorExpressionDAGChecker* parent = this->Parent;
- while (parent) {
- top = parent;
- parent = parent->Parent;
- }
- const char* prop = top->Property.c_str();
- if (tgt) {
- return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0;
- }
- 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;
- }
- std::string cmGeneratorExpressionDAGChecker::TopTarget() const
- {
- const cmGeneratorExpressionDAGChecker* top = this;
- const cmGeneratorExpressionDAGChecker* parent = this->Parent;
- while (parent) {
- top = parent;
- parent = parent->Parent;
- }
- return top->Target;
- }
- enum TransitiveProperty
- {
- #define DEFINE_ENUM_ENTRY(NAME) NAME,
- CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
- #undef DEFINE_ENUM_ENTRY
- TransitivePropertyTerminal
- };
- template <TransitiveProperty>
- bool additionalTest(const char* const /*unused*/)
- {
- return false;
- }
- template <>
- bool additionalTest<COMPILE_DEFINITIONS>(const char* const prop)
- {
- return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
- }
- #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); \
- }
- CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
- #undef DEFINE_TRANSITIVE_PROPERTY_METHOD
|