cmGeneratorExpression.cxx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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):
  17. Makefile(mf), Config(config), Backtrace(backtrace)
  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
  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. }
  92. //----------------------------------------------------------------------------
  93. bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
  94. {
  95. if(this->TargetInfo.find(expr))
  96. {
  97. if(!this->EvaluateTargetInfo(result))
  98. {
  99. return false;
  100. }
  101. }
  102. else if(strcmp(expr, "$<CONFIGURATION>") == 0)
  103. {
  104. result = this->Config? this->Config : "";
  105. }
  106. else
  107. {
  108. result = "Expression syntax not recognized.";
  109. return false;
  110. }
  111. return true;
  112. }
  113. //----------------------------------------------------------------------------
  114. bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result)
  115. {
  116. // Lookup the referenced target.
  117. std::string name = this->TargetInfo.match(3);
  118. cmTarget* target = this->Makefile->FindTargetToUse(name.c_str());
  119. if(!target)
  120. {
  121. result = "No target \"" + name + "\"";
  122. return false;
  123. }
  124. if(target->GetType() >= cmTarget::UTILITY &&
  125. target->GetType() != cmTarget::UNKNOWN_LIBRARY)
  126. {
  127. result = "Target \"" + name + "\" is not an executable or library.";
  128. return false;
  129. }
  130. // Lookup the target file with the given purpose.
  131. std::string purpose = this->TargetInfo.match(1);
  132. if(purpose == "")
  133. {
  134. // The target implementation file (.so.1.2, .dll, .exe, .a).
  135. result = target->GetFullPath(this->Config, false, true);
  136. }
  137. else if(purpose == "_LINKER")
  138. {
  139. // The file used to link to the target (.so, .lib, .a).
  140. if(!target->IsLinkable())
  141. {
  142. result = ("TARGET_LINKER_FILE is allowed only for libraries and "
  143. "executables with ENABLE_EXPORTS.");
  144. return false;
  145. }
  146. result = target->GetFullPath(this->Config, target->HasImportLibrary());
  147. }
  148. else if(purpose == "_SONAME")
  149. {
  150. // The target soname file (.so.1).
  151. if(target->IsDLLPlatform())
  152. {
  153. result = "TARGET_SONAME_FILE is not allowed for DLL target platforms.";
  154. return false;
  155. }
  156. if(target->GetType() != cmTarget::SHARED_LIBRARY)
  157. {
  158. result = "TARGET_SONAME_FILE is allowed only for SHARED libraries.";
  159. return false;
  160. }
  161. result = target->GetDirectory(this->Config);
  162. result += "/";
  163. result += target->GetSOName(this->Config);
  164. }
  165. // Extract the requested portion of the full path.
  166. std::string part = this->TargetInfo.match(2);
  167. if(part == "_NAME")
  168. {
  169. result = cmSystemTools::GetFilenameName(result);
  170. }
  171. else if(part == "_DIR")
  172. {
  173. result = cmSystemTools::GetFilenamePath(result);
  174. }
  175. return true;
  176. }