| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmGeneratorExpressionDAGChecker.h" | |
| #include <utility> | |
| #include <cm/optional> | |
| #include <cm/string_view> | |
| #include <cmext/string_view> | |
| #include "cmGenExContext.h" | |
| #include "cmGenExEvaluation.h" | |
| #include "cmGeneratorExpressionEvaluator.h" | |
| #include "cmGeneratorTarget.h" | |
| #include "cmLocalGenerator.h" | |
| #include "cmMessageType.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmake.h" | |
| cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( | |
| cmGeneratorTarget const* target, std::string property, | |
| GeneratorExpressionContent const* content, | |
| cmGeneratorExpressionDAGChecker* parent, cm::GenEx::Context const& context, | |
| cmListFileBacktrace backtrace, ComputingLinkLibraries computingLinkLibraries) | |
| : Parent(parent) | |
| , Top(parent ? parent->Top : this) | |
| , Target(target) | |
| , Property(std::move(property)) | |
| , Content(content) | |
| , Backtrace(std::move(backtrace)) | |
| , ComputingLinkLibraries_(computingLinkLibraries) | |
| { | |
| if (parent) { | |
| this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty; | |
| } else { | |
| this->TopIsTransitiveProperty = | |
| this->Target->IsTransitiveProperty(this->Property, context, this) | |
| .has_value(); | |
| } | |
| this->CheckResult = this->CheckGraph(); | |
| if (this->CheckResult == DAG && this->EvaluatingTransitiveProperty()) { | |
| auto const* top = this->Top; | |
| auto it = top->Seen.find(this->Target); | |
| if (it != top->Seen.end()) { | |
| std::set<std::string> const& propSet = it->second; | |
| if (propSet.find(this->Property) != propSet.end()) { | |
| this->CheckResult = ALREADY_SEEN; | |
| return; | |
| } | |
| } | |
| top->Seen[this->Target].insert(this->Property); | |
| } | |
| } | |
| cmGeneratorExpressionDAGChecker::Result | |
| cmGeneratorExpressionDAGChecker::Check() const | |
| { | |
| return this->CheckResult; | |
| } | |
| void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval, | |
| std::string const& expr) | |
| { | |
| if (this->CheckResult == DAG) { | |
| return; | |
| } | |
| eval->HadError = true; | |
| if (eval->Quiet) { | |
| return; | |
| } | |
| cmGeneratorExpressionDAGChecker const* parent = this->Parent; | |
| if (parent && !parent->Parent) { | |
| eval->Context.LG->GetCMakeInstance()->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Error evaluating generator expression:\n" | |
| " ", | |
| expr, | |
| "\n" | |
| "Self reference on target \"", | |
| eval->HeadTarget->GetName(), "\".\n"), | |
| parent->Backtrace); | |
| return; | |
| } | |
| { | |
| eval->Context.LG->GetCMakeInstance()->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Error evaluating generator expression:\n" | |
| " ", | |
| expr, | |
| "\n" | |
| "Dependency loop found."), | |
| eval->Backtrace); | |
| } | |
| int loopStep = 1; | |
| while (parent) { | |
| eval->Context.LG->GetCMakeInstance()->IssueMessage( | |
| MessageType::FATAL_ERROR, | |
| cmStrCat("Loop step ", loopStep, "\n ", | |
| parent->Content ? parent->Content->GetOriginalExpression() | |
| : expr, | |
| '\n'), | |
| parent->Backtrace); | |
| parent = parent->Parent; | |
| ++loopStep; | |
| } | |
| } | |
| cmGeneratorExpressionDAGChecker::Result | |
| cmGeneratorExpressionDAGChecker::CheckGraph() const | |
| { | |
| cmGeneratorExpressionDAGChecker const* 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 | |
| { | |
| return this->Top->TransitivePropertiesOnly; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnlyCMP0131() | |
| const | |
| { | |
| return this->Top->CMP0131; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingTransitiveProperty() const | |
| { | |
| return this->TopIsTransitiveProperty; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const | |
| { | |
| // Corresponds to GenexEvaluator::EvaluateExpression. | |
| return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") || | |
| cmHasLiteralPrefix(this->Property, "GENEX_EVAL:"); | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const | |
| { | |
| // Corresponds to checkInterfacePropertyCompatibility's special case | |
| // that evaluates the value of POSITION_INDEPENDENT_CODE as a genex. | |
| return this->Top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const | |
| { | |
| cm::string_view property(this->Top->Property); | |
| return property == "INCLUDE_DIRECTORIES"_s || | |
| property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s || | |
| property == "COMPILE_WRAPPERS"_s; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const | |
| { | |
| return this->Property == "SOURCES"_s || | |
| this->Property == "INTERFACE_SOURCES"_s; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const | |
| { | |
| cm::string_view property(this->Top->Property); | |
| return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || | |
| property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s || | |
| property == "LINKER_TYPE"_s || property == "LINK_WRAPPERS"_s; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const | |
| { | |
| cm::string_view property(this->Top->Property); | |
| return property == "LINK_OPTIONS"_s || property == "LINKER_TYPE"_s; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const | |
| { | |
| cm::string_view property(this->Top->Property); | |
| return property.length() > cmStrLen("_LINKER_LAUNCHER") && | |
| property.substr(property.length() - cmStrLen("_LINKER_LAUNCHER")) == | |
| "_LINKER_LAUNCHER"_s; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::IsComputingLinkLibraries() const | |
| { | |
| return this->Top->ComputingLinkLibraries_ == ComputingLinkLibraries::Yes; | |
| } | |
| bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( | |
| cmGeneratorTarget const* tgt, ForGenex genex) const | |
| { | |
| auto const* top = this->Top; | |
| cm::string_view prop(top->Property); | |
| if (tgt) { | |
| return top->Target == tgt && prop == "LINK_LIBRARIES"_s; | |
| } | |
| auto result = prop == "LINK_LIBRARIES"_s || | |
| prop == "INTERFACE_LINK_LIBRARIES"_s || | |
| prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s || | |
| prop == "LINK_INTERFACE_LIBRARIES"_s || | |
| prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s || | |
| cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || | |
| cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_"); | |
| return genex == ForGenex::LINK_LIBRARY || genex == ForGenex::LINK_GROUP | |
| ? result | |
| : (result || prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s); | |
| } | |
| cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const | |
| { | |
| return this->Top->Target; | |
| } |