cmFileSet.cxx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 "cmFileSet.h"
  4. #include <sstream>
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include <cmext/algorithm>
  9. #include <cmext/string_view>
  10. #include "cmsys/RegularExpression.hxx"
  11. #include "cmGeneratorExpression.h"
  12. #include "cmList.h"
  13. #include "cmListFileCache.h"
  14. #include "cmLocalGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmMessageType.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmSystemTools.h"
  19. #include "cmake.h"
  20. cm::static_string_view cmFileSetVisibilityToName(cmFileSetVisibility vis)
  21. {
  22. switch (vis) {
  23. case cmFileSetVisibility::Interface:
  24. return "INTERFACE"_s;
  25. case cmFileSetVisibility::Public:
  26. return "PUBLIC"_s;
  27. case cmFileSetVisibility::Private:
  28. return "PRIVATE"_s;
  29. }
  30. return ""_s;
  31. }
  32. cmFileSetVisibility cmFileSetVisibilityFromName(cm::string_view name,
  33. cmMakefile* mf)
  34. {
  35. if (name == "INTERFACE"_s) {
  36. return cmFileSetVisibility::Interface;
  37. }
  38. if (name == "PUBLIC"_s) {
  39. return cmFileSetVisibility::Public;
  40. }
  41. if (name == "PRIVATE"_s) {
  42. return cmFileSetVisibility::Private;
  43. }
  44. auto msg = cmStrCat("File set visibility \"", name, "\" is not valid.");
  45. if (mf) {
  46. mf->IssueMessage(MessageType::FATAL_ERROR, msg);
  47. } else {
  48. cmSystemTools::Error(msg);
  49. }
  50. return cmFileSetVisibility::Private;
  51. }
  52. bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis)
  53. {
  54. switch (vis) {
  55. case cmFileSetVisibility::Interface:
  56. return false;
  57. case cmFileSetVisibility::Public:
  58. case cmFileSetVisibility::Private:
  59. return true;
  60. }
  61. return false;
  62. }
  63. bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis)
  64. {
  65. switch (vis) {
  66. case cmFileSetVisibility::Interface:
  67. case cmFileSetVisibility::Public:
  68. return true;
  69. case cmFileSetVisibility::Private:
  70. return false;
  71. }
  72. return false;
  73. }
  74. bool cmFileSetTypeCanBeIncluded(std::string const& type)
  75. {
  76. return type == "HEADERS"_s;
  77. }
  78. cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
  79. cmFileSetVisibility visibility)
  80. : CMakeInstance(cmakeInstance)
  81. , Name(std::move(name))
  82. , Type(std::move(type))
  83. , Visibility(visibility)
  84. {
  85. }
  86. void cmFileSet::CopyEntries(cmFileSet const* fs)
  87. {
  88. cm::append(this->DirectoryEntries, fs->DirectoryEntries);
  89. cm::append(this->FileEntries, fs->FileEntries);
  90. }
  91. void cmFileSet::ClearDirectoryEntries()
  92. {
  93. this->DirectoryEntries.clear();
  94. }
  95. void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
  96. {
  97. this->DirectoryEntries.push_back(std::move(directories));
  98. }
  99. void cmFileSet::ClearFileEntries()
  100. {
  101. this->FileEntries.clear();
  102. }
  103. void cmFileSet::AddFileEntry(BT<std::string> files)
  104. {
  105. this->FileEntries.push_back(std::move(files));
  106. }
  107. std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
  108. cmFileSet::CompileFileEntries() const
  109. {
  110. std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
  111. for (auto const& entry : this->FileEntries) {
  112. for (auto const& ex : cmList{ entry.Value }) {
  113. cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
  114. auto cge = ge.Parse(ex);
  115. result.push_back(std::move(cge));
  116. }
  117. }
  118. return result;
  119. }
  120. std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
  121. cmFileSet::CompileDirectoryEntries() const
  122. {
  123. std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
  124. for (auto const& entry : this->DirectoryEntries) {
  125. for (auto const& ex : cmList{ entry.Value }) {
  126. cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
  127. auto cge = ge.Parse(ex);
  128. result.push_back(std::move(cge));
  129. }
  130. }
  131. return result;
  132. }
  133. std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
  134. const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges,
  135. cmLocalGenerator* lg, const std::string& config,
  136. const cmGeneratorTarget* target,
  137. cmGeneratorExpressionDAGChecker* dagChecker) const
  138. {
  139. std::vector<std::string> result;
  140. for (auto const& cge : cges) {
  141. auto entry = cge->Evaluate(lg, config, target, dagChecker);
  142. cmList dirs{ entry };
  143. for (std::string dir : dirs) {
  144. if (!cmSystemTools::FileIsFullPath(dir)) {
  145. dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
  146. }
  147. auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
  148. for (auto const& priorDir : result) {
  149. auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir);
  150. if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) &&
  151. (cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) ||
  152. cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) {
  153. lg->GetCMakeInstance()->IssueMessage(
  154. MessageType::FATAL_ERROR,
  155. cmStrCat(
  156. "Base directories in file set cannot be subdirectories of each "
  157. "other:\n ",
  158. priorDir, "\n ", dir),
  159. cge->GetBacktrace());
  160. return {};
  161. }
  162. }
  163. result.push_back(dir);
  164. }
  165. }
  166. return result;
  167. }
  168. void cmFileSet::EvaluateFileEntry(
  169. const std::vector<std::string>& dirs,
  170. std::map<std::string, std::vector<std::string>>& filesPerDir,
  171. const std::unique_ptr<cmCompiledGeneratorExpression>& cge,
  172. cmLocalGenerator* lg, const std::string& config,
  173. const cmGeneratorTarget* target,
  174. cmGeneratorExpressionDAGChecker* dagChecker) const
  175. {
  176. auto files = cge->Evaluate(lg, config, target, dagChecker);
  177. for (std::string file : cmList{ files }) {
  178. if (!cmSystemTools::FileIsFullPath(file)) {
  179. file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file);
  180. }
  181. auto collapsedFile = cmSystemTools::CollapseFullPath(file);
  182. bool found = false;
  183. std::string relDir;
  184. for (auto const& dir : dirs) {
  185. auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
  186. if (cmSystemTools::IsSubDirectory(collapsedFile, collapsedDir)) {
  187. found = true;
  188. relDir = cmSystemTools::GetParentDirectory(
  189. cmSystemTools::RelativePath(collapsedDir, collapsedFile));
  190. break;
  191. }
  192. }
  193. if (!found) {
  194. std::ostringstream e;
  195. e << "File:\n " << file
  196. << "\nmust be in one of the file set's base directories:";
  197. for (auto const& dir : dirs) {
  198. e << "\n " << dir;
  199. }
  200. lg->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
  201. cge->GetBacktrace());
  202. return;
  203. }
  204. filesPerDir[relDir].push_back(file);
  205. }
  206. }
  207. bool cmFileSet::IsValidName(const std::string& name)
  208. {
  209. static const cmsys::RegularExpression regex("^[a-z0-9][a-zA-Z0-9_]*$");
  210. cmsys::RegularExpressionMatch match;
  211. return regex.find(name.c_str(), match);
  212. }