1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
7 #include <unordered_map>
11 #include <cm/optional>
12 #include <cmext/algorithm>
13 #include <cmext/string_view>
15 #include "cmsys/RegularExpression.hxx"
17 #include "cmGeneratorExpression.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"
27 cm::static_string_view
cmFileSetVisibilityToName(cmFileSetVisibility vis
)
30 case cmFileSetVisibility::Interface
:
32 case cmFileSetVisibility::Public
:
34 case cmFileSetVisibility::Private
:
40 cmFileSetVisibility
cmFileSetVisibilityFromName(cm::string_view name
,
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.");
54 mf
->IssueMessage(MessageType::FATAL_ERROR
, msg
);
56 cmSystemTools::Error(msg
);
58 return cmFileSetVisibility::Private
;
61 bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis
)
64 case cmFileSetVisibility::Interface
:
66 case cmFileSetVisibility::Public
:
67 case cmFileSetVisibility::Private
:
73 bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis
)
76 case cmFileSetVisibility::Interface
:
77 case cmFileSetVisibility::Public
:
79 case cmFileSetVisibility::Private
:
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
));
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
));
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
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
);
197 (cmSystemTools::IsSubDirectory(dirCacheEntry
.collapsedDir
,
198 priorDirCacheEntry
.collapsedDir
) ||
199 cmSystemTools::IsSubDirectory(priorDirCacheEntry
.collapsedDir
,
200 dirCacheEntry
.collapsedDir
))) {
201 lg
->GetCMakeInstance()->IssueMessage(
202 MessageType::FATAL_ERROR
,
204 "Base directories in file set cannot be subdirectories of each "
206 priorDir
, "\n ", dir
),
207 cge
->GetBacktrace());
211 result
.push_back(dir
);
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
);
233 for (auto const& dir
: dirs
) {
234 auto collapsedDir
= cmSystemTools::CollapseFullPath(dir
);
235 if (cmSystemTools::IsSubDirectory(collapsedFile
, collapsedDir
)) {
237 relDir
= cmSystemTools::GetParentDirectory(
238 cmSystemTools::RelativePath(collapsedDir
, collapsedFile
));
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
) {
249 lg
->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR
, e
.str(),
250 cge
->GetBacktrace());
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
);