cmFileSet.cxx 7.6 KB

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