cmGeneratorExpression.cxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmGeneratorExpression.h"
  11. #include "cmMakefile.h"
  12. #include "cmTarget.h"
  13. //----------------------------------------------------------------------------
  14. cmGeneratorExpression::cmGeneratorExpression(
  15. cmMakefile* mf, const char* config,
  16. cmListFileBacktrace const& backtrace, bool quiet):
  17. Makefile(mf), Config(config), Backtrace(backtrace), Quiet(quiet)
  18. {
  19. this->TargetInfo.compile("^\\$<TARGET"
  20. "(|_SONAME|_LINKER)" // File with what purpose?
  21. "_FILE(|_NAME|_DIR):" // Filename component.
  22. "([A-Za-z0-9_-]+)" // Target name.
  23. ">$");
  24. }
  25. //----------------------------------------------------------------------------
  26. const char* cmGeneratorExpression::Process(std::string const& input)
  27. {
  28. return this->Process(input.c_str());
  29. }
  30. //----------------------------------------------------------------------------
  31. const char* cmGeneratorExpression::Process(const char* input)
  32. {
  33. this->Data.clear();
  34. // We construct and evaluate expressions directly in the output
  35. // buffer. Each expression is replaced by its own output value
  36. // after evaluation. A stack of barriers records the starting
  37. // indices of open (pending) expressions.
  38. for(const char* c = input; *c; ++c)
  39. {
  40. if(c[0] == '$' && c[1] == '<')
  41. {
  42. this->Barriers.push(this->Data.size());
  43. this->Data.push_back('$');
  44. this->Data.push_back('<');
  45. c += 1;
  46. }
  47. else if(c[0] == '>' && !this->Barriers.empty())
  48. {
  49. this->Data.push_back('>');
  50. if(!this->Evaluate()) { break; }
  51. this->Barriers.pop();
  52. }
  53. else
  54. {
  55. this->Data.push_back(c[0]);
  56. }
  57. }
  58. // Return a null-terminated output value.
  59. this->Data.push_back('\0');
  60. return &*this->Data.begin();
  61. }
  62. //----------------------------------------------------------------------------
  63. bool cmGeneratorExpression::Evaluate()
  64. {
  65. // The top-most barrier points at the beginning of the expression.
  66. size_t barrier = this->Barriers.top();
  67. // Construct a null-terminated representation of the expression.
  68. this->Data.push_back('\0');
  69. const char* expr = &*(this->Data.begin()+barrier);
  70. // Evaluate the expression.
  71. std::string result;
  72. if(this->Evaluate(expr, result))
  73. {
  74. // Success. Replace the expression with its evaluation result.
  75. this->Data.erase(this->Data.begin()+barrier, this->Data.end());
  76. this->Data.insert(this->Data.end(), result.begin(), result.end());
  77. return true;
  78. }
  79. else if(!this->Quiet)
  80. {
  81. // Failure. Report the error message.
  82. cmOStringStream e;
  83. e << "Error evaluating generator expression:\n"
  84. << " " << expr << "\n"
  85. << result;
  86. this->Makefile->GetCMakeInstance()
  87. ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
  88. this->Backtrace);
  89. return false;
  90. }
  91. return true;
  92. }
  93. //----------------------------------------------------------------------------
  94. bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
  95. {
  96. if(this->TargetInfo.find(expr))
  97. {
  98. if(!this->EvaluateTargetInfo(result))
  99. {
  100. return false;
  101. }
  102. }
  103. else if(strcmp(expr, "$<CONFIGURATION>") == 0)
  104. {
  105. result = this->Config? this->Config : "";
  106. }
  107. else
  108. {
  109. result = "Expression syntax not recognized.";
  110. return false;
  111. }
  112. return true;
  113. }
  114. //----------------------------------------------------------------------------
  115. bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result)
  116. {
  117. // Lookup the referenced target.
  118. std::string name = this->TargetInfo.match(3);
  119. cmTarget* target = this->Makefile->FindTargetToUse(name.c_str());
  120. if(!target)
  121. {
  122. result = "No target \"" + name + "\"";
  123. return false;
  124. }
  125. if(target->GetType() >= cmTarget::UTILITY &&
  126. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  127. {
  128. result = "Target \"" + name + "\" is not an executable or library.";
  129. return false;
  130. }
  131. this->Targets.insert(target);
  132. // Lookup the target file with the given purpose.
  133. std::string purpose = this->TargetInfo.match(1);
  134. if(purpose == "")
  135. {
  136. // The target implementation file (.so.1.2, .dll, .exe, .a).
  137. result = target->GetFullPath(this->Config, false, true);
  138. }
  139. else if(purpose == "_LINKER")
  140. {
  141. // The file used to link to the target (.so, .lib, .a).
  142. if(!target->IsLinkable())
  143. {
  144. result = ("TARGET_LINKER_FILE is allowed only for libraries and "
  145. "executables with ENABLE_EXPORTS.");
  146. return false;
  147. }
  148. result = target->GetFullPath(this->Config, target->HasImportLibrary());
  149. }
  150. else if(purpose == "_SONAME")
  151. {
  152. // The target soname file (.so.1).
  153. if(target->IsDLLPlatform())
  154. {
  155. result = "TARGET_SONAME_FILE is not allowed for DLL target platforms.";
  156. return false;
  157. }
  158. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  159. {
  160. result = "TARGET_SONAME_FILE is allowed only for SHARED libraries.";
  161. return false;
  162. }
  163. result = target->GetDirectory(this->Config);
  164. result += "/";
  165. result += target->GetSOName(this->Config);
  166. }
  167. // Extract the requested portion of the full path.
  168. std::string part = this->TargetInfo.match(2);
  169. if(part == "_NAME")
  170. {
  171. result = cmSystemTools::GetFilenameName(result);
  172. }
  173. else if(part == "_DIR")
  174. {
  175. result = cmSystemTools::GetFilenamePath(result);
  176. }
  177. return true;
  178. }