CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmFileSet.cxx
bloba00c10e6fd17732a901e3eb93465a2cd59c8d80f
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"
5 #include <sstream>
6 #include <string>
7 #include <unordered_map>
8 #include <utility>
9 #include <vector>
11 #include <cm/optional>
12 #include <cmext/algorithm>
13 #include <cmext/string_view>
15 #include "cmsys/RegularExpression.hxx"
17 #include "cmGeneratorExpression.h"
18 #include "cmList.h"
19 #include "cmListFileCache.h"
20 #include "cmLocalGenerator.h"
21 #include "cmMakefile.h"
22 #include "cmMessageType.h"
23 #include "cmStringAlgorithms.h"
24 #include "cmSystemTools.h"
25 #include "cmake.h"
27 cm::static_string_view cmFileSetVisibilityToName(cmFileSetVisibility vis)
29 switch (vis) {
30 case cmFileSetVisibility::Interface:
31 return "INTERFACE"_s;
32 case cmFileSetVisibility::Public:
33 return "PUBLIC"_s;
34 case cmFileSetVisibility::Private:
35 return "PRIVATE"_s;
37 return ""_s;
40 cmFileSetVisibility cmFileSetVisibilityFromName(cm::string_view name,
41 cmMakefile* mf)
43 if (name == "INTERFACE"_s) {
44 return cmFileSetVisibility::Interface;
46 if (name == "PUBLIC"_s) {
47 return cmFileSetVisibility::Public;
49 if (name == "PRIVATE"_s) {
50 return cmFileSetVisibility::Private;
52 auto msg = cmStrCat("File set visibility \"", name, "\" is not valid.");
53 if (mf) {
54 mf->IssueMessage(MessageType::FATAL_ERROR, msg);
55 } else {
56 cmSystemTools::Error(msg);
58 return cmFileSetVisibility::Private;
61 bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis)
63 switch (vis) {
64 case cmFileSetVisibility::Interface:
65 return false;
66 case cmFileSetVisibility::Public:
67 case cmFileSetVisibility::Private:
68 return true;
70 return false;
73 bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis)
75 switch (vis) {
76 case cmFileSetVisibility::Interface:
77 case cmFileSetVisibility::Public:
78 return true;
79 case cmFileSetVisibility::Private:
80 return false;
82 return false;
85 bool cmFileSetTypeCanBeIncluded(std::string const& type)
87 return type == "HEADERS"_s;
90 cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
91 cmFileSetVisibility visibility)
92 : CMakeInstance(cmakeInstance)
93 , Name(std::move(name))
94 , Type(std::move(type))
95 , Visibility(visibility)
99 void cmFileSet::CopyEntries(cmFileSet const* fs)
101 cm::append(this->DirectoryEntries, fs->DirectoryEntries);
102 cm::append(this->FileEntries, fs->FileEntries);
105 void cmFileSet::ClearDirectoryEntries()
107 this->DirectoryEntries.clear();
110 void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
112 this->DirectoryEntries.push_back(std::move(directories));
115 void cmFileSet::ClearFileEntries()
117 this->FileEntries.clear();
120 void cmFileSet::AddFileEntry(BT<std::string> files)
122 this->FileEntries.push_back(std::move(files));
125 std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
126 cmFileSet::CompileFileEntries() const
128 std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
130 for (auto const& entry : this->FileEntries) {
131 for (auto const& ex : cmList{ entry.Value }) {
132 cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
133 auto cge = ge.Parse(ex);
134 result.push_back(std::move(cge));
138 return result;
141 std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
142 cmFileSet::CompileDirectoryEntries() const
144 std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
146 for (auto const& entry : this->DirectoryEntries) {
147 for (auto const& ex : cmList{ entry.Value }) {
148 cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
149 auto cge = ge.Parse(ex);
150 result.push_back(std::move(cge));
154 return result;
157 std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
158 const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges,
159 cmLocalGenerator* lg, const std::string& config,
160 const cmGeneratorTarget* target,
161 cmGeneratorExpressionDAGChecker* dagChecker) const
163 struct DirCacheEntry
165 std::string collapsedDir;
166 cm::optional<cmSystemTools::FileId> fileId;
169 std::unordered_map<std::string, DirCacheEntry> dirCache;
170 std::vector<std::string> result;
171 for (auto const& cge : cges) {
172 auto entry = cge->Evaluate(lg, config, target, dagChecker);
173 cmList dirs{ entry };
174 for (std::string dir : dirs) {
175 if (!cmSystemTools::FileIsFullPath(dir)) {
176 dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
179 auto dirCacheResult = dirCache.emplace(dir, DirCacheEntry());
180 auto& dirCacheEntry = dirCacheResult.first->second;
181 const auto isNewCacheEntry = dirCacheResult.second;
183 if (isNewCacheEntry) {
184 cmSystemTools::FileId fileId;
185 auto isFileIdValid = cmSystemTools::GetFileId(dir, fileId);
186 dirCacheEntry.collapsedDir = cmSystemTools::CollapseFullPath(dir);
187 dirCacheEntry.fileId =
188 isFileIdValid ? cm::optional<decltype(fileId)>(fileId) : cm::nullopt;
191 for (auto const& priorDir : result) {
192 auto priorDirCacheEntry = dirCache.at(priorDir);
193 bool sameFile = dirCacheEntry.fileId.has_value() &&
194 priorDirCacheEntry.fileId.has_value() &&
195 (*dirCacheEntry.fileId == *priorDirCacheEntry.fileId);
196 if (!sameFile &&
197 (cmSystemTools::IsSubDirectory(dirCacheEntry.collapsedDir,
198 priorDirCacheEntry.collapsedDir) ||
199 cmSystemTools::IsSubDirectory(priorDirCacheEntry.collapsedDir,
200 dirCacheEntry.collapsedDir))) {
201 lg->GetCMakeInstance()->IssueMessage(
202 MessageType::FATAL_ERROR,
203 cmStrCat(
204 "Base directories in file set cannot be subdirectories of each "
205 "other:\n ",
206 priorDir, "\n ", dir),
207 cge->GetBacktrace());
208 return {};
211 result.push_back(dir);
214 return result;
217 void cmFileSet::EvaluateFileEntry(
218 const std::vector<std::string>& dirs,
219 std::map<std::string, std::vector<std::string>>& filesPerDir,
220 const std::unique_ptr<cmCompiledGeneratorExpression>& cge,
221 cmLocalGenerator* lg, const std::string& config,
222 const cmGeneratorTarget* target,
223 cmGeneratorExpressionDAGChecker* dagChecker) const
225 auto files = cge->Evaluate(lg, config, target, dagChecker);
226 for (std::string file : cmList{ files }) {
227 if (!cmSystemTools::FileIsFullPath(file)) {
228 file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file);
230 auto collapsedFile = cmSystemTools::CollapseFullPath(file);
231 bool found = false;
232 std::string relDir;
233 for (auto const& dir : dirs) {
234 auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
235 if (cmSystemTools::IsSubDirectory(collapsedFile, collapsedDir)) {
236 found = true;
237 relDir = cmSystemTools::GetParentDirectory(
238 cmSystemTools::RelativePath(collapsedDir, collapsedFile));
239 break;
242 if (!found) {
243 std::ostringstream e;
244 e << "File:\n " << file
245 << "\nmust be in one of the file set's base directories:";
246 for (auto const& dir : dirs) {
247 e << "\n " << dir;
249 lg->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
250 cge->GetBacktrace());
251 return;
254 filesPerDir[relDir].push_back(file);
258 bool cmFileSet::IsValidName(const std::string& name)
260 static const cmsys::RegularExpression regex("^[a-z0-9][a-zA-Z0-9_]*$");
262 cmsys::RegularExpressionMatch match;
263 return regex.find(name.c_str(), match);