Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmGeneratorExpressionDAGChecker.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2012 Stephen Kelly <steveire@gmail.com>
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12
13 #include "cmGeneratorExpressionDAGChecker.h"
14
15 #include "cmMakefile.h"
16
17 //----------------------------------------------------------------------------
18 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
19                 const cmListFileBacktrace &backtrace,
20                 const std::string &target,
21                 const std::string &property,
22                 const GeneratorExpressionContent *content,
23                 cmGeneratorExpressionDAGChecker *parent)
24   : Parent(parent), Target(target), Property(property),
25     Content(content), Backtrace(backtrace), TransitivePropertiesOnly(false)
26 {
27   const cmGeneratorExpressionDAGChecker *top = this;
28   const cmGeneratorExpressionDAGChecker *p = this->Parent;
29   while (p)
30     {
31     top = p;
32     p = p->Parent;
33     }
34   this->CheckResult = this->checkGraph();
35
36 #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) \
37   top->METHOD () ||
38
39   if (CheckResult == DAG && (
40       CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(TEST_TRANSITIVE_PROPERTY_METHOD)
41       false)
42      )
43     {
44     std::map<cmStdString, std::set<cmStdString> >::const_iterator it
45                                                     = top->Seen.find(target);
46     if (it != top->Seen.end())
47       {
48       const std::set<cmStdString> &propSet = it->second;
49       const std::set<cmStdString>::const_iterator i = propSet.find(property);
50       if (i != propSet.end())
51         {
52         this->CheckResult = ALREADY_SEEN;
53         return;
54         }
55       }
56     const_cast<cmGeneratorExpressionDAGChecker *>(top)
57                                             ->Seen[target].insert(property);
58     }
59 }
60
61 //----------------------------------------------------------------------------
62 cmGeneratorExpressionDAGChecker::Result
63 cmGeneratorExpressionDAGChecker::check() const
64 {
65   return this->CheckResult;
66 }
67
68 //----------------------------------------------------------------------------
69 void cmGeneratorExpressionDAGChecker::reportError(
70                   cmGeneratorExpressionContext *context,
71                   const std::string &expr)
72 {
73   if (this->CheckResult == DAG)
74     {
75     return;
76     }
77
78   context->HadError = true;
79   if (context->Quiet)
80     {
81     return;
82     }
83
84   const cmGeneratorExpressionDAGChecker *parent = this->Parent;
85
86   if (parent && !parent->Parent)
87     {
88     cmOStringStream e;
89     e << "Error evaluating generator expression:\n"
90       << "  " << expr << "\n"
91       << "Self reference on target \""
92       << context->HeadTarget->GetName() << "\".\n";
93     context->Makefile->GetCMakeInstance()
94       ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
95                       parent->Backtrace);
96     return;
97     }
98
99   {
100   cmOStringStream e;
101   e << "Error evaluating generator expression:\n"
102     << "  " << expr << "\n"
103     << "Dependency loop found.";
104   context->Makefile->GetCMakeInstance()
105     ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
106                     context->Backtrace);
107   }
108
109   int loopStep = 1;
110   while (parent)
111     {
112     cmOStringStream e;
113     e << "Loop step " << loopStep << "\n"
114       << "  "
115       << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
116       << "\n";
117     context->Makefile->GetCMakeInstance()
118       ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
119                       parent->Backtrace);
120     parent = parent->Parent;
121     ++loopStep;
122     }
123 }
124
125 //----------------------------------------------------------------------------
126 cmGeneratorExpressionDAGChecker::Result
127 cmGeneratorExpressionDAGChecker::checkGraph() const
128 {
129   const cmGeneratorExpressionDAGChecker *parent = this->Parent;
130   while (parent)
131     {
132     if (this->Target == parent->Target && this->Property == parent->Property)
133       {
134       return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
135       }
136     parent = parent->Parent;
137     }
138   return DAG;
139 }
140
141 //----------------------------------------------------------------------------
142 bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
143 {
144   const cmGeneratorExpressionDAGChecker *top = this;
145   const cmGeneratorExpressionDAGChecker *parent = this->Parent;
146   while (parent)
147     {
148     top = parent;
149     parent = parent->Parent;
150     }
151
152   return top->TransitivePropertiesOnly;
153 }
154
155 //----------------------------------------------------------------------------
156 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(const char *tgt)
157 {
158   const cmGeneratorExpressionDAGChecker *top = this;
159   const cmGeneratorExpressionDAGChecker *parent = this->Parent;
160   while (parent)
161     {
162     top = parent;
163     parent = parent->Parent;
164     }
165
166   const char *prop = top->Property.c_str();
167
168   if (tgt)
169     {
170     return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0;
171     }
172
173   return (strcmp(prop, "LINK_LIBRARIES") == 0
174        || strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0
175        || strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0
176        || strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 25) == 0
177        || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 34) == 0)
178        || strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0;
179 }
180
181 //----------------------------------------------------------------------------
182 bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() const
183 {
184   const char *prop = this->Property.c_str();
185   return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0
186        || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 );
187 }
188
189 //----------------------------------------------------------------------------
190 bool
191 cmGeneratorExpressionDAGChecker::EvaluatingSystemIncludeDirectories() const
192 {
193   const char *prop = this->Property.c_str();
194   return strcmp(prop, "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES") == 0;
195 }
196
197 //----------------------------------------------------------------------------
198 bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() const
199 {
200   const char *prop = this->Property.c_str();
201   return (strcmp(prop, "COMPILE_DEFINITIONS") == 0
202        || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0
203        || strncmp(prop, "COMPILE_DEFINITIONS_", 20) == 0);
204 }
205
206 //----------------------------------------------------------------------------
207 bool cmGeneratorExpressionDAGChecker::EvaluatingCompileOptions() const
208 {
209   const char *prop = this->Property.c_str();
210   return (strcmp(prop, "COMPILE_OPTIONS") == 0
211        || strcmp(prop, "INTERFACE_COMPILE_OPTIONS") == 0 );
212 }