Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmGeneratorExpressionEvaluator.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 #include "cmMakefile.h"
13
14 #include "cmGeneratorExpressionEvaluator.h"
15 #include "cmGeneratorExpressionParser.h"
16 #include "cmGeneratorExpressionDAGChecker.h"
17 #include "cmGeneratorExpression.h"
18
19 #include <cmsys/String.h>
20
21 #include <assert.h>
22
23 //----------------------------------------------------------------------------
24 #if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
25 static
26 #endif
27 void reportError(cmGeneratorExpressionContext *context,
28                         const std::string &expr, const std::string &result)
29 {
30   context->HadError = true;
31   if (context->Quiet)
32     {
33     return;
34     }
35
36   cmOStringStream e;
37   e << "Error evaluating generator expression:\n"
38     << "  " << expr << "\n"
39     << result;
40   context->Makefile->GetCMakeInstance()
41     ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
42                     context->Backtrace);
43 }
44
45 //----------------------------------------------------------------------------
46 struct cmGeneratorExpressionNode
47 {
48   enum {
49     DynamicParameters = 0,
50     OneOrMoreParameters = -1,
51     ZeroOrMoreParameters = -2
52   };
53   virtual ~cmGeneratorExpressionNode() {}
54
55   virtual bool GeneratesContent() const { return true; }
56
57   virtual bool RequiresLiteralInput() const { return false; }
58
59   virtual bool AcceptsArbitraryContentParameter() const
60     { return false; }
61
62   virtual int NumExpectedParameters() const { return 1; }
63
64   virtual std::string Evaluate(const std::vector<std::string> &parameters,
65                                cmGeneratorExpressionContext *context,
66                                const GeneratorExpressionContent *content,
67                                cmGeneratorExpressionDAGChecker *dagChecker
68                               ) const = 0;
69 };
70
71 //----------------------------------------------------------------------------
72 static const struct ZeroNode : public cmGeneratorExpressionNode
73 {
74   ZeroNode() {}
75
76   virtual bool GeneratesContent() const { return false; }
77
78   virtual bool AcceptsArbitraryContentParameter() const { return true; }
79
80   std::string Evaluate(const std::vector<std::string> &,
81                        cmGeneratorExpressionContext *,
82                        const GeneratorExpressionContent *,
83                        cmGeneratorExpressionDAGChecker *) const
84   {
85     // Unreachable
86     return std::string();
87   }
88 } zeroNode;
89
90 //----------------------------------------------------------------------------
91 static const struct OneNode : public cmGeneratorExpressionNode
92 {
93   OneNode() {}
94
95   virtual bool AcceptsArbitraryContentParameter() const { return true; }
96
97   std::string Evaluate(const std::vector<std::string> &,
98                        cmGeneratorExpressionContext *,
99                        const GeneratorExpressionContent *,
100                        cmGeneratorExpressionDAGChecker *) const
101   {
102     // Unreachable
103     return std::string();
104   }
105 } oneNode;
106
107 //----------------------------------------------------------------------------
108 static const struct OneNode buildInterfaceNode;
109
110 //----------------------------------------------------------------------------
111 static const struct ZeroNode installInterfaceNode;
112
113 //----------------------------------------------------------------------------
114 #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
115 static const struct OP ## Node : public cmGeneratorExpressionNode \
116 { \
117   OP ## Node () {} \
118   virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
119  \
120   std::string Evaluate(const std::vector<std::string> &parameters, \
121                        cmGeneratorExpressionContext *context, \
122                        const GeneratorExpressionContent *content, \
123                        cmGeneratorExpressionDAGChecker *) const \
124   { \
125     std::vector<std::string>::const_iterator it = parameters.begin(); \
126     const std::vector<std::string>::const_iterator end = parameters.end(); \
127     for ( ; it != end; ++it) \
128       { \
129       if (*it == #FAILURE_VALUE) \
130         { \
131         return #FAILURE_VALUE; \
132         } \
133       else if (*it != #SUCCESS_VALUE) \
134         { \
135         reportError(context, content->GetOriginalExpression(), \
136         "Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
137         return std::string(); \
138         } \
139       } \
140     return #SUCCESS_VALUE; \
141   } \
142 } OPNAME;
143
144 BOOLEAN_OP_NODE(andNode, AND, 1, 0)
145 BOOLEAN_OP_NODE(orNode, OR, 0, 1)
146
147 #undef BOOLEAN_OP_NODE
148
149 //----------------------------------------------------------------------------
150 static const struct NotNode : public cmGeneratorExpressionNode
151 {
152   NotNode() {}
153
154   std::string Evaluate(const std::vector<std::string> &parameters,
155                        cmGeneratorExpressionContext *context,
156                        const GeneratorExpressionContent *content,
157                        cmGeneratorExpressionDAGChecker *) const
158   {
159     if (*parameters.begin() != "0" && *parameters.begin() != "1")
160       {
161       reportError(context, content->GetOriginalExpression(),
162             "$<NOT> parameter must resolve to exactly one '0' or '1' value.");
163       return std::string();
164       }
165     return *parameters.begin() == "0" ? "1" : "0";
166   }
167 } notNode;
168
169 //----------------------------------------------------------------------------
170 static const struct BoolNode : public cmGeneratorExpressionNode
171 {
172   BoolNode() {}
173
174   virtual int NumExpectedParameters() const { return 1; }
175
176   std::string Evaluate(const std::vector<std::string> &parameters,
177                        cmGeneratorExpressionContext *,
178                        const GeneratorExpressionContent *,
179                        cmGeneratorExpressionDAGChecker *) const
180   {
181     return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
182   }
183 } boolNode;
184
185 //----------------------------------------------------------------------------
186 static const struct StrEqualNode : public cmGeneratorExpressionNode
187 {
188   StrEqualNode() {}
189
190   virtual int NumExpectedParameters() const { return 2; }
191
192   std::string Evaluate(const std::vector<std::string> &parameters,
193                        cmGeneratorExpressionContext *,
194                        const GeneratorExpressionContent *,
195                        cmGeneratorExpressionDAGChecker *) const
196   {
197     return *parameters.begin() == parameters[1] ? "1" : "0";
198   }
199 } strEqualNode;
200
201 //----------------------------------------------------------------------------
202 static const struct Angle_RNode : public cmGeneratorExpressionNode
203 {
204   Angle_RNode() {}
205
206   virtual int NumExpectedParameters() const { return 0; }
207
208   std::string Evaluate(const std::vector<std::string> &,
209                        cmGeneratorExpressionContext *,
210                        const GeneratorExpressionContent *,
211                        cmGeneratorExpressionDAGChecker *) const
212   {
213     return ">";
214   }
215 } angle_rNode;
216
217 //----------------------------------------------------------------------------
218 static const struct CommaNode : public cmGeneratorExpressionNode
219 {
220   CommaNode() {}
221
222   virtual int NumExpectedParameters() const { return 0; }
223
224   std::string Evaluate(const std::vector<std::string> &,
225                        cmGeneratorExpressionContext *,
226                        const GeneratorExpressionContent *,
227                        cmGeneratorExpressionDAGChecker *) const
228   {
229     return ",";
230   }
231 } commaNode;
232
233 //----------------------------------------------------------------------------
234 static const struct SemicolonNode : public cmGeneratorExpressionNode
235 {
236   SemicolonNode() {}
237
238   virtual int NumExpectedParameters() const { return 0; }
239
240   std::string Evaluate(const std::vector<std::string> &,
241                        cmGeneratorExpressionContext *,
242                        const GeneratorExpressionContent *,
243                        cmGeneratorExpressionDAGChecker *) const
244   {
245     return ";";
246   }
247 } semicolonNode;
248
249 //----------------------------------------------------------------------------
250 struct CompilerIdNode : public cmGeneratorExpressionNode
251 {
252   CompilerIdNode() {}
253
254   virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
255
256   std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
257                        cmGeneratorExpressionContext *context,
258                        const GeneratorExpressionContent *content,
259                        cmGeneratorExpressionDAGChecker *,
260                        const std::string &lang) const
261   {
262     const char *compilerId = context->Makefile ?
263                               context->Makefile->GetSafeDefinition((
264                               "CMAKE_" + lang + "_COMPILER_ID").c_str()) : "";
265     if (parameters.size() == 0)
266       {
267       return compilerId ? compilerId : "";
268       }
269     cmsys::RegularExpression compilerIdValidator;
270     compilerIdValidator.compile("^[A-Za-z0-9_]*$");
271     if (!compilerIdValidator.find(parameters.begin()->c_str()))
272       {
273       reportError(context, content->GetOriginalExpression(),
274                   "Expression syntax not recognized.");
275       return std::string();
276       }
277     if (!compilerId)
278       {
279       return parameters.front().empty() ? "1" : "0";
280       }
281
282     if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0)
283       {
284       return "1";
285       }
286     return "0";
287   }
288 };
289
290 //----------------------------------------------------------------------------
291 static const struct CCompilerIdNode : public CompilerIdNode
292 {
293   CCompilerIdNode() {}
294
295   std::string Evaluate(const std::vector<std::string> &parameters,
296                        cmGeneratorExpressionContext *context,
297                        const GeneratorExpressionContent *content,
298                        cmGeneratorExpressionDAGChecker *dagChecker) const
299   {
300     if (parameters.size() != 0 && parameters.size() != 1)
301       {
302       reportError(context, content->GetOriginalExpression(),
303           "$<C_COMPILER_ID> expression requires one or two parameters");
304       return std::string();
305       }
306     if (!context->HeadTarget)
307       {
308       reportError(context, content->GetOriginalExpression(),
309           "$<C_COMPILER_ID> may only be used with targets.  It may not "
310           "be used with add_custom_command.");
311       }
312     return this->EvaluateWithLanguage(parameters, context, content,
313                                       dagChecker, "C");
314   }
315 } cCompilerIdNode;
316
317 //----------------------------------------------------------------------------
318 static const struct CXXCompilerIdNode : public CompilerIdNode
319 {
320   CXXCompilerIdNode() {}
321
322   std::string Evaluate(const std::vector<std::string> &parameters,
323                        cmGeneratorExpressionContext *context,
324                        const GeneratorExpressionContent *content,
325                        cmGeneratorExpressionDAGChecker *dagChecker) const
326   {
327     if (parameters.size() != 0 && parameters.size() != 1)
328       {
329       reportError(context, content->GetOriginalExpression(),
330           "$<CXX_COMPILER_ID> expression requires one or two parameters");
331       return std::string();
332       }
333     if (!context->HeadTarget)
334       {
335       reportError(context, content->GetOriginalExpression(),
336           "$<CXX_COMPILER_ID> may only be used with targets.  It may not "
337           "be used with add_custom_command.");
338       }
339     return this->EvaluateWithLanguage(parameters, context, content,
340                                       dagChecker, "CXX");
341   }
342 } cxxCompilerIdNode;
343
344 //----------------------------------------------------------------------------
345 struct CompilerVersionNode : public cmGeneratorExpressionNode
346 {
347   CompilerVersionNode() {}
348
349   virtual int NumExpectedParameters() const { return ZeroOrMoreParameters; }
350
351   std::string EvaluateWithLanguage(const std::vector<std::string> &parameters,
352                        cmGeneratorExpressionContext *context,
353                        const GeneratorExpressionContent *content,
354                        cmGeneratorExpressionDAGChecker *,
355                        const std::string &lang) const
356   {
357     const char *compilerVersion = context->Makefile ?
358                               context->Makefile->GetSafeDefinition((
359                         "CMAKE_" + lang + "_COMPILER_VERSION").c_str()) : "";
360     if (parameters.size() == 0)
361       {
362       return compilerVersion ? compilerVersion : "";
363       }
364
365     cmsys::RegularExpression compilerIdValidator;
366     compilerIdValidator.compile("^[0-9\\.]*$");
367     if (!compilerIdValidator.find(parameters.begin()->c_str()))
368       {
369       reportError(context, content->GetOriginalExpression(),
370                   "Expression syntax not recognized.");
371       return std::string();
372       }
373     if (!compilerVersion)
374       {
375       return parameters.front().empty() ? "1" : "0";
376       }
377
378     return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
379                                       parameters.begin()->c_str(),
380                                       compilerVersion) ? "1" : "0";
381   }
382 };
383
384 //----------------------------------------------------------------------------
385 static const struct CCompilerVersionNode : public CompilerVersionNode
386 {
387   CCompilerVersionNode() {}
388
389   std::string Evaluate(const std::vector<std::string> &parameters,
390                        cmGeneratorExpressionContext *context,
391                        const GeneratorExpressionContent *content,
392                        cmGeneratorExpressionDAGChecker *dagChecker) const
393   {
394     if (parameters.size() != 0 && parameters.size() != 1)
395       {
396       reportError(context, content->GetOriginalExpression(),
397           "$<C_COMPILER_VERSION> expression requires one or two parameters");
398       return std::string();
399       }
400     if (!context->HeadTarget)
401       {
402       reportError(context, content->GetOriginalExpression(),
403           "$<C_COMPILER_VERSION> may only be used with targets.  It may not "
404           "be used with add_custom_command.");
405       }
406     return this->EvaluateWithLanguage(parameters, context, content,
407                                       dagChecker, "C");
408   }
409 } cCompilerVersionNode;
410
411 //----------------------------------------------------------------------------
412 static const struct CxxCompilerVersionNode : public CompilerVersionNode
413 {
414   CxxCompilerVersionNode() {}
415
416   std::string Evaluate(const std::vector<std::string> &parameters,
417                        cmGeneratorExpressionContext *context,
418                        const GeneratorExpressionContent *content,
419                        cmGeneratorExpressionDAGChecker *dagChecker) const
420   {
421     if (parameters.size() != 0 && parameters.size() != 1)
422       {
423       reportError(context, content->GetOriginalExpression(),
424           "$<CXX_COMPILER_VERSION> expression requires one or two "
425           "parameters");
426       return std::string();
427       }
428     if (!context->HeadTarget)
429       {
430       reportError(context, content->GetOriginalExpression(),
431           "$<CXX_COMPILER_VERSION> may only be used with targets.  It may "
432           "not be used with add_custom_command.");
433       }
434     return this->EvaluateWithLanguage(parameters, context, content,
435                                       dagChecker, "CXX");
436   }
437 } cxxCompilerVersionNode;
438
439
440 //----------------------------------------------------------------------------
441 static const struct VersionGreaterNode : public cmGeneratorExpressionNode
442 {
443   VersionGreaterNode() {}
444
445   virtual int NumExpectedParameters() const { return 2; }
446
447   std::string Evaluate(const std::vector<std::string> &parameters,
448                        cmGeneratorExpressionContext *,
449                        const GeneratorExpressionContent *,
450                        cmGeneratorExpressionDAGChecker *) const
451   {
452     return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
453                                          parameters.front().c_str(),
454                                          parameters[1].c_str()) ? "1" : "0";
455   }
456 } versionGreaterNode;
457
458 //----------------------------------------------------------------------------
459 static const struct VersionLessNode : public cmGeneratorExpressionNode
460 {
461   VersionLessNode() {}
462
463   virtual int NumExpectedParameters() const { return 2; }
464
465   std::string Evaluate(const std::vector<std::string> &parameters,
466                        cmGeneratorExpressionContext *,
467                        const GeneratorExpressionContent *,
468                        cmGeneratorExpressionDAGChecker *) const
469   {
470     return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
471                                          parameters.front().c_str(),
472                                          parameters[1].c_str()) ? "1" : "0";
473   }
474 } versionLessNode;
475
476 //----------------------------------------------------------------------------
477 static const struct VersionEqualNode : public cmGeneratorExpressionNode
478 {
479   VersionEqualNode() {}
480
481   virtual int NumExpectedParameters() const { return 2; }
482
483   std::string Evaluate(const std::vector<std::string> &parameters,
484                        cmGeneratorExpressionContext *,
485                        const GeneratorExpressionContent *,
486                        cmGeneratorExpressionDAGChecker *) const
487   {
488     return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
489                                          parameters.front().c_str(),
490                                          parameters[1].c_str()) ? "1" : "0";
491   }
492 } versionEqualNode;
493
494 //----------------------------------------------------------------------------
495 static const struct LinkOnlyNode : public cmGeneratorExpressionNode
496 {
497   LinkOnlyNode() {}
498
499   std::string Evaluate(const std::vector<std::string> &parameters,
500                        cmGeneratorExpressionContext *,
501                        const GeneratorExpressionContent *,
502                        cmGeneratorExpressionDAGChecker *dagChecker) const
503   {
504     if(!dagChecker->GetTransitivePropertiesOnly())
505       {
506       return parameters.front();
507       }
508     return "";
509   }
510 } linkOnlyNode;
511
512 //----------------------------------------------------------------------------
513 static const struct ConfigurationNode : public cmGeneratorExpressionNode
514 {
515   ConfigurationNode() {}
516
517   virtual int NumExpectedParameters() const { return 0; }
518
519   std::string Evaluate(const std::vector<std::string> &,
520                        cmGeneratorExpressionContext *context,
521                        const GeneratorExpressionContent *,
522                        cmGeneratorExpressionDAGChecker *) const
523   {
524     context->HadContextSensitiveCondition = true;
525     return context->Config ? context->Config : "";
526   }
527 } configurationNode;
528
529 //----------------------------------------------------------------------------
530 static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
531 {
532   ConfigurationTestNode() {}
533
534   virtual int NumExpectedParameters() const { return 1; }
535
536   std::string Evaluate(const std::vector<std::string> &parameters,
537                        cmGeneratorExpressionContext *context,
538                        const GeneratorExpressionContent *content,
539                        cmGeneratorExpressionDAGChecker *) const
540   {
541     cmsys::RegularExpression configValidator;
542     configValidator.compile("^[A-Za-z0-9_]*$");
543     if (!configValidator.find(parameters.begin()->c_str()))
544       {
545       reportError(context, content->GetOriginalExpression(),
546                   "Expression syntax not recognized.");
547       return std::string();
548       }
549     context->HadContextSensitiveCondition = true;
550     if (!context->Config)
551       {
552       return parameters.front().empty() ? "1" : "0";
553       }
554
555     if (cmsysString_strcasecmp(parameters.begin()->c_str(),
556                                   context->Config) == 0)
557       {
558       return "1";
559       }
560
561     if (context->CurrentTarget
562         && context->CurrentTarget->IsImported())
563       {
564       const char* loc = 0;
565       const char* imp = 0;
566       std::string suffix;
567       if (context->CurrentTarget->GetMappedConfig(context->Config,
568                                                   &loc,
569                                                   &imp,
570                                                   suffix))
571         {
572         // This imported target has an appropriate location
573         // for this (possibly mapped) config.
574         // Check if there is a proper config mapping for the tested config.
575         std::vector<std::string> mappedConfigs;
576         std::string mapProp = "MAP_IMPORTED_CONFIG_";
577         mapProp += cmSystemTools::UpperCase(context->Config);
578         if(const char* mapValue =
579                         context->CurrentTarget->GetProperty(mapProp.c_str()))
580           {
581           cmSystemTools::ExpandListArgument(cmSystemTools::UpperCase(mapValue),
582                                             mappedConfigs);
583           return std::find(mappedConfigs.begin(), mappedConfigs.end(),
584                            cmSystemTools::UpperCase(parameters.front()))
585               != mappedConfigs.end() ? "1" : "0";
586           }
587         }
588       }
589     return "0";
590   }
591 } configurationTestNode;
592
593 static const struct JoinNode : public cmGeneratorExpressionNode
594 {
595   JoinNode() {}
596
597   virtual int NumExpectedParameters() const { return 2; }
598
599   virtual bool AcceptsArbitraryContentParameter() const { return true; }
600
601   std::string Evaluate(const std::vector<std::string> &parameters,
602                        cmGeneratorExpressionContext *,
603                        const GeneratorExpressionContent *,
604                        cmGeneratorExpressionDAGChecker *) const
605   {
606     std::string result;
607
608     std::vector<std::string> list;
609     cmSystemTools::ExpandListArgument(parameters.front(), list);
610     std::string sep;
611     for(std::vector<std::string>::const_iterator li = list.begin();
612       li != list.end(); ++li)
613       {
614       result += sep + *li;
615       sep = parameters[1];
616       }
617     return result;
618   }
619 } joinNode;
620
621 #define TRANSITIVE_PROPERTY_NAME(PROPERTY) \
622   , #PROPERTY
623
624 //----------------------------------------------------------------------------
625 static const char* targetPropertyTransitiveWhitelist[] = {
626   0
627   CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
628 };
629
630 std::string getLinkedTargetsContent(const std::vector<std::string> &libraries,
631                                   cmTarget *target,
632                                   cmTarget *headTarget,
633                                   cmGeneratorExpressionContext *context,
634                                   cmGeneratorExpressionDAGChecker *dagChecker,
635                                   const std::string &interfacePropertyName)
636 {
637   cmGeneratorExpression ge(context->Backtrace);
638
639   std::string sep;
640   std::string depString;
641   for (std::vector<std::string>::const_iterator
642       it = libraries.begin();
643       it != libraries.end(); ++it)
644     {
645     if (*it == target->GetName())
646       {
647       // Broken code can have a target in its own link interface.
648       // Don't follow such link interface entries so as not to create a
649       // self-referencing loop.
650       continue;
651       }
652     if (context->Makefile->FindTargetToUse(it->c_str()))
653       {
654       depString +=
655         sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">";
656       sep = ";";
657       }
658     }
659   cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString);
660   std::string linkedTargetsContent = cge->Evaluate(context->Makefile,
661                       context->Config,
662                       context->Quiet,
663                       headTarget,
664                       target,
665                       dagChecker);
666   if (cge->GetHadContextSensitiveCondition())
667     {
668     context->HadContextSensitiveCondition = true;
669     }
670   return linkedTargetsContent;
671 }
672
673 //----------------------------------------------------------------------------
674 struct TransitiveWhitelistCompare
675 {
676   explicit TransitiveWhitelistCompare(const std::string &needle)
677     : Needle(needle) {}
678   bool operator() (const char *item)
679   { return strcmp(item, this->Needle.c_str()) == 0; }
680 private:
681   std::string Needle;
682 };
683
684 //----------------------------------------------------------------------------
685 static const struct TargetPropertyNode : public cmGeneratorExpressionNode
686 {
687   TargetPropertyNode() {}
688
689   // This node handles errors on parameter count itself.
690   virtual int NumExpectedParameters() const { return OneOrMoreParameters; }
691
692   std::string Evaluate(const std::vector<std::string> &parameters,
693                        cmGeneratorExpressionContext *context,
694                        const GeneratorExpressionContent *content,
695                        cmGeneratorExpressionDAGChecker *dagCheckerParent
696                       ) const
697   {
698     if (parameters.size() != 1 && parameters.size() != 2)
699       {
700       reportError(context, content->GetOriginalExpression(),
701           "$<TARGET_PROPERTY:...> expression requires one or two parameters");
702       return std::string();
703       }
704     cmsys::RegularExpression propertyNameValidator;
705     propertyNameValidator.compile("^[A-Za-z0-9_]+$");
706
707     cmTarget* target = context->HeadTarget;
708     std::string propertyName = *parameters.begin();
709
710     if (!target && parameters.size() == 1)
711       {
712       reportError(context, content->GetOriginalExpression(),
713           "$<TARGET_PROPERTY:prop> may only be used with targets.  It may not "
714           "be used with add_custom_command.  Specify the target to read a "
715           "property from using the $<TARGET_PROPERTY:tgt,prop> signature "
716           "instead.");
717       return std::string();
718       }
719
720     if (parameters.size() == 2)
721       {
722       if (parameters.begin()->empty() && parameters[1].empty())
723         {
724         reportError(context, content->GetOriginalExpression(),
725             "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
726             "target name and property name.");
727         return std::string();
728         }
729       if (parameters.begin()->empty())
730         {
731         reportError(context, content->GetOriginalExpression(),
732             "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
733             "target name.");
734         return std::string();
735         }
736
737       std::string targetName = parameters.front();
738       propertyName = parameters[1];
739       if (!cmGeneratorExpression::IsValidTargetName(targetName))
740         {
741         if (!propertyNameValidator.find(propertyName.c_str()))
742           {
743           ::reportError(context, content->GetOriginalExpression(),
744                         "Target name and property name not supported.");
745           return std::string();
746           }
747         ::reportError(context, content->GetOriginalExpression(),
748                       "Target name not supported.");
749         return std::string();
750         }
751       if(propertyName == "ALIASED_TARGET")
752         {
753         if(context->Makefile->IsAlias(targetName.c_str()))
754           {
755           if(cmTarget* tgt =
756                       context->Makefile->FindTargetToUse(targetName.c_str()))
757             {
758             return tgt->GetName();
759             }
760           }
761         return "";
762         }
763       target = context->Makefile->FindTargetToUse(
764                                                 targetName.c_str());
765
766       if (!target)
767         {
768         cmOStringStream e;
769         e << "Target \""
770           << targetName
771           << "\" not found.";
772         reportError(context, content->GetOriginalExpression(), e.str());
773         return std::string();
774         }
775         context->AllTargets.insert(target);
776       }
777
778     if (target == context->HeadTarget)
779       {
780       // Keep track of the properties seen while processing.
781       // The evaluation of the LINK_LIBRARIES generator expressions
782       // will check this to ensure that properties have one consistent
783       // value for all evaluations.
784       context->SeenTargetProperties.insert(propertyName);
785       }
786
787     if (propertyName.empty())
788       {
789       reportError(context, content->GetOriginalExpression(),
790           "$<TARGET_PROPERTY:...> expression requires a non-empty property "
791           "name.");
792       return std::string();
793       }
794
795     if (!propertyNameValidator.find(propertyName.c_str()))
796       {
797       ::reportError(context, content->GetOriginalExpression(),
798                     "Property name not supported.");
799       return std::string();
800       }
801
802     assert(target);
803
804     if (propertyName == "LINKER_LANGUAGE")
805       {
806       if (target->LinkLanguagePropagatesToDependents() &&
807           dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries())
808         {
809         reportError(context, content->GetOriginalExpression(),
810             "LINKER_LANGUAGE target property can not be used while evaluating "
811             "link libraries for a static library");
812         return std::string();
813         }
814       const char *lang = target->GetLinkerLanguage(context->Config);
815       return lang ? lang : "";
816       }
817
818     cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
819                                                target->GetName(),
820                                                propertyName,
821                                                content,
822                                                dagCheckerParent);
823
824     switch (dagChecker.check())
825       {
826     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
827       dagChecker.reportError(context, content->GetOriginalExpression());
828       return std::string();
829     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
830       // No error. We just skip cyclic references.
831       return std::string();
832     case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
833       for (size_t i = 1;
834           i < (sizeof(targetPropertyTransitiveWhitelist) /
835                 sizeof(*targetPropertyTransitiveWhitelist));
836           ++i)
837         {
838         if (targetPropertyTransitiveWhitelist[i] == propertyName)
839           {
840           // No error. We're not going to find anything new here.
841           return std::string();
842           }
843         }
844     case cmGeneratorExpressionDAGChecker::DAG:
845       break;
846       }
847
848     const char *prop = target->GetProperty(propertyName.c_str());
849
850     if (dagCheckerParent)
851       {
852       if (dagCheckerParent->EvaluatingLinkLibraries())
853         {
854         if(!prop)
855           {
856           return std::string();
857           }
858         }
859       else
860         {
861 #define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) \
862   dagCheckerParent->METHOD () ||
863
864         assert(
865           CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
866                                             ASSERT_TRANSITIVE_PROPERTY_METHOD)
867           false);
868         }
869       }
870
871     std::string linkedTargetsContent;
872
873     std::string interfacePropertyName;
874
875     if (propertyName == "INTERFACE_INCLUDE_DIRECTORIES"
876         || propertyName == "INCLUDE_DIRECTORIES")
877       {
878       interfacePropertyName = "INTERFACE_INCLUDE_DIRECTORIES";
879       }
880     else if (propertyName == "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")
881       {
882       interfacePropertyName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES";
883       }
884     else if (propertyName == "INTERFACE_COMPILE_DEFINITIONS"
885         || propertyName == "COMPILE_DEFINITIONS"
886         || strncmp(propertyName.c_str(), "COMPILE_DEFINITIONS_", 20) == 0)
887       {
888       interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
889       }
890     else if (propertyName == "INTERFACE_COMPILE_OPTIONS"
891         || propertyName == "COMPILE_OPTIONS")
892       {
893       interfacePropertyName = "INTERFACE_COMPILE_OPTIONS";
894       }
895
896     cmTarget *headTarget = context->HeadTarget ? context->HeadTarget : target;
897
898     const char **transBegin = targetPropertyTransitiveWhitelist + 1;
899     const char **transEnd = targetPropertyTransitiveWhitelist
900               + (sizeof(targetPropertyTransitiveWhitelist) /
901               sizeof(*targetPropertyTransitiveWhitelist));
902     if (std::find_if(transBegin, transEnd,
903               TransitiveWhitelistCompare(propertyName)) != transEnd)
904       {
905
906       std::vector<std::string> libs;
907       target->GetTransitivePropertyLinkLibraries(context->Config,
908                                                  headTarget, libs);
909       if (!libs.empty())
910         {
911         linkedTargetsContent =
912                   getLinkedTargetsContent(libs, target,
913                                           headTarget,
914                                           context, &dagChecker,
915                                           interfacePropertyName);
916         }
917       }
918     else if (std::find_if(transBegin, transEnd,
919               TransitiveWhitelistCompare(interfacePropertyName)) != transEnd)
920       {
921       const cmTarget::LinkImplementation *impl = target->GetLinkImplementation(
922                                                     context->Config,
923                                                     headTarget);
924       if(impl)
925         {
926         linkedTargetsContent =
927                   getLinkedTargetsContent(impl->Libraries, target,
928                                           headTarget,
929                                           context, &dagChecker,
930                                           interfacePropertyName);
931         }
932       }
933
934     linkedTargetsContent =
935           cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
936
937     if (!prop)
938       {
939       if (target->IsImported())
940         {
941         return linkedTargetsContent;
942         }
943       if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
944                                                        context->Config))
945         {
946         context->HadContextSensitiveCondition = true;
947         return target->GetLinkInterfaceDependentBoolProperty(
948                                                 propertyName,
949                                                 context->Config) ? "1" : "0";
950         }
951       if (target->IsLinkInterfaceDependentStringProperty(propertyName,
952                                                          context->Config))
953         {
954         context->HadContextSensitiveCondition = true;
955         const char *propContent =
956                               target->GetLinkInterfaceDependentStringProperty(
957                                                 propertyName,
958                                                 context->Config);
959         return propContent ? propContent : "";
960         }
961
962       return linkedTargetsContent;
963       }
964
965     for (size_t i = 1;
966          i < (sizeof(targetPropertyTransitiveWhitelist) /
967               sizeof(*targetPropertyTransitiveWhitelist));
968          ++i)
969       {
970       if (targetPropertyTransitiveWhitelist[i] == interfacePropertyName)
971         {
972         cmGeneratorExpression ge(context->Backtrace);
973         cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
974         std::string result = cge->Evaluate(context->Makefile,
975                             context->Config,
976                             context->Quiet,
977                             headTarget,
978                             target,
979                             &dagChecker);
980
981         if (cge->GetHadContextSensitiveCondition())
982           {
983           context->HadContextSensitiveCondition = true;
984           }
985         if (!linkedTargetsContent.empty())
986           {
987           result += (result.empty() ? "" : ";") + linkedTargetsContent;
988           }
989         return result;
990         }
991       }
992     return prop;
993   }
994 } targetPropertyNode;
995
996 //----------------------------------------------------------------------------
997 static const struct TargetNameNode : public cmGeneratorExpressionNode
998 {
999   TargetNameNode() {}
1000
1001   virtual bool GeneratesContent() const { return true; }
1002
1003   virtual bool AcceptsArbitraryContentParameter() const { return true; }
1004   virtual bool RequiresLiteralInput() const { return true; }
1005
1006   std::string Evaluate(const std::vector<std::string> &parameters,
1007                        cmGeneratorExpressionContext *,
1008                        const GeneratorExpressionContent *,
1009                        cmGeneratorExpressionDAGChecker *) const
1010   {
1011     return parameters.front();
1012   }
1013
1014   virtual int NumExpectedParameters() const { return 1; }
1015
1016 } targetNameNode;
1017
1018 //----------------------------------------------------------------------------
1019 static const char* targetPolicyWhitelist[] = {
1020   0
1021 #define TARGET_POLICY_STRING(POLICY) \
1022   , #POLICY
1023
1024   CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_STRING)
1025
1026 #undef TARGET_POLICY_STRING
1027 };
1028
1029 cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
1030 {
1031 #define RETURN_POLICY(POLICY) \
1032   if (strcmp(policy, #POLICY) == 0) \
1033   { \
1034     return tgt->GetPolicyStatus ## POLICY (); \
1035   } \
1036
1037   CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY)
1038
1039 #undef RETURN_POLICY
1040
1041   assert("!Unreachable code. Not a valid policy");
1042   return cmPolicies::WARN;
1043 }
1044
1045 cmPolicies::PolicyID policyForString(const char *policy_id)
1046 {
1047 #define RETURN_POLICY_ID(POLICY_ID) \
1048   if (strcmp(policy_id, #POLICY_ID) == 0) \
1049   { \
1050     return cmPolicies:: POLICY_ID; \
1051   } \
1052
1053   CM_FOR_EACH_TARGET_POLICY(RETURN_POLICY_ID)
1054
1055 #undef RETURN_POLICY_ID
1056
1057   assert("!Unreachable code. Not a valid policy");
1058   return cmPolicies::CMP0002;
1059 }
1060
1061 //----------------------------------------------------------------------------
1062 static const struct TargetPolicyNode : public cmGeneratorExpressionNode
1063 {
1064   TargetPolicyNode() {}
1065
1066   virtual int NumExpectedParameters() const { return 1; }
1067
1068   std::string Evaluate(const std::vector<std::string> &parameters,
1069                        cmGeneratorExpressionContext *context ,
1070                        const GeneratorExpressionContent *content,
1071                        cmGeneratorExpressionDAGChecker *) const
1072   {
1073     if (!context->HeadTarget)
1074       {
1075       reportError(context, content->GetOriginalExpression(),
1076           "$<TARGET_POLICY:prop> may only be used with targets.  It may not "
1077           "be used with add_custom_command.");
1078       return std::string();
1079       }
1080
1081     context->HadContextSensitiveCondition = true;
1082
1083     for (size_t i = 1;
1084          i < (sizeof(targetPolicyWhitelist) /
1085               sizeof(*targetPolicyWhitelist));
1086          ++i)
1087       {
1088       const char *policy = targetPolicyWhitelist[i];
1089       if (parameters.front() == policy)
1090         {
1091         cmMakefile *mf = context->HeadTarget->GetMakefile();
1092         switch(statusForTarget(context->HeadTarget, policy))
1093           {
1094           case cmPolicies::WARN:
1095             mf->IssueMessage(cmake::AUTHOR_WARNING,
1096                              mf->GetPolicies()->
1097                              GetPolicyWarning(policyForString(policy)));
1098           case cmPolicies::REQUIRED_IF_USED:
1099           case cmPolicies::REQUIRED_ALWAYS:
1100           case cmPolicies::OLD:
1101             return "0";
1102           case cmPolicies::NEW:
1103             return "1";
1104           }
1105         }
1106       }
1107     reportError(context, content->GetOriginalExpression(),
1108       "$<TARGET_POLICY:prop> may only be used with a limited number of "
1109       "policies.  Currently it may be used with the following policies:\n"
1110
1111 #define STRINGIFY_HELPER(X) #X
1112 #define STRINGIFY(X) STRINGIFY_HELPER(X)
1113
1114 #define TARGET_POLICY_LIST_ITEM(POLICY) \
1115       " * " STRINGIFY(POLICY) "\n"
1116
1117       CM_FOR_EACH_TARGET_POLICY(TARGET_POLICY_LIST_ITEM)
1118
1119 #undef TARGET_POLICY_LIST_ITEM
1120       );
1121     return std::string();
1122   }
1123
1124 } targetPolicyNode;
1125
1126 //----------------------------------------------------------------------------
1127 static const struct InstallPrefixNode : public cmGeneratorExpressionNode
1128 {
1129   InstallPrefixNode() {}
1130
1131   virtual bool GeneratesContent() const { return true; }
1132   virtual int NumExpectedParameters() const { return 0; }
1133
1134   std::string Evaluate(const std::vector<std::string> &,
1135                        cmGeneratorExpressionContext *context,
1136                        const GeneratorExpressionContent *content,
1137                        cmGeneratorExpressionDAGChecker *) const
1138   {
1139     reportError(context, content->GetOriginalExpression(),
1140                 "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
1141                 "should never be evaluated.");
1142     return std::string();
1143   }
1144
1145 } installPrefixNode;
1146
1147 //----------------------------------------------------------------------------
1148 template<bool linker, bool soname>
1149 struct TargetFilesystemArtifactResultCreator
1150 {
1151   static std::string Create(cmTarget* target,
1152                             cmGeneratorExpressionContext *context,
1153                             const GeneratorExpressionContent *content);
1154 };
1155
1156 //----------------------------------------------------------------------------
1157 template<>
1158 struct TargetFilesystemArtifactResultCreator<false, true>
1159 {
1160   static std::string Create(cmTarget* target,
1161                             cmGeneratorExpressionContext *context,
1162                             const GeneratorExpressionContent *content)
1163   {
1164     // The target soname file (.so.1).
1165     if(target->IsDLLPlatform())
1166       {
1167       ::reportError(context, content->GetOriginalExpression(),
1168                     "TARGET_SONAME_FILE is not allowed "
1169                     "for DLL target platforms.");
1170       return std::string();
1171       }
1172     if(target->GetType() != cmTarget::SHARED_LIBRARY)
1173       {
1174       ::reportError(context, content->GetOriginalExpression(),
1175                     "TARGET_SONAME_FILE is allowed only for "
1176                     "SHARED libraries.");
1177       return std::string();
1178       }
1179     std::string result = target->GetDirectory(context->Config);
1180     result += "/";
1181     result += target->GetSOName(context->Config);
1182     return result;
1183   }
1184 };
1185
1186 //----------------------------------------------------------------------------
1187 template<>
1188 struct TargetFilesystemArtifactResultCreator<true, false>
1189 {
1190   static std::string Create(cmTarget* target,
1191                             cmGeneratorExpressionContext *context,
1192                             const GeneratorExpressionContent *content)
1193   {
1194     // The file used to link to the target (.so, .lib, .a).
1195     if(!target->IsLinkable())
1196       {
1197       ::reportError(context, content->GetOriginalExpression(),
1198                     "TARGET_LINKER_FILE is allowed only for libraries and "
1199                     "executables with ENABLE_EXPORTS.");
1200       return std::string();
1201       }
1202     return target->GetFullPath(context->Config,
1203                                target->HasImportLibrary());
1204   }
1205 };
1206
1207 //----------------------------------------------------------------------------
1208 template<>
1209 struct TargetFilesystemArtifactResultCreator<false, false>
1210 {
1211   static std::string Create(cmTarget* target,
1212                             cmGeneratorExpressionContext *context,
1213                             const GeneratorExpressionContent *)
1214   {
1215     return target->GetFullPath(context->Config, false, true);
1216   }
1217 };
1218
1219
1220 //----------------------------------------------------------------------------
1221 template<bool dirQual, bool nameQual>
1222 struct TargetFilesystemArtifactResultGetter
1223 {
1224   static std::string Get(const std::string &result);
1225 };
1226
1227 //----------------------------------------------------------------------------
1228 template<>
1229 struct TargetFilesystemArtifactResultGetter<false, true>
1230 {
1231   static std::string Get(const std::string &result)
1232   { return cmSystemTools::GetFilenameName(result); }
1233 };
1234
1235 //----------------------------------------------------------------------------
1236 template<>
1237 struct TargetFilesystemArtifactResultGetter<true, false>
1238 {
1239   static std::string Get(const std::string &result)
1240   { return cmSystemTools::GetFilenamePath(result); }
1241 };
1242
1243 //----------------------------------------------------------------------------
1244 template<>
1245 struct TargetFilesystemArtifactResultGetter<false, false>
1246 {
1247   static std::string Get(const std::string &result)
1248   { return result; }
1249 };
1250
1251 //----------------------------------------------------------------------------
1252 template<bool linker, bool soname, bool dirQual, bool nameQual>
1253 struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
1254 {
1255   TargetFilesystemArtifact() {}
1256
1257   virtual int NumExpectedParameters() const { return 1; }
1258
1259   std::string Evaluate(const std::vector<std::string> &parameters,
1260                        cmGeneratorExpressionContext *context,
1261                        const GeneratorExpressionContent *content,
1262                        cmGeneratorExpressionDAGChecker *dagChecker) const
1263   {
1264     // Lookup the referenced target.
1265     std::string name = *parameters.begin();
1266
1267     if (!cmGeneratorExpression::IsValidTargetName(name))
1268       {
1269       ::reportError(context, content->GetOriginalExpression(),
1270                     "Expression syntax not recognized.");
1271       return std::string();
1272       }
1273     cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
1274     if(!target)
1275       {
1276       ::reportError(context, content->GetOriginalExpression(),
1277                     "No target \"" + name + "\"");
1278       return std::string();
1279       }
1280     if(target->GetType() >= cmTarget::OBJECT_LIBRARY &&
1281       target->GetType() != cmTarget::UNKNOWN_LIBRARY)
1282       {
1283       ::reportError(context, content->GetOriginalExpression(),
1284                   "Target \"" + name + "\" is not an executable or library.");
1285       return std::string();
1286       }
1287     if (dagChecker && dagChecker->EvaluatingLinkLibraries(name.c_str()))
1288       {
1289       ::reportError(context, content->GetOriginalExpression(),
1290                     "Expressions which require the linker language may not "
1291                     "be used while evaluating link libraries");
1292       return std::string();
1293       }
1294     context->DependTargets.insert(target);
1295     context->AllTargets.insert(target);
1296
1297     std::string result =
1298                 TargetFilesystemArtifactResultCreator<linker, soname>::Create(
1299                           target,
1300                           context,
1301                           content);
1302     if (context->HadError)
1303       {
1304       return std::string();
1305       }
1306     return
1307         TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
1308   }
1309 };
1310
1311 //----------------------------------------------------------------------------
1312 static const
1313 TargetFilesystemArtifact<false, false, false, false> targetFileNode;
1314 static const
1315 TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
1316 static const
1317 TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
1318 static const
1319 TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
1320 static const
1321 TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
1322 static const
1323 TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
1324 static const
1325 TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
1326 static const
1327 TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
1328 static const
1329 TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
1330
1331 //----------------------------------------------------------------------------
1332 static const
1333 cmGeneratorExpressionNode* GetNode(const std::string &identifier)
1334 {
1335   if (identifier == "0")
1336     return &zeroNode;
1337   else if (identifier == "1")
1338     return &oneNode;
1339   else if (identifier == "AND")
1340     return &andNode;
1341   else if (identifier == "OR")
1342     return &orNode;
1343   else if (identifier == "NOT")
1344     return &notNode;
1345   else if (identifier == "C_COMPILER_ID")
1346     return &cCompilerIdNode;
1347   else if (identifier == "CXX_COMPILER_ID")
1348     return &cxxCompilerIdNode;
1349   else if (identifier == "VERSION_GREATER")
1350     return &versionGreaterNode;
1351   else if (identifier == "VERSION_LESS")
1352     return &versionLessNode;
1353   else if (identifier == "VERSION_EQUAL")
1354     return &versionEqualNode;
1355   else if (identifier == "C_COMPILER_VERSION")
1356     return &cCompilerVersionNode;
1357   else if (identifier == "CXX_COMPILER_VERSION")
1358     return &cxxCompilerVersionNode;
1359   else if (identifier == "CONFIGURATION")
1360     return &configurationNode;
1361   else if (identifier == "CONFIG")
1362     return &configurationTestNode;
1363   else if (identifier == "TARGET_FILE")
1364     return &targetFileNode;
1365   else if (identifier == "TARGET_LINKER_FILE")
1366     return &targetLinkerFileNode;
1367   else if (identifier == "TARGET_SONAME_FILE")
1368     return &targetSoNameFileNode;
1369   else if (identifier == "TARGET_FILE_NAME")
1370     return &targetFileNameNode;
1371   else if (identifier == "TARGET_LINKER_FILE_NAME")
1372     return &targetLinkerFileNameNode;
1373   else if (identifier == "TARGET_SONAME_FILE_NAME")
1374     return &targetSoNameFileNameNode;
1375   else if (identifier == "TARGET_FILE_DIR")
1376     return &targetFileDirNode;
1377   else if (identifier == "TARGET_LINKER_FILE_DIR")
1378     return &targetLinkerFileDirNode;
1379   else if (identifier == "TARGET_SONAME_FILE_DIR")
1380     return &targetSoNameFileDirNode;
1381   else if (identifier == "STREQUAL")
1382     return &strEqualNode;
1383   else if (identifier == "BOOL")
1384     return &boolNode;
1385   else if (identifier == "ANGLE-R")
1386     return &angle_rNode;
1387   else if (identifier == "COMMA")
1388     return &commaNode;
1389   else if (identifier == "SEMICOLON")
1390     return &semicolonNode;
1391   else if (identifier == "TARGET_PROPERTY")
1392     return &targetPropertyNode;
1393   else if (identifier == "TARGET_NAME")
1394     return &targetNameNode;
1395   else if (identifier == "TARGET_POLICY")
1396     return &targetPolicyNode;
1397   else if (identifier == "BUILD_INTERFACE")
1398     return &buildInterfaceNode;
1399   else if (identifier == "INSTALL_INTERFACE")
1400     return &installInterfaceNode;
1401   else if (identifier == "INSTALL_PREFIX")
1402     return &installPrefixNode;
1403   else if (identifier == "JOIN")
1404     return &joinNode;
1405   else if (identifier == "LINK_ONLY")
1406     return &linkOnlyNode;
1407   return 0;
1408
1409 }
1410
1411 //----------------------------------------------------------------------------
1412 GeneratorExpressionContent::GeneratorExpressionContent(
1413                                                     const char *startContent,
1414                                                     unsigned int length)
1415   : StartContent(startContent), ContentLength(length)
1416 {
1417
1418 }
1419
1420 //----------------------------------------------------------------------------
1421 std::string GeneratorExpressionContent::GetOriginalExpression() const
1422 {
1423   return std::string(this->StartContent, this->ContentLength);
1424 }
1425
1426 //----------------------------------------------------------------------------
1427 std::string GeneratorExpressionContent::ProcessArbitraryContent(
1428     const cmGeneratorExpressionNode *node,
1429     const std::string &identifier,
1430     cmGeneratorExpressionContext *context,
1431     cmGeneratorExpressionDAGChecker *dagChecker,
1432     std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1433     pit) const
1434 {
1435   std::string result;
1436
1437   const
1438   std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1439                                       pend = this->ParamChildren.end();
1440   for ( ; pit != pend; ++pit)
1441     {
1442     std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1443                                                             = pit->begin();
1444     const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1445                                                               = pit->end();
1446     for ( ; it != end; ++it)
1447       {
1448       if (node->RequiresLiteralInput())
1449         {
1450         if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
1451           {
1452           reportError(context, this->GetOriginalExpression(),
1453                 "$<" + identifier + "> expression requires literal input.");
1454           return std::string();
1455           }
1456         }
1457       result += (*it)->Evaluate(context, dagChecker);
1458       if (context->HadError)
1459         {
1460         return std::string();
1461         }
1462       }
1463       if ((pit + 1) != pend)
1464         {
1465         result += ",";
1466         }
1467     }
1468   if (node->RequiresLiteralInput())
1469     {
1470     std::vector<std::string> parameters;
1471     parameters.push_back(result);
1472     return node->Evaluate(parameters, context, this, dagChecker);
1473     }
1474   return result;
1475 }
1476
1477 //----------------------------------------------------------------------------
1478 std::string GeneratorExpressionContent::Evaluate(
1479                             cmGeneratorExpressionContext *context,
1480                             cmGeneratorExpressionDAGChecker *dagChecker) const
1481 {
1482   std::string identifier;
1483   {
1484   std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1485                                           = this->IdentifierChildren.begin();
1486   const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1487                                           = this->IdentifierChildren.end();
1488   for ( ; it != end; ++it)
1489     {
1490     identifier += (*it)->Evaluate(context, dagChecker);
1491     if (context->HadError)
1492       {
1493       return std::string();
1494       }
1495     }
1496   }
1497
1498   const cmGeneratorExpressionNode *node = GetNode(identifier);
1499
1500   if (!node)
1501     {
1502     reportError(context, this->GetOriginalExpression(),
1503               "Expression did not evaluate to a known generator expression");
1504     return std::string();
1505     }
1506
1507   if (!node->GeneratesContent())
1508     {
1509     if (node->NumExpectedParameters() == 1
1510         && node->AcceptsArbitraryContentParameter())
1511       {
1512       if (this->ParamChildren.empty())
1513         {
1514         reportError(context, this->GetOriginalExpression(),
1515                   "$<" + identifier + "> expression requires a parameter.");
1516         }
1517       }
1518     else
1519       {
1520       std::vector<std::string> parameters;
1521       this->EvaluateParameters(node, identifier, context, dagChecker,
1522                                parameters);
1523       }
1524     return std::string();
1525     }
1526
1527   if (node->NumExpectedParameters() == 1
1528         && node->AcceptsArbitraryContentParameter())
1529     {
1530     return this->ProcessArbitraryContent(node, identifier, context,
1531                                          dagChecker,
1532                                          this->ParamChildren.begin());
1533     }
1534
1535   std::vector<std::string> parameters;
1536   this->EvaluateParameters(node, identifier, context, dagChecker, parameters);
1537   if (context->HadError)
1538     {
1539     return std::string();
1540     }
1541
1542   return node->Evaluate(parameters, context, this, dagChecker);
1543 }
1544
1545 //----------------------------------------------------------------------------
1546 std::string GeneratorExpressionContent::EvaluateParameters(
1547                                 const cmGeneratorExpressionNode *node,
1548                                 const std::string &identifier,
1549                                 cmGeneratorExpressionContext *context,
1550                                 cmGeneratorExpressionDAGChecker *dagChecker,
1551                                 std::vector<std::string> &parameters) const
1552 {
1553   const int numExpected = node->NumExpectedParameters();
1554   {
1555   std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1556                                         pit = this->ParamChildren.begin();
1557   const
1558   std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
1559                                         pend = this->ParamChildren.end();
1560   const bool acceptsArbitraryContent
1561                                   = node->AcceptsArbitraryContentParameter();
1562   for ( ; pit != pend; ++pit)
1563     {
1564     std::string parameter;
1565     std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
1566                                                               pit->begin();
1567     const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
1568                                                               pit->end();
1569     for ( ; it != end; ++it)
1570       {
1571       parameter += (*it)->Evaluate(context, dagChecker);
1572       if (context->HadError)
1573         {
1574         return std::string();
1575         }
1576       }
1577     parameters.push_back(parameter);
1578     if (acceptsArbitraryContent
1579         && parameters.size() == (unsigned int)numExpected - 1)
1580       {
1581       assert(pit != pend);
1582       std::string lastParam = this->ProcessArbitraryContent(node, identifier,
1583                                                             context,
1584                                                             dagChecker,
1585                                                             pit + 1);
1586       parameters.push_back(lastParam);
1587       return std::string();
1588       }
1589     }
1590   }
1591
1592   if ((numExpected > cmGeneratorExpressionNode::DynamicParameters
1593       && (unsigned int)numExpected != parameters.size()))
1594     {
1595     if (numExpected == 0)
1596       {
1597       reportError(context, this->GetOriginalExpression(),
1598                   "$<" + identifier + "> expression requires no parameters.");
1599       }
1600     else if (numExpected == 1)
1601       {
1602       reportError(context, this->GetOriginalExpression(),
1603                   "$<" + identifier + "> expression requires "
1604                   "exactly one parameter.");
1605       }
1606     else
1607       {
1608       cmOStringStream e;
1609       e << "$<" + identifier + "> expression requires "
1610         << numExpected
1611         << " comma separated parameters, but got "
1612         << parameters.size() << " instead.";
1613       reportError(context, this->GetOriginalExpression(), e.str());
1614       }
1615     return std::string();
1616     }
1617
1618   if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters
1619       && parameters.empty())
1620     {
1621     reportError(context, this->GetOriginalExpression(), "$<" + identifier
1622                       + "> expression requires at least one parameter.");
1623     }
1624   return std::string();
1625 }
1626
1627 //----------------------------------------------------------------------------
1628 static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
1629 {
1630   std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
1631                                                   = c.begin();
1632   const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
1633                                                   = c.end();
1634   for ( ; it != end; ++it)
1635     {
1636     delete *it;
1637     }
1638 }
1639
1640 //----------------------------------------------------------------------------
1641 GeneratorExpressionContent::~GeneratorExpressionContent()
1642 {
1643   deleteAll(this->IdentifierChildren);
1644
1645   typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
1646   std::vector<EvaluatorVector>::const_iterator pit =
1647                                                   this->ParamChildren.begin();
1648   const std::vector<EvaluatorVector>::const_iterator pend =
1649                                                   this->ParamChildren.end();
1650   for ( ; pit != pend; ++pit)
1651     {
1652     deleteAll(*pit);
1653     }
1654 }