1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmGeneratorExpressionDAGChecker.h"
9 #include <cm/string_view>
10 #include <cmext/string_view>
12 #include "cmGeneratorExpressionContext.h"
13 #include "cmGeneratorExpressionEvaluator.h"
14 #include "cmGeneratorTarget.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMessageType.h"
17 #include "cmStringAlgorithms.h"
20 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
21 cmGeneratorTarget
const* target
, std::string property
,
22 const GeneratorExpressionContent
* content
,
23 cmGeneratorExpressionDAGChecker
* parent
, cmLocalGenerator
const* contextLG
,
24 std::string
const& contextConfig
)
25 : cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target
,
26 std::move(property
), content
, parent
,
27 contextLG
, contextConfig
)
31 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
32 cmListFileBacktrace backtrace
, cmGeneratorTarget
const* target
,
33 std::string property
, const GeneratorExpressionContent
* content
,
34 cmGeneratorExpressionDAGChecker
* parent
, cmLocalGenerator
const* contextLG
,
35 std::string
const& contextConfig
)
37 , Top(parent
? parent
->Top
: this)
39 , Property(std::move(property
))
41 , Backtrace(std::move(backtrace
))
44 this->TopIsTransitiveProperty
= parent
->TopIsTransitiveProperty
;
46 this->TopIsTransitiveProperty
=
48 ->IsTransitiveProperty(this->Property
, contextLG
, contextConfig
,
49 this->EvaluatingLinkLibraries())
53 this->CheckResult
= this->CheckGraph();
55 if (this->CheckResult
== DAG
&& this->EvaluatingTransitiveProperty()) {
56 const auto* top
= this->Top
;
57 auto it
= top
->Seen
.find(this->Target
);
58 if (it
!= top
->Seen
.end()) {
59 const std::set
<std::string
>& propSet
= it
->second
;
60 if (propSet
.find(this->Property
) != propSet
.end()) {
61 this->CheckResult
= ALREADY_SEEN
;
65 top
->Seen
[this->Target
].insert(this->Property
);
69 cmGeneratorExpressionDAGChecker::Result
70 cmGeneratorExpressionDAGChecker::Check() const
72 return this->CheckResult
;
75 void cmGeneratorExpressionDAGChecker::ReportError(
76 cmGeneratorExpressionContext
* context
, const std::string
& expr
)
78 if (this->CheckResult
== DAG
) {
82 context
->HadError
= true;
87 const cmGeneratorExpressionDAGChecker
* parent
= this->Parent
;
89 if (parent
&& !parent
->Parent
) {
91 e
<< "Error evaluating generator expression:\n"
92 << " " << expr
<< "\n"
93 << "Self reference on target \"" << context
->HeadTarget
->GetName()
95 context
->LG
->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR
,
96 e
.str(), parent
->Backtrace
);
101 std::ostringstream e
;
102 /* clang-format off */
103 e
<< "Error evaluating generator expression:\n"
104 << " " << expr
<< "\n"
105 << "Dependency loop found.";
106 /* clang-format on */
107 context
->LG
->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR
,
108 e
.str(), context
->Backtrace
);
113 std::ostringstream e
;
114 e
<< "Loop step " << loopStep
<< "\n"
116 << (parent
->Content
? parent
->Content
->GetOriginalExpression() : expr
)
118 context
->LG
->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR
,
119 e
.str(), parent
->Backtrace
);
120 parent
= parent
->Parent
;
125 cmGeneratorExpressionDAGChecker::Result
126 cmGeneratorExpressionDAGChecker::CheckGraph() const
128 const cmGeneratorExpressionDAGChecker
* parent
= this->Parent
;
130 if (this->Target
== parent
->Target
&& this->Property
== parent
->Property
) {
131 return (parent
== this->Parent
) ? SELF_REFERENCE
: CYCLIC_REFERENCE
;
133 parent
= parent
->Parent
;
138 bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
140 return this->Top
->TransitivePropertiesOnly
;
143 bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnlyCMP0131()
146 return this->Top
->CMP0131
;
149 bool cmGeneratorExpressionDAGChecker::EvaluatingTransitiveProperty() const
151 return this->TopIsTransitiveProperty
;
154 bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
156 // Corresponds to GenexEvaluator::EvaluateExpression.
157 return cmHasLiteralPrefix(this->Property
, "TARGET_GENEX_EVAL:") ||
158 cmHasLiteralPrefix(this->Property
, "GENEX_EVAL:");
161 bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
163 // Corresponds to checkInterfacePropertyCompatibility's special case
164 // that evaluates the value of POSITION_INDEPENDENT_CODE as a genex.
165 return this->Top
->Property
== "INTERFACE_POSITION_INDEPENDENT_CODE";
168 bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
170 cm::string_view
property(this->Top
->Property
);
172 return property
== "INCLUDE_DIRECTORIES"_s
||
173 property
== "COMPILE_DEFINITIONS"_s
|| property
== "COMPILE_OPTIONS"_s
;
176 bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const
178 return this->Property
== "SOURCES"_s
||
179 this->Property
== "INTERFACE_SOURCES"_s
;
182 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
184 cm::string_view
property(this->Top
->Property
);
186 return property
== "LINK_DIRECTORIES"_s
|| property
== "LINK_OPTIONS"_s
||
187 property
== "LINK_DEPENDS"_s
|| property
== "LINK_LIBRARY_OVERRIDE"_s
||
188 property
== "LINKER_TYPE"_s
;
191 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
193 cm::string_view
property(this->Top
->Property
);
195 return property
== "LINK_OPTIONS"_s
|| property
== "LINKER_TYPE"_s
;
198 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
200 cm::string_view
property(this->Top
->Property
);
202 return property
.length() > cmStrLen("_LINKER_LAUNCHER") &&
203 property
.substr(property
.length() - cmStrLen("_LINKER_LAUNCHER")) ==
204 "_LINKER_LAUNCHER"_s
;
207 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
208 cmGeneratorTarget
const* tgt
, ForGenex genex
) const
210 const auto* top
= this->Top
;
212 cm::string_view
prop(top
->Property
);
215 return top
->Target
== tgt
&& prop
== "LINK_LIBRARIES"_s
;
218 auto result
= prop
== "LINK_LIBRARIES"_s
||
219 prop
== "INTERFACE_LINK_LIBRARIES"_s
||
220 prop
== "INTERFACE_LINK_LIBRARIES_DIRECT"_s
||
221 prop
== "LINK_INTERFACE_LIBRARIES"_s
||
222 prop
== "IMPORTED_LINK_INTERFACE_LIBRARIES"_s
||
223 cmHasLiteralPrefix(prop
, "LINK_INTERFACE_LIBRARIES_") ||
224 cmHasLiteralPrefix(prop
, "IMPORTED_LINK_INTERFACE_LIBRARIES_");
226 return genex
== ForGenex::LINK_LIBRARY
|| genex
== ForGenex::LINK_GROUP
228 : (result
|| prop
== "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s
);
231 cmGeneratorTarget
const* cmGeneratorExpressionDAGChecker::TopTarget() const
233 return this->Top
->Target
;