/src/CMake/Source/cmMakefile.cxx
Line | Count | Source |
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 "cmConfigure.h" // IWYU pragma: keep |
4 | | |
5 | | #include "cmMakefile.h" |
6 | | |
7 | | #include <algorithm> |
8 | | #include <array> |
9 | | #include <cassert> |
10 | | #include <cstdio> |
11 | | #include <cstdlib> |
12 | | #include <cstring> |
13 | | #include <sstream> |
14 | | #include <utility> |
15 | | |
16 | | #include <cm/iterator> |
17 | | #include <cm/memory> |
18 | | #include <cm/optional> |
19 | | #include <cm/type_traits> // IWYU pragma: keep |
20 | | #include <cm/vector> |
21 | | #include <cmext/algorithm> |
22 | | #include <cmext/string_view> |
23 | | |
24 | | #ifndef CMAKE_BOOTSTRAP |
25 | | # include <cm3p/json/value.h> |
26 | | # include <cm3p/json/writer.h> |
27 | | #endif |
28 | | |
29 | | #include "cmsys/FStream.hxx" |
30 | | #include "cmsys/RegularExpression.hxx" |
31 | | #include "cmsys/String.h" |
32 | | |
33 | | #ifndef CMAKE_BOOTSTRAP |
34 | | # include "cmBuildSbomGenerator.h" |
35 | | #endif |
36 | | #include "cmCustomCommand.h" |
37 | | #include "cmCustomCommandLines.h" |
38 | | #include "cmCustomCommandTypes.h" |
39 | | #include "cmExecutionStatus.h" |
40 | | #include "cmExpandedCommandArgument.h" // IWYU pragma: keep |
41 | | #include "cmExportBuildFileGenerator.h" |
42 | | #include "cmFileLockPool.h" |
43 | | #include "cmFunctionBlocker.h" |
44 | | #include "cmGeneratedFileStream.h" |
45 | | #include "cmGeneratorExpression.h" |
46 | | #include "cmGeneratorExpressionEvaluationFile.h" |
47 | | #include "cmGlobalGenerator.h" |
48 | | #include "cmInstallGenerator.h" // IWYU pragma: keep |
49 | | #include "cmInstallSubdirectoryGenerator.h" |
50 | | #include "cmList.h" |
51 | | #include "cmListFileCache.h" |
52 | | #include "cmLocalGenerator.h" |
53 | | #include "cmMessageType.h" |
54 | | #include "cmRange.h" |
55 | | #include "cmRule.h" |
56 | | #include "cmSourceFile.h" |
57 | | #include "cmSourceFileLocation.h" |
58 | | #include "cmSourceGroup.h" |
59 | | #include "cmState.h" |
60 | | #include "cmStateDirectory.h" |
61 | | #include "cmStateTypes.h" |
62 | | #include "cmStringAlgorithms.h" |
63 | | #include "cmSystemTools.h" |
64 | | #include "cmTarget.h" |
65 | | #include "cmTargetLinkLibraryType.h" |
66 | | #include "cmTest.h" |
67 | | #include "cmTestGenerator.h" // IWYU pragma: keep |
68 | | #include "cmVersion.h" |
69 | | #include "cmWorkingDirectory.h" |
70 | | #include "cmake.h" |
71 | | |
72 | | #ifndef CMAKE_BOOTSTRAP |
73 | | # include "cmMakefileProfilingData.h" |
74 | | # include "cmVariableWatch.h" |
75 | | #endif |
76 | | |
77 | | #ifdef CMake_ENABLE_DEBUGGER |
78 | | # include "cmDebuggerAdapter.h" |
79 | | #endif |
80 | | |
81 | | #ifndef __has_feature |
82 | | # define __has_feature(x) 0 |
83 | | #endif |
84 | | |
85 | | // Select a recursion limit that fits within the stack size. |
86 | | // See stack size flags in '../CompileFlags.cmake'. |
87 | | #ifndef CMake_DEFAULT_RECURSION_LIMIT |
88 | | # if __has_feature(address_sanitizer) |
89 | | # define CMake_DEFAULT_RECURSION_LIMIT 400 |
90 | | # elif defined(_MSC_VER) && defined(_DEBUG) |
91 | | # define CMake_DEFAULT_RECURSION_LIMIT 600 |
92 | | # elif defined(__ibmxl__) && defined(__linux) |
93 | | # define CMake_DEFAULT_RECURSION_LIMIT 600 |
94 | | # else |
95 | 403k | # define CMake_DEFAULT_RECURSION_LIMIT 1000 |
96 | | # endif |
97 | | #endif |
98 | | |
99 | | namespace { |
100 | | std::string const kCMAKE_CURRENT_LIST_DIR = "CMAKE_CURRENT_LIST_DIR"; |
101 | | std::string const kCMAKE_CURRENT_LIST_FILE = "CMAKE_CURRENT_LIST_FILE"; |
102 | | std::string const kCMAKE_PARENT_LIST_FILE = "CMAKE_PARENT_LIST_FILE"; |
103 | | |
104 | | std::string findClosestCommand(std::string const& name, |
105 | | std::vector<std::string> const& commands) |
106 | 0 | { |
107 | 0 | return cmFindClosestString(name, commands); |
108 | 0 | } |
109 | | |
110 | | class FileScopeBase |
111 | | { |
112 | | protected: |
113 | | cmMakefile* Makefile; |
114 | | |
115 | | private: |
116 | | std::string OldCurrent; |
117 | | cm::optional<std::string> OldParent; |
118 | | |
119 | | public: |
120 | | FileScopeBase(cmMakefile* mf) |
121 | 11.8k | : Makefile(mf) |
122 | 11.8k | { |
123 | 11.8k | #if !defined(CMAKE_BOOTSTRAP) |
124 | 11.8k | this->Makefile->GetGlobalGenerator()->GetFileLockPool().PushFileScope(); |
125 | 11.8k | #endif |
126 | 11.8k | } |
127 | | ~FileScopeBase() |
128 | 11.8k | { |
129 | 11.8k | #if !defined(CMAKE_BOOTSTRAP) |
130 | 11.8k | this->Makefile->GetGlobalGenerator()->GetFileLockPool().PopFileScope(); |
131 | 11.8k | #endif |
132 | 11.8k | } |
133 | | void PushListFileVars(std::string const& newCurrent) |
134 | 11.8k | { |
135 | 11.8k | if (cmValue p = this->Makefile->GetDefinition(kCMAKE_PARENT_LIST_FILE)) { |
136 | 0 | this->OldParent = *p; |
137 | 0 | } |
138 | 11.8k | if (cmValue c = this->Makefile->GetDefinition(kCMAKE_CURRENT_LIST_FILE)) { |
139 | 5.92k | this->OldCurrent = *c; |
140 | 5.92k | this->Makefile->AddDefinition(kCMAKE_PARENT_LIST_FILE, this->OldCurrent); |
141 | 5.92k | this->Makefile->MarkVariableAsUsed(kCMAKE_PARENT_LIST_FILE); |
142 | 5.92k | } |
143 | 11.8k | this->Makefile->AddDefinition(kCMAKE_CURRENT_LIST_FILE, newCurrent); |
144 | 11.8k | this->Makefile->AddDefinition(kCMAKE_CURRENT_LIST_DIR, |
145 | 11.8k | cmSystemTools::GetFilenamePath(newCurrent)); |
146 | 11.8k | this->Makefile->MarkVariableAsUsed(kCMAKE_CURRENT_LIST_FILE); |
147 | 11.8k | this->Makefile->MarkVariableAsUsed(kCMAKE_CURRENT_LIST_DIR); |
148 | 11.8k | } |
149 | | void PopListFileVars() |
150 | 11.8k | { |
151 | 11.8k | if (this->OldParent) { |
152 | 0 | this->Makefile->AddDefinition(kCMAKE_PARENT_LIST_FILE, *this->OldParent); |
153 | 0 | this->Makefile->MarkVariableAsUsed(kCMAKE_PARENT_LIST_FILE); |
154 | 11.8k | } else { |
155 | 11.8k | this->Makefile->RemoveDefinition(kCMAKE_PARENT_LIST_FILE); |
156 | 11.8k | } |
157 | 11.8k | this->Makefile->AddDefinition(kCMAKE_CURRENT_LIST_FILE, this->OldCurrent); |
158 | 11.8k | this->Makefile->AddDefinition( |
159 | 11.8k | kCMAKE_CURRENT_LIST_DIR, |
160 | 11.8k | cmSystemTools::GetFilenamePath(this->OldCurrent)); |
161 | 11.8k | this->Makefile->MarkVariableAsUsed(kCMAKE_CURRENT_LIST_FILE); |
162 | 11.8k | this->Makefile->MarkVariableAsUsed(kCMAKE_CURRENT_LIST_DIR); |
163 | 11.8k | } |
164 | | }; |
165 | | } |
166 | | |
167 | | class cmMessenger; |
168 | | |
169 | | cmDirectoryId::cmDirectoryId(std::string s) |
170 | 6.82k | : String(std::move(s)) |
171 | 6.82k | { |
172 | 6.82k | } |
173 | | |
174 | | // default is not to be building executables |
175 | | cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, |
176 | | cmStateSnapshot const& snapshot) |
177 | 19.8k | : GlobalGenerator(globalGenerator) |
178 | 19.8k | , StateSnapshot(snapshot) |
179 | 19.8k | { |
180 | 19.8k | this->IsSourceFileTryCompile = false; |
181 | | |
182 | 19.8k | this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); |
183 | | |
184 | | // Setup the default include complaint regular expression (match nothing). |
185 | 19.8k | this->ComplainFileRegularExpression = "^$"; |
186 | | |
187 | 19.8k | this->DefineFlags = " "; |
188 | | |
189 | 19.8k | this->cmDefineRegex.compile("#([ \t]*)cmakedefine[ \t]+([A-Za-z_0-9]*)"); |
190 | 19.8k | this->cmDefine01Regex.compile("#([ \t]*)cmakedefine01[ \t]+([A-Za-z_0-9]*)"); |
191 | 19.8k | this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{"); |
192 | | |
193 | 19.8k | this->StateSnapshot = |
194 | 19.8k | this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot( |
195 | 19.8k | this->StateSnapshot); |
196 | | |
197 | | // Enter a policy and diagnostic level for this directory. |
198 | 19.8k | this->PushPolicy(); |
199 | 19.8k | this->PushDiagnostic(); |
200 | | |
201 | | // push empty loop block |
202 | 19.8k | this->PushLoopBlockBarrier(); |
203 | | |
204 | | // By default the check is not done. It is enabled by |
205 | | // cmMakefile::Configure in the top level if necessary. |
206 | 19.8k | this->CheckCMP0000 = false; |
207 | | |
208 | 19.8k | #if !defined(CMAKE_BOOTSTRAP) |
209 | 19.8k | this->AddSourceGroup("", "^.*$"); |
210 | 19.8k | this->AddSourceGroup("Source Files", CM_SOURCE_REGEX); |
211 | 19.8k | this->AddSourceGroup("Header Files", CM_HEADER_REGEX); |
212 | 19.8k | this->AddSourceGroup("Precompile Header File", CM_PCH_REGEX); |
213 | 19.8k | this->AddSourceGroup("CMake Rules", "\\.rule$"); |
214 | 19.8k | this->AddSourceGroup("Resources", CM_RESOURCE_REGEX); |
215 | 19.8k | this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$"); |
216 | | |
217 | 19.8k | this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size(); |
218 | 19.8k | this->SourceGroups.emplace_back( |
219 | 19.8k | cm::make_unique<cmSourceGroup>("Object Libraries", "^MATCH_NO_SOURCES$")); |
220 | 19.8k | #endif |
221 | 19.8k | } |
222 | | |
223 | 19.8k | cmMakefile::~cmMakefile() = default; |
224 | | |
225 | | cmDirectoryId cmMakefile::GetDirectoryId() const |
226 | 5.92k | { |
227 | | // Use the instance pointer value to uniquely identify this directory. |
228 | | // If we ever need to expose this to CMake language code we should |
229 | | // add a read-only property in cmMakefile::GetProperty. |
230 | 5.92k | char buf[32]; |
231 | 5.92k | snprintf(buf, sizeof(buf), "(%p)", |
232 | 5.92k | static_cast<void const*>(this)); // cast avoids format warning |
233 | 5.92k | return std::string(buf); |
234 | 5.92k | } |
235 | | |
236 | | void cmMakefile::IssueMessage(MessageType t, std::string const& text, |
237 | | cmListFileBacktrace const& bt) const |
238 | 24.2k | { |
239 | 24.2k | if (!this->ExecutionStatusStack.empty()) { |
240 | 0 | if ((t == MessageType::FATAL_ERROR) || |
241 | 0 | (t == MessageType::INTERNAL_ERROR)) { |
242 | 0 | this->ExecutionStatusStack.back()->SetNestedError(); |
243 | 0 | } |
244 | 0 | } |
245 | 24.2k | this->GetCMakeInstance()->IssueMessage(t, text, bt); |
246 | 24.2k | } |
247 | | |
248 | | void cmMakefile::IssueDiagnostic(cmDiagnosticCategory category, |
249 | | std::string const& text, |
250 | | cmDiagnosticContext const& context) const |
251 | 0 | { |
252 | 0 | if (!this->ExecutionStatusStack.empty()) { |
253 | 0 | cmDiagnosticAction const action = this->GetDiagnosticAction(category); |
254 | 0 | if (action >= cmDiagnosticAction::SendError) { |
255 | 0 | this->ExecutionStatusStack.back()->SetNestedError(); |
256 | 0 | } |
257 | 0 | } |
258 | 0 | this->GetCMakeInstance()->IssueDiagnostic(category, text, |
259 | 0 | this->GetStateSnapshot(), context); |
260 | 0 | } |
261 | | |
262 | | void cmMakefile::IssuePolicyWarning(cmPolicies::PolicyID policy, |
263 | | cm::string_view preface, |
264 | | cm::string_view postface, |
265 | | cmListFileBacktrace const& bt) const |
266 | 0 | { |
267 | 0 | std::string msg = cmPolicies::GetPolicyWarning(policy); |
268 | 0 | if (!preface.empty() && !postface.empty()) { |
269 | 0 | msg = cmStrCat(preface, '\n', std::move(msg), '\n', postface); |
270 | 0 | } else if (!preface.empty()) { |
271 | 0 | msg = cmStrCat(preface, '\n', std::move(msg)); |
272 | 0 | } else if (!postface.empty()) { |
273 | 0 | msg = cmStrCat(std::move(msg), '\n', postface); |
274 | 0 | } |
275 | 0 | this->IssueDiagnostic(cmDiagnostics::CMD_POLICY, msg, |
276 | 0 | cmDiagnosticContext{ bt }); |
277 | 0 | } |
278 | | |
279 | | Message::LogLevel cmMakefile::GetCurrentLogLevel() const |
280 | 0 | { |
281 | 0 | cmake const* cmakeInstance = this->GetCMakeInstance(); |
282 | |
|
283 | 0 | Message::LogLevel const logLevelCliOrDefault = cmakeInstance->GetLogLevel(); |
284 | 0 | assert("Expected a valid log level here" && |
285 | 0 | logLevelCliOrDefault != Message::LogLevel::LOG_UNDEFINED); |
286 | |
|
287 | 0 | Message::LogLevel result = logLevelCliOrDefault; |
288 | | |
289 | | // If the log-level was set via the command line option, it takes precedence |
290 | | // over the CMAKE_MESSAGE_LOG_LEVEL variable. |
291 | 0 | if (!cmakeInstance->WasLogLevelSetViaCLI()) { |
292 | 0 | Message::LogLevel const logLevelFromVar = cmake::StringToLogLevel( |
293 | 0 | this->GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL")); |
294 | 0 | if (logLevelFromVar != Message::LogLevel::LOG_UNDEFINED) { |
295 | 0 | result = logLevelFromVar; |
296 | 0 | } |
297 | 0 | } |
298 | |
|
299 | 0 | return result; |
300 | 0 | } |
301 | | |
302 | | void cmMakefile::IssueInvalidTargetNameError( |
303 | | std::string const& targetName) const |
304 | 0 | { |
305 | 0 | this->IssueMessage( |
306 | 0 | MessageType::FATAL_ERROR, |
307 | 0 | cmStrCat("The target name \"", targetName, |
308 | 0 | "\" is reserved or not valid for certain " |
309 | 0 | "CMake features, such as generator expressions, and may result " |
310 | 0 | "in undefined behavior.")); |
311 | 0 | } |
312 | | |
313 | | void cmMakefile::MaybeWarnCMP0074(std::string const& rootVar, cmValue rootDef, |
314 | | cm::optional<std::string> const& rootEnv) |
315 | 0 | { |
316 | | // Warn if a <PackageName>_ROOT variable we may use is set. |
317 | 0 | if ((rootDef || rootEnv) && this->WarnedCMP0074.insert(rootVar).second) { |
318 | 0 | std::string e; |
319 | 0 | if (rootDef) { |
320 | 0 | e = cmStrCat(std::move(e), "CMake variable ", rootVar, " is set to:\n ", |
321 | 0 | *rootDef, '\n'); |
322 | 0 | } |
323 | 0 | if (rootEnv) { |
324 | 0 | e = cmStrCat(std::move(e), "Environment variable ", rootVar, |
325 | 0 | " is set to:\n ", *rootEnv, '\n'); |
326 | 0 | } |
327 | 0 | e += "For compatibility, CMake is ignoring the variable."; |
328 | 0 | this->IssuePolicyWarning(cmPolicies::CMP0074, {}, e); |
329 | 0 | } |
330 | 0 | } |
331 | | |
332 | | void cmMakefile::MaybeWarnCMP0144(std::string const& rootVar, cmValue rootDef, |
333 | | cm::optional<std::string> const& rootEnv) |
334 | 0 | { |
335 | | // Warn if a <PACKAGENAME>_ROOT variable we may use is set. |
336 | 0 | if ((rootDef || rootEnv) && this->WarnedCMP0144.insert(rootVar).second) { |
337 | 0 | std::string e; |
338 | 0 | if (rootDef) { |
339 | 0 | e = cmStrCat(std::move(e), "CMake variable ", rootVar, " is set to:\n ", |
340 | 0 | *rootDef, '\n'); |
341 | 0 | } |
342 | 0 | if (rootEnv) { |
343 | 0 | e = cmStrCat(std::move(e), "Environment variable ", rootVar, |
344 | 0 | " is set to:\n ", *rootEnv, '\n'); |
345 | 0 | } |
346 | 0 | e += "For compatibility, find_package is ignoring the variable, but " |
347 | 0 | "code in a .cmake module might still use it."; |
348 | 0 | this->IssuePolicyWarning(cmPolicies::CMP0144, {}, e); |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | cmBTStringRange cmMakefile::GetIncludeDirectoriesEntries() const |
353 | 35.5k | { |
354 | 35.5k | return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries(); |
355 | 35.5k | } |
356 | | |
357 | | cmBTStringRange cmMakefile::GetCompileOptionsEntries() const |
358 | 35.5k | { |
359 | 35.5k | return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries(); |
360 | 35.5k | } |
361 | | |
362 | | cmBTStringRange cmMakefile::GetCompileDefinitionsEntries() const |
363 | 0 | { |
364 | 0 | return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries(); |
365 | 0 | } |
366 | | |
367 | | cmBTStringRange cmMakefile::GetLinkOptionsEntries() const |
368 | 35.5k | { |
369 | 35.5k | return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries(); |
370 | 35.5k | } |
371 | | |
372 | | cmBTStringRange cmMakefile::GetLinkDirectoriesEntries() const |
373 | 35.5k | { |
374 | 35.5k | return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries(); |
375 | 35.5k | } |
376 | | |
377 | | cmListFileBacktrace cmMakefile::GetBacktrace() const |
378 | 835k | { |
379 | 835k | return this->Backtrace; |
380 | 835k | } |
381 | | |
382 | | cmFindPackageStack cmMakefile::GetFindPackageStack() const |
383 | 49.3k | { |
384 | 49.3k | return this->FindPackageStack; |
385 | 49.3k | } |
386 | | |
387 | | void cmMakefile::PrintCommandTrace(cmListFileFunction const& lff, |
388 | | cmListFileBacktrace const& bt, |
389 | | CommandMissingFromStack missing) const |
390 | 0 | { |
391 | | // Check if current file in the list of requested to trace... |
392 | 0 | std::vector<std::string> const& trace_only_this_files = |
393 | 0 | this->GetCMakeInstance()->GetTraceSources(); |
394 | 0 | std::string const& full_path = bt.Top().FilePath; |
395 | 0 | cm::string_view only_filename = |
396 | 0 | cmSystemTools::GetFilenameNameView(full_path); |
397 | 0 | bool trace = trace_only_this_files.empty(); |
398 | 0 | if (!trace) { |
399 | 0 | for (std::string const& file : trace_only_this_files) { |
400 | 0 | std::string::size_type const pos = full_path.rfind(file); |
401 | 0 | trace = (pos != std::string::npos) && |
402 | 0 | ((pos + file.size()) == full_path.size()) && |
403 | 0 | (only_filename == cmSystemTools::GetFilenameNameView(file)); |
404 | 0 | if (trace) { |
405 | 0 | break; |
406 | 0 | } |
407 | 0 | } |
408 | | // Do nothing if current file wasn't requested for trace... |
409 | 0 | if (!trace) { |
410 | 0 | return; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | 0 | std::vector<std::string> args; |
415 | 0 | std::string temp; |
416 | 0 | bool expand = this->GetCMakeInstance()->GetTraceExpand(); |
417 | |
|
418 | 0 | args.reserve(lff.Arguments().size()); |
419 | 0 | for (cmListFileArgument const& arg : lff.Arguments()) { |
420 | 0 | if (expand && arg.Delim != cmListFileArgument::Bracket) { |
421 | 0 | temp = arg.Value; |
422 | 0 | this->ExpandVariablesInString(temp); |
423 | 0 | args.push_back(temp); |
424 | 0 | } else { |
425 | 0 | args.push_back(arg.Value); |
426 | 0 | } |
427 | 0 | } |
428 | 0 | cm::optional<std::string> const& deferId = bt.Top().DeferId; |
429 | |
|
430 | 0 | std::ostringstream msg; |
431 | 0 | switch (this->GetCMakeInstance()->GetTraceFormat()) { |
432 | 0 | case cmake::TraceFormat::JSONv1: { |
433 | 0 | #ifndef CMAKE_BOOTSTRAP |
434 | 0 | Json::Value val; |
435 | 0 | Json::StreamWriterBuilder builder; |
436 | 0 | builder["indentation"] = ""; |
437 | 0 | val["file"] = full_path; |
438 | 0 | val["line"] = static_cast<Json::Value::Int64>(lff.Line()); |
439 | 0 | if (lff.Line() != lff.LineEnd()) { |
440 | 0 | val["line_end"] = static_cast<Json::Value::Int64>(lff.LineEnd()); |
441 | 0 | } |
442 | 0 | if (deferId) { |
443 | 0 | val["defer"] = *deferId; |
444 | 0 | } |
445 | 0 | val["cmd"] = lff.OriginalName(); |
446 | 0 | val["args"] = Json::Value(Json::arrayValue); |
447 | 0 | for (std::string const& arg : args) { |
448 | 0 | val["args"].append(arg); |
449 | 0 | } |
450 | 0 | val["time"] = cmSystemTools::GetTime(); |
451 | 0 | val["frame"] = int(missing == CommandMissingFromStack::Yes) + |
452 | 0 | static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size()); |
453 | 0 | val["global_frame"] = int(missing == CommandMissingFromStack::Yes) + |
454 | 0 | static_cast<Json::Value::UInt64>(this->RecursionDepth); |
455 | 0 | msg << Json::writeString(builder, val); |
456 | 0 | #endif |
457 | 0 | break; |
458 | 0 | } |
459 | 0 | case cmake::TraceFormat::Human: |
460 | 0 | msg << full_path << '(' << lff.Line() << "):"; |
461 | 0 | if (deferId) { |
462 | 0 | msg << "DEFERRED:" << *deferId << ':'; |
463 | 0 | } |
464 | 0 | msg << " " << lff.OriginalName() << '('; |
465 | |
|
466 | 0 | for (std::string const& arg : args) { |
467 | 0 | msg << arg << ' '; |
468 | 0 | } |
469 | 0 | msg << ')'; |
470 | 0 | break; |
471 | 0 | case cmake::TraceFormat::Undefined: |
472 | 0 | msg << "INTERNAL ERROR: Trace format is Undefined"; |
473 | 0 | break; |
474 | 0 | } |
475 | | |
476 | 0 | auto& f = this->GetCMakeInstance()->GetTraceFile(); |
477 | 0 | if (f) { |
478 | 0 | f << msg.str() << '\n'; |
479 | 0 | } else { |
480 | 0 | cmSystemTools::Message(msg.str()); |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | | cmMakefile::CallRAII::CallRAII(cmMakefile* mf, std::string const& file, |
485 | | cmExecutionStatus& status) |
486 | 0 | : CallRAII(mf, cmListFileContext::FromListFilePath(file), status) |
487 | 0 | { |
488 | 0 | } |
489 | | |
490 | | cmMakefile::CallRAII::CallRAII(cmMakefile* mf, cmListFileContext const& lfc, |
491 | | cmExecutionStatus& status) |
492 | 403k | : Makefile{ mf } |
493 | 403k | { |
494 | 403k | this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); |
495 | 403k | ++this->Makefile->RecursionDepth; |
496 | 403k | this->Makefile->ExecutionStatusStack.push_back(&status); |
497 | 403k | } |
498 | | |
499 | | cmMakefile::CallRAII::~CallRAII() |
500 | 403k | { |
501 | 403k | if (this->Makefile) { |
502 | 0 | this->Detach(); |
503 | 0 | } |
504 | 403k | } |
505 | | |
506 | | cmMakefile* cmMakefile::CallRAII::Detach() |
507 | 403k | { |
508 | 403k | assert(this->Makefile); |
509 | | |
510 | 403k | this->Makefile->ExecutionStatusStack.pop_back(); |
511 | 403k | --this->Makefile->RecursionDepth; |
512 | 403k | this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); |
513 | | |
514 | 403k | auto* const mf = this->Makefile; |
515 | 403k | this->Makefile = nullptr; |
516 | 403k | return mf; |
517 | 403k | } |
518 | | |
519 | | // Helper class to make sure the call stack is valid. |
520 | | class cmMakefile::CallScope : public CallRAII |
521 | | { |
522 | | public: |
523 | | CallScope(cmMakefile* mf, cmListFileFunction const& lff, |
524 | | cm::optional<std::string> deferId, cmExecutionStatus& status) |
525 | 403k | : CallScope{ mf, lff, |
526 | 403k | cmListFileContext::FromListFileFunction( |
527 | 403k | lff, mf->StateSnapshot.GetExecutionListFile(), |
528 | 403k | std::move(deferId)), |
529 | 403k | status } |
530 | 403k | { |
531 | 403k | } |
532 | | |
533 | | CallScope(cmMakefile* mf, cmListFileFunction const& lff, |
534 | | cmListFileContext const& lfc, cmExecutionStatus& status) |
535 | 403k | : CallRAII{ mf, lfc, status } |
536 | 403k | { |
537 | 403k | #if !defined(CMAKE_BOOTSTRAP) |
538 | 403k | this->ProfilingDataRAII = |
539 | 403k | this->Makefile->GetCMakeInstance()->CreateProfilingEntry( |
540 | 403k | "script", lff.LowerCaseName(), [&lff, &lfc]() -> Json::Value { |
541 | 0 | Json::Value argsValue = Json::objectValue; |
542 | 0 | if (!lff.Arguments().empty()) { |
543 | 0 | std::string args; |
544 | 0 | for (auto const& a : lff.Arguments()) { |
545 | 0 | args = cmStrCat(std::move(args), a.Value, ' '); |
546 | 0 | } |
547 | 0 | if (!args.empty()) { |
548 | 0 | args.pop_back(); |
549 | 0 | } |
550 | 0 | argsValue["functionArgs"] = args; |
551 | 0 | } |
552 | 0 | argsValue["location"] = cmStrCat(lfc.FilePath, ':', lfc.Line); |
553 | 0 | return argsValue; |
554 | 0 | }); |
555 | 403k | #endif |
556 | 403k | #ifdef CMake_ENABLE_DEBUGGER |
557 | 403k | if (this->Makefile->GetCMakeInstance()->GetDebugAdapter()) { |
558 | 0 | this->Makefile->GetCMakeInstance() |
559 | 0 | ->GetDebugAdapter() |
560 | 0 | ->OnBeginFunctionCall(mf, lfc.FilePath, lff); |
561 | 0 | } |
562 | 403k | #endif |
563 | 403k | } |
564 | | |
565 | | ~CallScope() |
566 | 403k | { |
567 | 403k | #if !defined(CMAKE_BOOTSTRAP) |
568 | 403k | this->ProfilingDataRAII.reset(); |
569 | 403k | #endif |
570 | 403k | auto* const mf = this->Detach(); |
571 | 403k | #ifdef CMake_ENABLE_DEBUGGER |
572 | 403k | if (mf->GetCMakeInstance()->GetDebugAdapter()) { |
573 | 0 | mf->GetCMakeInstance()->GetDebugAdapter()->OnEndFunctionCall(); |
574 | 0 | } |
575 | | #else |
576 | | static_cast<void>(mf); |
577 | | #endif |
578 | 403k | } |
579 | | |
580 | | CallScope(CallScope const&) = delete; |
581 | | CallScope& operator=(CallScope const&) = delete; |
582 | | |
583 | | private: |
584 | | #if !defined(CMAKE_BOOTSTRAP) |
585 | | cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII; |
586 | | #endif |
587 | | }; |
588 | | |
589 | | void cmMakefile::OnExecuteCommand(std::function<void()> callback) |
590 | 0 | { |
591 | 0 | this->ExecuteCommandCallback = std::move(callback); |
592 | 0 | } |
593 | | |
594 | | bool cmMakefile::ExecuteCommand(cmListFileFunction const& lff, |
595 | | cmExecutionStatus& status, |
596 | | cm::optional<std::string> deferId) |
597 | 450k | { |
598 | 450k | bool result = true; |
599 | | |
600 | | // quick return if blocked |
601 | 450k | if (this->IsFunctionBlocked(lff, status)) { |
602 | | // No error. |
603 | 47.4k | return result; |
604 | 47.4k | } |
605 | | |
606 | | // Place this call on the call stack. |
607 | 403k | CallScope stack_manager(this, lff, std::move(deferId), status); |
608 | 403k | static_cast<void>(stack_manager); |
609 | | |
610 | | // Check for maximum recursion depth. |
611 | 403k | size_t depthLimit = this->GetRecursionDepthLimit(); |
612 | 403k | if (this->RecursionDepth > depthLimit) { |
613 | 0 | this->IssueMessage( |
614 | 0 | MessageType::FATAL_ERROR, |
615 | 0 | cmStrCat("Maximum recursion depth of ", depthLimit, " exceeded")); |
616 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
617 | 0 | return false; |
618 | 0 | } |
619 | | |
620 | | // Lookup the command prototype. |
621 | 403k | if (cmState::Command command = |
622 | 403k | this->GetState()->GetCommandByExactName(lff.LowerCaseName())) { |
623 | | // Decide whether to invoke the command. |
624 | 403k | if (!cmSystemTools::GetFatalErrorOccurred()) { |
625 | | // if trace is enabled, print out invoke information |
626 | 403k | if (this->GetCMakeInstance()->GetTrace()) { |
627 | 0 | this->PrintCommandTrace(lff, this->Backtrace); |
628 | 0 | } |
629 | | // Try invoking the command. |
630 | 403k | bool invokeSucceeded = command(lff.Arguments(), status); |
631 | 403k | bool hadNestedError = status.GetNestedError(); |
632 | 403k | if (!invokeSucceeded || hadNestedError) { |
633 | 0 | if (!hadNestedError) { |
634 | | // The command invocation requested that we report an error. |
635 | 0 | std::string const error = |
636 | 0 | cmStrCat(lff.OriginalName(), ' ', status.GetError()); |
637 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, error); |
638 | 0 | } |
639 | 0 | result = false; |
640 | 0 | if (this->GetCMakeInstance()->GetCommandFailureAction() == |
641 | 0 | cmake::CommandFailureAction::FATAL_ERROR) { |
642 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
643 | 0 | } |
644 | 0 | } |
645 | 403k | if (this->GetCMakeInstance()->HasScriptModeExitCode() && |
646 | 0 | this->GetCMakeInstance()->RoleSupportsExitCode()) { |
647 | | // pass-through the exit code from inner cmake_language(EXIT) , |
648 | | // possibly from include() or similar command... |
649 | 0 | status.SetExitCode(this->GetCMakeInstance()->GetScriptModeExitCode()); |
650 | 0 | } |
651 | 403k | } |
652 | 403k | } else { |
653 | 0 | if (!cmSystemTools::GetFatalErrorOccurred()) { |
654 | 0 | std::string error = |
655 | 0 | cmStrCat("Unknown CMake command \"", lff.OriginalName(), "\"."); |
656 | 0 | std::string const suggestion = findClosestCommand( |
657 | 0 | lff.OriginalName(), this->GetState()->GetCommandNames()); |
658 | 0 | if (!suggestion.empty()) { |
659 | 0 | error = |
660 | 0 | cmStrCat(std::move(error), " Did you mean: \"", suggestion, "\"?"); |
661 | 0 | } |
662 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, error); |
663 | 0 | result = false; |
664 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
665 | 0 | } |
666 | 0 | } |
667 | | |
668 | 403k | if (this->ExecuteCommandCallback) { |
669 | 0 | this->ExecuteCommandCallback(); |
670 | 0 | } |
671 | | |
672 | 403k | return result; |
673 | 403k | } |
674 | | |
675 | | bool cmMakefile::IsImportedTargetGlobalScope() const |
676 | 11.8k | { |
677 | 11.8k | return this->CurrentImportedTargetScope == cm::ImportedTargetScope::Global; |
678 | 11.8k | } |
679 | | |
680 | | class cmMakefile::IncludeScope : public FileScopeBase |
681 | | { |
682 | | public: |
683 | | IncludeScope(cmMakefile* mf, std::string const& filenametoread, |
684 | | cm::PolicyScope policyScope, |
685 | | cm::DiagnosticScope diagnosticScope); |
686 | | ~IncludeScope(); |
687 | 0 | void Quiet() { this->ReportError = false; } |
688 | | |
689 | | IncludeScope(IncludeScope const&) = delete; |
690 | | IncludeScope& operator=(IncludeScope const&) = delete; |
691 | | |
692 | | private: |
693 | | cm::PolicyScope PolicyScope; |
694 | | cm::DiagnosticScope DiagnosticScope; |
695 | | bool ReportError = true; |
696 | | }; |
697 | | |
698 | | cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, |
699 | | std::string const& filenametoread, |
700 | | cm::PolicyScope policyScope, |
701 | | cm::DiagnosticScope diagnosticScope) |
702 | 0 | : FileScopeBase(mf) |
703 | 0 | , PolicyScope(policyScope) |
704 | 0 | , DiagnosticScope(diagnosticScope) |
705 | 0 | { |
706 | 0 | this->Makefile->Backtrace = this->Makefile->Backtrace.Push( |
707 | 0 | cmListFileContext::FromListFilePath(filenametoread)); |
708 | |
|
709 | 0 | this->Makefile->PushFunctionBlockerBarrier(); |
710 | |
|
711 | 0 | this->Makefile->StateSnapshot = |
712 | 0 | this->Makefile->GetState()->CreateIncludeFileSnapshot( |
713 | 0 | this->Makefile->StateSnapshot, filenametoread); |
714 | 0 | if (this->PolicyScope == cm::PolicyScope::Local) { |
715 | 0 | this->Makefile->PushPolicy(); |
716 | 0 | } |
717 | 0 | if (this->DiagnosticScope == cm::DiagnosticScope::Local) { |
718 | 0 | this->Makefile->PushDiagnostic(); |
719 | 0 | } |
720 | 0 | this->PushListFileVars(filenametoread); |
721 | 0 | } |
722 | | |
723 | | cmMakefile::IncludeScope::~IncludeScope() |
724 | 0 | { |
725 | 0 | this->PopListFileVars(); |
726 | 0 | if (this->DiagnosticScope == cm::DiagnosticScope::Local) { |
727 | | // Pop the scope we pushed for the script. |
728 | 0 | this->Makefile->PopDiagnostic(); |
729 | 0 | } |
730 | 0 | if (this->PolicyScope == cm::PolicyScope::Local) { |
731 | | // Pop the scope we pushed for the script. |
732 | 0 | this->Makefile->PopPolicy(); |
733 | 0 | } |
734 | 0 | this->Makefile->PopSnapshot(this->ReportError); |
735 | |
|
736 | 0 | this->Makefile->PopFunctionBlockerBarrier(this->ReportError); |
737 | |
|
738 | 0 | this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); |
739 | 0 | } |
740 | | |
741 | | bool cmMakefile::ReadDependentFile(std::string const& filename, |
742 | | cm::PolicyScope policyScope, |
743 | | cm::DiagnosticScope diagnosticScope) |
744 | 0 | { |
745 | 0 | std::string filenametoread = cmSystemTools::CollapseFullPath( |
746 | 0 | filename, this->GetCurrentSourceDirectory()); |
747 | |
|
748 | 0 | IncludeScope incScope(this, filenametoread, policyScope, diagnosticScope); |
749 | |
|
750 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
751 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
752 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse( |
753 | 0 | this, filenametoread); |
754 | 0 | } |
755 | 0 | #endif |
756 | |
|
757 | 0 | cmListFile listFile; |
758 | 0 | if (!listFile.ParseFile(filenametoread, this, this->Backtrace)) { |
759 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
760 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
761 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
762 | 0 | } |
763 | 0 | #endif |
764 | |
|
765 | 0 | return false; |
766 | 0 | } |
767 | | |
768 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
769 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
770 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
771 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully( |
772 | 0 | filenametoread, listFile.Functions); |
773 | 0 | } |
774 | 0 | #endif |
775 | |
|
776 | 0 | this->RunListFile(listFile, filenametoread); |
777 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
778 | 0 | incScope.Quiet(); |
779 | 0 | } |
780 | 0 | return true; |
781 | 0 | } |
782 | | |
783 | | class cmMakefile::ListFileScope : public FileScopeBase |
784 | | { |
785 | | public: |
786 | | ListFileScope(cmMakefile* mf, std::string const& filenametoread) |
787 | 11.8k | : FileScopeBase(mf) |
788 | 11.8k | { |
789 | 11.8k | this->Makefile->Backtrace = this->Makefile->Backtrace.Push( |
790 | 11.8k | cmListFileContext::FromListFilePath(filenametoread)); |
791 | | |
792 | 11.8k | this->Makefile->StateSnapshot = |
793 | 11.8k | this->Makefile->GetState()->CreateInlineListFileSnapshot( |
794 | 11.8k | this->Makefile->StateSnapshot, filenametoread); |
795 | 11.8k | assert(this->Makefile->StateSnapshot.IsValid()); |
796 | | |
797 | 11.8k | this->Makefile->PushFunctionBlockerBarrier(); |
798 | 11.8k | this->PushListFileVars(filenametoread); |
799 | 11.8k | } |
800 | | |
801 | | ~ListFileScope() |
802 | 11.8k | { |
803 | 11.8k | this->PopListFileVars(); |
804 | 11.8k | this->Makefile->PopSnapshot(this->ReportError); |
805 | 11.8k | this->Makefile->PopFunctionBlockerBarrier(this->ReportError); |
806 | 11.8k | this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); |
807 | 11.8k | } |
808 | | |
809 | 0 | void Quiet() { this->ReportError = false; } |
810 | | |
811 | | ListFileScope(ListFileScope const&) = delete; |
812 | | ListFileScope& operator=(ListFileScope const&) = delete; |
813 | | |
814 | | private: |
815 | | bool ReportError = true; |
816 | | }; |
817 | | |
818 | | class cmMakefile::DeferScope |
819 | | { |
820 | | public: |
821 | | DeferScope(cmMakefile* mf, std::string const& deferredInFile) |
822 | 0 | : Makefile(mf) |
823 | 0 | { |
824 | 0 | cmListFileContext lfc; |
825 | 0 | lfc.Line = cmListFileContext::DeferPlaceholderLine; |
826 | 0 | lfc.FilePath = deferredInFile; |
827 | 0 | this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); |
828 | 0 | this->Makefile->DeferRunning = true; |
829 | 0 | } |
830 | | |
831 | | ~DeferScope() |
832 | 0 | { |
833 | 0 | this->Makefile->DeferRunning = false; |
834 | 0 | this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); |
835 | 0 | } |
836 | | |
837 | | DeferScope(DeferScope const&) = delete; |
838 | | DeferScope& operator=(DeferScope const&) = delete; |
839 | | |
840 | | private: |
841 | | cmMakefile* Makefile; |
842 | | }; |
843 | | |
844 | | class cmMakefile::DeferCallScope |
845 | | { |
846 | | public: |
847 | | DeferCallScope(cmMakefile* mf, std::string const& deferredFromFile) |
848 | 0 | : Makefile(mf) |
849 | 0 | { |
850 | 0 | this->Makefile->StateSnapshot = |
851 | 0 | this->Makefile->GetState()->CreateDeferCallSnapshot( |
852 | 0 | this->Makefile->StateSnapshot, deferredFromFile); |
853 | 0 | assert(this->Makefile->StateSnapshot.IsValid()); |
854 | 0 | } |
855 | | |
856 | 0 | ~DeferCallScope() { this->Makefile->PopSnapshot(); } |
857 | | |
858 | | DeferCallScope(DeferCallScope const&) = delete; |
859 | | DeferCallScope& operator=(DeferCallScope const&) = delete; |
860 | | |
861 | | private: |
862 | | cmMakefile* Makefile; |
863 | | }; |
864 | | |
865 | | bool cmMakefile::ReadListFile(std::string const& filename) |
866 | 1 | { |
867 | 1 | std::string filenametoread = cmSystemTools::CollapseFullPath( |
868 | 1 | filename, this->GetCurrentSourceDirectory()); |
869 | | |
870 | 1 | ListFileScope scope(this, filenametoread); |
871 | | |
872 | 1 | #ifdef CMake_ENABLE_DEBUGGER |
873 | 1 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
874 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse( |
875 | 0 | this, filenametoread); |
876 | 0 | } |
877 | 1 | #endif |
878 | | |
879 | 1 | cmListFile listFile; |
880 | 1 | if (!listFile.ParseFile(filenametoread, this, this->Backtrace)) { |
881 | 1 | #ifdef CMake_ENABLE_DEBUGGER |
882 | 1 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
883 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
884 | 0 | } |
885 | 1 | #endif |
886 | | |
887 | 1 | return false; |
888 | 1 | } |
889 | | |
890 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
891 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
892 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
893 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully( |
894 | 0 | filenametoread, listFile.Functions); |
895 | 0 | } |
896 | 0 | #endif |
897 | |
|
898 | 0 | this->RunListFile(listFile, filenametoread); |
899 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
900 | 0 | scope.Quiet(); |
901 | 0 | } |
902 | 0 | return true; |
903 | 1 | } |
904 | | |
905 | | bool cmMakefile::ReadListFileAsString(std::string const& content, |
906 | | std::string const& virtualFileName) |
907 | 11.8k | { |
908 | 11.8k | std::string filenametoread = cmSystemTools::CollapseFullPath( |
909 | 11.8k | virtualFileName, this->GetCurrentSourceDirectory()); |
910 | | |
911 | 11.8k | ListFileScope scope(this, filenametoread); |
912 | | |
913 | 11.8k | cmListFile listFile; |
914 | 11.8k | if (!listFile.ParseString(content, virtualFileName, this, this->Backtrace)) { |
915 | 0 | return false; |
916 | 0 | } |
917 | | |
918 | 11.8k | #ifdef CMake_ENABLE_DEBUGGER |
919 | 11.8k | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
920 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully( |
921 | 0 | filenametoread, listFile.Functions); |
922 | 0 | } |
923 | 11.8k | #endif |
924 | | |
925 | 11.8k | this->RunListFile(listFile, filenametoread); |
926 | 11.8k | if (cmSystemTools::GetFatalErrorOccurred()) { |
927 | 0 | scope.Quiet(); |
928 | 0 | } |
929 | 11.8k | return true; |
930 | 11.8k | } |
931 | | |
932 | | void cmMakefile::RunListFile(cmListFile const& listFile, |
933 | | std::string const& filenametoread, |
934 | | DeferCommands* defer) |
935 | 11.8k | { |
936 | | // add this list file to the list of dependencies |
937 | 11.8k | this->ListFiles.push_back(filenametoread); |
938 | | |
939 | | // Run the parsed commands. |
940 | 11.8k | size_t const numberFunctions = listFile.Functions.size(); |
941 | 379k | for (size_t i = 0; i < numberFunctions; ++i) { |
942 | 367k | cmExecutionStatus status(*this); |
943 | 367k | this->ExecuteCommand(listFile.Functions[i], status); |
944 | 367k | if (cmSystemTools::GetFatalErrorOccurred()) { |
945 | 0 | break; |
946 | 0 | } |
947 | 367k | if (status.HasExitCode()) { |
948 | | // cmake_language EXIT was requested, early break. |
949 | 0 | this->GetCMakeInstance()->SetScriptModeExitCode(status.GetExitCode()); |
950 | 0 | break; |
951 | 0 | } |
952 | 367k | if (status.GetReturnInvoked()) { |
953 | 0 | this->RaiseScope(status.GetReturnVariables()); |
954 | | // Exit early due to return command. |
955 | 0 | break; |
956 | 0 | } |
957 | 367k | } |
958 | | |
959 | | // Run any deferred commands. |
960 | 11.8k | if (defer) { |
961 | | // Add a backtrace level indicating calls are deferred. |
962 | 0 | DeferScope scope(this, filenametoread); |
963 | | |
964 | | // Iterate by index in case one deferred call schedules another. |
965 | | // NOLINTNEXTLINE(modernize-loop-convert) |
966 | 0 | for (size_t i = 0; i < defer->Commands.size(); ++i) { |
967 | 0 | DeferCommand& d = defer->Commands[i]; |
968 | 0 | if (d.Id.empty()) { |
969 | | // Canceled. |
970 | 0 | continue; |
971 | 0 | } |
972 | | // Mark as executed. |
973 | 0 | std::string id = std::move(d.Id); |
974 | | |
975 | | // The deferred call may have come from another file. |
976 | 0 | DeferCallScope callScope(this, d.FilePath); |
977 | |
|
978 | 0 | cmExecutionStatus status(*this); |
979 | 0 | this->ExecuteCommand(d.Command, status, std::move(id)); |
980 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
981 | 0 | break; |
982 | 0 | } |
983 | 0 | } |
984 | 0 | } |
985 | 11.8k | } |
986 | | |
987 | | void cmMakefile::EnforceDirectoryLevelRules() const |
988 | 0 | { |
989 | | // Diagnose a violation of CMP0000 if necessary. |
990 | 0 | if (this->CheckCMP0000) { |
991 | 0 | std::string e = |
992 | 0 | cmStrCat("No cmake_minimum_required command is present. " |
993 | 0 | "A line of code such as\n" |
994 | 0 | " cmake_minimum_required(VERSION ", |
995 | 0 | cmVersion::GetMajorVersion(), '.', cmVersion::GetMinorVersion(), |
996 | 0 | ")\n" |
997 | 0 | "should be added at the top of the file. " |
998 | 0 | "The version specified may be lower if you wish to " |
999 | 0 | "support older CMake versions for this project. " |
1000 | 0 | "For more information run " |
1001 | 0 | "\"cmake --help-policy CMP0000\"."); |
1002 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, |
1003 | 0 | this->Backtrace); |
1004 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
1005 | 0 | } |
1006 | 0 | } |
1007 | | |
1008 | | void cmMakefile::AddEvaluationFile( |
1009 | | std::string const& inputFile, std::string const& targetName, |
1010 | | std::unique_ptr<cmCompiledGeneratorExpression> outputName, |
1011 | | std::unique_ptr<cmCompiledGeneratorExpression> condition, |
1012 | | std::string const& newLineCharacter, mode_t permissions, bool inputIsContent) |
1013 | 0 | { |
1014 | 0 | this->EvaluationFiles.push_back( |
1015 | 0 | cm::make_unique<cmGeneratorExpressionEvaluationFile>( |
1016 | 0 | inputFile, targetName, std::move(outputName), std::move(condition), |
1017 | 0 | inputIsContent, newLineCharacter, permissions, |
1018 | 0 | this->GetPolicyStatus(cmPolicies::CMP0070), |
1019 | 0 | this->GetPolicyStatus(cmPolicies::CMP0189))); |
1020 | 0 | } |
1021 | | |
1022 | | std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>> const& |
1023 | | cmMakefile::GetEvaluationFiles() const |
1024 | 0 | { |
1025 | 0 | return this->EvaluationFiles; |
1026 | 0 | } |
1027 | | |
1028 | | std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& |
1029 | | cmMakefile::GetExportBuildFileGenerators() const |
1030 | 5.92k | { |
1031 | 5.92k | return this->ExportBuildFileGenerators; |
1032 | 5.92k | } |
1033 | | |
1034 | | void cmMakefile::AddExportBuildFileGenerator( |
1035 | | std::unique_ptr<cmExportBuildFileGenerator> gen) |
1036 | 0 | { |
1037 | 0 | this->ExportBuildFileGenerators.emplace_back(std::move(gen)); |
1038 | 0 | } |
1039 | | |
1040 | | #ifndef CMAKE_BOOTSTRAP |
1041 | | std::vector<std::unique_ptr<cmBuildSbomGenerator>> const& |
1042 | | cmMakefile::GetBuildSbomGenerators() const |
1043 | 5.92k | { |
1044 | 5.92k | return this->BuildSbomGenerators; |
1045 | 5.92k | } |
1046 | | |
1047 | | void cmMakefile::AddBuildSbomGenerator( |
1048 | | std::unique_ptr<cmBuildSbomGenerator> gen) |
1049 | 0 | { |
1050 | 0 | this->BuildSbomGenerators.emplace_back(std::move(gen)); |
1051 | 0 | } |
1052 | | #endif |
1053 | | |
1054 | | namespace { |
1055 | | struct file_not_persistent |
1056 | | { |
1057 | | bool operator()(std::string const& path) const |
1058 | 11.8k | { |
1059 | 11.8k | return !(path.find("CMakeTmp") == std::string::npos && |
1060 | 11.8k | cmSystemTools::FileExists(path)); |
1061 | 11.8k | } |
1062 | | }; |
1063 | | } |
1064 | | |
1065 | | void cmMakefile::AddGeneratorAction(GeneratorAction&& action) |
1066 | 5.92k | { |
1067 | 5.92k | assert(!this->GeneratorActionsInvoked); |
1068 | 5.92k | this->GeneratorActions.emplace_back(std::move(action), this->Backtrace); |
1069 | 5.92k | } |
1070 | | |
1071 | | void cmMakefile::GeneratorAction::operator()(cmLocalGenerator& lg, |
1072 | | cmListFileBacktrace const& lfbt, |
1073 | | GeneratorActionWhen when) |
1074 | 5.92k | { |
1075 | 5.92k | if (this->When != when) { |
1076 | 0 | return; |
1077 | 0 | } |
1078 | | |
1079 | 5.92k | if (cc) { |
1080 | 5.92k | CCAction(lg, lfbt, std::move(cc)); |
1081 | 5.92k | } else { |
1082 | 0 | assert(Action); |
1083 | 0 | Action(lg, lfbt); |
1084 | 0 | } |
1085 | 5.92k | } |
1086 | | |
1087 | | void cmMakefile::DoGenerate(cmLocalGenerator& lg) |
1088 | 5.92k | { |
1089 | | // give all the commands a chance to do something |
1090 | | // after the file has been parsed before generation |
1091 | 5.92k | for (auto& action : this->GeneratorActions) { |
1092 | 5.92k | action.Value(lg, action.Backtrace, GeneratorActionWhen::AfterConfigure); |
1093 | 5.92k | } |
1094 | 5.92k | this->GeneratorActionsInvoked = true; |
1095 | | |
1096 | | // go through all configured files and see which ones still exist. |
1097 | | // we don't want cmake to re-run if a configured file is created and deleted |
1098 | | // during processing as that would make it a transient file that can't |
1099 | | // influence the build process |
1100 | 5.92k | cm::erase_if(this->OutputFiles, file_not_persistent()); |
1101 | | |
1102 | | // if a configured file is used as input for another configured file, |
1103 | | // and then deleted it will show up in the input list files so we |
1104 | | // need to scan those too |
1105 | 5.92k | cm::erase_if(this->ListFiles, file_not_persistent()); |
1106 | 5.92k | } |
1107 | | |
1108 | | // Generate the output file |
1109 | | void cmMakefile::Generate(cmLocalGenerator& lg) |
1110 | 5.92k | { |
1111 | 5.92k | this->DoGenerate(lg); |
1112 | 5.92k | cmValue oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY"); |
1113 | 5.92k | if (oldValue && |
1114 | 0 | cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, *oldValue, |
1115 | 0 | "2.4")) { |
1116 | 0 | this->GetCMakeInstance()->IssueMessage( |
1117 | 0 | MessageType::FATAL_ERROR, |
1118 | 0 | "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less " |
1119 | 0 | "than 2.4. This version of CMake only supports backwards compatibility " |
1120 | 0 | "with CMake 2.4 or later. For compatibility with older versions please " |
1121 | 0 | "use any CMake 2.8.x release or lower.", |
1122 | 0 | this->Backtrace); |
1123 | 0 | } |
1124 | 5.92k | } |
1125 | | |
1126 | | void cmMakefile::GenerateAfterGeneratorTargets(cmLocalGenerator& lg) |
1127 | 0 | { |
1128 | 0 | for (auto& action : this->GeneratorActions) { |
1129 | 0 | action.Value(lg, action.Backtrace, |
1130 | 0 | GeneratorActionWhen::AfterGeneratorTargets); |
1131 | 0 | } |
1132 | 0 | } |
1133 | | |
1134 | | namespace { |
1135 | | // There are still too many implicit backtraces through cmMakefile. As a |
1136 | | // workaround we reset the backtrace temporarily. |
1137 | | struct BacktraceGuard |
1138 | | { |
1139 | | BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current) |
1140 | 5.92k | : Backtrace(lfbt) |
1141 | 5.92k | , Previous(lfbt) |
1142 | 5.92k | { |
1143 | 5.92k | this->Backtrace = std::move(current); |
1144 | 5.92k | } |
1145 | | |
1146 | 5.92k | ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); } |
1147 | | |
1148 | | private: |
1149 | | cmListFileBacktrace& Backtrace; |
1150 | | cmListFileBacktrace Previous; |
1151 | | }; |
1152 | | } |
1153 | | |
1154 | | bool cmMakefile::ValidateCustomCommand( |
1155 | | cmCustomCommandLines const& commandLines) const |
1156 | 5.92k | { |
1157 | | // TODO: More strict? |
1158 | 5.92k | auto const it = |
1159 | 5.92k | std::find_if(commandLines.begin(), commandLines.end(), |
1160 | 5.92k | [](cmCustomCommandLine const& cl) { |
1161 | 5.92k | return !cl.empty() && !cl[0].empty() && cl[0][0] == '"'; |
1162 | 5.92k | }); |
1163 | 5.92k | if (it != commandLines.end()) { |
1164 | 0 | this->IssueMessage( |
1165 | 0 | MessageType::FATAL_ERROR, |
1166 | 0 | cmStrCat("COMMAND may not contain literal quotes:\n ", (*it)[0], '\n')); |
1167 | 0 | return false; |
1168 | 0 | } |
1169 | 5.92k | return true; |
1170 | 5.92k | } |
1171 | | |
1172 | | cmTarget* cmMakefile::GetCustomCommandTarget( |
1173 | | std::string const& target, cmObjectLibraryCommands objLibCommands, |
1174 | | cmListFileBacktrace const& lfbt) const |
1175 | 0 | { |
1176 | 0 | auto realTarget = target; |
1177 | |
|
1178 | 0 | auto ai = this->AliasTargets.find(target); |
1179 | 0 | if (ai != this->AliasTargets.end()) { |
1180 | 0 | realTarget = ai->second; |
1181 | 0 | } |
1182 | | |
1183 | | // Find the target to which to add the custom command. |
1184 | 0 | auto ti = this->Targets.find(realTarget); |
1185 | 0 | if (ti == this->Targets.end()) { |
1186 | 0 | std::string e; |
1187 | 0 | if (cmTarget const* t = this->FindTargetToUse(target)) { |
1188 | 0 | if (t->IsImported()) { |
1189 | 0 | e = cmStrCat(std::move(e), "TARGET '", target, |
1190 | 0 | "' is IMPORTED and does not build here."); |
1191 | 0 | } else { |
1192 | 0 | e = cmStrCat(std::move(e), "TARGET '", target, |
1193 | 0 | "' was not created in this directory."); |
1194 | 0 | } |
1195 | 0 | } else { |
1196 | 0 | e = cmStrCat(std::move(e), "No TARGET '", target, |
1197 | 0 | "' has been created in this directory."); |
1198 | 0 | } |
1199 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt); |
1200 | 0 | return nullptr; |
1201 | 0 | } |
1202 | | |
1203 | 0 | cmTarget* t = &ti->second; |
1204 | 0 | if (objLibCommands == cmObjectLibraryCommands::Reject && |
1205 | 0 | t->GetType() == cm::TargetType::OBJECT_LIBRARY) { |
1206 | 0 | auto e = cmStrCat( |
1207 | 0 | "Target \"", target, |
1208 | 0 | "\" is an OBJECT library " |
1209 | 0 | "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."); |
1210 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt); |
1211 | 0 | return nullptr; |
1212 | 0 | } |
1213 | 0 | if (t->GetType() == cm::TargetType::INTERFACE_LIBRARY) { |
1214 | 0 | auto e = cmStrCat( |
1215 | 0 | "Target \"", target, |
1216 | 0 | "\" is an INTERFACE library " |
1217 | 0 | "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."); |
1218 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, lfbt); |
1219 | 0 | return nullptr; |
1220 | 0 | } |
1221 | | |
1222 | 0 | return t; |
1223 | 0 | } |
1224 | | |
1225 | | cmTarget* cmMakefile::AddCustomCommandToTarget( |
1226 | | std::string const& target, cmCustomCommandType type, |
1227 | | std::unique_ptr<cmCustomCommand> cc) |
1228 | 0 | { |
1229 | 0 | auto const& byproducts = cc->GetByproducts(); |
1230 | 0 | auto const& commandLines = cc->GetCommandLines(); |
1231 | |
|
1232 | 0 | cmTarget* t = this->GetCustomCommandTarget( |
1233 | 0 | target, cmObjectLibraryCommands::Reject, this->Backtrace); |
1234 | | |
1235 | | // Validate custom commands. |
1236 | 0 | if (!t || !this->ValidateCustomCommand(commandLines)) { |
1237 | 0 | return t; |
1238 | 0 | } |
1239 | | |
1240 | | // Always create the byproduct sources and mark them generated. |
1241 | 0 | this->CreateGeneratedOutputs(byproducts); |
1242 | |
|
1243 | 0 | cc->RecordPolicyValues(this->GetStateSnapshot()); |
1244 | | |
1245 | | // Dispatch command creation to allow generator expressions in outputs. |
1246 | 0 | this->AddGeneratorAction( |
1247 | 0 | std::move(cc), |
1248 | 0 | [this, t, type](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
1249 | 0 | std::unique_ptr<cmCustomCommand> tcc) { |
1250 | 0 | BacktraceGuard guard(this->Backtrace, lfbt); |
1251 | 0 | tcc->SetBacktrace(lfbt); |
1252 | 0 | detail::AddCustomCommandToTarget(lg, cmCommandOrigin::Project, t, type, |
1253 | 0 | std::move(tcc)); |
1254 | 0 | }); |
1255 | |
|
1256 | 0 | return t; |
1257 | 0 | } |
1258 | | |
1259 | | void cmMakefile::AddCustomCommandToOutput( |
1260 | | std::unique_ptr<cmCustomCommand> cc, CommandSourceCallback const& callback, |
1261 | | bool replace) |
1262 | 0 | { |
1263 | 0 | auto const& outputs = cc->GetOutputs(); |
1264 | 0 | auto const& byproducts = cc->GetByproducts(); |
1265 | 0 | auto const& commandLines = cc->GetCommandLines(); |
1266 | | |
1267 | | // Make sure there is at least one output. |
1268 | 0 | if (outputs.empty()) { |
1269 | 0 | cmSystemTools::Error("Attempt to add a custom rule with no output!"); |
1270 | 0 | return; |
1271 | 0 | } |
1272 | | |
1273 | | // Validate custom commands. |
1274 | 0 | if (!this->ValidateCustomCommand(commandLines)) { |
1275 | 0 | return; |
1276 | 0 | } |
1277 | | |
1278 | | // Always create the output sources and mark them generated. |
1279 | 0 | this->CreateGeneratedOutputs(outputs); |
1280 | 0 | this->CreateGeneratedOutputs(byproducts); |
1281 | |
|
1282 | 0 | cc->RecordPolicyValues(this->GetStateSnapshot()); |
1283 | | |
1284 | | // Dispatch command creation to allow generator expressions in outputs. |
1285 | 0 | this->AddGeneratorAction( |
1286 | 0 | std::move(cc), |
1287 | 0 | [this, replace, callback](cmLocalGenerator& lg, |
1288 | 0 | cmListFileBacktrace const& lfbt, |
1289 | 0 | std::unique_ptr<cmCustomCommand> tcc) { |
1290 | 0 | BacktraceGuard guard(this->Backtrace, lfbt); |
1291 | 0 | tcc->SetBacktrace(lfbt); |
1292 | 0 | cmSourceFile* sf = detail::AddCustomCommandToOutput( |
1293 | 0 | lg, cmCommandOrigin::Project, std::move(tcc), replace); |
1294 | 0 | if (callback && sf) { |
1295 | 0 | callback(sf); |
1296 | 0 | } |
1297 | 0 | }); |
1298 | 0 | } |
1299 | | |
1300 | | void cmMakefile::AppendCustomCommandToOutput( |
1301 | | std::string const& output, std::vector<std::string> const& depends, |
1302 | | cmImplicitDependsList const& implicit_depends, |
1303 | | cmCustomCommandLines const& commandLines) |
1304 | 0 | { |
1305 | | // Validate custom commands. |
1306 | 0 | if (this->ValidateCustomCommand(commandLines)) { |
1307 | | // Dispatch command creation to allow generator expressions in outputs. |
1308 | 0 | this->AddGeneratorAction( |
1309 | 0 | [this, output, depends, implicit_depends, |
1310 | 0 | commandLines](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt) { |
1311 | 0 | BacktraceGuard guard(this->Backtrace, lfbt); |
1312 | 0 | detail::AppendCustomCommandToOutput(lg, lfbt, output, depends, |
1313 | 0 | implicit_depends, commandLines); |
1314 | 0 | }); |
1315 | 0 | } |
1316 | 0 | } |
1317 | | |
1318 | | cmRule* cmMakefile::AddRule(std::unique_ptr<cmRule> rule) |
1319 | 0 | { |
1320 | | // Add to the set of available rules. |
1321 | 0 | this->Rules[rule->GetName()] = rule.get(); |
1322 | 0 | this->GetGlobalGenerator()->IndexRule(rule.get()); |
1323 | 0 | this->GetStateSnapshot().GetDirectory().AddRuleName(rule->GetName()); |
1324 | | |
1325 | | // Transfer ownership to this cmMakefile object. |
1326 | 0 | this->RulesOwned.push_back(std::move(rule)); |
1327 | 0 | return this->RulesOwned.back().get(); |
1328 | 0 | } |
1329 | | |
1330 | | cmRule* cmMakefile::FindRuleToUse(std::string const& name) const |
1331 | 0 | { |
1332 | 0 | auto i = this->Rules.find(name); |
1333 | 0 | if (i != this->Rules.end()) { |
1334 | 0 | return i->second; |
1335 | 0 | } |
1336 | | |
1337 | | // Look for a target built in this project. |
1338 | 0 | return this->GetGlobalGenerator()->FindRule(name); |
1339 | 0 | } |
1340 | | |
1341 | | cmTarget* cmMakefile::AddUtilityCommand(std::string const& utilityName, |
1342 | | bool excludeFromAll, |
1343 | | std::unique_ptr<cmCustomCommand> cc) |
1344 | 5.92k | { |
1345 | 5.92k | auto const& depends = cc->GetDepends(); |
1346 | 5.92k | auto const& byproducts = cc->GetByproducts(); |
1347 | 5.92k | auto const& commandLines = cc->GetCommandLines(); |
1348 | 5.92k | cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll); |
1349 | | |
1350 | | // Validate custom commands. |
1351 | 5.92k | if ((commandLines.empty() && depends.empty()) || |
1352 | 5.92k | !this->ValidateCustomCommand(commandLines)) { |
1353 | 0 | return target; |
1354 | 0 | } |
1355 | | |
1356 | | // Always create the byproduct sources and mark them generated. |
1357 | 5.92k | this->CreateGeneratedOutputs(byproducts); |
1358 | | |
1359 | 5.92k | cc->RecordPolicyValues(this->GetStateSnapshot()); |
1360 | | |
1361 | | // Dispatch command creation to allow generator expressions in outputs. |
1362 | 5.92k | this->AddGeneratorAction( |
1363 | 5.92k | std::move(cc), |
1364 | 5.92k | [this, target](cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
1365 | 5.92k | std::unique_ptr<cmCustomCommand> tcc) { |
1366 | 5.92k | BacktraceGuard guard(this->Backtrace, lfbt); |
1367 | 5.92k | tcc->SetBacktrace(lfbt); |
1368 | 5.92k | detail::AddUtilityCommand(lg, cmCommandOrigin::Project, target, |
1369 | 5.92k | std::move(tcc)); |
1370 | 5.92k | }); |
1371 | | |
1372 | 5.92k | return target; |
1373 | 5.92k | } |
1374 | | |
1375 | | static void s_AddDefineFlag(std::string const& flag, std::string& dflags) |
1376 | 0 | { |
1377 | | // remove any \n\r |
1378 | 0 | std::string::size_type initSize = dflags.size(); |
1379 | 0 | dflags += ' '; |
1380 | 0 | dflags += flag; |
1381 | 0 | std::string::iterator flagStart = dflags.begin() + initSize + 1; |
1382 | 0 | std::replace(flagStart, dflags.end(), '\n', ' '); |
1383 | 0 | std::replace(flagStart, dflags.end(), '\r', ' '); |
1384 | 0 | } |
1385 | | |
1386 | | void cmMakefile::AddDefineFlag(std::string const& flag) |
1387 | 0 | { |
1388 | 0 | if (flag.empty()) { |
1389 | 0 | return; |
1390 | 0 | } |
1391 | | |
1392 | | // If this is really a definition, update COMPILE_DEFINITIONS. |
1393 | 0 | if (this->ParseDefineFlag(flag, false)) { |
1394 | 0 | return; |
1395 | 0 | } |
1396 | | |
1397 | | // Add this flag that does not look like a definition. |
1398 | 0 | s_AddDefineFlag(flag, this->DefineFlags); |
1399 | 0 | } |
1400 | | |
1401 | | static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags) |
1402 | 0 | { |
1403 | 0 | std::string::size_type const len = flag.length(); |
1404 | | // Remove all instances of the flag that are surrounded by |
1405 | | // whitespace or the beginning/end of the string. |
1406 | 0 | for (std::string::size_type lpos = dflags.find(flag, 0); |
1407 | 0 | lpos != std::string::npos; lpos = dflags.find(flag, lpos)) { |
1408 | 0 | std::string::size_type rpos = lpos + len; |
1409 | 0 | if ((lpos <= 0 || cmsysString_isspace(dflags[lpos - 1])) && |
1410 | 0 | (rpos >= dflags.size() || cmsysString_isspace(dflags[rpos]))) { |
1411 | 0 | dflags.erase(lpos, len); |
1412 | 0 | } else { |
1413 | 0 | ++lpos; |
1414 | 0 | } |
1415 | 0 | } |
1416 | 0 | } |
1417 | | |
1418 | | void cmMakefile::RemoveDefineFlag(std::string const& flag) |
1419 | 0 | { |
1420 | | // Check the length of the flag to remove. |
1421 | 0 | if (flag.empty()) { |
1422 | 0 | return; |
1423 | 0 | } |
1424 | | |
1425 | | // If this is really a definition, update COMPILE_DEFINITIONS. |
1426 | 0 | if (this->ParseDefineFlag(flag, true)) { |
1427 | 0 | return; |
1428 | 0 | } |
1429 | | |
1430 | | // Remove this flag that does not look like a definition. |
1431 | 0 | s_RemoveDefineFlag(flag, this->DefineFlags); |
1432 | 0 | } |
1433 | | |
1434 | | void cmMakefile::AddCompileDefinition(std::string const& option) |
1435 | 0 | { |
1436 | 0 | this->AppendProperty("COMPILE_DEFINITIONS", option); |
1437 | 0 | } |
1438 | | |
1439 | | void cmMakefile::AddCompileOption(std::string const& option) |
1440 | 0 | { |
1441 | 0 | this->AppendProperty("COMPILE_OPTIONS", option); |
1442 | 0 | } |
1443 | | |
1444 | | void cmMakefile::AddLinkOption(std::string const& option) |
1445 | 0 | { |
1446 | 0 | this->AppendProperty("LINK_OPTIONS", option); |
1447 | 0 | } |
1448 | | |
1449 | | void cmMakefile::AddLinkDirectory(std::string const& directory, bool before) |
1450 | 0 | { |
1451 | 0 | if (before) { |
1452 | 0 | this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry( |
1453 | 0 | BT<std::string>(directory, this->Backtrace)); |
1454 | 0 | } else { |
1455 | 0 | this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry( |
1456 | 0 | BT<std::string>(directory, this->Backtrace)); |
1457 | 0 | } |
1458 | 0 | } |
1459 | | |
1460 | | bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) |
1461 | 0 | { |
1462 | | // Create a regular expression to match valid definitions. |
1463 | 0 | static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$"); |
1464 | | |
1465 | | // Make sure the definition matches. |
1466 | 0 | if (!valid.find(def)) { |
1467 | 0 | return false; |
1468 | 0 | } |
1469 | | |
1470 | | // Get the definition part after the flag. |
1471 | 0 | char const* define = def.c_str() + 2; |
1472 | |
|
1473 | 0 | if (remove) { |
1474 | 0 | if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) { |
1475 | | // Expand the list. |
1476 | 0 | cmList defs{ *cdefs }; |
1477 | | |
1478 | | // Recompose the list without the definition. |
1479 | 0 | defs.remove_items({ define }); |
1480 | | |
1481 | | // Store the new list. |
1482 | 0 | this->SetProperty("COMPILE_DEFINITIONS", defs.to_string()); |
1483 | 0 | } |
1484 | 0 | } else { |
1485 | | // Append the definition to the directory property. |
1486 | 0 | this->AppendProperty("COMPILE_DEFINITIONS", define); |
1487 | 0 | } |
1488 | |
|
1489 | 0 | return true; |
1490 | 0 | } |
1491 | | |
1492 | | void cmMakefile::InitializeFromParent(cmMakefile* parent) |
1493 | 0 | { |
1494 | 0 | this->SystemIncludeDirectories = parent->SystemIncludeDirectories; |
1495 | | |
1496 | | // define flags |
1497 | 0 | this->DefineFlags = parent->DefineFlags; |
1498 | | |
1499 | | // Include transform property. There is no per-config version. |
1500 | 0 | { |
1501 | 0 | char const* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM"; |
1502 | 0 | this->SetProperty(prop, parent->GetProperty(prop)); |
1503 | 0 | } |
1504 | | |
1505 | | // labels |
1506 | 0 | this->SetProperty("LABELS", parent->GetProperty("LABELS")); |
1507 | | |
1508 | | // link libraries |
1509 | 0 | this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES")); |
1510 | | |
1511 | | // the initial project name |
1512 | 0 | this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName()); |
1513 | | |
1514 | | // Copy include regular expressions. |
1515 | 0 | this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression; |
1516 | | |
1517 | | // Non-global rules. |
1518 | 0 | this->Rules = parent->Rules; |
1519 | | |
1520 | | // Imported targets. |
1521 | 0 | this->ImportedTargets = parent->ImportedTargets; |
1522 | | |
1523 | | // Non-global Alias targets. |
1524 | 0 | this->AliasTargets = parent->AliasTargets; |
1525 | | |
1526 | | // Recursion depth. |
1527 | 0 | this->RecursionDepth = parent->RecursionDepth; |
1528 | 0 | } |
1529 | | |
1530 | | void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g) |
1531 | 0 | { |
1532 | 0 | if (g) { |
1533 | 0 | this->InstallGenerators.push_back(std::move(g)); |
1534 | 0 | } |
1535 | 0 | } |
1536 | | |
1537 | | void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g) |
1538 | 0 | { |
1539 | 0 | if (g) { |
1540 | 0 | this->TestGenerators.push_back(std::move(g)); |
1541 | 0 | } |
1542 | 0 | } |
1543 | | |
1544 | | void cmMakefile::PushFunctionScope(std::string const& fileName, |
1545 | | cmPolicies::PolicyMap const& pm, |
1546 | | cmDiagnostics::DiagnosticMap dm) |
1547 | 0 | { |
1548 | 0 | this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot( |
1549 | 0 | this->StateSnapshot, fileName); |
1550 | 0 | assert(this->StateSnapshot.IsValid()); |
1551 | |
|
1552 | 0 | this->PushLoopBlockBarrier(); |
1553 | |
|
1554 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
1555 | 0 | this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope(); |
1556 | 0 | #endif |
1557 | |
|
1558 | 0 | this->PushFunctionBlockerBarrier(); |
1559 | |
|
1560 | 0 | this->PushPolicy(true, pm); |
1561 | 0 | this->PushDiagnostic(true, dm); |
1562 | 0 | } |
1563 | | |
1564 | | void cmMakefile::PopFunctionScope(bool reportError) |
1565 | 0 | { |
1566 | 0 | this->PopDiagnostic(); |
1567 | 0 | this->PopPolicy(); |
1568 | |
|
1569 | 0 | this->PopSnapshot(reportError); |
1570 | |
|
1571 | 0 | this->PopFunctionBlockerBarrier(reportError); |
1572 | |
|
1573 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
1574 | 0 | this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope(); |
1575 | 0 | #endif |
1576 | |
|
1577 | 0 | this->PopLoopBlockBarrier(); |
1578 | 0 | } |
1579 | | |
1580 | | void cmMakefile::PushMacroScope(std::string const& fileName, |
1581 | | cmPolicies::PolicyMap const& pm, |
1582 | | cmDiagnostics::DiagnosticMap dm) |
1583 | 0 | { |
1584 | 0 | this->StateSnapshot = |
1585 | 0 | this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName); |
1586 | 0 | assert(this->StateSnapshot.IsValid()); |
1587 | |
|
1588 | 0 | this->PushFunctionBlockerBarrier(); |
1589 | |
|
1590 | 0 | this->PushPolicy(true, pm); |
1591 | 0 | this->PushDiagnostic(true, dm); |
1592 | 0 | } |
1593 | | |
1594 | | void cmMakefile::PopMacroScope(bool reportError) |
1595 | 0 | { |
1596 | 0 | this->PopDiagnostic(); |
1597 | 0 | this->PopPolicy(); |
1598 | 0 | this->PopSnapshot(reportError); |
1599 | |
|
1600 | 0 | this->PopFunctionBlockerBarrier(reportError); |
1601 | 0 | } |
1602 | | |
1603 | | bool cmMakefile::IsRootMakefile() const |
1604 | 0 | { |
1605 | 0 | return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid(); |
1606 | 0 | } |
1607 | | |
1608 | | class cmMakefile::BuildsystemFileScope : public FileScopeBase |
1609 | | { |
1610 | | public: |
1611 | | BuildsystemFileScope(cmMakefile* mf) |
1612 | 0 | : FileScopeBase(mf) |
1613 | 0 | { |
1614 | 0 | std::string currentStart = |
1615 | 0 | this->Makefile->GetCMakeInstance()->GetCMakeListFile( |
1616 | 0 | this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource()); |
1617 | 0 | this->Makefile->StateSnapshot.SetListFile(currentStart); |
1618 | 0 | this->Makefile->StateSnapshot = |
1619 | 0 | this->Makefile->StateSnapshot.GetState()->CreatePolicyScopeSnapshot( |
1620 | 0 | this->Makefile->StateSnapshot); |
1621 | 0 | this->Makefile->PushFunctionBlockerBarrier(); |
1622 | 0 | this->PushListFileVars(currentStart); |
1623 | |
|
1624 | 0 | this->GG = mf->GetGlobalGenerator(); |
1625 | 0 | this->CurrentMakefile = this->GG->GetCurrentMakefile(); |
1626 | 0 | this->Snapshot = this->GG->GetCMakeInstance()->GetCurrentSnapshot(); |
1627 | 0 | this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot); |
1628 | 0 | this->GG->SetCurrentMakefile(mf); |
1629 | 0 | } |
1630 | | |
1631 | | ~BuildsystemFileScope() |
1632 | 0 | { |
1633 | 0 | this->PopListFileVars(); |
1634 | 0 | this->Makefile->PopFunctionBlockerBarrier(this->ReportError); |
1635 | 0 | this->Makefile->PopSnapshot(this->ReportError); |
1636 | 0 | this->GG->SetCurrentMakefile(this->CurrentMakefile); |
1637 | 0 | this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot); |
1638 | 0 | } |
1639 | | |
1640 | 0 | void Quiet() { this->ReportError = false; } |
1641 | | |
1642 | | BuildsystemFileScope(BuildsystemFileScope const&) = delete; |
1643 | | BuildsystemFileScope& operator=(BuildsystemFileScope const&) = delete; |
1644 | | |
1645 | | private: |
1646 | | cmGlobalGenerator* GG; |
1647 | | cmMakefile* CurrentMakefile; |
1648 | | cmStateSnapshot Snapshot; |
1649 | | bool ReportError = true; |
1650 | | }; |
1651 | | |
1652 | | void cmMakefile::Configure() |
1653 | 0 | { |
1654 | 0 | std::string currentStart = this->GetCMakeInstance()->GetCMakeListFile( |
1655 | 0 | this->StateSnapshot.GetDirectory().GetCurrentSource()); |
1656 | | |
1657 | | // Add the bottom of all backtraces within this directory. |
1658 | | // We will never pop this scope because it should be available |
1659 | | // for messages during the generate step too. |
1660 | 0 | this->Backtrace = |
1661 | 0 | this->Backtrace.Push(cmListFileContext::FromListFilePath(currentStart)); |
1662 | |
|
1663 | 0 | BuildsystemFileScope scope(this); |
1664 | | |
1665 | | // make sure the CMakeFiles dir is there |
1666 | 0 | std::string filesDir = cmStrCat( |
1667 | 0 | this->StateSnapshot.GetDirectory().GetCurrentBinary(), "/CMakeFiles"); |
1668 | 0 | cmSystemTools::MakeDirectory(filesDir); |
1669 | |
|
1670 | 0 | assert(cmSystemTools::FileExists(currentStart, true)); |
1671 | | |
1672 | | // In the top-most directory, cmake_minimum_required() may not have been |
1673 | | // called yet, so ApplyPolicyVersion() may not have handled the default |
1674 | | // policy value. Check them here. |
1675 | 0 | if (this->GetPolicyStatus(cmPolicies::CMP0198) == cmPolicies::WARN) { |
1676 | 0 | if (cmValue defaultValue = |
1677 | 0 | this->GetDefinition("CMAKE_POLICY_DEFAULT_CMP0198")) { |
1678 | 0 | if (*defaultValue == "NEW") { |
1679 | 0 | this->SetPolicy(cmPolicies::CMP0198, cmPolicies::NEW); |
1680 | 0 | } else if (*defaultValue == "OLD") { |
1681 | 0 | this->SetPolicy(cmPolicies::CMP0198, cmPolicies::OLD); |
1682 | 0 | } |
1683 | 0 | } |
1684 | 0 | } |
1685 | | |
1686 | | // Set CMAKE_PARENT_LIST_FILE for CMakeLists.txt based on CMP0198 policy |
1687 | 0 | this->UpdateParentListFileVariable(); |
1688 | |
|
1689 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
1690 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
1691 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnBeginFileParse( |
1692 | 0 | this, currentStart); |
1693 | 0 | } |
1694 | 0 | #endif |
1695 | |
|
1696 | 0 | cmListFile listFile; |
1697 | 0 | if (!listFile.ParseFile(currentStart, this, this->Backtrace)) { |
1698 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
1699 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
1700 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
1701 | 0 | } |
1702 | 0 | #endif |
1703 | |
|
1704 | 0 | return; |
1705 | 0 | } |
1706 | | |
1707 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
1708 | 0 | if (this->GetCMakeInstance()->GetDebugAdapter()) { |
1709 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnEndFileParse(); |
1710 | 0 | this->GetCMakeInstance()->GetDebugAdapter()->OnFileParsedSuccessfully( |
1711 | 0 | currentStart, listFile.Functions); |
1712 | 0 | } |
1713 | 0 | #endif |
1714 | |
|
1715 | 0 | if (this->IsRootMakefile()) { |
1716 | 0 | bool hasVersion = false; |
1717 | | // search for the right policy command |
1718 | 0 | for (cmListFileFunction const& func : listFile.Functions) { |
1719 | 0 | if (func.LowerCaseName() == "cmake_minimum_required"_s) { |
1720 | 0 | hasVersion = true; |
1721 | 0 | break; |
1722 | 0 | } |
1723 | 0 | } |
1724 | | // if no policy command is found this is an error if they use any |
1725 | | // non advanced functions or a lot of functions |
1726 | 0 | if (!hasVersion) { |
1727 | 0 | bool isProblem = true; |
1728 | 0 | if (listFile.Functions.size() < 30) { |
1729 | | // the list of simple commands DO NOT ADD TO THIS LIST!!!!! |
1730 | | // these commands must have backwards compatibility forever and |
1731 | | // and that is a lot longer than your tiny mind can comprehend mortal |
1732 | 0 | std::set<std::string> allowedCommands; |
1733 | 0 | allowedCommands.insert("project"); |
1734 | 0 | allowedCommands.insert("set"); |
1735 | 0 | allowedCommands.insert("if"); |
1736 | 0 | allowedCommands.insert("endif"); |
1737 | 0 | allowedCommands.insert("else"); |
1738 | 0 | allowedCommands.insert("elseif"); |
1739 | 0 | allowedCommands.insert("add_executable"); |
1740 | 0 | allowedCommands.insert("add_library"); |
1741 | 0 | allowedCommands.insert("target_link_libraries"); |
1742 | 0 | allowedCommands.insert("option"); |
1743 | 0 | allowedCommands.insert("message"); |
1744 | 0 | isProblem = false; |
1745 | 0 | for (cmListFileFunction const& func : listFile.Functions) { |
1746 | 0 | if (!cm::contains(allowedCommands, func.LowerCaseName())) { |
1747 | 0 | isProblem = true; |
1748 | 0 | break; |
1749 | 0 | } |
1750 | 0 | } |
1751 | 0 | } |
1752 | |
|
1753 | 0 | if (isProblem) { |
1754 | | // Tell the top level cmMakefile to diagnose |
1755 | | // this violation of CMP0000. |
1756 | 0 | this->SetCheckCMP0000(true); |
1757 | | |
1758 | | // Implicitly set the version for the user. |
1759 | 0 | cmPolicies::ApplyPolicyVersion(this, 3, 5, 0, |
1760 | 0 | cmPolicies::WarnCompat::Off); |
1761 | 0 | } |
1762 | 0 | } |
1763 | 0 | bool hasProject = false; |
1764 | | // search for a project command |
1765 | 0 | for (cmListFileFunction const& func : listFile.Functions) { |
1766 | 0 | if (func.LowerCaseName() == "project"_s) { |
1767 | 0 | hasProject = true; |
1768 | 0 | break; |
1769 | 0 | } |
1770 | 0 | } |
1771 | | // if no project command is found, add one |
1772 | 0 | if (!hasProject) { |
1773 | 0 | this->IssueDiagnostic( |
1774 | 0 | cmDiagnostics::CMD_AUTHOR, |
1775 | 0 | "No project() command is present. The top-level CMakeLists.txt " |
1776 | 0 | "file must contain a literal, direct call to the project() command. " |
1777 | 0 | "Add a line of code such as\n" |
1778 | 0 | " project(ProjectName)\n" |
1779 | 0 | "near the top of the file, but after cmake_minimum_required().\n" |
1780 | 0 | "CMake is pretending there is a \"project(Project)\" command on " |
1781 | 0 | "the first line."); |
1782 | 0 | cmListFileFunction project{ |
1783 | 0 | "project", 0, 0, { { "Project", cmListFileArgument::Unquoted, 0 } } |
1784 | 0 | }; |
1785 | 0 | listFile.Functions.insert(listFile.Functions.begin(), project); |
1786 | 0 | } |
1787 | 0 | } |
1788 | |
|
1789 | 0 | this->Defer = cm::make_unique<DeferCommands>(); |
1790 | 0 | this->RunListFile(listFile, currentStart, this->Defer.get()); |
1791 | 0 | this->Defer.reset(); |
1792 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
1793 | 0 | scope.Quiet(); |
1794 | 0 | } |
1795 | | |
1796 | | // at the end handle any old style subdirs |
1797 | 0 | std::vector<cmMakefile*> subdirs = this->UnConfiguredDirectories; |
1798 | | |
1799 | | // for each subdir recurse |
1800 | 0 | auto sdi = subdirs.begin(); |
1801 | 0 | for (; sdi != subdirs.end(); ++sdi) { |
1802 | 0 | (*sdi)->StateSnapshot.InitializeFromParent_ForSubdirsCommand(); |
1803 | 0 | this->ConfigureSubDirectory(*sdi); |
1804 | 0 | } |
1805 | |
|
1806 | 0 | this->AddCMakeDependFilesFromUser(); |
1807 | 0 | } |
1808 | | |
1809 | | void cmMakefile::ConfigureSubDirectory(cmMakefile* mf) |
1810 | 0 | { |
1811 | 0 | mf->InitializeFromParent(this); |
1812 | 0 | std::string currentStart = mf->GetCurrentSourceDirectory(); |
1813 | 0 | if (this->GetCMakeInstance()->GetDebugOutput()) { |
1814 | 0 | std::string msg = cmStrCat(" Entering ", currentStart); |
1815 | 0 | cmSystemTools::Message(msg); |
1816 | 0 | } |
1817 | |
|
1818 | 0 | std::string currentStartFile = |
1819 | 0 | this->GetCMakeInstance()->GetCMakeListFile(currentStart); |
1820 | 0 | if (!cmSystemTools::FileExists(currentStartFile, true)) { |
1821 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
1822 | 0 | cmStrCat("The source directory\n ", currentStart, |
1823 | 0 | "\n" |
1824 | 0 | "does not contain a CMakeLists.txt file.")); |
1825 | 0 | return; |
1826 | 0 | } |
1827 | | // finally configure the subdir |
1828 | 0 | mf->Configure(); |
1829 | |
|
1830 | 0 | if (this->GetCMakeInstance()->GetDebugOutput()) { |
1831 | 0 | auto msg = |
1832 | 0 | cmStrCat(" Returning to ", this->GetCurrentSourceDirectory()); |
1833 | 0 | cmSystemTools::Message(msg); |
1834 | 0 | } |
1835 | 0 | } |
1836 | | |
1837 | | void cmMakefile::AddSubDirectory(std::string const& srcPath, |
1838 | | std::string const& binPath, |
1839 | | bool excludeFromAll, bool immediate, |
1840 | | bool system) |
1841 | 0 | { |
1842 | 0 | if (this->DeferRunning) { |
1843 | 0 | this->IssueMessage( |
1844 | 0 | MessageType::FATAL_ERROR, |
1845 | 0 | "Subdirectories may not be created during deferred execution."); |
1846 | 0 | return; |
1847 | 0 | } |
1848 | | |
1849 | | // Make sure the binary directory is unique. |
1850 | 0 | if (!this->EnforceUniqueDir(srcPath, binPath)) { |
1851 | 0 | return; |
1852 | 0 | } |
1853 | | |
1854 | 0 | cmStateSnapshot newSnapshot = |
1855 | 0 | this->GetState()->CreateBuildsystemDirectorySnapshot(this->StateSnapshot); |
1856 | |
|
1857 | 0 | newSnapshot.GetDirectory().SetCurrentSource(srcPath); |
1858 | 0 | newSnapshot.GetDirectory().SetCurrentBinary(binPath); |
1859 | |
|
1860 | 0 | cmSystemTools::MakeDirectory(binPath); |
1861 | |
|
1862 | 0 | auto subMfu = |
1863 | 0 | cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot); |
1864 | 0 | auto* subMf = subMfu.get(); |
1865 | 0 | this->GetGlobalGenerator()->AddMakefile(std::move(subMfu)); |
1866 | |
|
1867 | 0 | if (excludeFromAll) { |
1868 | 0 | subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); |
1869 | 0 | } |
1870 | 0 | if (system) { |
1871 | 0 | subMf->SetProperty("SYSTEM", "TRUE"); |
1872 | 0 | } |
1873 | |
|
1874 | 0 | if (immediate) { |
1875 | 0 | this->ConfigureSubDirectory(subMf); |
1876 | 0 | } else { |
1877 | 0 | this->UnConfiguredDirectories.push_back(subMf); |
1878 | 0 | } |
1879 | |
|
1880 | 0 | this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>( |
1881 | 0 | subMf, binPath, this->GetBacktrace())); |
1882 | 0 | } |
1883 | | |
1884 | | std::string const& cmMakefile::GetCurrentSourceDirectory() const |
1885 | 28.2k | { |
1886 | 28.2k | return this->StateSnapshot.GetDirectory().GetCurrentSource(); |
1887 | 28.2k | } |
1888 | | |
1889 | | std::string const& cmMakefile::GetCurrentBinaryDirectory() const |
1890 | 6.92k | { |
1891 | 6.92k | return this->StateSnapshot.GetDirectory().GetCurrentBinary(); |
1892 | 6.92k | } |
1893 | | |
1894 | | cmTarget* cmMakefile::FindImportedTarget(std::string const& name) const |
1895 | 0 | { |
1896 | 0 | auto const i = this->ImportedTargets.find(name); |
1897 | 0 | if (i != this->ImportedTargets.end()) { |
1898 | 0 | return i->second; |
1899 | 0 | } |
1900 | 0 | return nullptr; |
1901 | 0 | } |
1902 | | |
1903 | | std::vector<cmTarget*> cmMakefile::GetImportedTargets() const |
1904 | 5.92k | { |
1905 | 5.92k | std::vector<cmTarget*> tgts; |
1906 | 5.92k | tgts.reserve(this->ImportedTargets.size()); |
1907 | 17.7k | for (auto const& impTarget : this->ImportedTargets) { |
1908 | 17.7k | tgts.push_back(impTarget.second); |
1909 | 17.7k | } |
1910 | 5.92k | return tgts; |
1911 | 5.92k | } |
1912 | | |
1913 | | void cmMakefile::AddIncludeDirectories(std::vector<std::string> const& incs, |
1914 | | bool before) |
1915 | 0 | { |
1916 | 0 | if (incs.empty()) { |
1917 | 0 | return; |
1918 | 0 | } |
1919 | | |
1920 | 0 | std::string entryString = cmList::to_string(incs); |
1921 | 0 | if (before) { |
1922 | 0 | this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry( |
1923 | 0 | BT<std::string>(entryString, this->Backtrace)); |
1924 | 0 | } else { |
1925 | 0 | this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry( |
1926 | 0 | BT<std::string>(entryString, this->Backtrace)); |
1927 | 0 | } |
1928 | | |
1929 | | // Property on each target: |
1930 | 0 | for (auto& target : this->Targets) { |
1931 | 0 | cmTarget& t = target.second; |
1932 | 0 | t.InsertInclude(BT<std::string>(entryString, this->Backtrace), before); |
1933 | 0 | } |
1934 | 0 | } |
1935 | | |
1936 | | void cmMakefile::AddSystemIncludeDirectories(std::set<std::string> const& incs) |
1937 | 0 | { |
1938 | 0 | if (incs.empty()) { |
1939 | 0 | return; |
1940 | 0 | } |
1941 | | |
1942 | 0 | this->SystemIncludeDirectories.insert(incs.begin(), incs.end()); |
1943 | |
|
1944 | 0 | for (auto& target : this->Targets) { |
1945 | 0 | cmTarget& t = target.second; |
1946 | 0 | t.AddSystemIncludeDirectories(incs); |
1947 | 0 | } |
1948 | 0 | } |
1949 | | |
1950 | | void cmMakefile::AddDefinition(std::string const& name, cm::string_view value) |
1951 | 296k | { |
1952 | 296k | this->StateSnapshot.SetDefinition(name, value); |
1953 | | |
1954 | 296k | #ifndef CMAKE_BOOTSTRAP |
1955 | 296k | cmVariableWatch* vv = this->GetVariableWatch(); |
1956 | 296k | if (vv) { |
1957 | 296k | vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS, |
1958 | 296k | value.data(), this); |
1959 | 296k | } |
1960 | 296k | #endif |
1961 | 296k | } |
1962 | | |
1963 | | void cmMakefile::AddDefinitionBool(std::string const& name, bool value) |
1964 | 0 | { |
1965 | 0 | this->AddDefinition(name, value ? "ON" : "OFF"); |
1966 | 0 | } |
1967 | | |
1968 | | void cmMakefile::AddCacheDefinition(std::string const& name, cmValue value, |
1969 | | cmValue doc, |
1970 | | cmStateEnums::CacheEntryType type, |
1971 | | bool force) |
1972 | 0 | { |
1973 | 0 | cmValue existingValue = this->GetState()->GetInitializedCacheValue(name); |
1974 | | // must be outside the following if() to keep it alive long enough |
1975 | 0 | std::string nvalue; |
1976 | |
|
1977 | 0 | if (existingValue && |
1978 | 0 | (this->GetState()->GetCacheEntryType(name) == |
1979 | 0 | cmStateEnums::UNINITIALIZED)) { |
1980 | | // if this is not a force, then use the value from the cache |
1981 | | // if it is a force, then use the value being passed in |
1982 | 0 | if (!force) { |
1983 | 0 | value = existingValue; |
1984 | 0 | } |
1985 | 0 | if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) { |
1986 | 0 | cmList files(value); |
1987 | 0 | for (auto& file : files) { |
1988 | 0 | if (!cmIsOff(file)) { |
1989 | 0 | file = cmSystemTools::ToNormalizedPathOnDisk(file); |
1990 | 0 | } |
1991 | 0 | } |
1992 | 0 | nvalue = files.to_string(); |
1993 | 0 | value = cmValue{ nvalue }; |
1994 | |
|
1995 | 0 | this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type); |
1996 | 0 | value = this->GetState()->GetInitializedCacheValue(name); |
1997 | 0 | } |
1998 | 0 | } |
1999 | 0 | this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type); |
2000 | 0 | switch (this->GetPolicyStatus(cmPolicies::CMP0126)) { |
2001 | 0 | case cmPolicies::WARN: |
2002 | 0 | if (this->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0126") && |
2003 | 0 | this->IsNormalDefinitionSet(name)) { |
2004 | 0 | this->IssuePolicyWarning( |
2005 | 0 | cmPolicies::CMP0126, {}, |
2006 | 0 | cmStrCat("For compatibility with older versions of CMake, " |
2007 | 0 | "normal variable \""_s, |
2008 | 0 | name, "\" will be removed from the current scope."_s)); |
2009 | 0 | } |
2010 | 0 | CM_FALLTHROUGH; |
2011 | 0 | case cmPolicies::OLD: |
2012 | | // if there was a definition then remove it |
2013 | 0 | this->StateSnapshot.RemoveDefinition(name); |
2014 | 0 | break; |
2015 | 0 | case cmPolicies::NEW: |
2016 | 0 | break; |
2017 | 0 | } |
2018 | 0 | } |
2019 | | |
2020 | | void cmMakefile::MarkVariableAsUsed(std::string const& var) |
2021 | 53.3k | { |
2022 | 53.3k | this->StateSnapshot.GetDefinition(var); |
2023 | 53.3k | } |
2024 | | |
2025 | | bool cmMakefile::VariableInitialized(std::string const& var) const |
2026 | 0 | { |
2027 | 0 | return this->StateSnapshot.IsInitialized(var); |
2028 | 0 | } |
2029 | | |
2030 | | void cmMakefile::MaybeWarnUninitialized(std::string const& variable, |
2031 | | char const* sourceFilename) const |
2032 | 0 | { |
2033 | | // check to see if we need to print a warning |
2034 | | // if strict mode is on and the variable has |
2035 | | // not been "cleared"/initialized with a set(foo ) call |
2036 | 0 | cmDiagnosticAction const action = |
2037 | 0 | this->GetDiagnosticAction(cmDiagnostics::CMD_UNINITIALIZED); |
2038 | 0 | if (action != cmDiagnostics::Ignore && |
2039 | 0 | !this->VariableInitialized(variable)) { |
2040 | 0 | if (this->CheckSystemVars || |
2041 | 0 | (sourceFilename && this->IsProjectFile(sourceFilename))) { |
2042 | 0 | this->IssueDiagnostic( |
2043 | 0 | cmDiagnostics::CMD_UNINITIALIZED, |
2044 | 0 | cmStrCat("uninitialized variable '", variable, '\'')); |
2045 | 0 | } |
2046 | 0 | } |
2047 | 0 | } |
2048 | | |
2049 | | void cmMakefile::RemoveDefinition(std::string const& name) |
2050 | 17.7k | { |
2051 | 17.7k | this->StateSnapshot.RemoveDefinition(name); |
2052 | 17.7k | #ifndef CMAKE_BOOTSTRAP |
2053 | 17.7k | cmVariableWatch* vv = this->GetVariableWatch(); |
2054 | 17.7k | if (vv) { |
2055 | 17.7k | vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS, |
2056 | 17.7k | nullptr, this); |
2057 | 17.7k | } |
2058 | 17.7k | #endif |
2059 | 17.7k | } |
2060 | | |
2061 | | void cmMakefile::RemoveCacheDefinition(std::string const& name) const |
2062 | 23.7k | { |
2063 | 23.7k | this->GetState()->RemoveCacheEntry(name); |
2064 | 23.7k | } |
2065 | | |
2066 | | void cmMakefile::SetProjectName(std::string const& p) |
2067 | 0 | { |
2068 | 0 | this->StateSnapshot.SetProjectName(p); |
2069 | 0 | } |
2070 | | |
2071 | | void cmMakefile::AddGlobalLinkInformation(cmTarget& target) |
2072 | 29.6k | { |
2073 | | // for these targets do not add anything |
2074 | 29.6k | switch (target.GetType()) { |
2075 | 0 | case cm::TargetType::UTILITY: |
2076 | 0 | case cm::TargetType::GLOBAL_TARGET: |
2077 | 11.8k | case cm::TargetType::INTERFACE_LIBRARY: |
2078 | 11.8k | return; |
2079 | 17.7k | default:; |
2080 | 29.6k | } |
2081 | | |
2082 | 17.7k | if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { |
2083 | 0 | cmList linkLibs{ *linkLibsProp }; |
2084 | |
|
2085 | 0 | for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) { |
2086 | 0 | std::string libraryName = *j; |
2087 | 0 | cmTargetLinkLibraryType libType = GENERAL_LibraryType; |
2088 | 0 | if (libraryName == "optimized"_s) { |
2089 | 0 | libType = OPTIMIZED_LibraryType; |
2090 | 0 | ++j; |
2091 | 0 | libraryName = *j; |
2092 | 0 | } else if (libraryName == "debug"_s) { |
2093 | 0 | libType = DEBUG_LibraryType; |
2094 | 0 | ++j; |
2095 | 0 | libraryName = *j; |
2096 | 0 | } |
2097 | | // This is equivalent to the target_link_libraries plain signature. |
2098 | 0 | target.AddLinkLibrary(*this, libraryName, libType); |
2099 | 0 | target.AppendProperty( |
2100 | 0 | "INTERFACE_LINK_LIBRARIES", |
2101 | 0 | target.GetDebugGeneratorExpressions(libraryName, libType)); |
2102 | 0 | } |
2103 | 0 | } |
2104 | 17.7k | } |
2105 | | |
2106 | | void cmMakefile::AddAlias(std::string const& lname, std::string const& tgtName, |
2107 | | bool globallyVisible) |
2108 | 11.8k | { |
2109 | 11.8k | this->AliasTargets[lname] = tgtName; |
2110 | 11.8k | if (globallyVisible) { |
2111 | 11.8k | this->GetGlobalGenerator()->AddAlias(lname, tgtName); |
2112 | 11.8k | } |
2113 | 11.8k | } |
2114 | | |
2115 | | cmTarget* cmMakefile::AddLibrary(std::string const& lname, cm::TargetType type, |
2116 | | std::vector<std::string> const& srcs, |
2117 | | bool excludeFromAll) |
2118 | 23.7k | { |
2119 | 23.7k | assert(type == cm::TargetType::STATIC_LIBRARY || |
2120 | 23.7k | type == cm::TargetType::SHARED_LIBRARY || |
2121 | 23.7k | type == cm::TargetType::MODULE_LIBRARY || |
2122 | 23.7k | type == cm::TargetType::OBJECT_LIBRARY || |
2123 | 23.7k | type == cm::TargetType::INTERFACE_LIBRARY); |
2124 | | |
2125 | 23.7k | cmTarget* target = this->AddNewTarget(type, lname); |
2126 | | // Clear its dependencies. Otherwise, dependencies might persist |
2127 | | // over changes in CMakeLists.txt, making the information stale and |
2128 | | // hence useless. |
2129 | 23.7k | target->ClearDependencyInformation(*this); |
2130 | 23.7k | if (excludeFromAll) { |
2131 | 0 | target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); |
2132 | 0 | } |
2133 | 23.7k | target->AddSources(srcs); |
2134 | 23.7k | this->AddGlobalLinkInformation(*target); |
2135 | 23.7k | return target; |
2136 | 23.7k | } |
2137 | | |
2138 | | cmTarget* cmMakefile::AddExecutable(std::string const& exeName, |
2139 | | std::vector<std::string> const& srcs, |
2140 | | bool excludeFromAll) |
2141 | 5.92k | { |
2142 | 5.92k | cmTarget* target = this->AddNewTarget(cm::TargetType::EXECUTABLE, exeName); |
2143 | 5.92k | if (excludeFromAll) { |
2144 | 0 | target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); |
2145 | 0 | } |
2146 | 5.92k | target->AddSources(srcs); |
2147 | 5.92k | this->AddGlobalLinkInformation(*target); |
2148 | 5.92k | return target; |
2149 | 5.92k | } |
2150 | | |
2151 | | cmTarget* cmMakefile::AddNewTarget(cm::TargetType type, |
2152 | | std::string const& name) |
2153 | 35.5k | { |
2154 | 35.5k | return &this->CreateNewTarget(name, type).first; |
2155 | 35.5k | } |
2156 | | |
2157 | | cmTarget* cmMakefile::AddSynthesizedTarget(cm::TargetType type, |
2158 | | std::string const& name) |
2159 | 0 | { |
2160 | 0 | return &this |
2161 | 0 | ->CreateNewTarget(name, type, cmTarget::PerConfig::Yes, |
2162 | 0 | cmTarget::Visibility::Generated) |
2163 | 0 | .first; |
2164 | 0 | } |
2165 | | |
2166 | | std::pair<cmTarget&, bool> cmMakefile::CreateNewTarget( |
2167 | | std::string const& name, cm::TargetType type, cmTarget::PerConfig perConfig, |
2168 | | cmTarget::Visibility vis) |
2169 | 35.5k | { |
2170 | 35.5k | auto ib = |
2171 | 35.5k | this->Targets.emplace(name, cmTarget(name, type, vis, this, perConfig)); |
2172 | 35.5k | auto it = ib.first; |
2173 | 35.5k | if (!ib.second) { |
2174 | 0 | return std::make_pair(std::ref(it->second), false); |
2175 | 0 | } |
2176 | 35.5k | this->OrderedTargets.push_back(&it->second); |
2177 | 35.5k | this->GetGlobalGenerator()->IndexTarget(&it->second); |
2178 | 35.5k | this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name); |
2179 | 35.5k | return std::make_pair(std::ref(it->second), true); |
2180 | 35.5k | } |
2181 | | |
2182 | | cmTarget* cmMakefile::AddNewUtilityTarget(std::string const& utilityName, |
2183 | | bool excludeFromAll) |
2184 | 5.92k | { |
2185 | 5.92k | cmTarget* target = this->AddNewTarget(cm::TargetType::UTILITY, utilityName); |
2186 | 5.92k | if (excludeFromAll) { |
2187 | 5.92k | target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); |
2188 | 5.92k | } |
2189 | 5.92k | return target; |
2190 | 5.92k | } |
2191 | | |
2192 | | #if !defined(CMAKE_BOOTSTRAP) |
2193 | | |
2194 | | void cmMakefile::ResolveSourceGroupGenex(cmLocalGenerator* lg) |
2195 | 0 | { |
2196 | 0 | for (auto const& sourceGroup : this->SourceGroups) { |
2197 | 0 | sourceGroup->ResolveGenex(lg, {}); |
2198 | 0 | } |
2199 | 0 | } |
2200 | | |
2201 | | cmSourceGroup* cmMakefile::GetSourceGroup( |
2202 | | std::vector<std::string> const& name) const |
2203 | 278k | { |
2204 | 278k | cmSourceGroup* sg = nullptr; |
2205 | | |
2206 | | // first look for source group starting with the same as the one we want |
2207 | 975k | for (auto const& srcGroup : this->SourceGroups) { |
2208 | 975k | std::string const& sgName = srcGroup->GetName(); |
2209 | 975k | if (sgName == name[0]) { |
2210 | 139k | sg = srcGroup.get(); |
2211 | 139k | break; |
2212 | 139k | } |
2213 | 975k | } |
2214 | | |
2215 | 278k | if (sg) { |
2216 | | // iterate through its children to find match source group |
2217 | 139k | for (unsigned int i = 1; i < name.size(); ++i) { |
2218 | 0 | sg = sg->LookupChild(name[i]); |
2219 | 0 | if (!sg) { |
2220 | 0 | break; |
2221 | 0 | } |
2222 | 0 | } |
2223 | 139k | } |
2224 | 278k | return sg; |
2225 | 278k | } |
2226 | | |
2227 | | void cmMakefile::AddSourceGroup(std::string const& name, cm::string_view regex) |
2228 | 139k | { |
2229 | 139k | std::vector<std::string> nameVector; |
2230 | 139k | nameVector.push_back(name); |
2231 | 139k | this->AddSourceGroup(nameVector, regex); |
2232 | 139k | } |
2233 | | |
2234 | | void cmMakefile::AddSourceGroup(std::vector<std::string> const& name, |
2235 | | cm::string_view regex) |
2236 | 139k | { |
2237 | 139k | cmSourceGroup* sg = nullptr; |
2238 | 139k | std::vector<std::string> currentName; |
2239 | 139k | int i = 0; |
2240 | 139k | int const lastElement = static_cast<int>(name.size() - 1); |
2241 | 278k | for (i = lastElement; i >= 0; --i) { |
2242 | 139k | currentName.assign(name.begin(), name.begin() + i + 1); |
2243 | 139k | sg = this->GetSourceGroup(currentName); |
2244 | 139k | if (sg) { |
2245 | 0 | break; |
2246 | 0 | } |
2247 | 139k | } |
2248 | | |
2249 | | // i now contains the index of the last found component |
2250 | 139k | if (i == lastElement) { |
2251 | | // group already exists, replace its regular expression |
2252 | 0 | if (regex.data() && sg) { |
2253 | | // We only want to set the regular expression. If there are already |
2254 | | // source files in the group, we don't want to remove them. |
2255 | 0 | sg->SetGroupRegex(regex); |
2256 | 0 | } |
2257 | 0 | return; |
2258 | 0 | } |
2259 | 139k | if (i == -1) { |
2260 | | // group does not exist nor belong to any existing group |
2261 | | // add its first component |
2262 | 139k | this->SourceGroups.emplace_back( |
2263 | 139k | cm::make_unique<cmSourceGroup>(name[0], regex)); |
2264 | 139k | sg = this->GetSourceGroup(currentName); |
2265 | 139k | i = 0; // last component found |
2266 | 139k | } |
2267 | 139k | if (!sg) { |
2268 | 0 | cmSystemTools::Error("Could not create source group "); |
2269 | 0 | return; |
2270 | 0 | } |
2271 | | // build the whole source group path |
2272 | 139k | for (++i; i <= lastElement; ++i) { |
2273 | 0 | sg->AddChild(cm::make_unique<cmSourceGroup>(name[i], cm::string_view{}, |
2274 | 0 | sg->GetFullName())); |
2275 | 0 | sg = sg->LookupChild(name[i]); |
2276 | 0 | } |
2277 | | |
2278 | 139k | sg->SetGroupRegex(regex); |
2279 | 139k | } |
2280 | | |
2281 | | cmSourceGroup* cmMakefile::GetOrCreateSourceGroup( |
2282 | | std::vector<std::string> const& folders) |
2283 | 0 | { |
2284 | 0 | cmSourceGroup* sg = this->GetSourceGroup(folders); |
2285 | 0 | if (!sg) { |
2286 | 0 | this->AddSourceGroup(folders); |
2287 | 0 | sg = this->GetSourceGroup(folders); |
2288 | 0 | } |
2289 | 0 | return sg; |
2290 | 0 | } |
2291 | | |
2292 | | cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(std::string const& name) |
2293 | 0 | { |
2294 | 0 | auto p = this->GetDefinition("SOURCE_GROUP_DELIMITER"); |
2295 | 0 | return this->GetOrCreateSourceGroup( |
2296 | 0 | cmTokenize(name, p ? cm::string_view(*p) : R"(\/)"_s)); |
2297 | 0 | } |
2298 | | #endif |
2299 | | |
2300 | | bool cmMakefile::IsOn(std::string const& name) const |
2301 | 94.3k | { |
2302 | 94.3k | return this->GetDefinition(name).IsOn(); |
2303 | 94.3k | } |
2304 | | |
2305 | | bool cmMakefile::IsSet(std::string const& name) const |
2306 | 0 | { |
2307 | 0 | cmValue value = this->GetDefinition(name); |
2308 | 0 | if (!value) { |
2309 | 0 | return false; |
2310 | 0 | } |
2311 | | |
2312 | 0 | if (value->empty()) { |
2313 | 0 | return false; |
2314 | 0 | } |
2315 | | |
2316 | 0 | if (cmIsNOTFOUND(*value)) { |
2317 | 0 | return false; |
2318 | 0 | } |
2319 | | |
2320 | 0 | return true; |
2321 | 0 | } |
2322 | | |
2323 | | bool cmMakefile::PlatformIs32Bit() const |
2324 | 0 | { |
2325 | 0 | if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) { |
2326 | 0 | if (*plat_abi == "ELF X32"_s) { |
2327 | 0 | return false; |
2328 | 0 | } |
2329 | 0 | } |
2330 | 0 | if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) { |
2331 | 0 | return atoi(sizeof_dptr->c_str()) == 4; |
2332 | 0 | } |
2333 | 0 | return false; |
2334 | 0 | } |
2335 | | |
2336 | | bool cmMakefile::PlatformIs64Bit() const |
2337 | 0 | { |
2338 | 0 | if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) { |
2339 | 0 | return atoi(sizeof_dptr->c_str()) == 8; |
2340 | 0 | } |
2341 | 0 | return false; |
2342 | 0 | } |
2343 | | |
2344 | | bool cmMakefile::PlatformIsx32() const |
2345 | 0 | { |
2346 | 0 | if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) { |
2347 | 0 | if (*plat_abi == "ELF X32"_s) { |
2348 | 0 | return true; |
2349 | 0 | } |
2350 | 0 | } |
2351 | 0 | return false; |
2352 | 0 | } |
2353 | | |
2354 | | cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const |
2355 | 0 | { |
2356 | 0 | std::string sdkRoot; |
2357 | 0 | sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT"); |
2358 | 0 | sdkRoot = cmSystemTools::LowerCase(sdkRoot); |
2359 | |
|
2360 | 0 | struct |
2361 | 0 | { |
2362 | 0 | std::string name; |
2363 | 0 | AppleSDK sdk; |
2364 | 0 | } const sdkDatabase[]{ |
2365 | 0 | { "appletvos", AppleSDK::AppleTVOS }, |
2366 | 0 | { "appletvsimulator", AppleSDK::AppleTVSimulator }, |
2367 | 0 | { "iphoneos", AppleSDK::IPhoneOS }, |
2368 | 0 | { "iphonesimulator", AppleSDK::IPhoneSimulator }, |
2369 | 0 | { "watchos", AppleSDK::WatchOS }, |
2370 | 0 | { "watchsimulator", AppleSDK::WatchSimulator }, |
2371 | 0 | { "xros", AppleSDK::XROS }, |
2372 | 0 | { "xrsimulator", AppleSDK::XRSimulator }, |
2373 | 0 | }; |
2374 | |
|
2375 | 0 | for (auto const& entry : sdkDatabase) { |
2376 | 0 | if (cmHasPrefix(sdkRoot, entry.name) || |
2377 | 0 | sdkRoot.find(cmStrCat('/', entry.name)) != std::string::npos) { |
2378 | 0 | return entry.sdk; |
2379 | 0 | } |
2380 | 0 | } |
2381 | | |
2382 | 0 | return AppleSDK::MacOS; |
2383 | 0 | } |
2384 | | |
2385 | | bool cmMakefile::PlatformIsAppleEmbedded() const |
2386 | 0 | { |
2387 | 0 | return this->GetAppleSDKType() != AppleSDK::MacOS; |
2388 | 0 | } |
2389 | | |
2390 | | bool cmMakefile::PlatformIsAppleSimulator() const |
2391 | 0 | { |
2392 | 0 | return std::set<AppleSDK>{ |
2393 | 0 | AppleSDK::AppleTVSimulator, |
2394 | 0 | AppleSDK::IPhoneSimulator, |
2395 | 0 | AppleSDK::WatchSimulator, |
2396 | 0 | AppleSDK::XRSimulator, |
2397 | 0 | } |
2398 | 0 | .count(this->GetAppleSDKType()); |
2399 | 0 | } |
2400 | | |
2401 | | bool cmMakefile::PlatformIsAppleCatalyst() const |
2402 | 0 | { |
2403 | 0 | std::string systemName; |
2404 | 0 | systemName = this->GetSafeDefinition("CMAKE_SYSTEM_NAME"); |
2405 | 0 | systemName = cmSystemTools::LowerCase(systemName); |
2406 | 0 | return systemName == "ios" && this->GetAppleSDKType() == AppleSDK::MacOS; |
2407 | 0 | } |
2408 | | |
2409 | | bool cmMakefile::PlatformSupportsAppleTextStubs() const |
2410 | 2.16k | { |
2411 | 2.16k | return this->IsOn("APPLE") && this->IsSet("CMAKE_TAPI"); |
2412 | 2.16k | } |
2413 | | |
2414 | | char const* cmMakefile::GetSONameFlag(std::string const& language) const |
2415 | 0 | { |
2416 | 0 | std::string name = "CMAKE_SHARED_LIBRARY_SONAME"; |
2417 | 0 | if (!language.empty()) { |
2418 | 0 | name += "_"; |
2419 | 0 | name += language; |
2420 | 0 | } |
2421 | 0 | name += "_FLAG"; |
2422 | 0 | return this->GetDefinition(name).GetCStr(); |
2423 | 0 | } |
2424 | | |
2425 | | bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const |
2426 | 5.92k | { |
2427 | 5.92k | if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) { |
2428 | 5.92k | return true; |
2429 | 5.92k | } |
2430 | | // If we are doing an in-source build, then the test will always fail |
2431 | 0 | if (cmSystemTools::SameFile(this->GetHomeDirectory(), |
2432 | 0 | this->GetHomeOutputDirectory())) { |
2433 | 0 | return !this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD"); |
2434 | 0 | } |
2435 | | |
2436 | 0 | return !cmSystemTools::IsSubDirectory(fileName, this->GetHomeDirectory()) || |
2437 | 0 | cmSystemTools::IsSubDirectory(fileName, this->GetHomeOutputDirectory()) || |
2438 | 0 | cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory()); |
2439 | 0 | } |
2440 | | |
2441 | | std::string const& cmMakefile::GetRequiredDefinition( |
2442 | | std::string const& name) const |
2443 | 0 | { |
2444 | 0 | static std::string const empty; |
2445 | 0 | cmValue def = this->GetDefinition(name); |
2446 | 0 | if (!def) { |
2447 | 0 | cmSystemTools::Error("Error required internal CMake variable not " |
2448 | 0 | "set, cmake may not be built correctly.\n" |
2449 | 0 | "Missing variable is:\n" + |
2450 | 0 | name); |
2451 | 0 | return empty; |
2452 | 0 | } |
2453 | 0 | return *def; |
2454 | 0 | } |
2455 | | |
2456 | | bool cmMakefile::IsDefinitionSet(std::string const& name) const |
2457 | 0 | { |
2458 | 0 | cmValue def = this->StateSnapshot.GetDefinition(name); |
2459 | 0 | if (!def) { |
2460 | 0 | def = this->GetState()->GetInitializedCacheValue(name); |
2461 | 0 | } |
2462 | 0 | #ifndef CMAKE_BOOTSTRAP |
2463 | 0 | if (cmVariableWatch* vv = this->GetVariableWatch()) { |
2464 | 0 | if (!def) { |
2465 | 0 | vv->VariableAccessed( |
2466 | 0 | name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this); |
2467 | 0 | } |
2468 | 0 | } |
2469 | 0 | #endif |
2470 | 0 | return def != nullptr; |
2471 | 0 | } |
2472 | | |
2473 | | bool cmMakefile::IsNormalDefinitionSet(std::string const& name) const |
2474 | 5.92k | { |
2475 | 5.92k | cmValue def = this->StateSnapshot.GetDefinition(name); |
2476 | 5.92k | #ifndef CMAKE_BOOTSTRAP |
2477 | 5.92k | if (cmVariableWatch* vv = this->GetVariableWatch()) { |
2478 | 5.92k | if (!def) { |
2479 | 5.92k | vv->VariableAccessed( |
2480 | 5.92k | name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this); |
2481 | 5.92k | } |
2482 | 5.92k | } |
2483 | 5.92k | #endif |
2484 | 5.92k | return def != nullptr; |
2485 | 5.92k | } |
2486 | | |
2487 | | cmValue cmMakefile::GetDefinition(std::string const& name) const |
2488 | 6.40M | { |
2489 | 6.40M | cmValue def = this->StateSnapshot.GetDefinition(name); |
2490 | 6.40M | if (!def) { |
2491 | 5.94M | def = this->GetState()->GetInitializedCacheValue(name); |
2492 | 5.94M | } |
2493 | 6.40M | #ifndef CMAKE_BOOTSTRAP |
2494 | 6.40M | cmVariableWatch* vv = this->GetVariableWatch(); |
2495 | 6.40M | if (vv) { |
2496 | 6.40M | bool const watch_function_executed = |
2497 | 6.40M | vv->VariableAccessed(name, |
2498 | 6.40M | def ? cmVariableWatch::VARIABLE_READ_ACCESS |
2499 | 6.40M | : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS, |
2500 | 6.40M | def.GetCStr(), this); |
2501 | | |
2502 | 6.40M | if (watch_function_executed) { |
2503 | | // A callback was executed and may have caused re-allocation of the |
2504 | | // variable storage. Look it up again for now. |
2505 | | // FIXME: Refactor variable storage to avoid this problem. |
2506 | 0 | def = this->StateSnapshot.GetDefinition(name); |
2507 | 0 | if (!def) { |
2508 | 0 | def = this->GetState()->GetInitializedCacheValue(name); |
2509 | 0 | } |
2510 | 0 | } |
2511 | 6.40M | } |
2512 | 6.40M | #endif |
2513 | 6.40M | return def; |
2514 | 6.40M | } |
2515 | | |
2516 | | std::string const& cmMakefile::GetSafeDefinition(std::string const& name) const |
2517 | 1.22M | { |
2518 | 1.22M | return this->GetDefinition(name); |
2519 | 1.22M | } |
2520 | | |
2521 | | std::vector<std::string> cmMakefile::GetDefinitions() const |
2522 | 0 | { |
2523 | 0 | std::vector<std::string> res = this->StateSnapshot.ClosureKeys(); |
2524 | 0 | cm::append(res, this->GetState()->GetCacheEntryKeys()); |
2525 | 0 | std::sort(res.begin(), res.end()); |
2526 | 0 | return res; |
2527 | 0 | } |
2528 | | |
2529 | | std::string const& cmMakefile::ExpandVariablesInString( |
2530 | | std::string& source) const |
2531 | 0 | { |
2532 | 0 | return this->ExpandVariablesInString(source, false, false); |
2533 | 0 | } |
2534 | | |
2535 | | std::string const& cmMakefile::ExpandVariablesInString( |
2536 | | std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly, |
2537 | | char const* filename, long line, bool removeEmpty, bool replaceAt) const |
2538 | 1.68M | { |
2539 | | // Sanity check the @ONLY mode. |
2540 | 1.68M | if (atOnly && (!noEscapes || !removeEmpty)) { |
2541 | | // This case should never be called. At-only is for |
2542 | | // configure-file/string which always does no escapes. |
2543 | 0 | this->IssueMessage(MessageType::INTERNAL_ERROR, |
2544 | 0 | "ExpandVariablesInString @ONLY called " |
2545 | 0 | "on something with escapes."); |
2546 | 0 | return source; |
2547 | 0 | } |
2548 | | |
2549 | 1.68M | std::string errorstr; |
2550 | 1.68M | MessageType mtype = this->ExpandVariablesInStringImpl( |
2551 | 1.68M | errorstr, source, escapeQuotes, noEscapes, atOnly, filename, line, |
2552 | 1.68M | replaceAt); |
2553 | 1.68M | if (mtype != MessageType::LOG) { |
2554 | 0 | if (mtype == MessageType::FATAL_ERROR) { |
2555 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
2556 | 0 | } |
2557 | 0 | this->IssueMessage(mtype, errorstr); |
2558 | 0 | } |
2559 | | |
2560 | 1.68M | return source; |
2561 | 1.68M | } |
2562 | | |
2563 | | enum t_domain |
2564 | | { |
2565 | | NORMAL, |
2566 | | ENVIRONMENT, |
2567 | | CACHE |
2568 | | }; |
2569 | | |
2570 | | struct t_lookup |
2571 | | { |
2572 | | t_domain domain = NORMAL; |
2573 | | size_t loc = 0; |
2574 | | }; |
2575 | | |
2576 | | bool cmMakefile::IsProjectFile(char const* filename) const |
2577 | 0 | { |
2578 | 0 | std::string const& cmakeRoot = cmSystemTools::GetCMakeRoot(); |
2579 | 0 | if (cmSystemTools::IsSubDirectory(filename, cmakeRoot) && |
2580 | 0 | (cmSystemTools::IsSubDirectory(cmakeRoot, this->GetHomeDirectory()) || |
2581 | 0 | cmSystemTools::IsSubDirectory(cmakeRoot, |
2582 | 0 | this->GetHomeOutputDirectory()))) { |
2583 | 0 | return false; |
2584 | 0 | } |
2585 | 0 | return cmSystemTools::IsSubDirectory(filename, this->GetHomeDirectory()) || |
2586 | 0 | (cmSystemTools::IsSubDirectory(filename, this->GetHomeOutputDirectory()) && |
2587 | 0 | !cmSystemTools::IsSubDirectory(filename, "/CMakeFiles")); |
2588 | 0 | } |
2589 | | |
2590 | | size_t cmMakefile::GetRecursionDepthLimit() const |
2591 | 403k | { |
2592 | 403k | size_t depth = CMake_DEFAULT_RECURSION_LIMIT; |
2593 | 403k | if (cmValue depthStr = |
2594 | 403k | this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH")) { |
2595 | 0 | unsigned long depthUL; |
2596 | 0 | if (cmStrToULong(depthStr.GetCStr(), &depthUL)) { |
2597 | 0 | depth = depthUL; |
2598 | 0 | } |
2599 | 403k | } else if (cm::optional<std::string> depthEnv = |
2600 | 403k | cmSystemTools::GetEnvVar("CMAKE_MAXIMUM_RECURSION_DEPTH")) { |
2601 | 0 | unsigned long depthUL; |
2602 | 0 | if (cmStrToULong(*depthEnv, &depthUL)) { |
2603 | 0 | depth = depthUL; |
2604 | 0 | } |
2605 | 0 | } |
2606 | 403k | return depth; |
2607 | 403k | } |
2608 | | |
2609 | | size_t cmMakefile::GetRecursionDepth() const |
2610 | 0 | { |
2611 | 0 | return this->RecursionDepth; |
2612 | 0 | } |
2613 | | |
2614 | | void cmMakefile::SetRecursionDepth(size_t recursionDepth) |
2615 | 0 | { |
2616 | 0 | this->RecursionDepth = recursionDepth; |
2617 | 0 | } |
2618 | | |
2619 | | std::string cmMakefile::NewDeferId() const |
2620 | 0 | { |
2621 | 0 | return this->GetGlobalGenerator()->NewDeferId(); |
2622 | 0 | } |
2623 | | |
2624 | | bool cmMakefile::DeferCall(std::string id, std::string file, |
2625 | | cmListFileFunction lff) |
2626 | 0 | { |
2627 | 0 | if (!this->Defer) { |
2628 | 0 | return false; |
2629 | 0 | } |
2630 | 0 | this->Defer->Commands.emplace_back( |
2631 | 0 | DeferCommand{ std::move(id), std::move(file), std::move(lff) }); |
2632 | 0 | return true; |
2633 | 0 | } |
2634 | | |
2635 | | bool cmMakefile::DeferCancelCall(std::string const& id) |
2636 | 0 | { |
2637 | 0 | if (!this->Defer) { |
2638 | 0 | return false; |
2639 | 0 | } |
2640 | 0 | for (DeferCommand& dc : this->Defer->Commands) { |
2641 | 0 | if (dc.Id == id) { |
2642 | 0 | dc.Id.clear(); |
2643 | 0 | } |
2644 | 0 | } |
2645 | 0 | return true; |
2646 | 0 | } |
2647 | | |
2648 | | cm::optional<std::string> cmMakefile::DeferGetCallIds() const |
2649 | 0 | { |
2650 | 0 | cm::optional<std::string> ids; |
2651 | 0 | if (this->Defer) { |
2652 | 0 | ids = cmList::to_string( |
2653 | 0 | cmMakeRange(this->Defer->Commands) |
2654 | 0 | .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); }) |
2655 | 0 | .transform( |
2656 | 0 | [](DeferCommand const& dc) -> std::string const& { return dc.Id; })); |
2657 | 0 | } |
2658 | 0 | return ids; |
2659 | 0 | } |
2660 | | |
2661 | | cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const |
2662 | 0 | { |
2663 | 0 | cm::optional<std::string> call; |
2664 | 0 | if (this->Defer) { |
2665 | 0 | std::string tmp; |
2666 | 0 | for (DeferCommand const& dc : this->Defer->Commands) { |
2667 | 0 | if (dc.Id == id) { |
2668 | 0 | tmp = dc.Command.OriginalName(); |
2669 | 0 | for (cmListFileArgument const& arg : dc.Command.Arguments()) { |
2670 | 0 | tmp = cmStrCat(std::move(tmp), ';', arg.Value); |
2671 | 0 | } |
2672 | 0 | break; |
2673 | 0 | } |
2674 | 0 | } |
2675 | 0 | call = std::move(tmp); |
2676 | 0 | } |
2677 | 0 | return call; |
2678 | 0 | } |
2679 | | |
2680 | | namespace { |
2681 | | cmPolicies::PolicyStatus CheckCMP0219Impl(cmPolicies::PolicyStatus status, |
2682 | | std::string const& calleeName, |
2683 | | bool hasBackslashes, |
2684 | | std::set<std::string>& warned) |
2685 | 0 | { |
2686 | 0 | if (status == cmPolicies::WARN && hasBackslashes && |
2687 | 0 | warned.insert(calleeName).second) { |
2688 | 0 | return cmPolicies::WARN; |
2689 | 0 | } |
2690 | | // Suppress WARN when there are no backslashes or already warned. |
2691 | 0 | return status == cmPolicies::NEW ? cmPolicies::NEW : cmPolicies::OLD; |
2692 | 0 | } |
2693 | | } |
2694 | | |
2695 | | cmPolicies::PolicyStatus cmMakefile::CheckCMP0219( |
2696 | | std::string const& calleeName, std::vector<std::string> const& args) |
2697 | 0 | { |
2698 | 0 | bool const hasBackslashes = |
2699 | 0 | std::any_of(args.begin(), args.end(), [](std::string const& s) { |
2700 | 0 | return s.find('\\') != std::string::npos; |
2701 | 0 | }); |
2702 | 0 | return CheckCMP0219Impl(GetPolicyStatus(cmPolicies::CMP0219), calleeName, |
2703 | 0 | hasBackslashes, WarnedCMP0219); |
2704 | 0 | } |
2705 | | |
2706 | | cmPolicies::PolicyStatus cmMakefile::CheckCMP0219( |
2707 | | std::string const& calleeName, std::vector<cmListFileArgument> const& args) |
2708 | 0 | { |
2709 | 0 | bool const hasBackslashes = |
2710 | 0 | std::any_of(args.begin(), args.end(), [](cmListFileArgument const& s) { |
2711 | 0 | return s.Value.find('\\') != std::string::npos; |
2712 | 0 | }); |
2713 | 0 | return CheckCMP0219Impl(GetPolicyStatus(cmPolicies::CMP0219), calleeName, |
2714 | 0 | hasBackslashes, WarnedCMP0219); |
2715 | 0 | } |
2716 | | |
2717 | | void cmMakefile::IssueCMP0219Warning( |
2718 | | std::string const& calleeName, std::vector<std::string> const& args) const |
2719 | 0 | { |
2720 | 0 | std::string oldArgs; |
2721 | 0 | for (std::string const& arg : args) { |
2722 | 0 | if (arg.find('\\') == std::string::npos) { |
2723 | 0 | continue; |
2724 | 0 | } |
2725 | 0 | if (!oldArgs.empty()) { |
2726 | 0 | oldArgs += '\n'; |
2727 | 0 | } |
2728 | 0 | oldArgs = cmStrCat(std::move(oldArgs), " \"", arg, '"'); |
2729 | 0 | } |
2730 | |
|
2731 | 0 | std::string newArgs = oldArgs; |
2732 | 0 | cmSystemTools::ReplaceString(newArgs, "\\", "\\\\"); |
2733 | |
|
2734 | 0 | this->IssueDiagnostic( |
2735 | 0 | cmDiagnostics::CMD_POLICY, |
2736 | 0 | cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0219), |
2737 | 0 | "\n" |
2738 | 0 | "Command \"", |
2739 | 0 | calleeName, |
2740 | 0 | "\" called with arguments containing backslashes.\n" |
2741 | 0 | "Since the policy is not set, backslashes in the arguments:\n", |
2742 | 0 | oldArgs, |
2743 | 0 | "\n" |
2744 | 0 | "will be interpreted as escape sequences for compatibility.\n" |
2745 | 0 | "Set the policy to NEW to instead pass\n", |
2746 | 0 | newArgs, |
2747 | 0 | "\n" |
2748 | 0 | "so that argument parsing will preserve the original values.")); |
2749 | 0 | } |
2750 | | |
2751 | | void cmMakefile::IssueCMP0219Warning( |
2752 | | std::string const& calleeName, |
2753 | | std::vector<cmListFileArgument> const& args) const |
2754 | 0 | { |
2755 | 0 | std::vector<std::string> stringArgs; |
2756 | 0 | stringArgs.reserve(args.size()); |
2757 | 0 | for (cmListFileArgument const& arg : args) { |
2758 | 0 | stringArgs.push_back(arg.Value); |
2759 | 0 | } |
2760 | 0 | this->IssueCMP0219Warning(calleeName, stringArgs); |
2761 | 0 | } |
2762 | | |
2763 | | MessageType cmMakefile::ExpandVariablesInStringImpl( |
2764 | | std::string& errorstr, std::string& source, bool escapeQuotes, |
2765 | | bool noEscapes, bool atOnly, char const* filename, long line, |
2766 | | bool replaceAt) const |
2767 | 1.68M | { |
2768 | | // This method replaces ${VAR} and @VAR@ where VAR is looked up |
2769 | | // with GetDefinition(), if not found in the map, nothing is expanded. |
2770 | | // It also supports the $ENV{VAR} syntax where VAR is looked up in |
2771 | | // the current environment variables. |
2772 | | |
2773 | 1.68M | char const* in = source.c_str(); |
2774 | 1.68M | char const* last = in; |
2775 | 1.68M | std::string result; |
2776 | 1.68M | result.reserve(source.size()); |
2777 | 1.68M | std::vector<t_lookup> openstack; |
2778 | 1.68M | bool error = false; |
2779 | 1.68M | bool done = false; |
2780 | 1.68M | MessageType mtype = MessageType::LOG; |
2781 | | |
2782 | 1.68M | cmState* state = this->GetCMakeInstance()->GetState(); |
2783 | | |
2784 | 1.68M | static std::string const lineVar = "CMAKE_CURRENT_LIST_LINE"; |
2785 | 21.1M | do { |
2786 | 21.1M | char inc = *in; |
2787 | 21.1M | switch (inc) { |
2788 | 100k | case '}': |
2789 | 100k | if (!openstack.empty()) { |
2790 | 100k | t_lookup var = openstack.back(); |
2791 | 100k | openstack.pop_back(); |
2792 | 100k | result.append(last, in - last); |
2793 | 100k | std::string const& lookup = result.substr(var.loc); |
2794 | 100k | cmValue value = nullptr; |
2795 | 100k | std::string varresult; |
2796 | 100k | std::string svalue; |
2797 | 100k | switch (var.domain) { |
2798 | 100k | case NORMAL: |
2799 | 100k | if (filename && lookup == lineVar) { |
2800 | 0 | cmListFileContext const& top = this->Backtrace.Top(); |
2801 | 0 | if (top.DeferId) { |
2802 | 0 | varresult = cmStrCat("DEFERRED:"_s, *top.DeferId); |
2803 | 0 | } else { |
2804 | 0 | varresult = std::to_string(line); |
2805 | 0 | } |
2806 | 100k | } else { |
2807 | 100k | value = this->GetDefinition(lookup); |
2808 | 100k | } |
2809 | 100k | break; |
2810 | 0 | case ENVIRONMENT: |
2811 | 0 | if (cmSystemTools::GetEnv(lookup, svalue)) { |
2812 | 0 | value = cmValue(svalue); |
2813 | 0 | } |
2814 | 0 | break; |
2815 | 0 | case CACHE: |
2816 | 0 | value = state->GetCacheEntryValue(lookup); |
2817 | 0 | break; |
2818 | 100k | } |
2819 | | // Get the string we're meant to append to. |
2820 | 100k | if (value) { |
2821 | 100k | if (escapeQuotes) { |
2822 | 0 | varresult = cmEscapeQuotes(*value); |
2823 | 100k | } else { |
2824 | 100k | varresult = *value; |
2825 | 100k | } |
2826 | 100k | } else { |
2827 | 0 | this->MaybeWarnUninitialized(lookup, filename); |
2828 | 0 | } |
2829 | 100k | result.replace(var.loc, result.size() - var.loc, varresult); |
2830 | | // Start looking from here on out. |
2831 | 100k | last = in + 1; |
2832 | 100k | } |
2833 | 100k | break; |
2834 | 201k | case '$': |
2835 | 201k | if (!atOnly) { |
2836 | 201k | t_lookup lookup; |
2837 | 201k | char const* next = in + 1; |
2838 | 201k | char const* start = nullptr; |
2839 | 201k | char nextc = *next; |
2840 | 201k | if (nextc == '{') { |
2841 | | // Looking for a variable. |
2842 | 100k | start = in + 2; |
2843 | 100k | lookup.domain = NORMAL; |
2844 | 100k | } else if (nextc == '<') { |
2845 | 100k | } else if (!nextc) { |
2846 | 0 | result.append(last, next - last); |
2847 | 0 | last = next; |
2848 | 0 | } else if (cmHasLiteralPrefix(next, "ENV{")) { |
2849 | | // Looking for an environment variable. |
2850 | 0 | start = in + 5; |
2851 | 0 | lookup.domain = ENVIRONMENT; |
2852 | 0 | } else if (cmHasLiteralPrefix(next, "CACHE{")) { |
2853 | | // Looking for a cache variable. |
2854 | 0 | start = in + 7; |
2855 | 0 | lookup.domain = CACHE; |
2856 | 0 | } else { |
2857 | 0 | if (this->cmNamedCurly.find(next)) { |
2858 | 0 | errorstr = cmStrCat("Syntax $", |
2859 | 0 | std::string(next, this->cmNamedCurly.end()), |
2860 | 0 | "{} is not supported. Only ${}, $ENV{}, " |
2861 | 0 | "and $CACHE{} are allowed."); |
2862 | 0 | mtype = MessageType::FATAL_ERROR; |
2863 | 0 | error = true; |
2864 | 0 | } |
2865 | 0 | } |
2866 | 201k | if (start) { |
2867 | 100k | result.append(last, in - last); |
2868 | 100k | last = start; |
2869 | 100k | in = start - 1; |
2870 | 100k | lookup.loc = result.size(); |
2871 | 100k | openstack.push_back(lookup); |
2872 | 100k | } |
2873 | 201k | break; |
2874 | 201k | } |
2875 | 0 | CM_FALLTHROUGH; |
2876 | 0 | case '\\': |
2877 | 0 | if (!noEscapes) { |
2878 | 0 | char const* next = in + 1; |
2879 | 0 | char nextc = *next; |
2880 | 0 | if (nextc == 't') { |
2881 | 0 | result.append(last, in - last); |
2882 | 0 | result.push_back('\t'); |
2883 | 0 | last = next + 1; |
2884 | 0 | } else if (nextc == 'n') { |
2885 | 0 | result.append(last, in - last); |
2886 | 0 | result.push_back('\n'); |
2887 | 0 | last = next + 1; |
2888 | 0 | } else if (nextc == 'r') { |
2889 | 0 | result.append(last, in - last); |
2890 | 0 | result.push_back('\r'); |
2891 | 0 | last = next + 1; |
2892 | 0 | } else if (nextc == ';' && openstack.empty()) { |
2893 | | // Handled in ExpandListArgument; pass the backslash literally. |
2894 | 0 | } else if (cmsysString_isalnum(nextc) || nextc == '\0') { |
2895 | 0 | errorstr += "Invalid character escape '\\"; |
2896 | 0 | if (nextc) { |
2897 | 0 | errorstr += nextc; |
2898 | 0 | errorstr += "'."; |
2899 | 0 | } else { |
2900 | 0 | errorstr += "' (at end of input)."; |
2901 | 0 | } |
2902 | 0 | error = true; |
2903 | 0 | } else { |
2904 | | // Take what we've found so far, skipping the escape character. |
2905 | 0 | result.append(last, in - last); |
2906 | | // Start tracking from the next character. |
2907 | 0 | last = in + 1; |
2908 | 0 | } |
2909 | | // Skip the next character since it was escaped, but don't read past |
2910 | | // the end of the string. |
2911 | 0 | if (*last) { |
2912 | 0 | ++in; |
2913 | 0 | } |
2914 | 0 | } |
2915 | 0 | break; |
2916 | 0 | case '\n': |
2917 | | // Onto the next line. |
2918 | 0 | ++line; |
2919 | 0 | break; |
2920 | 5.92k | case '\0': |
2921 | 5.92k | done = true; |
2922 | 5.92k | break; |
2923 | 0 | case '@': |
2924 | 0 | if (replaceAt) { |
2925 | 0 | char const* nextAt = strchr(in + 1, '@'); |
2926 | 0 | if (nextAt && nextAt != in + 1 && |
2927 | 0 | nextAt == |
2928 | 0 | in + 1 + |
2929 | 0 | std::strspn(in + 1, |
2930 | 0 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
2931 | 0 | "abcdefghijklmnopqrstuvwxyz" |
2932 | 0 | "0123456789/_.+-")) { |
2933 | 0 | std::string variable(in + 1, nextAt - in - 1); |
2934 | |
|
2935 | 0 | std::string varresult; |
2936 | 0 | if (filename && variable == lineVar) { |
2937 | 0 | varresult = std::to_string(line); |
2938 | 0 | } else { |
2939 | 0 | cmValue def = this->GetDefinition(variable); |
2940 | 0 | if (def) { |
2941 | 0 | varresult = *def; |
2942 | 0 | } else { |
2943 | 0 | this->MaybeWarnUninitialized(variable, filename); |
2944 | 0 | } |
2945 | 0 | } |
2946 | |
|
2947 | 0 | if (escapeQuotes) { |
2948 | 0 | varresult = cmEscapeQuotes(varresult); |
2949 | 0 | } |
2950 | | // Skip over the variable. |
2951 | 0 | result.append(last, in - last); |
2952 | 0 | result.append(varresult); |
2953 | 0 | in = nextAt; |
2954 | 0 | last = in + 1; |
2955 | 0 | break; |
2956 | 0 | } |
2957 | 0 | } |
2958 | | // Failed to find a valid @ expansion; treat it as literal. |
2959 | 0 | CM_FALLTHROUGH; |
2960 | 20.8M | default: { |
2961 | 20.8M | if (!openstack.empty() && |
2962 | 758k | !(cmsysString_isalnum(inc) || inc == '_' || inc == '/' || |
2963 | 0 | inc == '.' || inc == '+' || inc == '-')) { |
2964 | 0 | errorstr = |
2965 | 0 | cmStrCat(std::move(errorstr), "Invalid character ('", inc); |
2966 | 0 | result.append(last, in - last); |
2967 | 0 | errorstr = cmStrCat(std::move(errorstr), "') in a variable name: '", |
2968 | 0 | result.substr(openstack.back().loc), '\''); |
2969 | 0 | mtype = MessageType::FATAL_ERROR; |
2970 | 0 | error = true; |
2971 | 0 | } |
2972 | 20.8M | break; |
2973 | 0 | } |
2974 | 21.1M | } |
2975 | | // Look at the next character. |
2976 | 21.1M | } while (!error && !done && *++in); |
2977 | | |
2978 | | // Check for open variable references yet. |
2979 | 1.68M | if (!error && !openstack.empty()) { |
2980 | 0 | errorstr += "There is an unterminated variable reference."; |
2981 | 0 | error = true; |
2982 | 0 | } |
2983 | | |
2984 | 1.68M | if (error) { |
2985 | 0 | std::string e = "Syntax error in cmake code "; |
2986 | 0 | if (filename) { |
2987 | | // This filename and line number may be more specific than the |
2988 | | // command context because one command invocation can have |
2989 | | // arguments on multiple lines. |
2990 | 0 | e = cmStrCat(std::move(e), "at\n ", filename, ':', line, '\n'); |
2991 | 0 | } |
2992 | 0 | errorstr = cmStrCat(e, "when parsing string\n ", source, '\n', |
2993 | 0 | std::move(errorstr)); |
2994 | 0 | mtype = MessageType::FATAL_ERROR; |
2995 | 1.68M | } else { |
2996 | | // Append the rest of the unchanged part of the string. |
2997 | 1.68M | result.append(last); |
2998 | | |
2999 | 1.68M | source = result; |
3000 | 1.68M | } |
3001 | | |
3002 | 1.68M | return mtype; |
3003 | 1.68M | } |
3004 | | |
3005 | | void cmMakefile::RemoveVariablesInString(std::string& source, |
3006 | | bool atOnly) const |
3007 | 0 | { |
3008 | 0 | if (!atOnly) { |
3009 | 0 | cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})"); |
3010 | 0 | while (var.find(source)) { |
3011 | 0 | source.erase(var.start(), var.end() - var.start()); |
3012 | 0 | } |
3013 | 0 | } |
3014 | |
|
3015 | 0 | if (!atOnly) { |
3016 | 0 | cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})"); |
3017 | 0 | while (varb.find(source)) { |
3018 | 0 | source.erase(varb.start(), varb.end() - varb.start()); |
3019 | 0 | } |
3020 | 0 | } |
3021 | 0 | cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)"); |
3022 | 0 | while (var2.find(source)) { |
3023 | 0 | source.erase(var2.start(), var2.end() - var2.start()); |
3024 | 0 | } |
3025 | 0 | } |
3026 | | |
3027 | | void cmMakefile::InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault) |
3028 | 0 | { |
3029 | 0 | if (this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { |
3030 | 0 | return; |
3031 | 0 | } |
3032 | 0 | std::string initConfigs; |
3033 | 0 | if (this->GetCMakeInstance()->GetIsInTryCompile() || |
3034 | 0 | !cmSystemTools::GetEnv("CMAKE_CONFIGURATION_TYPES", initConfigs)) { |
3035 | 0 | initConfigs = genDefault; |
3036 | 0 | } |
3037 | 0 | this->AddCacheDefinition( |
3038 | 0 | "CMAKE_CONFIGURATION_TYPES", initConfigs, |
3039 | 0 | "Semicolon separated list of supported configuration types, " |
3040 | 0 | "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, " |
3041 | 0 | "anything else will be ignored.", |
3042 | 0 | cmStateEnums::STRING); |
3043 | 0 | } |
3044 | | |
3045 | | std::string cmMakefile::GetDefaultConfiguration() const |
3046 | 0 | { |
3047 | 0 | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
3048 | 0 | return std::string{}; |
3049 | 0 | } |
3050 | 0 | return this->GetSafeDefinition("CMAKE_BUILD_TYPE"); |
3051 | 0 | } |
3052 | | |
3053 | | std::vector<std::string> cmMakefile::GetGeneratorConfigs( |
3054 | | GeneratorConfigQuery mode) const |
3055 | 138k | { |
3056 | 138k | cmList configs; |
3057 | 138k | if (this->GetGlobalGenerator()->IsMultiConfig()) { |
3058 | 0 | configs.assign(this->GetDefinition("CMAKE_CONFIGURATION_TYPES")); |
3059 | 138k | } else if (mode != cmMakefile::OnlyMultiConfig) { |
3060 | 138k | std::string const& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); |
3061 | 138k | if (!buildType.empty()) { |
3062 | 106k | configs.emplace_back(buildType); |
3063 | 106k | } |
3064 | 138k | } |
3065 | 138k | if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) { |
3066 | 0 | configs.emplace_back(); |
3067 | 0 | } |
3068 | 138k | return std::move(configs.data()); |
3069 | 138k | } |
3070 | | |
3071 | | bool cmMakefile::IsFunctionBlocked(cmListFileFunction const& lff, |
3072 | | cmExecutionStatus& status) |
3073 | 450k | { |
3074 | | // if there are no blockers get out of here |
3075 | 450k | if (this->FunctionBlockers.empty()) { |
3076 | 403k | return false; |
3077 | 403k | } |
3078 | | |
3079 | 47.4k | return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status); |
3080 | 450k | } |
3081 | | |
3082 | | void cmMakefile::PushFunctionBlockerBarrier() |
3083 | 11.8k | { |
3084 | 11.8k | this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size()); |
3085 | 11.8k | } |
3086 | | |
3087 | | void cmMakefile::PopFunctionBlockerBarrier(bool reportError) |
3088 | 11.8k | { |
3089 | | // Remove any extra entries pushed on the barrier. |
3090 | 11.8k | FunctionBlockersType::size_type barrier = |
3091 | 11.8k | this->FunctionBlockerBarriers.back(); |
3092 | 11.8k | while (this->FunctionBlockers.size() > barrier) { |
3093 | 0 | std::unique_ptr<cmFunctionBlocker> fb( |
3094 | 0 | std::move(this->FunctionBlockers.top())); |
3095 | 0 | this->FunctionBlockers.pop(); |
3096 | 0 | if (reportError) { |
3097 | | // Report the context in which the unclosed block was opened. |
3098 | 0 | cmListFileContext const& lfc = fb->GetStartingContext(); |
3099 | 0 | std::ostringstream e; |
3100 | | /* clang-format off */ |
3101 | 0 | e << "A logical block opening on the line\n" |
3102 | 0 | " " << lfc << "\n" |
3103 | 0 | "is not closed."; |
3104 | | /* clang-format on */ |
3105 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
3106 | 0 | reportError = false; |
3107 | 0 | } |
3108 | 0 | } |
3109 | | |
3110 | | // Remove the barrier. |
3111 | 11.8k | this->FunctionBlockerBarriers.pop_back(); |
3112 | 11.8k | } |
3113 | | |
3114 | | void cmMakefile::PushLoopBlock() |
3115 | 5.92k | { |
3116 | 5.92k | assert(!this->LoopBlockCounter.empty()); |
3117 | 5.92k | this->LoopBlockCounter.top()++; |
3118 | 5.92k | } |
3119 | | |
3120 | | void cmMakefile::PopLoopBlock() |
3121 | 5.92k | { |
3122 | 5.92k | assert(!this->LoopBlockCounter.empty()); |
3123 | 5.92k | assert(this->LoopBlockCounter.top() > 0); |
3124 | 5.92k | this->LoopBlockCounter.top()--; |
3125 | 5.92k | } |
3126 | | |
3127 | | void cmMakefile::PushLoopBlockBarrier() |
3128 | 19.8k | { |
3129 | 19.8k | this->LoopBlockCounter.push(0); |
3130 | 19.8k | } |
3131 | | |
3132 | | void cmMakefile::PopLoopBlockBarrier() |
3133 | 0 | { |
3134 | 0 | assert(!this->LoopBlockCounter.empty()); |
3135 | 0 | assert(this->LoopBlockCounter.top() == 0); |
3136 | 0 | this->LoopBlockCounter.pop(); |
3137 | 0 | } |
3138 | | |
3139 | | bool cmMakefile::IsLoopBlock() const |
3140 | 0 | { |
3141 | 0 | assert(!this->LoopBlockCounter.empty()); |
3142 | 0 | return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0; |
3143 | 0 | } |
3144 | | |
3145 | | bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs, |
3146 | | std::vector<std::string>& outArgs) const |
3147 | 408k | { |
3148 | 408k | std::string const& filename = this->GetBacktrace().Top().FilePath; |
3149 | 408k | std::string value; |
3150 | 408k | outArgs.reserve(inArgs.size()); |
3151 | 1.68M | for (cmListFileArgument const& i : inArgs) { |
3152 | | // No expansion in a bracket argument. |
3153 | 1.68M | if (i.Delim == cmListFileArgument::Bracket) { |
3154 | 0 | outArgs.push_back(i.Value); |
3155 | 0 | continue; |
3156 | 0 | } |
3157 | | // Expand the variables in the argument. |
3158 | 1.68M | value = i.Value; |
3159 | 1.68M | this->ExpandVariablesInString(value, false, false, false, filename.c_str(), |
3160 | 1.68M | i.Line, false, false); |
3161 | | |
3162 | | // If the argument is quoted, it should be one argument. |
3163 | | // Otherwise, it may be a list of arguments. |
3164 | 1.68M | if (i.Delim == cmListFileArgument::Quoted) { |
3165 | 35.5k | outArgs.push_back(value); |
3166 | 1.64M | } else { |
3167 | 1.64M | cmExpandList(value, outArgs); |
3168 | 1.64M | } |
3169 | 1.68M | } |
3170 | 408k | return !cmSystemTools::GetFatalErrorOccurred(); |
3171 | 408k | } |
3172 | | |
3173 | | bool cmMakefile::ExpandArguments( |
3174 | | std::vector<cmListFileArgument> const& inArgs, |
3175 | | std::vector<cmExpandedCommandArgument>& outArgs) const |
3176 | 0 | { |
3177 | 0 | std::string const& filename = this->GetBacktrace().Top().FilePath; |
3178 | 0 | std::string value; |
3179 | 0 | outArgs.reserve(inArgs.size()); |
3180 | 0 | for (cmListFileArgument const& i : inArgs) { |
3181 | | // No expansion in a bracket argument. |
3182 | 0 | if (i.Delim == cmListFileArgument::Bracket) { |
3183 | 0 | outArgs.emplace_back(i.Value, true); |
3184 | 0 | continue; |
3185 | 0 | } |
3186 | | // Expand the variables in the argument. |
3187 | 0 | value = i.Value; |
3188 | 0 | this->ExpandVariablesInString(value, false, false, false, filename.c_str(), |
3189 | 0 | i.Line, false, false); |
3190 | | |
3191 | | // If the argument is quoted, it should be one argument. |
3192 | | // Otherwise, it may be a list of arguments. |
3193 | 0 | if (i.Delim == cmListFileArgument::Quoted) { |
3194 | 0 | outArgs.emplace_back(value, true); |
3195 | 0 | } else { |
3196 | 0 | cmList stringArgs{ value }; |
3197 | 0 | for (std::string const& stringArg : stringArgs) { |
3198 | 0 | outArgs.emplace_back(stringArg, false); |
3199 | 0 | } |
3200 | 0 | } |
3201 | 0 | } |
3202 | 0 | return !cmSystemTools::GetFatalErrorOccurred(); |
3203 | 0 | } |
3204 | | |
3205 | | void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb) |
3206 | 5.92k | { |
3207 | 5.92k | if (!this->ExecutionStatusStack.empty()) { |
3208 | | // Record the context in which the blocker is created. |
3209 | 5.92k | fb->SetStartingContext(this->Backtrace.Top()); |
3210 | 5.92k | } |
3211 | | |
3212 | 5.92k | this->FunctionBlockers.push(std::move(fb)); |
3213 | 5.92k | } |
3214 | | |
3215 | | std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker() |
3216 | 5.92k | { |
3217 | 5.92k | assert(!this->FunctionBlockers.empty()); |
3218 | 5.92k | assert(this->FunctionBlockerBarriers.empty() || |
3219 | 5.92k | this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back()); |
3220 | | |
3221 | 5.92k | auto b = std::move(this->FunctionBlockers.top()); |
3222 | 5.92k | this->FunctionBlockers.pop(); |
3223 | 5.92k | return b; |
3224 | 5.92k | } |
3225 | | |
3226 | | std::string const& cmMakefile::GetHomeDirectory() const |
3227 | 0 | { |
3228 | 0 | return this->GetCMakeInstance()->GetHomeDirectory(); |
3229 | 0 | } |
3230 | | |
3231 | | std::string const& cmMakefile::GetHomeOutputDirectory() const |
3232 | 0 | { |
3233 | 0 | return this->GetCMakeInstance()->GetHomeOutputDirectory(); |
3234 | 0 | } |
3235 | | |
3236 | | void cmMakefile::SetScriptModeFile(std::string const& scriptfile) |
3237 | 1 | { |
3238 | 1 | this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile); |
3239 | 1 | } |
3240 | | |
3241 | | void cmMakefile::SetArgcArgv(std::vector<std::string> const& args) |
3242 | 1 | { |
3243 | 1 | this->AddDefinition("CMAKE_ARGC", std::to_string(args.size())); |
3244 | | |
3245 | 4 | for (auto i = 0u; i < args.size(); ++i) { |
3246 | 3 | this->AddDefinition(cmStrCat("CMAKE_ARGV", i), args[i]); |
3247 | 3 | } |
3248 | 1 | } |
3249 | | |
3250 | | cmSourceFile* cmMakefile::GetSource(std::string const& sourceName, |
3251 | | cmSourceFileLocationKind kind) const |
3252 | 107k | { |
3253 | | // First check "Known" paths (avoids the creation of cmSourceFileLocation) |
3254 | 107k | if (kind == cmSourceFileLocationKind::Known) { |
3255 | 73.0k | auto sfsi = this->KnownFileSearchIndex.find(sourceName); |
3256 | 73.0k | if (sfsi != this->KnownFileSearchIndex.end()) { |
3257 | 6.69k | return sfsi->second; |
3258 | 6.69k | } |
3259 | 73.0k | } |
3260 | | |
3261 | 100k | cmSourceFileLocation sfl(this, sourceName, kind); |
3262 | 100k | auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); |
3263 | | #if defined(_WIN32) || defined(__APPLE__) |
3264 | | name = cmSystemTools::LowerCase(name); |
3265 | | #endif |
3266 | 100k | auto sfsi = this->SourceFileSearchIndex.find(name); |
3267 | 100k | if (sfsi != this->SourceFileSearchIndex.end()) { |
3268 | 34.0k | for (auto* sf : sfsi->second) { |
3269 | 34.0k | if (sf->Matches(sfl)) { |
3270 | 20.6k | return sf; |
3271 | 20.6k | } |
3272 | 34.0k | } |
3273 | 27.1k | } |
3274 | 80.3k | return nullptr; |
3275 | 100k | } |
3276 | | |
3277 | | cmSourceFile* cmMakefile::CreateSource(std::string const& sourceName, |
3278 | | bool generated, |
3279 | | cmSourceFileLocationKind kind) |
3280 | 24.0k | { |
3281 | 24.0k | auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind); |
3282 | 24.0k | auto name = |
3283 | 24.0k | this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName()); |
3284 | | #if defined(_WIN32) || defined(__APPLE__) |
3285 | | name = cmSystemTools::LowerCase(name); |
3286 | | #endif |
3287 | 24.0k | this->SourceFileSearchIndex[name].push_back(sf.get()); |
3288 | | // for "Known" paths add direct lookup (used for faster lookup in GetSource) |
3289 | 24.0k | if (kind == cmSourceFileLocationKind::Known) { |
3290 | 12.2k | this->KnownFileSearchIndex[sourceName] = sf.get(); |
3291 | 12.2k | } |
3292 | | |
3293 | 24.0k | this->SourceFiles.push_back(std::move(sf)); |
3294 | | |
3295 | 24.0k | return this->SourceFiles.back().get(); |
3296 | 24.0k | } |
3297 | | |
3298 | | cmSourceFile* cmMakefile::GetOrCreateSource(std::string const& sourceName, |
3299 | | bool generated, |
3300 | | cmSourceFileLocationKind kind) |
3301 | 45.2k | { |
3302 | 45.2k | if (cmSourceFile* esf = this->GetSource(sourceName, kind)) { |
3303 | 27.0k | return esf; |
3304 | 27.0k | } |
3305 | 18.1k | return this->CreateSource(sourceName, generated, kind); |
3306 | 45.2k | } |
3307 | | |
3308 | | cmSourceFile* cmMakefile::GetOrCreateGeneratedSource( |
3309 | | std::string const& sourceName) |
3310 | 5.92k | { |
3311 | 5.92k | cmSourceFile* sf = |
3312 | 5.92k | this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known); |
3313 | 5.92k | sf->MarkAsGenerated(); // In case we did not create the source file. |
3314 | 5.92k | return sf; |
3315 | 5.92k | } |
3316 | | |
3317 | | void cmMakefile::CreateGeneratedOutputs( |
3318 | | std::vector<std::string> const& outputs) |
3319 | 5.92k | { |
3320 | 5.92k | for (std::string const& o : outputs) { |
3321 | 0 | if (cmGeneratorExpression::Find(o) == std::string::npos) { |
3322 | 0 | this->GetOrCreateGeneratedSource(o); |
3323 | 0 | } |
3324 | 0 | } |
3325 | 5.92k | } |
3326 | | |
3327 | | void cmMakefile::AddTargetObject(std::string const& tgtName, |
3328 | | std::string const& objFile) |
3329 | 1.12k | { |
3330 | 1.12k | cmSourceFile* sf = |
3331 | 1.12k | this->GetOrCreateSource(objFile, true, cmSourceFileLocationKind::Known); |
3332 | 1.12k | sf->SetSpecialSourceType(cmSourceFile::SpecialSourceType::Object); |
3333 | 1.12k | sf->SetObjectLibrary(tgtName); |
3334 | 1.12k | sf->SetProperty("EXTERNAL_OBJECT", "1"); |
3335 | | // TODO: Compute a language for this object based on the associated source |
3336 | | // file that compiles to it. Needs a policy as it likely affects link |
3337 | | // language selection if done unconditionally. |
3338 | 1.12k | #if !defined(CMAKE_BOOTSTRAP) |
3339 | 1.12k | this->SourceGroups[this->ObjectLibrariesSourceGroupIndex]->AddGroupFile( |
3340 | 1.12k | sf->ResolveFullPath()); |
3341 | 1.12k | #endif |
3342 | 1.12k | } |
3343 | | |
3344 | | void cmMakefile::EnableLanguage(std::vector<std::string> const& languages, |
3345 | | bool optional) |
3346 | 0 | { |
3347 | 0 | if (this->DeferRunning) { |
3348 | 0 | this->IssueMessage( |
3349 | 0 | MessageType::FATAL_ERROR, |
3350 | 0 | "Languages may not be enabled during deferred execution."); |
3351 | 0 | return; |
3352 | 0 | } |
3353 | 0 | if (char const* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) { |
3354 | 0 | this->AddDefinition("CMAKE_CFG_INTDIR", def); |
3355 | 0 | } |
3356 | |
|
3357 | 0 | std::vector<std::string> unique_languages; |
3358 | 0 | { |
3359 | 0 | std::vector<std::string> duplicate_languages; |
3360 | 0 | for (std::string const& language : languages) { |
3361 | 0 | if (!cm::contains(unique_languages, language)) { |
3362 | 0 | unique_languages.push_back(language); |
3363 | 0 | } else if (!cm::contains(duplicate_languages, language)) { |
3364 | 0 | duplicate_languages.push_back(language); |
3365 | 0 | } |
3366 | 0 | } |
3367 | 0 | if (!duplicate_languages.empty()) { |
3368 | 0 | auto quantity = duplicate_languages.size() == 1 ? " has"_s : "s have"_s; |
3369 | 0 | this->IssueDiagnostic( |
3370 | 0 | cmDiagnostics::CMD_AUTHOR, |
3371 | 0 | cmStrCat("Languages to be enabled may not be specified more " |
3372 | 0 | "than once at the same time. The following language", |
3373 | 0 | quantity, " been specified multiple times: ", |
3374 | 0 | cmJoin(duplicate_languages, ", "))); |
3375 | 0 | } |
3376 | 0 | } |
3377 | | |
3378 | | // If RC is explicitly listed we need to do it after other languages. |
3379 | | // On some platforms we enable RC implicitly while enabling others. |
3380 | | // Do not let that look like recursive enable_language(RC). |
3381 | 0 | std::vector<std::string> languages_without_RC; |
3382 | 0 | std::vector<std::string> languages_for_RC; |
3383 | 0 | languages_without_RC.reserve(unique_languages.size()); |
3384 | 0 | for (std::string const& language : unique_languages) { |
3385 | 0 | if (language == "RC"_s) { |
3386 | 0 | languages_for_RC.push_back(language); |
3387 | 0 | } else { |
3388 | 0 | languages_without_RC.push_back(language); |
3389 | 0 | } |
3390 | 0 | } |
3391 | 0 | if (!languages_without_RC.empty()) { |
3392 | 0 | this->GetGlobalGenerator()->EnableLanguage(languages_without_RC, this, |
3393 | 0 | optional); |
3394 | 0 | } |
3395 | 0 | if (!languages_for_RC.empty()) { |
3396 | 0 | this->GetGlobalGenerator()->EnableLanguage(languages_for_RC, this, |
3397 | 0 | optional); |
3398 | 0 | } |
3399 | 0 | } |
3400 | | |
3401 | | int cmMakefile::TryCompile(std::string const& srcdir, |
3402 | | std::string const& bindir, |
3403 | | std::string const& projectName, |
3404 | | std::string const& targetName, bool fast, int jobs, |
3405 | | std::vector<std::string> const* cmakeArgs, |
3406 | | std::string& output) |
3407 | 0 | { |
3408 | 0 | this->IsSourceFileTryCompile = fast; |
3409 | | // does the binary directory exist ? If not create it... |
3410 | 0 | if (!cmSystemTools::FileIsDirectory(bindir)) { |
3411 | 0 | cmSystemTools::MakeDirectory(bindir); |
3412 | 0 | } |
3413 | | |
3414 | | // change to the tests directory and run cmake |
3415 | | // use the cmake object instead of calling cmake |
3416 | 0 | cmWorkingDirectory workdir(bindir); |
3417 | 0 | if (workdir.Failed()) { |
3418 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, workdir.GetError()); |
3419 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
3420 | 0 | this->IsSourceFileTryCompile = false; |
3421 | 0 | return 1; |
3422 | 0 | } |
3423 | | |
3424 | | // unset the NINJA_STATUS environment variable while running try compile. |
3425 | | // since we parse the output, we need to ensure there aren't any unexpected |
3426 | | // characters that will cause issues, such as ANSI color escape codes. |
3427 | 0 | cm::optional<cmSystemTools::ScopedEnv> maybeNinjaStatus; |
3428 | 0 | if (this->GetGlobalGenerator()->IsNinja()) { |
3429 | 0 | maybeNinjaStatus.emplace("NINJA_STATUS="); |
3430 | 0 | } |
3431 | | |
3432 | | // make sure the same generator is used |
3433 | | // use this program as the cmake to be run, it should not |
3434 | | // be run that way but the cmake object requires a valid path |
3435 | 0 | cmake cm(cmState::Role::Project, cmState::TryCompile::Yes); |
3436 | 0 | auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); |
3437 | 0 | if (!gg) { |
3438 | 0 | this->IssueMessage(MessageType::INTERNAL_ERROR, |
3439 | 0 | cmStrCat("Global generator '", |
3440 | 0 | this->GetGlobalGenerator()->GetName(), |
3441 | 0 | "' could not be created.")); |
3442 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
3443 | 0 | this->IsSourceFileTryCompile = false; |
3444 | 0 | return 1; |
3445 | 0 | } |
3446 | 0 | gg->RecursionDepth = this->RecursionDepth; |
3447 | 0 | cm.SetGlobalGenerator(std::move(gg)); |
3448 | | |
3449 | | // copy trace state |
3450 | 0 | cm.SetTraceRedirect(this->GetCMakeInstance()); |
3451 | | |
3452 | | // do a configure |
3453 | 0 | cm.SetHomeDirectory(srcdir); |
3454 | 0 | cm.SetHomeOutputDirectory(bindir); |
3455 | 0 | cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE")); |
3456 | 0 | cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM")); |
3457 | 0 | cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET")); |
3458 | 0 | cm.LoadCache(); |
3459 | 0 | if (!cm.GetGlobalGenerator()->IsMultiConfig()) { |
3460 | 0 | if (cmValue config = |
3461 | 0 | this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) { |
3462 | | // Tell the single-configuration generator which one to use. |
3463 | | // Add this before the user-provided CMake arguments in case |
3464 | | // one of the arguments is -DCMAKE_BUILD_TYPE=... |
3465 | 0 | cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration", |
3466 | 0 | cmStateEnums::STRING); |
3467 | 0 | } |
3468 | 0 | } |
3469 | 0 | cmValue recursionDepth = |
3470 | 0 | this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH"); |
3471 | 0 | if (recursionDepth) { |
3472 | 0 | cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth, |
3473 | 0 | "Maximum recursion depth", cmStateEnums::STRING); |
3474 | 0 | } |
3475 | | // if cmake args were provided then pass them in |
3476 | 0 | if (cmakeArgs) { |
3477 | | // FIXME: Workaround to ignore unused CLI variables in try-compile. |
3478 | | // |
3479 | | // Ideally we should use SetArgs for options like -Wno-unused-cli. |
3480 | | // However, there is a subtle problem when certain arguments are passed to |
3481 | | // a macro wrapping around try_compile or try_run that does not escape |
3482 | | // semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In |
3483 | | // this case a list argument like "-DVAR=a;b" gets split into multiple |
3484 | | // cmake arguments "-DVAR=a" and "b". Currently SetCacheArgs ignores |
3485 | | // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that |
3486 | | // the try_compile or try_run does not get the proper value of VAR. If we |
3487 | | // call SetArgs here then it would treat "b" as the source directory and |
3488 | | // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b |
3489 | | // does not exist", thus breaking the try_compile or try_run completely. |
3490 | | // |
3491 | | // Strictly speaking the bug is in the wrapper macro because the CMake |
3492 | | // language has always flattened nested lists and the macro should escape |
3493 | | // the semicolons in its arguments before forwarding them. However, this |
3494 | | // bug is so subtle that projects typically work anyway, usually because |
3495 | | // the value VAR=a is sufficient for the try_compile or try_run to get the |
3496 | | // correct result. Calling SetArgs here would break such projects that |
3497 | | // previously built. Instead we work around the issue by never reporting |
3498 | | // unused arguments and ignoring options such as -Wno-unused-cli. |
3499 | 0 | cm.GetCurrentSnapshot().SetDiagnostic(cmDiagnostics::CMD_UNUSED_CLI, |
3500 | 0 | cmDiagnostics::Ignore, true); |
3501 | | // cm.SetArgs(*cmakeArgs, true); |
3502 | |
|
3503 | 0 | cm.SetCacheArgs(*cmakeArgs); |
3504 | 0 | } |
3505 | | // to save time we pass the EnableLanguage info directly |
3506 | 0 | cm.GetGlobalGenerator()->SetupTryCompile(this->GetGlobalGenerator(), this); |
3507 | 0 | for (unsigned dc = 1; dc < cmDiagnostics::CategoryCount; ++dc) { |
3508 | 0 | auto const category = static_cast<cmDiagnosticCategory>(dc); |
3509 | 0 | if (this->GetDiagnosticAction(category) == cmDiagnostics::Ignore) { |
3510 | 0 | cm.GetCurrentSnapshot().SetDiagnostic(category, cmDiagnostics::Ignore, |
3511 | 0 | false); |
3512 | 0 | } |
3513 | 0 | } |
3514 | 0 | if (cm.Configure() != 0) { |
3515 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
3516 | 0 | "Failed to configure test project build system."); |
3517 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
3518 | 0 | this->IsSourceFileTryCompile = false; |
3519 | 0 | return 1; |
3520 | 0 | } |
3521 | | |
3522 | 0 | if (cm.Generate() != 0) { |
3523 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
3524 | 0 | "Failed to generate test project build system."); |
3525 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
3526 | 0 | this->IsSourceFileTryCompile = false; |
3527 | 0 | return 1; |
3528 | 0 | } |
3529 | | |
3530 | | // finally call the generator to actually build the resulting project |
3531 | 0 | int ret = this->GetGlobalGenerator()->TryCompile( |
3532 | 0 | jobs, bindir, projectName, targetName, fast, output, this); |
3533 | |
|
3534 | 0 | this->IsSourceFileTryCompile = false; |
3535 | 0 | return ret; |
3536 | 0 | } |
3537 | | |
3538 | | bool cmMakefile::GetIsSourceFileTryCompile() const |
3539 | 0 | { |
3540 | 0 | return this->IsSourceFileTryCompile; |
3541 | 0 | } |
3542 | | |
3543 | | cmake* cmMakefile::GetCMakeInstance() const |
3544 | 24.4M | { |
3545 | 24.4M | return this->GlobalGenerator->GetCMakeInstance(); |
3546 | 24.4M | } |
3547 | | |
3548 | | cmMessenger* cmMakefile::GetMessenger() const |
3549 | 0 | { |
3550 | 0 | return this->GetCMakeInstance()->GetMessenger(); |
3551 | 0 | } |
3552 | | |
3553 | | cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const |
3554 | 807k | { |
3555 | 807k | return this->GlobalGenerator; |
3556 | 807k | } |
3557 | | |
3558 | | #ifndef CMAKE_BOOTSTRAP |
3559 | | cmVariableWatch* cmMakefile::GetVariableWatch() const |
3560 | 6.72M | { |
3561 | 6.72M | if (this->GetCMakeInstance()) { |
3562 | 6.72M | return this->GetCMakeInstance()->GetVariableWatch(); |
3563 | 6.72M | } |
3564 | 0 | return nullptr; |
3565 | 6.72M | } |
3566 | | #endif |
3567 | | |
3568 | | cmState* cmMakefile::GetState() const |
3569 | 6.98M | { |
3570 | 6.98M | return this->GetCMakeInstance()->GetState(); |
3571 | 6.98M | } |
3572 | | |
3573 | | void cmMakefile::DisplayStatus(std::string const& message, float s) const |
3574 | 0 | { |
3575 | 0 | cmake* cm = this->GetCMakeInstance(); |
3576 | 0 | if (cm->GetState()->GetRole() == cmState::Role::FindPackage) { |
3577 | | // don't output any STATUS message in --find-package mode, since they will |
3578 | | // directly be fed to the compiler, which will be confused. |
3579 | 0 | return; |
3580 | 0 | } |
3581 | 0 | cm->UpdateProgress(message, s); |
3582 | |
|
3583 | 0 | #ifdef CMake_ENABLE_DEBUGGER |
3584 | 0 | if (cm->GetDebugAdapter()) { |
3585 | 0 | cm->GetDebugAdapter()->OnMessageOutput(MessageType::MESSAGE, message); |
3586 | 0 | } |
3587 | 0 | #endif |
3588 | 0 | } |
3589 | | |
3590 | | std::string cmMakefile::GetModulesFile(cm::string_view filename, bool& system, |
3591 | | bool debug, |
3592 | | std::string& debugBuffer) const |
3593 | 0 | { |
3594 | 0 | std::string result; |
3595 | |
|
3596 | 0 | std::string moduleInCMakeRoot; |
3597 | 0 | std::string moduleInCMakeModulePath; |
3598 | | |
3599 | | // Always search in CMAKE_MODULE_PATH: |
3600 | 0 | cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH"); |
3601 | 0 | if (cmakeModulePath) { |
3602 | 0 | cmList modulePath{ *cmakeModulePath }; |
3603 | | |
3604 | | // Look through the possible module directories. |
3605 | 0 | for (std::string itempl : modulePath) { |
3606 | 0 | cmSystemTools::ConvertToUnixSlashes(itempl); |
3607 | 0 | itempl += "/"; |
3608 | 0 | itempl += filename; |
3609 | 0 | if (cmSystemTools::FileExists(itempl)) { |
3610 | 0 | moduleInCMakeModulePath = itempl; |
3611 | 0 | break; |
3612 | 0 | } |
3613 | 0 | if (debug) { |
3614 | 0 | debugBuffer = cmStrCat(std::move(debugBuffer), " ", itempl, '\n'); |
3615 | 0 | } |
3616 | 0 | } |
3617 | 0 | } |
3618 | | |
3619 | | // Always search in the standard modules location. |
3620 | 0 | moduleInCMakeRoot = |
3621 | 0 | cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename); |
3622 | 0 | cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot); |
3623 | 0 | if (!cmSystemTools::FileExists(moduleInCMakeRoot)) { |
3624 | 0 | if (debug) { |
3625 | 0 | debugBuffer = |
3626 | 0 | cmStrCat(std::move(debugBuffer), " ", moduleInCMakeRoot, '\n'); |
3627 | 0 | } |
3628 | 0 | moduleInCMakeRoot.clear(); |
3629 | 0 | } |
3630 | | |
3631 | | // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file |
3632 | | // from which we are being called is located itself in CMAKE_ROOT, then |
3633 | | // prefer results from CMAKE_ROOT depending on the policy setting. |
3634 | 0 | if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) { |
3635 | 0 | cmValue currentFile = this->GetDefinition(kCMAKE_CURRENT_LIST_FILE); |
3636 | 0 | std::string mods = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/"); |
3637 | 0 | if (currentFile && cmSystemTools::IsSubDirectory(*currentFile, mods)) { |
3638 | 0 | system = true; |
3639 | 0 | result = moduleInCMakeRoot; |
3640 | 0 | } else { |
3641 | 0 | system = false; |
3642 | 0 | result = moduleInCMakeModulePath; |
3643 | 0 | } |
3644 | 0 | } else if (!moduleInCMakeModulePath.empty()) { |
3645 | 0 | system = false; |
3646 | 0 | result = moduleInCMakeModulePath; |
3647 | 0 | } else { |
3648 | 0 | system = true; |
3649 | 0 | result = moduleInCMakeRoot; |
3650 | 0 | } |
3651 | |
|
3652 | | #if defined(_WIN32) || defined(__APPLE__) |
3653 | | if (!result.empty()) { |
3654 | | std::string const requestedName = |
3655 | | cmSystemTools::GetFilenameName(std::string{ filename }); |
3656 | | std::string actualName; |
3657 | | cmsys::Status const status = |
3658 | | cmSystemTools::ReadNameOnDisk(result, actualName); |
3659 | | if (status && actualName != requestedName) { |
3660 | | this->IssueDiagnostic( |
3661 | | cmDiagnostics::CMD_AUTHOR, |
3662 | | cmStrCat("The module name\n ", requestedName, |
3663 | | "\n" |
3664 | | "does not match the case of the module file name on disk\n" |
3665 | | " ", |
3666 | | cmSystemTools::GetFilenamePath(result), '/', actualName, |
3667 | | "\n" |
3668 | | "This may fail on case-sensitive file systems. " |
3669 | | "Use the module name\n ", |
3670 | | actualName, "\ninstead.")); |
3671 | | } |
3672 | | } |
3673 | | #endif |
3674 | |
|
3675 | 0 | return result; |
3676 | 0 | } |
3677 | | |
3678 | | void cmMakefile::ConfigureString(std::string const& input, std::string& output, |
3679 | | bool atOnly, bool escapeQuotes) const |
3680 | 0 | { |
3681 | | // Split input to handle one line at a time. |
3682 | 0 | std::string::const_iterator lineStart = input.begin(); |
3683 | 0 | while (lineStart != input.end()) { |
3684 | | // Find the end of this line. |
3685 | 0 | std::string::const_iterator lineEnd = lineStart; |
3686 | 0 | while (lineEnd != input.end() && *lineEnd != '\n') { |
3687 | 0 | ++lineEnd; |
3688 | 0 | } |
3689 | | |
3690 | | // Copy the line. |
3691 | 0 | std::string line(lineStart, lineEnd); |
3692 | | |
3693 | | // Skip the newline character. |
3694 | 0 | bool haveNewline = (lineEnd != input.end()); |
3695 | 0 | if (haveNewline) { |
3696 | 0 | ++lineEnd; |
3697 | 0 | } |
3698 | | |
3699 | | // Replace #cmakedefine instances. |
3700 | 0 | if (this->cmDefineRegex.find(line)) { |
3701 | 0 | cmValue def = this->GetDefinition(this->cmDefineRegex.match(2)); |
3702 | 0 | if (!def.IsOff()) { |
3703 | 0 | std::string const indentation = this->cmDefineRegex.match(1); |
3704 | 0 | cmSystemTools::ReplaceString(line, |
3705 | 0 | cmStrCat('#', indentation, "cmakedefine"), |
3706 | 0 | cmStrCat('#', indentation, "define")); |
3707 | 0 | output += line; |
3708 | 0 | } else { |
3709 | 0 | output += "/* #undef "; |
3710 | 0 | output += this->cmDefineRegex.match(2); |
3711 | 0 | output += " */"; |
3712 | 0 | } |
3713 | 0 | } else if (this->cmDefine01Regex.find(line)) { |
3714 | 0 | std::string const indentation = this->cmDefine01Regex.match(1); |
3715 | 0 | cmValue def = this->GetDefinition(this->cmDefine01Regex.match(2)); |
3716 | 0 | cmSystemTools::ReplaceString(line, |
3717 | 0 | cmStrCat('#', indentation, "cmakedefine01"), |
3718 | 0 | cmStrCat('#', indentation, "define")); |
3719 | 0 | output += line; |
3720 | 0 | if (!def.IsOff()) { |
3721 | 0 | output += " 1"; |
3722 | 0 | } else { |
3723 | 0 | output += " 0"; |
3724 | 0 | } |
3725 | 0 | } else { |
3726 | 0 | output += line; |
3727 | 0 | } |
3728 | |
|
3729 | 0 | if (haveNewline) { |
3730 | 0 | output += '\n'; |
3731 | 0 | } |
3732 | | |
3733 | | // Move to the next line. |
3734 | 0 | lineStart = lineEnd; |
3735 | 0 | } |
3736 | | |
3737 | | // Perform variable replacements. |
3738 | 0 | char const* filename = nullptr; |
3739 | 0 | long lineNumber = -1; |
3740 | 0 | if (!this->Backtrace.Empty()) { |
3741 | 0 | auto const& currentTrace = this->Backtrace.Top(); |
3742 | 0 | filename = currentTrace.FilePath.c_str(); |
3743 | 0 | lineNumber = currentTrace.Line; |
3744 | 0 | } |
3745 | 0 | this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, filename, |
3746 | 0 | lineNumber, true, true); |
3747 | 0 | } |
3748 | | |
3749 | | int cmMakefile::ConfigureFile(std::string const& infile, |
3750 | | std::string const& outfile, bool copyonly, |
3751 | | bool atOnly, bool escapeQuotes, |
3752 | | mode_t permissions, cmNewLineStyle newLine) |
3753 | 0 | { |
3754 | 0 | int res = 1; |
3755 | 0 | if (!this->CanIWriteThisFile(outfile)) { |
3756 | 0 | cmSystemTools::Error(cmStrCat("Attempt to write file: ", outfile, |
3757 | 0 | " into a source directory.")); |
3758 | 0 | return 0; |
3759 | 0 | } |
3760 | 0 | if (!cmSystemTools::FileExists(infile)) { |
3761 | 0 | cmSystemTools::Error(cmStrCat("File ", infile, " does not exist.")); |
3762 | 0 | return 0; |
3763 | 0 | } |
3764 | 0 | std::string soutfile = outfile; |
3765 | 0 | std::string const& sinfile = infile; |
3766 | 0 | this->AddCMakeDependFile(sinfile); |
3767 | 0 | cmSystemTools::ConvertToUnixSlashes(soutfile); |
3768 | | |
3769 | | // Re-generate if non-temporary outputs are missing. |
3770 | | // when we finalize the configuration we will remove all |
3771 | | // output files that now don't exist. |
3772 | 0 | this->AddCMakeOutputFile(soutfile); |
3773 | |
|
3774 | 0 | if (permissions == 0) { |
3775 | 0 | cmSystemTools::GetPermissions(sinfile, permissions); |
3776 | 0 | } |
3777 | |
|
3778 | 0 | std::string::size_type pos = soutfile.rfind('/'); |
3779 | 0 | if (pos != std::string::npos) { |
3780 | 0 | std::string path = soutfile.substr(0, pos); |
3781 | 0 | cmSystemTools::MakeDirectory(path); |
3782 | 0 | } |
3783 | |
|
3784 | 0 | if (copyonly) { |
3785 | 0 | auto const copy_status = |
3786 | 0 | cmSystemTools::CopyFileIfDifferent(sinfile, soutfile); |
3787 | 0 | if (!copy_status) { |
3788 | 0 | this->IssueMessage( |
3789 | 0 | MessageType::FATAL_ERROR, |
3790 | 0 | cmStrCat("Fail to copy ", |
3791 | 0 | copy_status.Path == cmsys::SystemTools::CopyStatus::SourcePath |
3792 | 0 | ? "source" |
3793 | 0 | : "destination", |
3794 | 0 | "file: ", copy_status.GetString())); |
3795 | 0 | res = 0; |
3796 | 0 | } else { |
3797 | 0 | auto const status = cmSystemTools::SetPermissions(soutfile, permissions); |
3798 | 0 | if (!status) { |
3799 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, status.GetString()); |
3800 | 0 | res = 0; |
3801 | 0 | } |
3802 | 0 | } |
3803 | 0 | return res; |
3804 | 0 | } |
3805 | | |
3806 | 0 | std::string newLineCharacters = "\n"; |
3807 | 0 | if (newLine.IsValid()) { |
3808 | 0 | newLineCharacters = newLine.GetCharacters(); |
3809 | 0 | } |
3810 | 0 | cmsys::ifstream fin(sinfile.c_str()); |
3811 | 0 | if (!fin) { |
3812 | 0 | cmSystemTools::Error("Could not open file for read in copy operation " + |
3813 | 0 | sinfile); |
3814 | 0 | return 0; |
3815 | 0 | } |
3816 | | |
3817 | 0 | cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin); |
3818 | 0 | if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) { |
3819 | 0 | this->IssueMessage( |
3820 | 0 | MessageType::FATAL_ERROR, |
3821 | 0 | cmStrCat("File starts with a Byte-Order-Mark that is not UTF-8:\n ", |
3822 | 0 | sinfile)); |
3823 | 0 | return 0; |
3824 | 0 | } |
3825 | | // rewind to copy BOM to output file |
3826 | 0 | fin.seekg(0); |
3827 | | |
3828 | | // now copy input to output and expand variables in the |
3829 | | // input file at the same time |
3830 | 0 | std::string inLine; |
3831 | 0 | std::string outLine; |
3832 | 0 | std::string content; |
3833 | 0 | while (cmSystemTools::GetLineFromStream(fin, inLine)) { |
3834 | 0 | outLine.clear(); |
3835 | 0 | this->ConfigureString(inLine, outLine, atOnly, escapeQuotes); |
3836 | 0 | content += outLine; |
3837 | 0 | content += newLineCharacters; |
3838 | 0 | } |
3839 | 0 | fin.close(); |
3840 | | #ifdef _WIN32 |
3841 | | if (!newLine.IsValid()) { |
3842 | | // Translate new lines as writing in text mode would. |
3843 | | cmSystemTools::ReplaceString(content, "\n", "\r\n"); |
3844 | | } |
3845 | | #endif |
3846 | | |
3847 | | // Avoid writing a temporary file just to find out nothing changed. |
3848 | 0 | if (!cmSystemTools::FileHasContent(soutfile, content)) { |
3849 | 0 | std::string tempOutputFile = cmStrCat(soutfile, ".tmp"); |
3850 | 0 | cmsys::ofstream fout(tempOutputFile.c_str(), |
3851 | 0 | std::ios::out | std::ios::trunc | std::ios::binary); |
3852 | 0 | if (!fout) { |
3853 | 0 | cmSystemTools::Error("Could not open file for write in copy operation " + |
3854 | 0 | tempOutputFile); |
3855 | 0 | cmSystemTools::ReportLastSystemError(""); |
3856 | 0 | return 0; |
3857 | 0 | } |
3858 | 0 | fout << content; |
3859 | 0 | fout.close(); |
3860 | | |
3861 | | // The content is known to differ, so replace the output without |
3862 | | // comparing the files again. |
3863 | 0 | cmsys::Status status; |
3864 | 0 | if (!cmSystemTools::RenameFile(tempOutputFile, soutfile)) { |
3865 | 0 | status = cmSystemTools::CopyFileAlways(tempOutputFile, soutfile); |
3866 | 0 | cmSystemTools::RemoveFile(tempOutputFile); |
3867 | 0 | } |
3868 | 0 | if (!status) { |
3869 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, status.GetString()); |
3870 | 0 | return 0; |
3871 | 0 | } |
3872 | 0 | } |
3873 | | |
3874 | 0 | auto status = cmSystemTools::SetPermissions(soutfile, permissions); |
3875 | 0 | if (!status) { |
3876 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, status.GetString()); |
3877 | 0 | res = 0; |
3878 | 0 | } |
3879 | |
|
3880 | 0 | return res; |
3881 | 0 | } |
3882 | | |
3883 | | void cmMakefile::SetProperty(std::string const& prop, cmValue value) |
3884 | 5.92k | { |
3885 | 5.92k | this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace); |
3886 | 5.92k | } |
3887 | | |
3888 | | void cmMakefile::AppendProperty(std::string const& prop, |
3889 | | std::string const& value, bool asString) |
3890 | 0 | { |
3891 | 0 | this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString, |
3892 | 0 | this->Backtrace); |
3893 | 0 | } |
3894 | | |
3895 | | cmValue cmMakefile::GetProperty(std::string const& prop) const |
3896 | 53.3k | { |
3897 | | // Check for computed properties. |
3898 | 53.3k | static std::string output; |
3899 | 53.3k | if (prop == "TESTS"_s) { |
3900 | 0 | std::vector<std::string> keys; |
3901 | | // get list of keys |
3902 | 0 | auto const* t = this; |
3903 | 0 | std::transform( |
3904 | 0 | t->Tests.begin(), t->Tests.end(), std::back_inserter(keys), |
3905 | 0 | [](decltype(t->Tests)::value_type const& pair) { return pair.first; }); |
3906 | 0 | output = cmList::to_string(keys); |
3907 | 0 | return cmValue(output); |
3908 | 0 | } |
3909 | | |
3910 | 53.3k | return this->StateSnapshot.GetDirectory().GetProperty(prop); |
3911 | 53.3k | } |
3912 | | |
3913 | | cmValue cmMakefile::GetProperty(std::string const& prop, bool chain) const |
3914 | 0 | { |
3915 | 0 | return this->StateSnapshot.GetDirectory().GetProperty(prop, chain); |
3916 | 0 | } |
3917 | | |
3918 | | bool cmMakefile::GetPropertyAsBool(std::string const& prop) const |
3919 | 35.5k | { |
3920 | 35.5k | return this->GetProperty(prop).IsOn(); |
3921 | 35.5k | } |
3922 | | |
3923 | | std::vector<std::string> cmMakefile::GetPropertyKeys() const |
3924 | 0 | { |
3925 | 0 | return this->StateSnapshot.GetDirectory().GetPropertyKeys(); |
3926 | 0 | } |
3927 | | |
3928 | | cmTarget* cmMakefile::FindLocalNonAliasTarget(std::string const& name) const |
3929 | 261k | { |
3930 | 261k | auto i = this->Targets.find(name); |
3931 | 261k | if (i != this->Targets.end()) { |
3932 | 43.2k | return &i->second; |
3933 | 43.2k | } |
3934 | 218k | return nullptr; |
3935 | 261k | } |
3936 | | |
3937 | | cmTest* cmMakefile::CreateTest(std::string const& testName) |
3938 | 0 | { |
3939 | 0 | cmTest* test = this->GetTest(testName); |
3940 | 0 | if (test) { |
3941 | 0 | return test; |
3942 | 0 | } |
3943 | 0 | auto newTest = cm::make_unique<cmTest>(this); |
3944 | 0 | test = newTest.get(); |
3945 | 0 | newTest->SetName(testName); |
3946 | 0 | this->Tests[testName] = std::move(newTest); |
3947 | 0 | return test; |
3948 | 0 | } |
3949 | | |
3950 | | cmTest* cmMakefile::GetTest(std::string const& testName) const |
3951 | 0 | { |
3952 | 0 | auto mi = this->Tests.find(testName); |
3953 | 0 | if (mi != this->Tests.end()) { |
3954 | 0 | return mi->second.get(); |
3955 | 0 | } |
3956 | 0 | return nullptr; |
3957 | 0 | } |
3958 | | |
3959 | | void cmMakefile::GetTests(std::string const& config, |
3960 | | std::vector<cmTest*>& tests) const |
3961 | 0 | { |
3962 | 0 | for (auto const& generator : this->GetTestGenerators()) { |
3963 | 0 | if (generator->TestsForConfig(config)) { |
3964 | 0 | tests.push_back(generator->GetTest()); |
3965 | 0 | } |
3966 | 0 | } |
3967 | 0 | } |
3968 | | |
3969 | | void cmMakefile::AddCMakeDependFilesFromUser() |
3970 | 0 | { |
3971 | 0 | cmList deps; |
3972 | 0 | if (cmValue deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) { |
3973 | 0 | deps.assign(*deps_str); |
3974 | 0 | } |
3975 | 0 | for (auto const& dep : deps) { |
3976 | 0 | if (cmSystemTools::FileIsFullPath(dep)) { |
3977 | 0 | this->AddCMakeDependFile(dep); |
3978 | 0 | } else { |
3979 | 0 | std::string f = cmStrCat(this->GetCurrentSourceDirectory(), '/', dep); |
3980 | 0 | this->AddCMakeDependFile(f); |
3981 | 0 | } |
3982 | 0 | } |
3983 | 0 | } |
3984 | | |
3985 | | std::string cmMakefile::FormatListFileStack() const |
3986 | 0 | { |
3987 | 0 | std::vector<std::string> listFiles; |
3988 | 0 | for (auto snp = this->StateSnapshot; snp.IsValid(); |
3989 | 0 | snp = snp.GetCallStackParent()) { |
3990 | 0 | listFiles.emplace_back(snp.GetExecutionListFile()); |
3991 | 0 | } |
3992 | |
|
3993 | 0 | if (listFiles.empty()) { |
3994 | 0 | return {}; |
3995 | 0 | } |
3996 | | |
3997 | 0 | auto depth = 1; |
3998 | 0 | std::transform(listFiles.begin(), listFiles.end(), listFiles.begin(), |
3999 | 0 | [&depth](std::string const& file) { |
4000 | 0 | return cmStrCat('[', depth++, "]\t", file); |
4001 | 0 | }); |
4002 | |
|
4003 | 0 | return cmJoinStrings(cmMakeRange(listFiles.rbegin(), listFiles.rend()), |
4004 | 0 | "\n "_s, {}); |
4005 | 0 | } |
4006 | | |
4007 | | void cmMakefile::PushScope() |
4008 | 0 | { |
4009 | 0 | this->StateSnapshot = |
4010 | 0 | this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot); |
4011 | 0 | this->PushLoopBlockBarrier(); |
4012 | |
|
4013 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
4014 | 0 | this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope(); |
4015 | 0 | #endif |
4016 | 0 | } |
4017 | | |
4018 | | void cmMakefile::PopScope() |
4019 | 0 | { |
4020 | 0 | #if !defined(CMAKE_BOOTSTRAP) |
4021 | 0 | this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope(); |
4022 | 0 | #endif |
4023 | |
|
4024 | 0 | this->PopLoopBlockBarrier(); |
4025 | |
|
4026 | 0 | this->PopSnapshot(); |
4027 | 0 | } |
4028 | | |
4029 | | void cmMakefile::RaiseScope(std::string const& var, char const* varDef) |
4030 | 0 | { |
4031 | 0 | if (var.empty()) { |
4032 | 0 | return; |
4033 | 0 | } |
4034 | | |
4035 | 0 | if (!this->StateSnapshot.RaiseScope(var, varDef)) { |
4036 | 0 | this->IssueDiagnostic( |
4037 | 0 | cmDiagnostics::CMD_AUTHOR, |
4038 | 0 | cmStrCat("Cannot set \"", var, "\": current scope has no parent.")); |
4039 | 0 | return; |
4040 | 0 | } |
4041 | | |
4042 | 0 | #ifndef CMAKE_BOOTSTRAP |
4043 | 0 | cmVariableWatch* vv = this->GetVariableWatch(); |
4044 | 0 | if (vv) { |
4045 | 0 | vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS, |
4046 | 0 | varDef, this); |
4047 | 0 | } |
4048 | 0 | #endif |
4049 | 0 | } |
4050 | | |
4051 | | void cmMakefile::RaiseScope(std::vector<std::string> const& variables) |
4052 | 0 | { |
4053 | 0 | for (auto const& varName : variables) { |
4054 | 0 | if (this->IsNormalDefinitionSet(varName)) { |
4055 | 0 | this->RaiseScope(varName, this->GetDefinition(varName)); |
4056 | 0 | } else { |
4057 | | // unset variable in parent scope |
4058 | 0 | this->RaiseScope(varName, nullptr); |
4059 | 0 | } |
4060 | 0 | } |
4061 | 0 | } |
4062 | | |
4063 | | cmStateSnapshot::WarnCMP0220 cmMakefile::RaiseToRoot(std::string const& var, |
4064 | | char const* varDef) |
4065 | 0 | { |
4066 | 0 | if (var.empty()) { |
4067 | 0 | return cmStateSnapshot::WarnCMP0220::No; |
4068 | 0 | } |
4069 | 0 | cmStateSnapshot::WarnCMP0220 const warnCMP0220 = |
4070 | 0 | this->StateSnapshot.RaiseToRoot(var, varDef, |
4071 | 0 | cmStateSnapshot::CheckCMP0220::No); |
4072 | 0 | #ifndef CMAKE_BOOTSTRAP |
4073 | 0 | cmVariableWatch* vv = this->GetVariableWatch(); |
4074 | 0 | if (vv) { |
4075 | 0 | vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS, |
4076 | 0 | varDef, this); |
4077 | 0 | } |
4078 | 0 | #endif |
4079 | 0 | return warnCMP0220; |
4080 | 0 | } |
4081 | | |
4082 | | cmTarget* cmMakefile::AddImportedTarget(std::string const& name, |
4083 | | cm::TargetType type, |
4084 | | cm::ImportedTargetScope scope) |
4085 | 49.3k | { |
4086 | | // Create the target. |
4087 | 49.3k | auto target = |
4088 | 49.3k | cm::make_unique<cmTarget>(name, type, cmTarget::ImportedVisibility(scope), |
4089 | 49.3k | this, cmTarget::PerConfig::Yes); |
4090 | | |
4091 | | // Add to the set of available imported targets. |
4092 | 49.3k | this->ImportedTargets[name] = target.get(); |
4093 | 49.3k | this->GetGlobalGenerator()->IndexTarget(target.get()); |
4094 | 49.3k | this->GetStateSnapshot().GetDirectory().AddImportedTargetName(name); |
4095 | | |
4096 | | // Transfer ownership to this cmMakefile object. |
4097 | 49.3k | this->ImportedTargetsOwned.push_back(std::move(target)); |
4098 | 49.3k | return this->ImportedTargetsOwned.back().get(); |
4099 | 49.3k | } |
4100 | | |
4101 | | cmTarget* cmMakefile::AddForeignTarget(std::string const& origin, |
4102 | | std::string const& name) |
4103 | 0 | { |
4104 | 0 | auto foreign_name = cmStrCat("@foreign_", origin, "::", name); |
4105 | 0 | auto target = cm::make_unique<cmTarget>( |
4106 | 0 | foreign_name, cm::TargetType::INTERFACE_LIBRARY, |
4107 | 0 | cmTarget::Visibility::Foreign, this, cmTarget::PerConfig::Yes); |
4108 | |
|
4109 | 0 | this->ImportedTargets[foreign_name] = target.get(); |
4110 | 0 | this->GetGlobalGenerator()->IndexTarget(target.get()); |
4111 | 0 | this->GetStateSnapshot().GetDirectory().AddImportedTargetName(foreign_name); |
4112 | |
|
4113 | 0 | this->ImportedTargetsOwned.push_back(std::move(target)); |
4114 | 0 | return this->ImportedTargetsOwned.back().get(); |
4115 | 0 | } |
4116 | | |
4117 | | cmTarget* cmMakefile::FindForeignTarget(std::string const& origin, |
4118 | | std::string const& name) const |
4119 | 0 | { |
4120 | 0 | return this->FindTargetToUse(cmStrCat("@foreign_", origin, "::", name), |
4121 | 0 | cm::TargetDomain::FOREIGN); |
4122 | 0 | } |
4123 | | |
4124 | | cmTarget* cmMakefile::FindTargetToUse(std::string const& name, |
4125 | | cm::TargetDomainSet domains) const |
4126 | 290k | { |
4127 | | // Look for an imported target. These take priority because they |
4128 | | // are more local in scope and do not have to be globally unique. |
4129 | 290k | auto targetName = name; |
4130 | 290k | if (domains.contains(cm::TargetDomain::ALIAS)) { |
4131 | | // Look for local alias targets. |
4132 | 278k | auto alias = this->AliasTargets.find(name); |
4133 | 278k | if (alias != this->AliasTargets.end()) { |
4134 | 16.4k | targetName = alias->second; |
4135 | 16.4k | } |
4136 | 278k | } |
4137 | 290k | auto const imported = this->ImportedTargets.find(targetName); |
4138 | | |
4139 | 290k | bool const useForeign = domains.contains(cm::TargetDomain::FOREIGN); |
4140 | 290k | bool const useNative = domains.contains(cm::TargetDomain::NATIVE); |
4141 | | |
4142 | 290k | if (imported != this->ImportedTargets.end()) { |
4143 | 32.4k | if (imported->second->IsForeign() ? useForeign : useNative) { |
4144 | 32.4k | return imported->second; |
4145 | 32.4k | } |
4146 | 32.4k | } |
4147 | | |
4148 | | // Look for a target built in this directory. |
4149 | 257k | if (cmTarget* t = this->FindLocalNonAliasTarget(name)) { |
4150 | 39.2k | if (t->IsForeign() ? useForeign : useNative) { |
4151 | 39.2k | return t; |
4152 | 39.2k | } |
4153 | 39.2k | } |
4154 | | |
4155 | | // Look for a target built in this project. |
4156 | 218k | return this->GetGlobalGenerator()->FindTarget(name, domains); |
4157 | 257k | } |
4158 | | |
4159 | | bool cmMakefile::IsAlias(std::string const& name) const |
4160 | 90.3k | { |
4161 | 90.3k | if (cm::contains(this->AliasTargets, name)) { |
4162 | 43 | return true; |
4163 | 43 | } |
4164 | 90.3k | return this->GetGlobalGenerator()->IsAlias(name); |
4165 | 90.3k | } |
4166 | | |
4167 | | bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg, |
4168 | | bool isCustom) const |
4169 | 78.4k | { |
4170 | 78.4k | if (this->IsAlias(name)) { |
4171 | 0 | msg = cmStrCat("cannot create target \"", name, |
4172 | 0 | "\" because an alias with the same name already exists."); |
4173 | 0 | return false; |
4174 | 0 | } |
4175 | 78.4k | if (cmTarget* existing = this->FindTargetToUse(name)) { |
4176 | | // The name given conflicts with an existing target. Produce an |
4177 | | // error in a compatible way. |
4178 | 0 | if (existing->IsImported()) { |
4179 | | // Imported targets were not supported in previous versions. |
4180 | | // This is new code, so we can make it an error. |
4181 | 0 | msg = cmStrCat( |
4182 | 0 | "cannot create target \"", name, |
4183 | 0 | "\" because an imported target with the same name already exists."); |
4184 | 0 | return false; |
4185 | 0 | } |
4186 | | |
4187 | | // The conflict is with a non-imported target. |
4188 | | // Allow this if the user has requested support. |
4189 | 0 | cmake* cm = this->GetCMakeInstance(); |
4190 | 0 | if (isCustom && existing->GetType() == cm::TargetType::UTILITY && |
4191 | 0 | this != existing->GetMakefile() && |
4192 | 0 | cm->GetState()->GetGlobalPropertyAsBool( |
4193 | 0 | "ALLOW_DUPLICATE_CUSTOM_TARGETS")) { |
4194 | 0 | return true; |
4195 | 0 | } |
4196 | | |
4197 | | // Produce an error that tells the user how to work around the |
4198 | | // problem. |
4199 | 0 | std::ostringstream e; |
4200 | 0 | e << "cannot create target \"" << name |
4201 | 0 | << "\" because another target with the same name already exists. " |
4202 | 0 | "The existing target is "; |
4203 | 0 | switch (existing->GetType()) { |
4204 | 0 | case cm::TargetType::EXECUTABLE: |
4205 | 0 | e << "an executable "; |
4206 | 0 | break; |
4207 | 0 | case cm::TargetType::STATIC_LIBRARY: |
4208 | 0 | e << "a static library "; |
4209 | 0 | break; |
4210 | 0 | case cm::TargetType::SHARED_LIBRARY: |
4211 | 0 | e << "a shared library "; |
4212 | 0 | break; |
4213 | 0 | case cm::TargetType::MODULE_LIBRARY: |
4214 | 0 | e << "a module library "; |
4215 | 0 | break; |
4216 | 0 | case cm::TargetType::UTILITY: |
4217 | 0 | e << "a custom target "; |
4218 | 0 | break; |
4219 | 0 | case cm::TargetType::INTERFACE_LIBRARY: |
4220 | 0 | e << "an interface library "; |
4221 | 0 | break; |
4222 | 0 | default: |
4223 | 0 | break; |
4224 | 0 | } |
4225 | 0 | e << "created in source directory \"" |
4226 | 0 | << existing->GetMakefile()->GetCurrentSourceDirectory() |
4227 | 0 | << "\". " |
4228 | 0 | "See documentation for policy CMP0002 for more details."; |
4229 | 0 | msg = e.str(); |
4230 | 0 | return false; |
4231 | 0 | } |
4232 | 78.4k | return true; |
4233 | 78.4k | } |
4234 | | |
4235 | | bool cmMakefile::EnforceUniqueDir(std::string const& srcPath, |
4236 | | std::string const& binPath) const |
4237 | 0 | { |
4238 | | // Make sure the binary directory is unique. |
4239 | 0 | cmGlobalGenerator* gg = this->GetGlobalGenerator(); |
4240 | 0 | if (gg->BinaryDirectoryIsNew(binPath)) { |
4241 | 0 | return true; |
4242 | 0 | } |
4243 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
4244 | 0 | cmStrCat("The binary directory\n" |
4245 | 0 | " ", |
4246 | 0 | binPath, |
4247 | 0 | "\n" |
4248 | 0 | "is already used to build a source directory. " |
4249 | 0 | "It cannot be used to build source directory\n" |
4250 | 0 | " ", |
4251 | 0 | srcPath, |
4252 | 0 | "\n" |
4253 | 0 | "Specify a unique binary directory name.")); |
4254 | |
|
4255 | 0 | return false; |
4256 | 0 | } |
4257 | | |
4258 | | static std::string const matchVariables[] = { |
4259 | | "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3", |
4260 | | "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7", |
4261 | | "CMAKE_MATCH_8", "CMAKE_MATCH_9" |
4262 | | }; |
4263 | | |
4264 | | static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT"; |
4265 | | |
4266 | | void cmMakefile::ClearMatches() |
4267 | 0 | { |
4268 | 0 | cmValue nMatchesStr = this->GetDefinition(nMatchesVariable); |
4269 | 0 | if (!nMatchesStr) { |
4270 | 0 | return; |
4271 | 0 | } |
4272 | 0 | int nMatches = atoi(nMatchesStr->c_str()); |
4273 | 0 | for (int i = 0; i <= nMatches; i++) { |
4274 | 0 | std::string const& var = matchVariables[i]; |
4275 | 0 | std::string const& s = this->GetSafeDefinition(var); |
4276 | 0 | if (!s.empty()) { |
4277 | 0 | this->AddDefinition(var, ""); |
4278 | 0 | this->MarkVariableAsUsed(var); |
4279 | 0 | } |
4280 | 0 | } |
4281 | 0 | this->AddDefinition(nMatchesVariable, "0"); |
4282 | 0 | this->MarkVariableAsUsed(nMatchesVariable); |
4283 | 0 | } |
4284 | | |
4285 | | void cmMakefile::StoreMatches(cmsys::RegularExpression& re) |
4286 | 0 | { |
4287 | 0 | char highest = 0; |
4288 | 0 | for (int i = 0; i < 10; i++) { |
4289 | 0 | std::string const& m = re.match(i); |
4290 | 0 | if (!m.empty()) { |
4291 | 0 | std::string const& var = matchVariables[i]; |
4292 | 0 | this->AddDefinition(var, m); |
4293 | 0 | this->MarkVariableAsUsed(var); |
4294 | 0 | highest = static_cast<char>('0' + i); |
4295 | 0 | } |
4296 | 0 | } |
4297 | 0 | char nMatches[] = { highest, '\0' }; |
4298 | 0 | this->AddDefinition(nMatchesVariable, nMatches); |
4299 | 0 | this->MarkVariableAsUsed(nMatchesVariable); |
4300 | 0 | } |
4301 | | |
4302 | | cmStateSnapshot cmMakefile::GetStateSnapshot() const |
4303 | 96.8k | { |
4304 | 96.8k | return this->StateSnapshot; |
4305 | 96.8k | } |
4306 | | |
4307 | | cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id, |
4308 | | bool parent_scope) const |
4309 | 19.6M | { |
4310 | 19.6M | return this->StateSnapshot.GetPolicy(id, parent_scope); |
4311 | 19.6M | } |
4312 | | |
4313 | | bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const |
4314 | 3.55k | { |
4315 | | // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting. |
4316 | 3.55k | if (cmValue val = this->GetDefinition(var)) { |
4317 | 0 | return val.IsOn(); |
4318 | 0 | } |
4319 | | // Enable optional policy warnings with --debug-output, --trace, |
4320 | | // or --trace-expand. |
4321 | 3.55k | cmake* cm = this->GetCMakeInstance(); |
4322 | 3.55k | return cm->GetDebugOutput() || cm->GetTrace(); |
4323 | 3.55k | } |
4324 | | |
4325 | | bool cmMakefile::SetPolicy(char const* id, cmPolicies::PolicyStatus status) |
4326 | 0 | { |
4327 | 0 | cmPolicies::PolicyID pid; |
4328 | 0 | if (!cmPolicies::GetPolicyID(id, /* out */ pid)) { |
4329 | 0 | this->IssueMessage( |
4330 | 0 | MessageType::FATAL_ERROR, |
4331 | 0 | cmStrCat("Policy \"", id, "\" is not known to this version of CMake.")); |
4332 | 0 | return false; |
4333 | 0 | } |
4334 | 0 | return this->SetPolicy(pid, status); |
4335 | 0 | } |
4336 | | |
4337 | | bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, |
4338 | | cmPolicies::PolicyStatus status) |
4339 | 2.69M | { |
4340 | | // A removed policy may be set only to NEW. |
4341 | 2.69M | if (cmPolicies::IsRemoved(id) && status != cmPolicies::NEW) { |
4342 | 0 | std::string msg = cmPolicies::GetRemovedPolicyError(id); |
4343 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, msg); |
4344 | 0 | return false; |
4345 | 0 | } |
4346 | | |
4347 | | // Deprecate old policies. |
4348 | 2.69M | if (status == cmPolicies::OLD && id <= cmPolicies::CMP0161 && |
4349 | 0 | !(this->GetCMakeInstance()->GetIsInTryCompile() && |
4350 | 0 | ( |
4351 | | // Policies set by cmCoreTryCompile::TryCompileCode. |
4352 | 0 | id == cmPolicies::CMP0083 || id == cmPolicies::CMP0091 || |
4353 | 0 | id == cmPolicies::CMP0104 || id == cmPolicies::CMP0123 || |
4354 | 0 | id == cmPolicies::CMP0126 || id == cmPolicies::CMP0128 || |
4355 | 0 | id == cmPolicies::CMP0136 || id == cmPolicies::CMP0141 || |
4356 | 0 | id == cmPolicies::CMP0155 || id == cmPolicies::CMP0157))) { |
4357 | 0 | std::unique_ptr<PolicyPushPop> ps; |
4358 | 0 | std::unique_ptr<DiagnosticPushPop> ds; |
4359 | |
|
4360 | 0 | cmPolicies::PolicyStatus const cmp0218 = |
4361 | 0 | this->GetPolicyStatus(cmPolicies::CMP0218); |
4362 | 0 | if (cmp0218 != cmPolicies::NEW) { |
4363 | 0 | if (cmp0218 != cmPolicies::OLD) { |
4364 | | // Suppress warnings about using old variables. |
4365 | 0 | ps = cm::make_unique<PolicyPushPop>(this); |
4366 | 0 | this->SetPolicy(cmPolicies::CMP0218, cmPolicies::OLD); |
4367 | 0 | } |
4368 | |
|
4369 | 0 | ds = cm::make_unique<DiagnosticPushPop>(this); |
4370 | | |
4371 | | // Use old variables to determine diagnostic action. |
4372 | 0 | cmValue const warn = this->GetDefinition("CMAKE_WARN_DEPRECATED"); |
4373 | 0 | if (warn.IsSet() && !warn.IsOn()) { |
4374 | 0 | this->SetDiagnostic(cmDiagnostics::CMD_DEPRECATED, |
4375 | 0 | cmDiagnostics::Ignore); |
4376 | 0 | } else if (this->IsOn("CMAKE_ERROR_DEPRECATED")) { |
4377 | 0 | this->SetDiagnostic(cmDiagnostics::CMD_DEPRECATED, |
4378 | 0 | cmDiagnostics::SendError); |
4379 | 0 | } else { |
4380 | 0 | this->SetDiagnostic(cmDiagnostics::CMD_DEPRECATED, |
4381 | 0 | cmDiagnostics::Warn); |
4382 | 0 | } |
4383 | 0 | } |
4384 | |
|
4385 | 0 | this->IssueDiagnostic(cmDiagnostics::CMD_DEPRECATED, |
4386 | 0 | cmPolicies::GetPolicyDeprecatedWarning(id)); |
4387 | 0 | } |
4388 | | |
4389 | 2.69M | this->StateSnapshot.SetPolicy(id, status); |
4390 | | |
4391 | | // Handle CMAKE_PARENT_LIST_FILE for CMP0198 policy changes |
4392 | 2.69M | if (id == cmPolicies::CMP0198 && |
4393 | 11.8k | this->GetCMakeInstance()->GetState()->GetRole() == |
4394 | 11.8k | cmState::Role::Project) { |
4395 | 11.8k | this->UpdateParentListFileVariable(); |
4396 | 11.8k | } |
4397 | | |
4398 | 2.69M | return true; |
4399 | 2.69M | } |
4400 | | |
4401 | | cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m) |
4402 | 0 | : Makefile(m) |
4403 | 0 | { |
4404 | 0 | this->Makefile->PushPolicy(); |
4405 | 0 | } |
4406 | | |
4407 | | cmMakefile::PolicyPushPop::~PolicyPushPop() |
4408 | 0 | { |
4409 | 0 | this->Makefile->PopPolicy(); |
4410 | 0 | } |
4411 | | |
4412 | | void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm) |
4413 | 19.8k | { |
4414 | 19.8k | this->StateSnapshot.PushPolicy(pm, weak); |
4415 | 19.8k | } |
4416 | | |
4417 | | void cmMakefile::PopPolicy() |
4418 | 0 | { |
4419 | 0 | if (!this->StateSnapshot.PopPolicy()) { |
4420 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
4421 | 0 | "cmake_policy POP without matching PUSH"); |
4422 | 0 | } |
4423 | 0 | } |
4424 | | |
4425 | | cmDiagnosticAction cmMakefile::GetDiagnosticAction( |
4426 | | cmDiagnosticCategory category) const |
4427 | 0 | { |
4428 | 0 | return this->StateSnapshot.GetDiagnostic(category); |
4429 | 0 | } |
4430 | | |
4431 | | bool cmMakefile::SetDiagnostic(cmDiagnosticCategory category, |
4432 | | cmDiagnosticAction action, bool recursive) |
4433 | 0 | { |
4434 | 0 | this->StateSnapshot.SetDiagnostic(category, action, recursive); |
4435 | 0 | return true; |
4436 | 0 | } |
4437 | | |
4438 | | bool cmMakefile::PromoteDiagnostic(cmDiagnosticCategory category, |
4439 | | cmDiagnosticAction action, bool recursive) |
4440 | 0 | { |
4441 | 0 | this->StateSnapshot.PromoteDiagnostic(category, action, recursive); |
4442 | 0 | return true; |
4443 | 0 | } |
4444 | | |
4445 | | bool cmMakefile::DemoteDiagnostic(cmDiagnosticCategory category, |
4446 | | cmDiagnosticAction action, bool recursive) |
4447 | 0 | { |
4448 | 0 | this->StateSnapshot.DemoteDiagnostic(category, action, recursive); |
4449 | 0 | return true; |
4450 | 0 | } |
4451 | | |
4452 | | cmMakefile::DiagnosticPushPop::DiagnosticPushPop(cmMakefile* m) |
4453 | 0 | : Makefile(m) |
4454 | 0 | { |
4455 | 0 | this->Makefile->PushDiagnostic(); |
4456 | 0 | } |
4457 | | |
4458 | | cmMakefile::DiagnosticPushPop::~DiagnosticPushPop() |
4459 | 0 | { |
4460 | 0 | this->Makefile->PopDiagnostic(); |
4461 | 0 | } |
4462 | | |
4463 | | void cmMakefile::PushDiagnostic(bool weak, cmDiagnostics::DiagnosticMap dm) |
4464 | 19.8k | { |
4465 | 19.8k | this->StateSnapshot.PushDiagnostic(dm, weak); |
4466 | 19.8k | } |
4467 | | |
4468 | | void cmMakefile::PopDiagnostic() |
4469 | 0 | { |
4470 | 0 | if (!this->StateSnapshot.PopDiagnostic()) { |
4471 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
4472 | 0 | "cmake_diagnostic POP without matching PUSH"); |
4473 | 0 | } |
4474 | 0 | } |
4475 | | |
4476 | | void cmMakefile::PopSnapshot(bool reportError) |
4477 | 11.8k | { |
4478 | | // cmStateSnapshot manages nested policy/diagnostic scopes within it. |
4479 | | // Since the scope corresponding to the snapshot is closing, |
4480 | | // reject any still-open nested policy/diagnostic scopes with an error. |
4481 | 11.8k | for (;;) { |
4482 | 11.8k | if (this->StateSnapshot.CanPopPolicyScope()) { |
4483 | 0 | if (reportError) { |
4484 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
4485 | 0 | "cmake_policy PUSH without matching POP"); |
4486 | 0 | reportError = false; |
4487 | 0 | } |
4488 | 0 | this->PopPolicy(); |
4489 | 11.8k | } else if (this->StateSnapshot.CanPopDiagnosticScope()) { |
4490 | 0 | if (reportError) { |
4491 | 0 | this->IssueMessage(MessageType::FATAL_ERROR, |
4492 | 0 | "cmake_diagnostic PUSH without matching POP"); |
4493 | 0 | reportError = false; |
4494 | 0 | } |
4495 | 0 | this->PopDiagnostic(); |
4496 | 11.8k | } else { |
4497 | 11.8k | break; |
4498 | 11.8k | } |
4499 | 11.8k | } |
4500 | | |
4501 | 11.8k | this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot); |
4502 | 11.8k | assert(this->StateSnapshot.IsValid()); |
4503 | 11.8k | } |
4504 | | |
4505 | | bool cmMakefile::SetPolicyVersion(std::string const& version_min, |
4506 | | std::string const& version_max) |
4507 | 11.8k | { |
4508 | 11.8k | return cmPolicies::ApplyPolicyVersion(this, version_min, version_max, |
4509 | 11.8k | cmPolicies::WarnCompat::On); |
4510 | 11.8k | } |
4511 | | |
4512 | | void cmMakefile::UpdateParentListFileVariable() |
4513 | 11.8k | { |
4514 | | // CMP0198 determines CMAKE_PARENT_LIST_FILE behavior in CMakeLists.txt |
4515 | 11.8k | if (this->GetPolicyStatus(cmPolicies::CMP0198) == cmPolicies::NEW) { |
4516 | 0 | this->RemoveDefinition(kCMAKE_PARENT_LIST_FILE); |
4517 | 11.8k | } else { |
4518 | 11.8k | std::string currentSourceDir = |
4519 | 11.8k | this->StateSnapshot.GetDirectory().GetCurrentSource(); |
4520 | 11.8k | std::string currentStart = |
4521 | 11.8k | this->GetCMakeInstance()->GetCMakeListFile(currentSourceDir); |
4522 | | |
4523 | 11.8k | this->AddDefinition(kCMAKE_PARENT_LIST_FILE, currentStart); |
4524 | 11.8k | } |
4525 | 11.8k | } |
4526 | | |
4527 | | cmMakefile::VariablePushPop::VariablePushPop(cmMakefile* m) |
4528 | 0 | : Makefile(m) |
4529 | 0 | { |
4530 | 0 | this->Makefile->StateSnapshot = |
4531 | 0 | this->Makefile->GetState()->CreateVariableScopeSnapshot( |
4532 | 0 | this->Makefile->StateSnapshot); |
4533 | 0 | } |
4534 | | |
4535 | | cmMakefile::VariablePushPop::~VariablePushPop() |
4536 | 0 | { |
4537 | 0 | this->Makefile->PopSnapshot(); |
4538 | 0 | } |
4539 | | |
4540 | | void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const |
4541 | 84.9k | { |
4542 | | /* Record the setting of every policy. */ |
4543 | 84.9k | using PolicyID = cmPolicies::PolicyID; |
4544 | 19.3M | for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT; |
4545 | 19.2M | pid = static_cast<PolicyID>(pid + 1)) { |
4546 | 19.2M | pm.Set(pid, this->GetPolicyStatus(pid)); |
4547 | 19.2M | } |
4548 | 84.9k | } |
4549 | | |
4550 | | void cmMakefile::RecordDiagnostics(cmDiagnostics::DiagnosticMap& dm) const |
4551 | 0 | { |
4552 | | /* Record the setting of every diagnostic category. */ |
4553 | 0 | for (unsigned n = 0; n < cmDiagnostics::CategoryCount; ++n) { |
4554 | 0 | cmDiagnosticCategory const dc = static_cast<cmDiagnosticCategory>(n); |
4555 | 0 | dm[dc] = this->GetDiagnosticAction(dc); |
4556 | 0 | } |
4557 | 0 | } |
4558 | | |
4559 | | cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf, |
4560 | | std::string const& fileName, |
4561 | | cmPolicies::PolicyMap const& pm, |
4562 | | cmDiagnostics::DiagnosticMap dm) |
4563 | 0 | : Makefile(mf) |
4564 | 0 | { |
4565 | 0 | this->Makefile->PushFunctionScope(fileName, pm, dm); |
4566 | 0 | } |
4567 | | |
4568 | | cmMakefile::FunctionPushPop::~FunctionPushPop() |
4569 | 0 | { |
4570 | 0 | this->Makefile->PopFunctionScope(this->ReportError); |
4571 | 0 | } |
4572 | | |
4573 | | cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf, |
4574 | | std::string const& fileName, |
4575 | | cmPolicies::PolicyMap const& pm, |
4576 | | cmDiagnostics::DiagnosticMap dm) |
4577 | 0 | : Makefile(mf) |
4578 | 0 | { |
4579 | 0 | this->Makefile->PushMacroScope(fileName, pm, dm); |
4580 | 0 | } |
4581 | | |
4582 | | cmMakefile::MacroPushPop::~MacroPushPop() |
4583 | 0 | { |
4584 | 0 | this->Makefile->PopMacroScope(this->ReportError); |
4585 | 0 | } |
4586 | | |
4587 | | cmMakefile::FindPackageStackRAII::FindPackageStackRAII( |
4588 | | cmMakefile* mf, std::string const& name, |
4589 | | std::shared_ptr<cmPackageInformation const> pkgInfo) |
4590 | 0 | : Makefile(mf) |
4591 | 0 | { |
4592 | 0 | this->Makefile->FindPackageStack = |
4593 | 0 | this->Makefile->FindPackageStack.Push(cmFindPackageCall{ |
4594 | 0 | name, |
4595 | 0 | std::move(pkgInfo), |
4596 | 0 | this->Makefile->FindPackageStackNextIndex, |
4597 | 0 | }); |
4598 | 0 | this->Makefile->FindPackageStackNextIndex++; |
4599 | 0 | } |
4600 | | |
4601 | | cmMakefile::FindPackageStackRAII::~FindPackageStackRAII() |
4602 | 0 | { |
4603 | 0 | this->Makefile->FindPackageStackNextIndex = |
4604 | 0 | this->Makefile->FindPackageStack.Top().Index + 1; |
4605 | 0 | this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop(); |
4606 | |
|
4607 | 0 | if (!this->Makefile->FindPackageStack.Empty()) { |
4608 | | // We have just finished an inner package found as a dependency of an |
4609 | | // outer package. Targets created in the outer package after this |
4610 | | // point may depend on the inner package, so if they are exported, |
4611 | | // their find_dependency call for the outer package should be |
4612 | | // ordered after the find_dependency call for the inner package. |
4613 | | // |
4614 | | // Any targets created by the outer package before the inner package |
4615 | | // was loaded will have already saved a copy of the outer package |
4616 | | // stack with its original index. Replace the top entry with a new |
4617 | | // one representing the same outer package with a new index. |
4618 | 0 | cmFindPackageCall outer = this->Makefile->FindPackageStack.Top(); |
4619 | 0 | this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop(); |
4620 | |
|
4621 | 0 | outer.Index = this->Makefile->FindPackageStackNextIndex; |
4622 | 0 | this->Makefile->FindPackageStackNextIndex++; |
4623 | |
|
4624 | 0 | this->Makefile->FindPackageStack = |
4625 | 0 | this->Makefile->FindPackageStack.Push(outer); |
4626 | 0 | } |
4627 | 0 | } |
4628 | | |
4629 | | cmMakefile::DebugFindPkgRAII::DebugFindPkgRAII(cmMakefile* mf, |
4630 | | std::string const& pkg) |
4631 | 0 | : Makefile(mf) |
4632 | 0 | , OldValue(this->Makefile->DebugFindPkg) |
4633 | 0 | { |
4634 | 0 | this->Makefile->DebugFindPkg = |
4635 | 0 | this->Makefile->GetCMakeInstance()->GetDebugFindPkgOutput(pkg); |
4636 | 0 | } |
4637 | | |
4638 | | cmMakefile::DebugFindPkgRAII::~DebugFindPkgRAII() |
4639 | 0 | { |
4640 | 0 | this->Makefile->DebugFindPkg = this->OldValue; |
4641 | 0 | } |
4642 | | |
4643 | | bool cmMakefile::GetDebugFindPkgMode() const |
4644 | 0 | { |
4645 | 0 | return this->DebugFindPkg; |
4646 | 0 | } |