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