/src/CMake/Source/cmGlobalGenerator.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 "cmGlobalGenerator.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <cassert> |
7 | | #include <cstdio> |
8 | | #include <cstdlib> |
9 | | #include <cstring> |
10 | | #include <functional> |
11 | | #include <initializer_list> |
12 | | #include <iterator> |
13 | | #include <sstream> |
14 | | #include <utility> |
15 | | |
16 | | #include <cm/memory> |
17 | | #include <cm/optional> |
18 | | #include <cmext/algorithm> |
19 | | #include <cmext/string_view> |
20 | | |
21 | | #include "cmsys/Directory.hxx" |
22 | | #include "cmsys/FStream.hxx" |
23 | | #include "cmsys/RegularExpression.hxx" |
24 | | |
25 | | #include "cm_codecvt_Encoding.hxx" |
26 | | |
27 | | #include "cmAlgorithms.h" |
28 | | #include "cmArgumentParserTypes.h" |
29 | | #include "cmBuildArgs.h" |
30 | | #include "cmCMakePath.h" |
31 | | #include "cmCPackPropertiesGenerator.h" |
32 | | #include "cmComputeTargetDepends.h" |
33 | | #include "cmCryptoHash.h" |
34 | | #include "cmCustomCommand.h" |
35 | | #include "cmCustomCommandLines.h" |
36 | | #include "cmCustomCommandTypes.h" |
37 | | #include "cmDiagnostics.h" |
38 | | #include "cmDuration.h" |
39 | | #include "cmExperimental.h" |
40 | | #include "cmExportBuildFileGenerator.h" |
41 | | #include "cmExternalMakefileProjectGenerator.h" |
42 | | #include "cmGeneratedFileStream.h" |
43 | | #include "cmGeneratorExpression.h" |
44 | | #include "cmGeneratorTarget.h" |
45 | | #include "cmInstallGenerator.h" |
46 | | #include "cmInstallRuntimeDependencySet.h" |
47 | | #include "cmInstallSbomExportGenerator.h" |
48 | | #include "cmLinkLineComputer.h" |
49 | | #include "cmList.h" |
50 | | #include "cmListFileCache.h" |
51 | | #include "cmLocalGenerator.h" |
52 | | #include "cmMSVC60LinkLineComputer.h" |
53 | | #include "cmMakefile.h" |
54 | | #include "cmMessageType.h" |
55 | | #include "cmOutputConverter.h" |
56 | | #include "cmPolicies.h" |
57 | | #include "cmRange.h" |
58 | | #include "cmSbomArguments.h" |
59 | | #include "cmSourceFile.h" |
60 | | #include "cmState.h" |
61 | | #include "cmStateDirectory.h" |
62 | | #include "cmStateTypes.h" |
63 | | #include "cmStringAlgorithms.h" |
64 | | #include "cmSyntheticTargetCache.h" |
65 | | #include "cmSystemTools.h" |
66 | | #include "cmValue.h" |
67 | | #include "cmVersion.h" |
68 | | #include "cmWorkingDirectory.h" |
69 | | #include "cmXcFramework.h" |
70 | | #include "cmake.h" |
71 | | |
72 | | #if !defined(CMAKE_BOOTSTRAP) |
73 | | # include <cm3p/json/value.h> |
74 | | # include <cm3p/json/writer.h> |
75 | | |
76 | | # include "cmQtAutoGenGlobalInitializer.h" |
77 | | #endif |
78 | | |
79 | | std::string const kCMAKE_PLATFORM_INFO_INITIALIZED = |
80 | | "CMAKE_PLATFORM_INFO_INITIALIZED"; |
81 | | |
82 | | class cmInstalledFile; |
83 | | |
84 | | namespace detail { |
85 | | std::string GeneratedMakeCommand::QuotedPrintable() const |
86 | 0 | { |
87 | 0 | std::string output; |
88 | 0 | char const* sep = ""; |
89 | 0 | int flags = 0; |
90 | 0 | #if !defined(_WIN32) |
91 | 0 | flags |= cmOutputConverter::Shell_Flag_IsUnix; |
92 | 0 | #endif |
93 | 0 | for (auto const& arg : this->PrimaryCommand) { |
94 | 0 | output += cmStrCat(sep, cmOutputConverter::EscapeForShell(arg, flags)); |
95 | 0 | sep = " "; |
96 | 0 | } |
97 | 0 | return output; |
98 | 0 | } |
99 | | } |
100 | | |
101 | | bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1, |
102 | | cmTarget const* t2) const |
103 | 0 | { |
104 | 0 | int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str()); |
105 | 0 | if (nameResult == 0) { |
106 | 0 | return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory().c_str(), |
107 | 0 | t2->GetMakefile()->GetCurrentBinaryDirectory().c_str()) < 0; |
108 | 0 | } |
109 | 0 | return nameResult < 0; |
110 | 0 | } |
111 | | |
112 | | cmGlobalGenerator::cmGlobalGenerator(cmake* cm) |
113 | 1 | : CMakeInstance(cm) |
114 | 1 | { |
115 | | // By default the .SYMBOLIC dependency is not needed on symbolic rules. |
116 | 1 | this->NeedSymbolicMark = false; |
117 | | |
118 | | // by default use the native paths |
119 | 1 | this->ForceUnixPaths = false; |
120 | | |
121 | | // By default do not try to support color. |
122 | 1 | this->ToolSupportsColor = false; |
123 | | |
124 | | // By default do not use link scripts. |
125 | 1 | this->UseLinkScript = false; |
126 | | |
127 | | // Whether an install target is needed. |
128 | 1 | this->InstallTargetEnabled = false; |
129 | | |
130 | | // how long to let try compiles run |
131 | 1 | this->TryCompileTimeout = cmDuration::zero(); |
132 | | |
133 | 1 | this->CurrentConfigureMakefile = nullptr; |
134 | 1 | this->TryCompileOuterMakefile = nullptr; |
135 | | |
136 | 1 | this->FirstTimeProgress = 0.0f; |
137 | | |
138 | 1 | cm->GetState()->SetIsGeneratorMultiConfig(false); |
139 | 1 | cm->GetState()->SetMinGWMake(false); |
140 | 1 | cm->GetState()->SetMSYSShell(false); |
141 | 1 | cm->GetState()->SetNMake(false); |
142 | 1 | cm->GetState()->SetWatcomWMake(false); |
143 | 1 | cm->GetState()->SetWindowsShell(false); |
144 | 1 | cm->GetState()->SetWindowsVSIDE(false); |
145 | | |
146 | 1 | cm->GetState()->SetFastbuildMake(false); |
147 | 1 | #if !defined(CMAKE_BOOTSTRAP) |
148 | 1 | Json::StreamWriterBuilder wbuilder; |
149 | 1 | wbuilder["indentation"] = "\t"; |
150 | 1 | this->JsonWriter = |
151 | 1 | std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter()); |
152 | 1 | #endif |
153 | 1 | } |
154 | | |
155 | | cmGlobalGenerator::~cmGlobalGenerator() |
156 | 1 | { |
157 | 1 | this->ClearGeneratorMembers(); |
158 | 1 | } |
159 | | codecvt_Encoding cmGlobalGenerator::GetMakefileEncoding() const |
160 | 0 | { |
161 | 0 | return codecvt_Encoding::None; |
162 | 0 | } |
163 | | |
164 | | #if !defined(CMAKE_BOOTSTRAP) |
165 | | Json::Value cmGlobalGenerator::GetJson() const |
166 | 0 | { |
167 | 0 | Json::Value generator = Json::objectValue; |
168 | 0 | generator["name"] = this->GetName(); |
169 | 0 | generator["multiConfig"] = this->IsMultiConfig(); |
170 | 0 | return generator; |
171 | 0 | } |
172 | | #endif |
173 | | |
174 | | bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i, |
175 | | cmMakefile* mf) |
176 | 0 | { |
177 | 0 | if (i.empty()) { |
178 | 0 | return true; |
179 | 0 | } |
180 | | |
181 | 0 | std::ostringstream e; |
182 | | /* clang-format off */ |
183 | 0 | e << |
184 | 0 | "Generator\n" |
185 | 0 | " " << this->GetName() << "\n" |
186 | 0 | "does not support instance specification, but instance\n" |
187 | 0 | " " << i << "\n" |
188 | 0 | "was specified."; |
189 | | /* clang-format on */ |
190 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
191 | 0 | return false; |
192 | 0 | } |
193 | | |
194 | | bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p, |
195 | | cmMakefile* mf) |
196 | 0 | { |
197 | 0 | if (p.empty()) { |
198 | 0 | return true; |
199 | 0 | } |
200 | | |
201 | 0 | std::ostringstream e; |
202 | | /* clang-format off */ |
203 | 0 | e << |
204 | 0 | "Generator\n" |
205 | 0 | " " << this->GetName() << "\n" |
206 | 0 | "does not support platform specification, but platform\n" |
207 | 0 | " " << p << "\n" |
208 | 0 | "was specified."; |
209 | | /* clang-format on */ |
210 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
211 | 0 | return false; |
212 | 0 | } |
213 | | |
214 | | bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool, |
215 | | cmMakefile* mf) |
216 | 0 | { |
217 | 0 | if (ts.empty()) { |
218 | 0 | return true; |
219 | 0 | } |
220 | 0 | std::ostringstream e; |
221 | | /* clang-format off */ |
222 | 0 | e << |
223 | 0 | "Generator\n" |
224 | 0 | " " << this->GetName() << "\n" |
225 | 0 | "does not support toolset specification, but toolset\n" |
226 | 0 | " " << ts << "\n" |
227 | 0 | "was specified."; |
228 | | /* clang-format on */ |
229 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
230 | 0 | return false; |
231 | 0 | } |
232 | | |
233 | | std::string cmGlobalGenerator::SelectMakeProgram( |
234 | | std::string const& inMakeProgram, std::string const& makeDefault) const |
235 | 0 | { |
236 | 0 | std::string makeProgram = inMakeProgram; |
237 | 0 | if (cmIsOff(makeProgram)) { |
238 | 0 | cmValue makeProgramCSTR = |
239 | 0 | this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM"); |
240 | 0 | if (makeProgramCSTR.IsOff()) { |
241 | 0 | makeProgram = makeDefault; |
242 | 0 | } else { |
243 | 0 | makeProgram = *makeProgramCSTR; |
244 | 0 | } |
245 | 0 | if (cmIsOff(makeProgram) && !makeProgram.empty()) { |
246 | 0 | makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND"; |
247 | 0 | } |
248 | 0 | } |
249 | 0 | return makeProgram; |
250 | 0 | } |
251 | | |
252 | | void cmGlobalGenerator::ResolveLanguageCompiler(std::string const& lang, |
253 | | cmMakefile* mf, |
254 | | bool optional) const |
255 | 0 | { |
256 | 0 | std::string langComp = cmStrCat("CMAKE_", lang, "_COMPILER"); |
257 | |
|
258 | 0 | if (!mf->GetDefinition(langComp)) { |
259 | 0 | if (!optional) { |
260 | 0 | cmSystemTools::Error( |
261 | 0 | cmStrCat(langComp, " not set, after EnableLanguage")); |
262 | 0 | } |
263 | 0 | return; |
264 | 0 | } |
265 | 0 | std::string const& name = mf->GetRequiredDefinition(langComp); |
266 | 0 | std::string path; |
267 | 0 | if (!cmSystemTools::FileIsFullPath(name)) { |
268 | 0 | path = cmSystemTools::FindProgram(name); |
269 | 0 | } else { |
270 | 0 | path = name; |
271 | 0 | } |
272 | 0 | if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) { |
273 | 0 | return; |
274 | 0 | } |
275 | 0 | cmValue cname = |
276 | 0 | this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp); |
277 | | |
278 | | // Split compiler from arguments |
279 | 0 | cmList cnameArgList; |
280 | 0 | if (cname && !cname->empty()) { |
281 | 0 | cnameArgList.assign(*cname); |
282 | 0 | cname = cmValue(cnameArgList.front()); |
283 | 0 | } |
284 | |
|
285 | 0 | std::string changeVars; |
286 | 0 | if (cname && !optional) { |
287 | 0 | cmCMakePath cachedPath; |
288 | 0 | if (!cmSystemTools::FileIsFullPath(*cname)) { |
289 | 0 | cachedPath = cmSystemTools::FindProgram(*cname); |
290 | 0 | } else { |
291 | 0 | cachedPath = *cname; |
292 | 0 | } |
293 | 0 | cmCMakePath foundPath = path; |
294 | 0 | if (foundPath.Normal() != cachedPath.Normal()) { |
295 | 0 | cmValue cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty( |
296 | 0 | "__CMAKE_DELETE_CACHE_CHANGE_VARS_"); |
297 | 0 | if (cvars) { |
298 | 0 | changeVars += *cvars; |
299 | 0 | changeVars += ";"; |
300 | 0 | } |
301 | 0 | changeVars += langComp; |
302 | 0 | changeVars += ";"; |
303 | 0 | changeVars += *cname; |
304 | 0 | this->GetCMakeInstance()->GetState()->SetGlobalProperty( |
305 | 0 | "__CMAKE_DELETE_CACHE_CHANGE_VARS_", changeVars); |
306 | 0 | } |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen) |
311 | 0 | { |
312 | 0 | this->BuildExportSets[gen->GetMainExportFileName()] = gen; |
313 | 0 | } |
314 | | |
315 | | void cmGlobalGenerator::AddBuildExportExportSet( |
316 | | cmExportBuildFileGenerator* gen) |
317 | 0 | { |
318 | 0 | this->BuildExportExportSets[gen->GetMainExportFileName()] = gen; |
319 | 0 | this->AddBuildExportSet(gen); |
320 | 0 | } |
321 | | |
322 | | void cmGlobalGenerator::ForceLinkerLanguages() |
323 | 0 | { |
324 | 0 | } |
325 | | |
326 | | bool cmGlobalGenerator::CheckTargetsForMissingSources() const |
327 | 0 | { |
328 | 0 | bool failed = false; |
329 | 0 | for (auto const& localGen : this->LocalGenerators) { |
330 | 0 | for (auto const& target : localGen->GetGeneratorTargets()) { |
331 | 0 | if (!target->CanCompileSources() || |
332 | 0 | target->GetProperty("ghs_integrity_app").IsOn()) { |
333 | 0 | continue; |
334 | 0 | } |
335 | | |
336 | 0 | if (target->GetAllConfigSources().empty()) { |
337 | 0 | std::ostringstream e; |
338 | 0 | e << "No SOURCES given to target: " << target->GetName(); |
339 | 0 | this->GetCMakeInstance()->IssueMessage( |
340 | 0 | MessageType::FATAL_ERROR, e.str(), target->GetBacktrace()); |
341 | 0 | failed = true; |
342 | 0 | } |
343 | 0 | } |
344 | 0 | } |
345 | 0 | return failed; |
346 | 0 | } |
347 | | |
348 | | void cmGlobalGenerator::CheckTargetLinkLibraries() const |
349 | 0 | { |
350 | 0 | for (auto const& generator : this->LocalGenerators) { |
351 | 0 | for (auto const& gt : generator->GetGeneratorTargets()) { |
352 | 0 | gt->CheckLinkLibraries(); |
353 | 0 | } |
354 | 0 | for (auto const& gt : generator->GetOwnedImportedGeneratorTargets()) { |
355 | 0 | gt->CheckLinkLibraries(); |
356 | 0 | } |
357 | 0 | } |
358 | 0 | } |
359 | | |
360 | | bool cmGlobalGenerator::CheckTargetsForType() const |
361 | 0 | { |
362 | 0 | if (!this->GetLanguageEnabled("Swift")) { |
363 | 0 | return false; |
364 | 0 | } |
365 | 0 | bool failed = false; |
366 | 0 | for (auto const& generator : this->LocalGenerators) { |
367 | 0 | for (auto const& target : generator->GetGeneratorTargets()) { |
368 | 0 | std::string systemName = |
369 | 0 | target->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"); |
370 | 0 | if (systemName.find("Windows") == std::string::npos) { |
371 | 0 | continue; |
372 | 0 | } |
373 | | |
374 | 0 | if (target->GetType() == cmStateEnums::EXECUTABLE) { |
375 | 0 | std::vector<std::string> const& configs = |
376 | 0 | target->Makefile->GetGeneratorConfigs( |
377 | 0 | cmMakefile::IncludeEmptyConfig); |
378 | 0 | for (std::string const& config : configs) { |
379 | 0 | if (target->IsWin32Executable(config) && |
380 | 0 | target->GetLinkerLanguage(config) == "Swift") { |
381 | 0 | this->GetCMakeInstance()->IssueMessage( |
382 | 0 | MessageType::FATAL_ERROR, |
383 | 0 | "WIN32_EXECUTABLE property is not supported on Swift " |
384 | 0 | "executables", |
385 | 0 | target->GetBacktrace()); |
386 | 0 | failed = true; |
387 | 0 | } |
388 | 0 | } |
389 | 0 | } |
390 | 0 | } |
391 | 0 | } |
392 | 0 | return failed; |
393 | 0 | } |
394 | | |
395 | | void cmGlobalGenerator::MarkTargetsForPchReuse() const |
396 | 0 | { |
397 | 0 | for (auto const& generator : this->LocalGenerators) { |
398 | 0 | for (auto const& target : generator->GetGeneratorTargets()) { |
399 | 0 | if (auto* reuseTarget = target->GetPchReuseTarget()) { |
400 | 0 | reuseTarget->MarkAsPchReused(); |
401 | 0 | } |
402 | 0 | } |
403 | 0 | } |
404 | 0 | } |
405 | | |
406 | | bool cmGlobalGenerator::IsExportedTargetsFile( |
407 | | std::string const& filename) const |
408 | 0 | { |
409 | 0 | auto const it = this->BuildExportSets.find(filename); |
410 | 0 | if (it == this->BuildExportSets.end()) { |
411 | 0 | return false; |
412 | 0 | } |
413 | 0 | return !cm::contains(this->BuildExportExportSets, filename); |
414 | 0 | } |
415 | | |
416 | | // Find the make program for the generator, required for try compiles |
417 | | bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) |
418 | 0 | { |
419 | 0 | if (this->FindMakeProgramFile.empty()) { |
420 | 0 | cmSystemTools::Error( |
421 | 0 | "Generator implementation error, " |
422 | 0 | "all generators must specify this->FindMakeProgramFile"); |
423 | 0 | return false; |
424 | 0 | } |
425 | 0 | if (mf->GetDefinition("CMAKE_MAKE_PROGRAM").IsOff()) { |
426 | 0 | std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile); |
427 | 0 | if (!setMakeProgram.empty()) { |
428 | 0 | mf->ReadListFile(setMakeProgram); |
429 | 0 | } |
430 | 0 | } |
431 | 0 | if (mf->GetDefinition("CMAKE_MAKE_PROGRAM").IsOff()) { |
432 | 0 | std::ostringstream err; |
433 | 0 | err << "CMake was unable to find a build program corresponding to \"" |
434 | 0 | << this->GetName() |
435 | 0 | << "\". CMAKE_MAKE_PROGRAM is not set. You " |
436 | 0 | "probably need to select a different build tool."; |
437 | 0 | cmSystemTools::Error(err.str()); |
438 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
439 | 0 | return false; |
440 | 0 | } |
441 | 0 | std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); |
442 | | // if there are spaces in the make program use short path |
443 | | // but do not short path the actual program name, as |
444 | | // this can cause trouble with VSExpress |
445 | 0 | if (makeProgram.find(' ') != std::string::npos) { |
446 | 0 | std::string dir; |
447 | 0 | std::string file; |
448 | 0 | cmSystemTools::SplitProgramPath(makeProgram, dir, file); |
449 | 0 | std::string saveFile = file; |
450 | 0 | cmSystemTools::GetShortPath(makeProgram, makeProgram); |
451 | 0 | cmSystemTools::SplitProgramPath(makeProgram, dir, file); |
452 | 0 | makeProgram = cmStrCat(dir, '/', saveFile); |
453 | 0 | mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program", |
454 | 0 | cmStateEnums::FILEPATH); |
455 | 0 | } |
456 | 0 | return true; |
457 | 0 | } |
458 | | |
459 | | bool cmGlobalGenerator::CheckLanguages( |
460 | | std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const |
461 | 0 | { |
462 | 0 | return true; |
463 | 0 | } |
464 | | |
465 | | // enable the given language |
466 | | // |
467 | | // The following files are loaded in this order: |
468 | | // |
469 | | // First figure out what OS we are running on: |
470 | | // |
471 | | // CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake |
472 | | // CMakeDetermineSystem.cmake - figure out os info and create |
473 | | // CMakeSystem.cmake IF CMAKE_SYSTEM |
474 | | // not set |
475 | | // CMakeSystem.cmake - configured file created by |
476 | | // CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED |
477 | | |
478 | | // CMakeSystemSpecificInitialize.cmake |
479 | | // - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake |
480 | | |
481 | | // Next try and enable all languages found in the languages vector |
482 | | // |
483 | | // FOREACH LANG in languages |
484 | | // CMake(LANG)Compiler.cmake - configured file create by |
485 | | // CMakeDetermine(LANG)Compiler.cmake |
486 | | // CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and |
487 | | // creates CMake(LANG)Compiler.cmake |
488 | | // CMake(LANG)Compiler.cmake - configured file created by |
489 | | // CMakeDetermine(LANG)Compiler.cmake |
490 | | // |
491 | | // CMakeSystemSpecificInformation.cmake |
492 | | // - includes Platform/${CMAKE_SYSTEM_NAME}.cmake |
493 | | // may use compiler stuff |
494 | | |
495 | | // FOREACH LANG in languages |
496 | | // CMake(LANG)Information.cmake |
497 | | // - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake |
498 | | // CMakeTest(LANG)Compiler.cmake |
499 | | // - Make sure the compiler works with a try compile if |
500 | | // CMakeDetermine(LANG) was loaded |
501 | | // |
502 | | // CMake(LANG)LinkerInformation.cmake |
503 | | // - loads Platform/Linker/${CMAKE_SYSTEM_NAME}-${LINKER}.cmake |
504 | | // |
505 | | // Now load a few files that can override values set in any of the above |
506 | | // (PROJECTNAME)Compatibility.cmake |
507 | | // - load any backwards compatibility stuff for current project |
508 | | // ${CMAKE_USER_MAKE_RULES_OVERRIDE} |
509 | | // - allow users a chance to override system variables |
510 | | // |
511 | | // |
512 | | |
513 | | void cmGlobalGenerator::EnableLanguage( |
514 | | std::vector<std::string> const& languages, cmMakefile* mf, bool optional) |
515 | 0 | { |
516 | 0 | if (!this->IsMultiConfig() && |
517 | 0 | !this->GetCMakeInstance()->GetIsInTryCompile()) { |
518 | 0 | std::string envBuildType; |
519 | 0 | if (!mf->GetDefinition("CMAKE_BUILD_TYPE") && |
520 | 0 | cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) { |
521 | 0 | mf->AddCacheDefinition( |
522 | 0 | "CMAKE_BUILD_TYPE", envBuildType, |
523 | 0 | "Choose the type of build. Options include: empty, " |
524 | 0 | "Debug, Release, RelWithDebInfo, MinSizeRel.", |
525 | 0 | cmStateEnums::STRING); |
526 | 0 | } |
527 | 0 | } |
528 | |
|
529 | 0 | if (languages.empty()) { |
530 | 0 | cmSystemTools::Error("EnableLanguage must have a lang specified!"); |
531 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
532 | 0 | return; |
533 | 0 | } |
534 | | |
535 | 0 | std::set<std::string> cur_languages(languages.begin(), languages.end()); |
536 | 0 | for (std::string const& li : cur_languages) { |
537 | 0 | if (!this->LanguagesInProgress.insert(li).second) { |
538 | 0 | std::ostringstream e; |
539 | 0 | e << "Language '" << li |
540 | 0 | << "' is currently being enabled. " |
541 | 0 | "Recursive call not allowed."; |
542 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
543 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
544 | 0 | return; |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | 0 | if (this->TryCompileOuterMakefile) { |
549 | | // In a try-compile we can only enable languages provided by caller. |
550 | 0 | for (std::string const& lang : languages) { |
551 | 0 | if (lang == "NONE") { |
552 | 0 | this->SetLanguageEnabled("NONE", mf); |
553 | 0 | } else { |
554 | 0 | if (!cm::contains(this->LanguagesReady, lang)) { |
555 | 0 | std::ostringstream e; |
556 | 0 | e << "The test project needs language " << lang |
557 | 0 | << " which is not enabled."; |
558 | 0 | this->TryCompileOuterMakefile->IssueMessage(MessageType::FATAL_ERROR, |
559 | 0 | e.str()); |
560 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
561 | 0 | return; |
562 | 0 | } |
563 | 0 | } |
564 | 0 | } |
565 | 0 | } |
566 | | |
567 | 0 | bool fatalError = false; |
568 | |
|
569 | 0 | mf->AddDefinitionBool("RUN_CONFIGURE", true); |
570 | 0 | std::string rootBin = |
571 | 0 | cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles"); |
572 | | |
573 | | // If the configuration files path has been set, |
574 | | // then we are in a try compile and need to copy the enable language |
575 | | // files from the parent cmake bin dir, into the try compile bin dir |
576 | 0 | if (!this->ConfiguredFilesPath.empty()) { |
577 | 0 | rootBin = this->ConfiguredFilesPath; |
578 | 0 | } |
579 | 0 | rootBin += '/'; |
580 | 0 | rootBin += cmVersion::GetCMakeVersion(); |
581 | | |
582 | | // set the dir for parent files so they can be used by modules |
583 | 0 | mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin); |
584 | |
|
585 | 0 | if (!this->CMakeInstance->GetIsInTryCompile()) { |
586 | | // Keep a mark in the cache to indicate that we've initialized the |
587 | | // platform information directory. If the platform information |
588 | | // directory exists but the mark is missing then CMakeCache.txt |
589 | | // has been removed or replaced without also removing the CMakeFiles/ |
590 | | // directory. In this case remove the platform information directory |
591 | | // so that it will be re-initialized and the relevant information |
592 | | // restored in the cache. |
593 | 0 | if (cmSystemTools::FileIsDirectory(rootBin) && |
594 | 0 | !mf->IsOn(kCMAKE_PLATFORM_INFO_INITIALIZED)) { |
595 | 0 | cmSystemTools::RemoveADirectory(rootBin); |
596 | 0 | } |
597 | 0 | this->GetCMakeInstance()->AddCacheEntry( |
598 | 0 | kCMAKE_PLATFORM_INFO_INITIALIZED, "1", |
599 | 0 | "Platform information initialized", cmStateEnums::INTERNAL); |
600 | 0 | } |
601 | | |
602 | | // try and load the CMakeSystem.cmake if it is there |
603 | 0 | std::string fpath = rootBin; |
604 | 0 | bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED"); |
605 | 0 | if (readCMakeSystem) { |
606 | 0 | fpath += "/CMakeSystem.cmake"; |
607 | 0 | if (cmSystemTools::FileExists(fpath)) { |
608 | 0 | mf->ReadListFile(fpath); |
609 | 0 | } |
610 | 0 | } |
611 | | |
612 | | // Load the CMakeDetermineSystem.cmake file and find out |
613 | | // what platform we are running on |
614 | 0 | if (!mf->GetDefinition("CMAKE_SYSTEM")) { |
615 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
616 | | cmSystemTools::WindowsVersion windowsVersion = |
617 | | cmSystemTools::GetWindowsVersion(); |
618 | | auto windowsVersionString = cmStrCat(windowsVersion.dwMajorVersion, '.', |
619 | | windowsVersion.dwMinorVersion, '.', |
620 | | windowsVersion.dwBuildNumber); |
621 | | mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString); |
622 | | #endif |
623 | | // Read the DetermineSystem file |
624 | 0 | std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake"); |
625 | 0 | mf->ReadListFile(systemFile); |
626 | | // load the CMakeSystem.cmake from the binary directory |
627 | | // this file is configured by the CMakeDetermineSystem.cmake file |
628 | 0 | fpath = cmStrCat(rootBin, "/CMakeSystem.cmake"); |
629 | 0 | mf->ReadListFile(fpath); |
630 | 0 | } |
631 | |
|
632 | 0 | if (readCMakeSystem) { |
633 | | // Tell the generator about the instance, if any. |
634 | 0 | std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"); |
635 | 0 | if (!this->SetGeneratorInstance(instance, mf)) { |
636 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
637 | 0 | return; |
638 | 0 | } |
639 | | |
640 | | // Tell the generator about the target system. |
641 | 0 | std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME"); |
642 | 0 | if (!this->SetSystemName(system, mf)) { |
643 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
644 | 0 | return; |
645 | 0 | } |
646 | | |
647 | | // Tell the generator about the platform, if any. |
648 | 0 | std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"); |
649 | 0 | if (!this->SetGeneratorPlatform(platform, mf)) { |
650 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
651 | 0 | return; |
652 | 0 | } |
653 | | |
654 | | // Tell the generator about the toolset, if any. |
655 | 0 | std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"); |
656 | 0 | if (!this->SetGeneratorToolset(toolset, false, mf)) { |
657 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
658 | 0 | return; |
659 | 0 | } |
660 | | |
661 | | // Find the native build tool for this generator. |
662 | 0 | if (!this->FindMakeProgram(mf)) { |
663 | 0 | return; |
664 | 0 | } |
665 | | |
666 | | // One-time includes of user-provided project setup files |
667 | 0 | mf->GetState()->SetInTopLevelIncludes(true); |
668 | 0 | std::string includes = |
669 | 0 | mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES"); |
670 | 0 | cmList includesList{ includes }; |
671 | 0 | for (std::string setupFile : includesList) { |
672 | | // Any relative path without a .cmake extension is checked for valid |
673 | | // cmake modules. This logic should be consistent with CMake's include() |
674 | | // command. Otherwise default to checking relative path w.r.t. source |
675 | | // directory |
676 | 0 | if (!cmSystemTools::FileIsFullPath(setupFile) && |
677 | 0 | !cmHasLiteralSuffix(setupFile, ".cmake")) { |
678 | 0 | std::string mfile = mf->GetModulesFile(cmStrCat(setupFile, ".cmake")); |
679 | 0 | if (mfile.empty()) { |
680 | 0 | cmSystemTools::Error(cmStrCat( |
681 | 0 | "CMAKE_PROJECT_TOP_LEVEL_INCLUDES module:\n ", setupFile)); |
682 | 0 | mf->GetState()->SetInTopLevelIncludes(false); |
683 | 0 | return; |
684 | 0 | } |
685 | 0 | setupFile = mfile; |
686 | 0 | } |
687 | 0 | std::string absSetupFile = cmSystemTools::CollapseFullPath( |
688 | 0 | setupFile, mf->GetCurrentSourceDirectory()); |
689 | 0 | if (!cmSystemTools::FileExists(absSetupFile)) { |
690 | 0 | cmSystemTools::Error( |
691 | 0 | cmStrCat("CMAKE_PROJECT_TOP_LEVEL_INCLUDES file does not exist: ", |
692 | 0 | setupFile)); |
693 | 0 | mf->GetState()->SetInTopLevelIncludes(false); |
694 | 0 | return; |
695 | 0 | } |
696 | 0 | if (cmSystemTools::FileIsDirectory(absSetupFile)) { |
697 | 0 | cmSystemTools::Error( |
698 | 0 | cmStrCat("CMAKE_PROJECT_TOP_LEVEL_INCLUDES file is a directory: ", |
699 | 0 | setupFile)); |
700 | 0 | mf->GetState()->SetInTopLevelIncludes(false); |
701 | 0 | return; |
702 | 0 | } |
703 | 0 | if (!mf->ReadListFile(absSetupFile)) { |
704 | 0 | cmSystemTools::Error( |
705 | 0 | cmStrCat("Failed reading CMAKE_PROJECT_TOP_LEVEL_INCLUDES file: ", |
706 | 0 | setupFile)); |
707 | 0 | mf->GetState()->SetInTopLevelIncludes(false); |
708 | 0 | return; |
709 | 0 | } |
710 | 0 | } |
711 | 0 | } |
712 | 0 | mf->GetState()->SetInTopLevelIncludes(false); |
713 | | |
714 | | // Check that the languages are supported by the generator and its |
715 | | // native build tool found above. |
716 | 0 | if (!this->CheckLanguages(languages, mf)) { |
717 | 0 | return; |
718 | 0 | } |
719 | | |
720 | | // **** Load the system specific initialization if not yet loaded |
721 | 0 | if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) { |
722 | 0 | fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake"); |
723 | 0 | if (!mf->ReadListFile(fpath)) { |
724 | 0 | cmSystemTools::Error("Could not find cmake module file: " |
725 | 0 | "CMakeSystemSpecificInitialize.cmake"); |
726 | 0 | } |
727 | 0 | } |
728 | |
|
729 | 0 | std::map<std::string, bool> needTestLanguage; |
730 | 0 | std::map<std::string, bool> needSetLanguageEnabledMaps; |
731 | | // foreach language |
732 | | // load the CMakeDetermine(LANG)Compiler.cmake file to find |
733 | | // the compiler |
734 | |
|
735 | 0 | for (std::string const& lang : languages) { |
736 | 0 | needSetLanguageEnabledMaps[lang] = false; |
737 | |
|
738 | 0 | if (lang == "Rust" && |
739 | 0 | !cmExperimental::HasSupportEnabled(*this->Makefiles[0].get(), |
740 | 0 | cmExperimental::Feature::Rust)) { |
741 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, |
742 | 0 | "Experimental Rust support is not enabled."); |
743 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
744 | 0 | return; |
745 | 0 | } |
746 | | |
747 | 0 | if (lang == "NONE") { |
748 | 0 | this->SetLanguageEnabled("NONE", mf); |
749 | 0 | continue; |
750 | 0 | } |
751 | 0 | std::string loadedLang = cmStrCat("CMAKE_", lang, "_COMPILER_LOADED"); |
752 | 0 | if (!mf->GetDefinition(loadedLang)) { |
753 | 0 | fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake"); |
754 | | |
755 | | // If the existing build tree was already configured with this |
756 | | // version of CMake then try to load the configured file first |
757 | | // to avoid duplicate compiler tests. |
758 | 0 | if (cmSystemTools::FileExists(fpath)) { |
759 | 0 | if (!mf->ReadListFile(fpath)) { |
760 | 0 | cmSystemTools::Error( |
761 | 0 | cmStrCat("Could not find cmake module file: ", fpath)); |
762 | 0 | } |
763 | | // if this file was found then the language was already determined |
764 | | // to be working |
765 | 0 | needTestLanguage[lang] = false; |
766 | 0 | this->SetLanguageEnabledFlag(lang, mf); |
767 | 0 | needSetLanguageEnabledMaps[lang] = true; |
768 | | // this can only be called after loading CMake(LANG)Compiler.cmake |
769 | 0 | } |
770 | 0 | } |
771 | |
|
772 | 0 | if (!this->GetLanguageEnabled(lang)) { |
773 | 0 | if (this->CMakeInstance->GetIsInTryCompile()) { |
774 | 0 | cmSystemTools::Error("This should not have happened. " |
775 | 0 | "If you see this message, you are probably " |
776 | 0 | "using a broken CMakeLists.txt file or a " |
777 | 0 | "problematic release of CMake"); |
778 | 0 | } |
779 | | // if the CMake(LANG)Compiler.cmake file was not found then |
780 | | // load CMakeDetermine(LANG)Compiler.cmake |
781 | 0 | std::string determineCompiler = |
782 | 0 | cmStrCat("CMakeDetermine", lang, "Compiler.cmake"); |
783 | 0 | std::string determineFile = mf->GetModulesFile(determineCompiler); |
784 | 0 | if (!mf->ReadListFile(determineFile)) { |
785 | 0 | cmSystemTools::Error( |
786 | 0 | cmStrCat("Could not find cmake module file: ", determineCompiler)); |
787 | 0 | } |
788 | 0 | if (cmSystemTools::GetFatalErrorOccurred()) { |
789 | 0 | return; |
790 | 0 | } |
791 | 0 | needTestLanguage[lang] = true; |
792 | | // Some generators like visual studio should not use the env variables |
793 | | // So the global generator can specify that in this variable |
794 | 0 | if ((mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::OLD || |
795 | 0 | mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::WARN) && |
796 | 0 | !mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) { |
797 | | // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER |
798 | | // into the environment, in case user scripts want to run |
799 | | // configure, or sub cmakes |
800 | 0 | std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER"); |
801 | 0 | std::string compilerEnv = |
802 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR"); |
803 | 0 | std::string const& envVar = mf->GetRequiredDefinition(compilerEnv); |
804 | 0 | std::string const& envVarValue = |
805 | 0 | mf->GetRequiredDefinition(compilerName); |
806 | 0 | std::string env = cmStrCat(envVar, '=', envVarValue); |
807 | 0 | cmSystemTools::PutEnv(env); |
808 | 0 | } |
809 | | |
810 | | // if determineLanguage was called then load the file it |
811 | | // configures CMake(LANG)Compiler.cmake |
812 | 0 | fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake"); |
813 | 0 | if (!mf->ReadListFile(fpath)) { |
814 | 0 | cmSystemTools::Error( |
815 | 0 | cmStrCat("Could not find cmake module file: ", fpath)); |
816 | 0 | } |
817 | 0 | this->SetLanguageEnabledFlag(lang, mf); |
818 | 0 | needSetLanguageEnabledMaps[lang] = true; |
819 | | // this can only be called after loading CMake(LANG)Compiler.cmake |
820 | | // the language must be enabled for try compile to work, but we do |
821 | | // not know if it is a working compiler yet so set the test language |
822 | | // flag |
823 | 0 | needTestLanguage[lang] = true; |
824 | 0 | } // end if(!this->GetLanguageEnabled(lang) ) |
825 | 0 | } // end loop over languages |
826 | | |
827 | | // **** Load the system specific information if not yet loaded |
828 | 0 | if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) { |
829 | 0 | fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake"); |
830 | 0 | if (!mf->ReadListFile(fpath)) { |
831 | 0 | cmSystemTools::Error("Could not find cmake module file: " |
832 | 0 | "CMakeSystemSpecificInformation.cmake"); |
833 | 0 | } |
834 | 0 | } |
835 | | // loop over languages again loading CMake(LANG)Information.cmake |
836 | | // |
837 | 0 | for (std::string const& lang : languages) { |
838 | 0 | if (lang == "NONE") { |
839 | 0 | this->SetLanguageEnabled("NONE", mf); |
840 | 0 | continue; |
841 | 0 | } |
842 | | |
843 | | // Check that the compiler was found. |
844 | 0 | std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER"); |
845 | 0 | std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR"); |
846 | 0 | std::ostringstream noCompiler; |
847 | 0 | cmValue compilerFile = mf->GetDefinition(compilerName); |
848 | 0 | if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) { |
849 | 0 | noCompiler << "No " << compilerName << " could be found.\n"; |
850 | 0 | } else if ((lang != "RC") && (lang != "ASM_MARMASM") && |
851 | 0 | (lang != "ASM_MASM")) { |
852 | 0 | if (!cmSystemTools::FileIsFullPath(*compilerFile)) { |
853 | | /* clang-format off */ |
854 | 0 | noCompiler << |
855 | 0 | "The " << compilerName << ":\n" |
856 | 0 | " " << *compilerFile << "\n" |
857 | 0 | "is not a full path and was not found in the PATH." |
858 | | #ifdef _WIN32 |
859 | | " Perhaps the extension is missing?" |
860 | | #endif |
861 | 0 | "\n" |
862 | 0 | ; |
863 | | /* clang-format on */ |
864 | 0 | } else if (!cmSystemTools::FileExists(*compilerFile)) { |
865 | | /* clang-format off */ |
866 | 0 | noCompiler << |
867 | 0 | "The " << compilerName << ":\n" |
868 | 0 | " " << *compilerFile << "\n" |
869 | 0 | "is not a full path to an existing compiler tool.\n" |
870 | 0 | ; |
871 | | /* clang-format on */ |
872 | 0 | } |
873 | 0 | } |
874 | 0 | if (!noCompiler.str().empty()) { |
875 | | // Skip testing this language since the compiler is not found. |
876 | 0 | needTestLanguage[lang] = false; |
877 | 0 | if (!optional) { |
878 | | // The compiler was not found and it is not optional. Remove |
879 | | // CMake(LANG)Compiler.cmake so we try again next time CMake runs. |
880 | 0 | std::string compilerLangFile = |
881 | 0 | cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake"); |
882 | 0 | cmSystemTools::RemoveFile(compilerLangFile); |
883 | 0 | if (!this->CMakeInstance->GetIsInTryCompile()) { |
884 | 0 | this->PrintCompilerAdvice(noCompiler, lang, |
885 | 0 | mf->GetDefinition(compilerEnv)); |
886 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str()); |
887 | 0 | fatalError = true; |
888 | 0 | } |
889 | 0 | } |
890 | 0 | } |
891 | |
|
892 | 0 | std::string langLoadedVar = |
893 | 0 | cmStrCat("CMAKE_", lang, "_INFORMATION_LOADED"); |
894 | 0 | if (!mf->GetDefinition(langLoadedVar)) { |
895 | 0 | fpath = cmStrCat("CMake", lang, "Information.cmake"); |
896 | 0 | std::string informationFile = mf->GetModulesFile(fpath); |
897 | 0 | if (informationFile.empty()) { |
898 | 0 | cmSystemTools::Error( |
899 | 0 | cmStrCat("Could not find cmake module file: ", fpath)); |
900 | 0 | } else if (!mf->ReadListFile(informationFile)) { |
901 | 0 | cmSystemTools::Error( |
902 | 0 | cmStrCat("Could not process cmake module file: ", informationFile)); |
903 | 0 | } |
904 | 0 | } |
905 | 0 | if (needSetLanguageEnabledMaps[lang]) { |
906 | 0 | this->SetLanguageEnabledMaps(lang, mf); |
907 | 0 | } |
908 | 0 | this->LanguagesReady.insert(lang); |
909 | | |
910 | | // Test the compiler for the language just setup |
911 | | // (but only if a compiler has been actually found) |
912 | | // At this point we should have enough info for a try compile |
913 | | // which is used in the backward stuff |
914 | | // If the language is untested then test it now with a try compile. |
915 | 0 | if (needTestLanguage[lang]) { |
916 | 0 | if (!this->CMakeInstance->GetIsInTryCompile()) { |
917 | 0 | std::string testLang = cmStrCat("CMakeTest", lang, "Compiler.cmake"); |
918 | 0 | std::string ifpath = mf->GetModulesFile(testLang); |
919 | 0 | if (!mf->ReadListFile(ifpath)) { |
920 | 0 | cmSystemTools::Error( |
921 | 0 | cmStrCat("Could not find cmake module file: ", testLang)); |
922 | 0 | } |
923 | 0 | std::string compilerWorks = |
924 | 0 | cmStrCat("CMAKE_", lang, "_COMPILER_WORKS"); |
925 | | // if the compiler did not work, then remove the |
926 | | // CMake(LANG)Compiler.cmake file so that it will get tested the |
927 | | // next time cmake is run |
928 | 0 | if (!mf->IsOn(compilerWorks)) { |
929 | 0 | std::string compilerLangFile = |
930 | 0 | cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake"); |
931 | 0 | cmSystemTools::RemoveFile(compilerLangFile); |
932 | 0 | } |
933 | 0 | } // end if in try compile |
934 | 0 | } // end need test language |
935 | | |
936 | | // load linker configuration, if required |
937 | 0 | if (mf->IsOn(cmStrCat("CMAKE_", lang, "_COMPILER_WORKS")) && |
938 | 0 | mf->IsOn(cmStrCat("CMAKE_", lang, "_USE_LINKER_INFORMATION"))) { |
939 | 0 | std::string langLinkerLoadedVar = |
940 | 0 | cmStrCat("CMAKE_", lang, "_LINKER_INFORMATION_LOADED"); |
941 | 0 | if (!mf->GetDefinition(langLinkerLoadedVar)) { |
942 | 0 | fpath = cmStrCat("CMake", lang, "LinkerInformation.cmake"); |
943 | 0 | std::string informationFile = mf->GetModulesFile(fpath); |
944 | 0 | if (informationFile.empty()) { |
945 | 0 | informationFile = mf->GetModulesFile(cmStrCat("Internal/", fpath)); |
946 | 0 | } |
947 | 0 | if (informationFile.empty()) { |
948 | 0 | cmSystemTools::Error( |
949 | 0 | cmStrCat("Could not find cmake module file: ", fpath)); |
950 | 0 | } else if (!mf->ReadListFile(informationFile)) { |
951 | 0 | cmSystemTools::Error(cmStrCat( |
952 | 0 | "Could not process cmake module file: ", informationFile)); |
953 | 0 | } |
954 | 0 | } |
955 | |
|
956 | 0 | if (needTestLanguage[lang]) { |
957 | 0 | if (!this->CMakeInstance->GetIsInTryCompile()) { |
958 | 0 | std::string testLang = |
959 | 0 | cmStrCat("Internal/CMakeInspect", lang, "Linker.cmake"); |
960 | 0 | std::string ifpath = mf->GetModulesFile(testLang); |
961 | 0 | if (!mf->ReadListFile(ifpath)) { |
962 | 0 | cmSystemTools::Error( |
963 | 0 | cmStrCat("Could not find cmake module file: ", testLang)); |
964 | 0 | } |
965 | 0 | } |
966 | 0 | } |
967 | 0 | } |
968 | | |
969 | | // Translate compiler ids for compatibility. |
970 | 0 | this->CheckCompilerIdCompatibility(mf, lang); |
971 | 0 | } // end for each language |
972 | | |
973 | | // Now load files that can override any settings on the platform or for |
974 | | // the project First load the project compatibility file if it is in |
975 | | // cmake |
976 | 0 | std::string projectCompatibility = |
977 | 0 | cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", |
978 | 0 | mf->GetSafeDefinition("PROJECT_NAME"), "Compatibility.cmake"); |
979 | 0 | if (cmSystemTools::FileExists(projectCompatibility)) { |
980 | 0 | mf->ReadListFile(projectCompatibility); |
981 | 0 | } |
982 | | // Inform any extra generator of the new language. |
983 | 0 | if (this->ExtraGenerator) { |
984 | 0 | this->ExtraGenerator->EnableLanguage(languages, mf, false); |
985 | 0 | } |
986 | |
|
987 | 0 | if (fatalError) { |
988 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
989 | 0 | } |
990 | |
|
991 | 0 | for (std::string const& lang : cur_languages) { |
992 | 0 | this->LanguagesInProgress.erase(lang); |
993 | 0 | } |
994 | 0 | } |
995 | | |
996 | | void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os, |
997 | | std::string const& lang, |
998 | | cmValue envVar) const |
999 | 0 | { |
1000 | | // Subclasses override this method if they do not support this advice. |
1001 | 0 | os << "Tell CMake where to find the compiler by setting "; |
1002 | 0 | if (envVar) { |
1003 | 0 | os << "either the environment variable \"" << *envVar << "\" or "; |
1004 | 0 | } |
1005 | 0 | os << "the CMake cache entry CMAKE_" << lang |
1006 | 0 | << "_COMPILER " |
1007 | 0 | "to the full path to the compiler, or to the compiler name " |
1008 | 0 | "if it is in the PATH."; |
1009 | 0 | } |
1010 | | |
1011 | | void cmGlobalGenerator::CheckCompilerIdCompatibility( |
1012 | | cmMakefile* mf, std::string const& lang) const |
1013 | 0 | { |
1014 | 0 | std::string compilerIdVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID"); |
1015 | 0 | std::string const compilerId = mf->GetSafeDefinition(compilerIdVar); |
1016 | |
|
1017 | 0 | if (compilerId == "XLClang") { |
1018 | 0 | switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) { |
1019 | 0 | case cmPolicies::WARN: |
1020 | 0 | if (!this->CMakeInstance->GetIsInTryCompile() && |
1021 | 0 | mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) { |
1022 | 0 | std::ostringstream w; |
1023 | | /* clang-format off */ |
1024 | 0 | w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n" |
1025 | 0 | "Converting " << lang << |
1026 | 0 | R"( compiler id "XLClang" to "XL" for compatibility.)" |
1027 | 0 | ; |
1028 | | /* clang-format on */ |
1029 | 0 | mf->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str()); |
1030 | 0 | } |
1031 | 0 | CM_FALLTHROUGH; |
1032 | 0 | case cmPolicies::OLD: |
1033 | | // OLD behavior is to convert XLClang to XL. |
1034 | 0 | mf->AddDefinition(compilerIdVar, "XL"); |
1035 | 0 | break; |
1036 | 0 | case cmPolicies::NEW: |
1037 | | // NEW behavior is to keep AppleClang. |
1038 | 0 | break; |
1039 | 0 | } |
1040 | 0 | } |
1041 | | |
1042 | 0 | if (compilerId == "LCC") { |
1043 | 0 | switch (mf->GetPolicyStatus(cmPolicies::CMP0129)) { |
1044 | 0 | case cmPolicies::WARN: |
1045 | 0 | if (!this->CMakeInstance->GetIsInTryCompile() && |
1046 | 0 | mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0129")) { |
1047 | 0 | std::ostringstream w; |
1048 | | /* clang-format off */ |
1049 | 0 | w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0129) << "\n" |
1050 | 0 | "Converting " << lang << |
1051 | 0 | R"( compiler id "LCC" to "GNU" for compatibility.)" |
1052 | 0 | ; |
1053 | | /* clang-format on */ |
1054 | 0 | mf->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, w.str()); |
1055 | 0 | } |
1056 | 0 | CM_FALLTHROUGH; |
1057 | 0 | case cmPolicies::OLD: |
1058 | | // OLD behavior is to convert LCC to GNU. |
1059 | 0 | mf->AddDefinition(compilerIdVar, "GNU"); |
1060 | 0 | if (lang == "C") { |
1061 | 0 | mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1"); |
1062 | 0 | } else if (lang == "CXX") { |
1063 | 0 | mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1"); |
1064 | 0 | } else if (lang == "Fortran") { |
1065 | 0 | mf->AddDefinition("CMAKE_COMPILER_IS_GNUG77", "1"); |
1066 | 0 | } |
1067 | 0 | { |
1068 | | // Fix compiler versions. |
1069 | 0 | std::string version = cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"); |
1070 | 0 | std::string emulated = cmStrCat("CMAKE_", lang, "_SIMULATE_VERSION"); |
1071 | 0 | std::string emulatedId = cmStrCat("CMAKE_", lang, "_SIMULATE_ID"); |
1072 | 0 | std::string const& actual = mf->GetRequiredDefinition(emulated); |
1073 | 0 | mf->AddDefinition(version, actual); |
1074 | 0 | mf->RemoveDefinition(emulatedId); |
1075 | 0 | mf->RemoveDefinition(emulated); |
1076 | 0 | } |
1077 | 0 | break; |
1078 | 0 | case cmPolicies::NEW: |
1079 | | // NEW behavior is to keep LCC. |
1080 | 0 | break; |
1081 | 0 | } |
1082 | 0 | } |
1083 | 0 | } |
1084 | | |
1085 | | std::string cmGlobalGenerator::GetLanguageOutputExtension( |
1086 | | cmSourceFile const& source) const |
1087 | 0 | { |
1088 | 0 | std::string const& lang = source.GetLanguage(); |
1089 | 0 | if (!lang.empty()) { |
1090 | 0 | if (lang == "Rust") { |
1091 | | // Rust source file can be compiled into different type of outputs. So |
1092 | | // we need to change the extension based on the Rust_EMIT property. |
1093 | 0 | if (cmValue const rustEmit = source.GetRustEmitProperty()) { |
1094 | 0 | return this->GetRustEmitOutputExtension(rustEmit); |
1095 | 0 | } |
1096 | 0 | } |
1097 | 0 | return this->GetLanguageOutputExtension(lang); |
1098 | 0 | } |
1099 | | // if no language is found then check to see if it is already an |
1100 | | // output extension for some language. In that case it should be ignored |
1101 | | // and in this map, so it will not be compiled but will just be used. |
1102 | 0 | std::string const& ext = source.GetExtension(); |
1103 | 0 | if (!ext.empty()) { |
1104 | 0 | if (this->OutputExtensions.count(ext)) { |
1105 | 0 | return ext; |
1106 | 0 | } |
1107 | 0 | } |
1108 | 0 | return ""; |
1109 | 0 | } |
1110 | | |
1111 | | std::string cmGlobalGenerator::GetLanguageOutputExtension( |
1112 | | std::string const& lang) const |
1113 | 0 | { |
1114 | 0 | auto const it = this->LanguageToOutputExtension.find(lang); |
1115 | 0 | if (it != this->LanguageToOutputExtension.end()) { |
1116 | 0 | return it->second; |
1117 | 0 | } |
1118 | 0 | return ""; |
1119 | 0 | } |
1120 | | |
1121 | | std::string cmGlobalGenerator::GetRustEmitOutputExtension( |
1122 | | std::string const& emitValue) const |
1123 | 0 | { |
1124 | 0 | auto const it = this->RustEmitToOutputExtension.find(emitValue); |
1125 | 0 | if (it != this->RustEmitToOutputExtension.end()) { |
1126 | 0 | return it->second; |
1127 | 0 | } |
1128 | 0 | return ""; |
1129 | 0 | } |
1130 | | |
1131 | | cm::string_view cmGlobalGenerator::GetLanguageFromExtension( |
1132 | | cm::string_view ext) const |
1133 | 0 | { |
1134 | | // if there is an extension and it starts with . then move past the |
1135 | | // . because the extensions are not stored with a . in the map |
1136 | 0 | if (ext.empty()) { |
1137 | 0 | return ""; |
1138 | 0 | } |
1139 | 0 | if (ext.front() == '.') { |
1140 | 0 | ext = ext.substr(1); |
1141 | 0 | } |
1142 | 0 | #if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L |
1143 | 0 | auto const it = this->ExtensionToLanguage.find(ext); |
1144 | | #else |
1145 | | auto const it = this->ExtensionToLanguage.find(std::string(ext)); |
1146 | | #endif |
1147 | 0 | if (it != this->ExtensionToLanguage.end()) { |
1148 | 0 | return it->second; |
1149 | 0 | } |
1150 | 0 | return ""; |
1151 | 0 | } |
1152 | | |
1153 | | /* SetLanguageEnabled() is now split in two parts: |
1154 | | at first the enabled-flag is set. This can then be used in EnabledLanguage() |
1155 | | for checking whether the language is already enabled. After setting this |
1156 | | flag still the values from the cmake variables have to be copied into the |
1157 | | internal maps, this is done in SetLanguageEnabledMaps() which is called |
1158 | | after the system- and compiler specific files have been loaded. |
1159 | | |
1160 | | This split was done originally so that compiler-specific configuration |
1161 | | files could change the object file extension |
1162 | | (CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied |
1163 | | to the C++ maps. |
1164 | | */ |
1165 | | void cmGlobalGenerator::SetLanguageEnabled(std::string const& l, |
1166 | | cmMakefile* mf) |
1167 | 0 | { |
1168 | 0 | this->SetLanguageEnabledFlag(l, mf); |
1169 | 0 | this->SetLanguageEnabledMaps(l, mf); |
1170 | 0 | } |
1171 | | |
1172 | | void cmGlobalGenerator::SetLanguageEnabledFlag(std::string const& l, |
1173 | | cmMakefile* mf) |
1174 | 0 | { |
1175 | 0 | this->CMakeInstance->GetState()->SetLanguageEnabled(l); |
1176 | | |
1177 | | // Fill the language-to-extension map with the current variable |
1178 | | // settings to make sure it is available for the try_compile() |
1179 | | // command source file signature. In SetLanguageEnabledMaps this |
1180 | | // will be done again to account for any compiler- or |
1181 | | // platform-specific entries. |
1182 | 0 | this->FillExtensionToLanguageMap(l, mf); |
1183 | 0 | } |
1184 | | |
1185 | | void cmGlobalGenerator::SetLanguageEnabledMaps(std::string const& l, |
1186 | | cmMakefile* mf) |
1187 | 0 | { |
1188 | | // use LanguageToLinkerPreference to detect whether this functions has |
1189 | | // run before |
1190 | 0 | if (cm::contains(this->LanguageToLinkerPreference, l)) { |
1191 | 0 | return; |
1192 | 0 | } |
1193 | | |
1194 | 0 | std::string linkerPrefVar = cmStrCat("CMAKE_", l, "_LINKER_PREFERENCE"); |
1195 | 0 | cmValue linkerPref = mf->GetDefinition(linkerPrefVar); |
1196 | 0 | int preference = 0; |
1197 | 0 | if (cmNonempty(linkerPref)) { |
1198 | 0 | if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) { |
1199 | | // backward compatibility: before 2.6 LINKER_PREFERENCE |
1200 | | // was either "None" or "Preferred", and only the first character was |
1201 | | // tested. So if there is a custom language out there and it is |
1202 | | // "Preferred", set its preference high |
1203 | 0 | if ((*linkerPref)[0] == 'P') { |
1204 | 0 | preference = 100; |
1205 | 0 | } else { |
1206 | 0 | preference = 0; |
1207 | 0 | } |
1208 | 0 | } |
1209 | 0 | } |
1210 | |
|
1211 | 0 | if (preference < 0) { |
1212 | 0 | std::string msg = |
1213 | 0 | cmStrCat(linkerPrefVar, " is negative, adjusting it to 0"); |
1214 | 0 | cmSystemTools::Message(msg, "Warning"); |
1215 | 0 | preference = 0; |
1216 | 0 | } |
1217 | |
|
1218 | 0 | this->LanguageToLinkerPreference[l] = preference; |
1219 | |
|
1220 | 0 | std::string outputExtensionVar = cmStrCat("CMAKE_", l, "_OUTPUT_EXTENSION"); |
1221 | 0 | if (cmValue p = mf->GetDefinition(outputExtensionVar)) { |
1222 | 0 | std::string outputExtension = *p; |
1223 | 0 | this->LanguageToOutputExtension[l] = outputExtension; |
1224 | 0 | this->OutputExtensions[outputExtension] = outputExtension; |
1225 | 0 | if (cmHasPrefix(outputExtension, '.')) { |
1226 | 0 | outputExtension = outputExtension.substr(1); |
1227 | 0 | this->OutputExtensions[outputExtension] = outputExtension; |
1228 | 0 | } |
1229 | 0 | } |
1230 | |
|
1231 | 0 | if (l == "Rust") { |
1232 | 0 | std::string const emitValues = |
1233 | 0 | mf->GetSafeDefinition("CMAKE_Rust_EMIT_VALUES"); |
1234 | 0 | cmList emitList{ emitValues }; |
1235 | 0 | for (std::string const& v : emitList) { |
1236 | 0 | std::string emitOutputExtension = |
1237 | 0 | cmStrCat("CMAKE_Rust_EMIT_", v, "_OUTPUT_EXTENSION"); |
1238 | 0 | if (cmValue outputExtension = mf->GetDefinition(emitOutputExtension)) { |
1239 | 0 | this->RustEmitToOutputExtension[v] = outputExtension; |
1240 | 0 | } |
1241 | 0 | } |
1242 | 0 | } |
1243 | | |
1244 | | // The map was originally filled by SetLanguageEnabledFlag, but |
1245 | | // since then the compiler- and platform-specific files have been |
1246 | | // loaded which might have added more entries. |
1247 | 0 | this->FillExtensionToLanguageMap(l, mf); |
1248 | |
|
1249 | 0 | std::string ignoreExtensionsVar = |
1250 | 0 | cmStrCat("CMAKE_", l, "_IGNORE_EXTENSIONS"); |
1251 | 0 | std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar); |
1252 | 0 | cmList extensionList{ ignoreExts }; |
1253 | 0 | for (std::string const& i : extensionList) { |
1254 | 0 | this->IgnoreExtensions[i] = true; |
1255 | 0 | } |
1256 | 0 | } |
1257 | | |
1258 | | void cmGlobalGenerator::FillExtensionToLanguageMap(std::string const& l, |
1259 | | cmMakefile* mf) |
1260 | 0 | { |
1261 | 0 | std::string extensionsVar = cmStrCat("CMAKE_", l, "_SOURCE_FILE_EXTENSIONS"); |
1262 | 0 | std::string const& exts = mf->GetSafeDefinition(extensionsVar); |
1263 | 0 | cmList extensionList{ exts }; |
1264 | 0 | for (std::string const& i : extensionList) { |
1265 | 0 | this->ExtensionToLanguage[i] = l; |
1266 | 0 | } |
1267 | 0 | } |
1268 | | |
1269 | | cmValue cmGlobalGenerator::GetGlobalSetting(std::string const& name) const |
1270 | 0 | { |
1271 | 0 | assert(!this->Makefiles.empty()); |
1272 | 0 | return this->Makefiles[0]->GetDefinition(name); |
1273 | 0 | } |
1274 | | |
1275 | | bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const |
1276 | 0 | { |
1277 | 0 | assert(!this->Makefiles.empty()); |
1278 | 0 | return this->Makefiles[0]->IsOn(name); |
1279 | 0 | } |
1280 | | |
1281 | | std::string cmGlobalGenerator::GetSafeGlobalSetting( |
1282 | | std::string const& name) const |
1283 | 0 | { |
1284 | 0 | assert(!this->Makefiles.empty()); |
1285 | 0 | return this->Makefiles[0]->GetDefinition(name); |
1286 | 0 | } |
1287 | | |
1288 | | bool cmGlobalGenerator::IgnoreFile(cm::string_view ext) const |
1289 | 0 | { |
1290 | 0 | if (!this->GetLanguageFromExtension(ext).empty()) { |
1291 | 0 | return false; |
1292 | 0 | } |
1293 | 0 | return (this->IgnoreExtensions.count(std::string(ext)) > 0); |
1294 | 0 | } |
1295 | | |
1296 | | bool cmGlobalGenerator::GetLanguageEnabled(std::string const& l) const |
1297 | 0 | { |
1298 | 0 | return this->CMakeInstance->GetState()->GetLanguageEnabled(l); |
1299 | 0 | } |
1300 | | |
1301 | | void cmGlobalGenerator::ClearEnabledLanguages() |
1302 | 0 | { |
1303 | 0 | this->CMakeInstance->GetState()->ClearEnabledLanguages(); |
1304 | 0 | } |
1305 | | |
1306 | | void cmGlobalGenerator::CreateLocalGenerators() |
1307 | 0 | { |
1308 | 0 | this->LocalGeneratorSearchIndex.clear(); |
1309 | 0 | this->LocalGenerators.clear(); |
1310 | 0 | this->LocalGenerators.reserve(this->Makefiles.size()); |
1311 | 0 | for (auto const& m : this->Makefiles) { |
1312 | 0 | auto lg = this->CreateLocalGenerator(m.get()); |
1313 | 0 | this->IndexLocalGenerator(lg.get()); |
1314 | 0 | this->LocalGenerators.push_back(std::move(lg)); |
1315 | 0 | } |
1316 | 0 | } |
1317 | | |
1318 | | void cmGlobalGenerator::Configure() |
1319 | 0 | { |
1320 | 0 | this->FirstTimeProgress = 0.0f; |
1321 | 0 | this->ClearGeneratorMembers(); |
1322 | 0 | this->NextDeferId = 0; |
1323 | |
|
1324 | 0 | cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot(); |
1325 | |
|
1326 | 0 | snapshot.GetDirectory().SetCurrentSource( |
1327 | 0 | this->CMakeInstance->GetHomeDirectory()); |
1328 | 0 | snapshot.GetDirectory().SetCurrentBinary( |
1329 | 0 | this->CMakeInstance->GetHomeOutputDirectory()); |
1330 | |
|
1331 | 0 | auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot); |
1332 | 0 | auto* dirMf = dirMfu.get(); |
1333 | 0 | this->Makefiles.push_back(std::move(dirMfu)); |
1334 | 0 | dirMf->SetRecursionDepth(this->RecursionDepth); |
1335 | 0 | this->IndexMakefile(dirMf); |
1336 | |
|
1337 | 0 | this->BinaryDirectories.insert( |
1338 | 0 | this->CMakeInstance->GetHomeOutputDirectory()); |
1339 | |
|
1340 | 0 | if (this->ExtraGenerator && !this->CMakeInstance->GetIsInTryCompile()) { |
1341 | 0 | this->CMakeInstance->IssueDiagnostic( |
1342 | 0 | cmDiagnostics::CMD_DEPRECATED, |
1343 | 0 | cmStrCat("Support for \"Extra Generators\" like\n ", |
1344 | 0 | this->ExtraGenerator->GetName(), |
1345 | 0 | "\nis deprecated and will be removed from a future version " |
1346 | 0 | "of CMake. IDEs may use the cmake-file-api(7) to view " |
1347 | 0 | "CMake-generated project build trees.")); |
1348 | 0 | } |
1349 | | |
1350 | | // now do it |
1351 | 0 | dirMf->Configure(); |
1352 | 0 | dirMf->EnforceDirectoryLevelRules(); |
1353 | | |
1354 | | // Put a copy of each global target in every directory. |
1355 | 0 | { |
1356 | 0 | std::vector<GlobalTargetInfo> globalTargets; |
1357 | 0 | this->CreateDefaultGlobalTargets(globalTargets); |
1358 | |
|
1359 | 0 | for (auto const& mf : this->Makefiles) { |
1360 | 0 | for (GlobalTargetInfo const& globalTarget : globalTargets) { |
1361 | 0 | this->CreateGlobalTarget(globalTarget, mf.get()); |
1362 | 0 | } |
1363 | 0 | } |
1364 | 0 | } |
1365 | |
|
1366 | 0 | this->ReserveGlobalTargetCodegen(); |
1367 | | |
1368 | | // update the cache entry for the number of local generators, this is used |
1369 | | // for progress |
1370 | 0 | this->GetCMakeInstance()->AddCacheEntry( |
1371 | 0 | "CMAKE_NUMBER_OF_MAKEFILES", std::to_string(this->Makefiles.size()), |
1372 | 0 | "number of local generators", cmStateEnums::INTERNAL); |
1373 | 0 | } |
1374 | | |
1375 | | void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes) |
1376 | 0 | { |
1377 | 0 | this->CreateLocalGenerators(); |
1378 | | // Commit side effects only if we are actually generating |
1379 | 0 | if (targetTypes == TargetTypes::AllTargets) { |
1380 | 0 | this->CheckTargetProperties(); |
1381 | 0 | } |
1382 | 0 | this->CreateGeneratorTargets(targetTypes); |
1383 | 0 | if (targetTypes == TargetTypes::AllTargets) { |
1384 | 0 | this->ComputeBuildFileGenerators(); |
1385 | 0 | } |
1386 | 0 | } |
1387 | | |
1388 | | void cmGlobalGenerator::CreateImportedGenerationObjects( |
1389 | | cmMakefile* mf, std::vector<std::string> const& targets, |
1390 | | std::vector<cmGeneratorTarget const*>& exports) |
1391 | 0 | { |
1392 | 0 | this->CreateGenerationObjects(ImportedOnly); |
1393 | 0 | auto const mfit = |
1394 | 0 | std::find_if(this->Makefiles.begin(), this->Makefiles.end(), |
1395 | 0 | [mf](std::unique_ptr<cmMakefile> const& item) { |
1396 | 0 | return item.get() == mf; |
1397 | 0 | }); |
1398 | 0 | auto& lg = |
1399 | 0 | this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)]; |
1400 | 0 | for (std::string const& t : targets) { |
1401 | 0 | cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t); |
1402 | 0 | if (gt) { |
1403 | 0 | exports.push_back(gt); |
1404 | 0 | } |
1405 | 0 | } |
1406 | 0 | } |
1407 | | |
1408 | | cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile( |
1409 | | std::string const& filename) const |
1410 | 0 | { |
1411 | 0 | auto const it = this->BuildExportSets.find(filename); |
1412 | 0 | return it == this->BuildExportSets.end() ? nullptr : it->second; |
1413 | 0 | } |
1414 | | |
1415 | | void cmGlobalGenerator::AddCMP0068WarnTarget(std::string const& target) |
1416 | 0 | { |
1417 | 0 | this->CMP0068WarnTargets.insert(target); |
1418 | 0 | } |
1419 | | |
1420 | | bool cmGlobalGenerator::ShouldWarnCMP0210(std::string const& lang) |
1421 | 0 | { |
1422 | 0 | return this->WarnedCMP0210Languages.insert(lang).second; |
1423 | 0 | } |
1424 | | |
1425 | | bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const |
1426 | 0 | { |
1427 | | // If the property is not enabled then okay. |
1428 | 0 | if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool( |
1429 | 0 | "ALLOW_DUPLICATE_CUSTOM_TARGETS")) { |
1430 | 0 | return true; |
1431 | 0 | } |
1432 | | |
1433 | | // This generator does not support duplicate custom targets. |
1434 | 0 | std::ostringstream e; |
1435 | | // clang-format off |
1436 | 0 | e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS " |
1437 | 0 | "global property. " |
1438 | 0 | "The \"" << this->GetName() << "\" generator does not support " |
1439 | 0 | "duplicate custom targets. " |
1440 | 0 | "Consider using a Makefiles generator or fix the project to not " |
1441 | 0 | "use duplicate target names."; |
1442 | | // clang-format on |
1443 | 0 | cmSystemTools::Error(e.str()); |
1444 | 0 | return false; |
1445 | 0 | } |
1446 | | |
1447 | | void cmGlobalGenerator::ComputeBuildFileGenerators() |
1448 | 0 | { |
1449 | 0 | for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { |
1450 | 0 | std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens = |
1451 | 0 | this->Makefiles[i]->GetExportBuildFileGenerators(); |
1452 | 0 | for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) { |
1453 | 0 | g->Compute(this->LocalGenerators[i].get()); |
1454 | 0 | } |
1455 | 0 | } |
1456 | 0 | } |
1457 | | |
1458 | | bool cmGlobalGenerator::UnsupportedVariableIsDefined(std::string const& name, |
1459 | | bool supported) const |
1460 | 0 | { |
1461 | 0 | if (!supported && this->Makefiles.front()->GetDefinition(name)) { |
1462 | 0 | std::ostringstream e; |
1463 | | /* clang-format off */ |
1464 | 0 | e << |
1465 | 0 | "Generator\n" |
1466 | 0 | " " << this->GetName() << "\n" |
1467 | 0 | "does not support variable\n" |
1468 | 0 | " " << name << "\n" |
1469 | 0 | "but it has been specified." |
1470 | 0 | ; |
1471 | | /* clang-format on */ |
1472 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
1473 | 0 | return true; |
1474 | 0 | } |
1475 | | |
1476 | 0 | return false; |
1477 | 0 | } |
1478 | | |
1479 | | bool cmGlobalGenerator::Compute() |
1480 | 0 | { |
1481 | | // Make sure unsupported variables are not used. |
1482 | 0 | if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE", |
1483 | 0 | this->SupportsDefaultBuildType())) { |
1484 | 0 | return false; |
1485 | 0 | } |
1486 | 0 | if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS", |
1487 | 0 | this->SupportsCrossConfigs())) { |
1488 | 0 | return false; |
1489 | 0 | } |
1490 | 0 | if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS", |
1491 | 0 | this->SupportsDefaultConfigs())) { |
1492 | 0 | return false; |
1493 | 0 | } |
1494 | 0 | if (!this->InspectConfigTypeVariables()) { |
1495 | 0 | return false; |
1496 | 0 | } |
1497 | | |
1498 | 0 | if (cmValue v = this->CMakeInstance->GetCacheDefinition( |
1499 | 0 | "CMAKE_INTERMEDIATE_DIR_STRATEGY")) { |
1500 | 0 | this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_INTERMEDIATE_DIR_STRATEGY"); |
1501 | 0 | if (*v == "FULL") { |
1502 | 0 | this->IntDirStrategy = IntermediateDirStrategy::Full; |
1503 | 0 | } else if (*v == "SHORT") { |
1504 | 0 | this->IntDirStrategy = IntermediateDirStrategy::Short; |
1505 | 0 | } else { |
1506 | 0 | this->GetCMakeInstance()->IssueMessage( |
1507 | 0 | MessageType::FATAL_ERROR, |
1508 | 0 | cmStrCat("Unsupported intermediate directory strategy '", *v, '\'')); |
1509 | 0 | return false; |
1510 | 0 | } |
1511 | 0 | } |
1512 | 0 | if (cmValue v = this->CMakeInstance->GetCacheDefinition( |
1513 | 0 | "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY")) { |
1514 | 0 | this->GetCMakeInstance()->MarkCliAsUsed( |
1515 | 0 | "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY"); |
1516 | 0 | if (*v == "FULL") { |
1517 | 0 | this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Full; |
1518 | 0 | } else if (*v == "SHORT") { |
1519 | 0 | this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Short; |
1520 | 0 | } else { |
1521 | 0 | this->GetCMakeInstance()->IssueMessage( |
1522 | 0 | MessageType::FATAL_ERROR, |
1523 | 0 | cmStrCat("Unsupported autogen intermediate directory strategy '", *v, |
1524 | 0 | '\'')); |
1525 | 0 | return false; |
1526 | 0 | } |
1527 | 0 | } |
1528 | | |
1529 | | // Some generators track files replaced during the Generate. |
1530 | | // Start with an empty vector: |
1531 | 0 | this->FilesReplacedDuringGenerate.clear(); |
1532 | | |
1533 | | // clear targets to issue warning CMP0068 for |
1534 | 0 | this->CMP0068WarnTargets.clear(); |
1535 | | |
1536 | | // Check whether this generator is allowed to run. |
1537 | 0 | if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) { |
1538 | 0 | return false; |
1539 | 0 | } |
1540 | 0 | this->FinalizeTargetConfiguration(); |
1541 | |
|
1542 | 0 | if (!this->AddBuildDatabaseTargets()) { |
1543 | 0 | return false; |
1544 | 0 | } |
1545 | | |
1546 | 0 | this->CreateGenerationObjects(); |
1547 | | |
1548 | | // at this point this->LocalGenerators has been filled, |
1549 | | // so create the map from project name to vector of local generators |
1550 | 0 | this->FillProjectMap(); |
1551 | |
|
1552 | 0 | this->CreateFileGenerateOutputs(); |
1553 | | |
1554 | | // Iterate through all targets and add verification targets for header sets |
1555 | 0 | if (!this->AddHeaderSetVerification()) { |
1556 | 0 | return false; |
1557 | 0 | } |
1558 | | |
1559 | 0 | #ifndef CMAKE_BOOTSTRAP |
1560 | 0 | this->QtAutoGen = |
1561 | 0 | cm::make_unique<cmQtAutoGenGlobalInitializer>(this->LocalGenerators); |
1562 | 0 | if (!this->QtAutoGen->InitializeCustomTargets()) { |
1563 | 0 | return false; |
1564 | 0 | } |
1565 | 0 | #endif |
1566 | | |
1567 | | // Perform up-front computation in order to handle errors (such as unknown |
1568 | | // features) at this point. While processing the compile features we also |
1569 | | // calculate and cache the language standard required by the compile |
1570 | | // features. |
1571 | | // |
1572 | | // Synthetic targets performed this inside of |
1573 | | // `cmLocalGenerator::DiscoverSyntheticTargets` |
1574 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1575 | 0 | if (!localGen->ComputeTargetCompileFeatures()) { |
1576 | 0 | return false; |
1577 | 0 | } |
1578 | 0 | } |
1579 | | |
1580 | | // We now have all targets set up and std levels constructed. Add |
1581 | | // `__CMAKE::CXX*` targets as link dependencies to all targets which need |
1582 | | // them. |
1583 | | // |
1584 | | // Synthetic targets performed this inside of |
1585 | | // `cmLocalGenerator::DiscoverSyntheticTargets` |
1586 | 0 | if (!this->ApplyCXXStdTargets()) { |
1587 | 0 | return false; |
1588 | 0 | } |
1589 | | |
1590 | | // Iterate through all targets and set up C++20 module targets. |
1591 | | // Create target templates for each imported target with C++20 modules. |
1592 | | // INTERFACE library with BMI-generating rules and a collation step? |
1593 | | // Maybe INTERFACE libraries with modules files should just do BMI-only? |
1594 | | // Make `add_dependencies(imported_target |
1595 | | // $<$<TARGET_NAME_IF_EXISTS:uses_imported>:synth1> |
1596 | | // $<$<TARGET_NAME_IF_EXISTS:other_uses_imported>:synth2>)` |
1597 | | // |
1598 | | // Note that synthetic target creation performs the above marked |
1599 | | // steps on the created targets. |
1600 | 0 | if (!this->DiscoverSyntheticTargets()) { |
1601 | 0 | return false; |
1602 | 0 | } |
1603 | | |
1604 | | // Perform after-generator-target generator actions. These involve collecting |
1605 | | // information gathered during the construction of generator targets. |
1606 | 0 | for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { |
1607 | 0 | this->Makefiles[i]->GenerateAfterGeneratorTargets( |
1608 | 0 | *this->LocalGenerators[i]); |
1609 | 0 | } |
1610 | | |
1611 | | // Add generator specific helper commands |
1612 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1613 | 0 | localGen->AddHelperCommands(); |
1614 | 0 | } |
1615 | |
|
1616 | 0 | this->MarkTargetsForPchReuse(); |
1617 | | |
1618 | | // Add automatically generated sources (e.g. unity build). |
1619 | | // Add unity sources after computing compile features. Unity sources do |
1620 | | // not change the set of languages or features, but we need to know them |
1621 | | // to filter out sources that are scanned for C++ module dependencies. |
1622 | 0 | if (!this->AddAutomaticSources()) { |
1623 | 0 | return false; |
1624 | 0 | } |
1625 | | |
1626 | 0 | #ifndef CMAKE_BOOTSTRAP |
1627 | 0 | bool isTryCompile = this->GetGlobalSetting("IN_TRY_COMPILE").IsOn(); |
1628 | 0 | bool sbomEnabled = cmExperimental::HasSupportEnabled( |
1629 | 0 | *this->Makefiles[0], cmExperimental::Feature::GenerateSbom); |
1630 | | |
1631 | | // Automatically generate SBOM files if enabled. |
1632 | 0 | cmValue sbomFormat = this->GetGlobalSetting("CMAKE_INSTALL_SBOM_FORMATS"); |
1633 | 0 | if (sbomFormat.IsSet() && !this->Makefiles[0]->ExplicitlyGeneratesSbom() && |
1634 | 0 | sbomEnabled && !isTryCompile) { |
1635 | 0 | std::string location = |
1636 | 0 | this->Makefiles[0]->GetSafeDefinition("CMAKE_INSTALL_LIBDIR"); |
1637 | 0 | if (location.empty()) { |
1638 | 0 | location = "lib"; |
1639 | 0 | } |
1640 | |
|
1641 | 0 | std::string projectName = this->LocalGenerators[0]->GetProjectName(); |
1642 | 0 | cmSbomArguments sbomDefaultArgs; |
1643 | 0 | sbomDefaultArgs.ProjectName = projectName; |
1644 | 0 | for (auto& exportSet : this->ExportSets) { |
1645 | 0 | sbomDefaultArgs.PackageName = exportSet.first; |
1646 | 0 | std::string dest = cmStrCat(location, "/sbom/", projectName); |
1647 | 0 | this->Makefiles[0]->AddInstallGenerator( |
1648 | 0 | cm::make_unique<cmInstallSbomExportGenerator>( |
1649 | 0 | &exportSet.second, dest, "", std::vector<std::string>(), "", |
1650 | 0 | cmInstallGenerator::SelectMessageLevel(this->Makefiles[0].get()), |
1651 | 0 | false, std::move(sbomDefaultArgs), "", |
1652 | 0 | this->Makefiles[0]->GetBacktrace())); |
1653 | 0 | } |
1654 | 0 | } |
1655 | 0 | #endif |
1656 | |
|
1657 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1658 | 0 | cmMakefile* mf = localGen->GetMakefile(); |
1659 | 0 | for (auto const& g : mf->GetInstallGenerators()) { |
1660 | 0 | if (!g->Compute(localGen.get())) { |
1661 | 0 | return false; |
1662 | 0 | } |
1663 | 0 | } |
1664 | 0 | } |
1665 | | |
1666 | 0 | this->AddExtraIDETargets(); |
1667 | |
|
1668 | 0 | #ifndef CMAKE_BOOTSTRAP |
1669 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1670 | 0 | localGen->ResolveSourceGroupGenex(); |
1671 | 0 | } |
1672 | 0 | #endif |
1673 | | |
1674 | | // Trace the dependencies, after that no custom commands should be added |
1675 | | // because their dependencies might not be handled correctly |
1676 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1677 | 0 | localGen->TraceDependencies(); |
1678 | 0 | } |
1679 | | |
1680 | | // Make sure that all (non-imported) targets have source files added! |
1681 | 0 | if (this->CheckTargetsForMissingSources()) { |
1682 | 0 | return false; |
1683 | 0 | } |
1684 | | |
1685 | 0 | this->ForceLinkerLanguages(); |
1686 | | |
1687 | | // Compute the manifest of main targets generated. |
1688 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1689 | 0 | localGen->ComputeTargetManifest(); |
1690 | 0 | } |
1691 | | |
1692 | | // Compute the inter-target dependencies. |
1693 | 0 | if (!this->ComputeTargetDepends()) { |
1694 | 0 | return false; |
1695 | 0 | } |
1696 | 0 | this->ComputeTargetOrder(); |
1697 | |
|
1698 | 0 | if (this->CheckTargetsForType()) { |
1699 | 0 | return false; |
1700 | 0 | } |
1701 | | |
1702 | 0 | for (auto const& localGen : this->LocalGenerators) { |
1703 | 0 | localGen->ComputeHomeRelativeOutputPath(); |
1704 | 0 | localGen->ComputeSourceGroupSearchIndex(); |
1705 | 0 | } |
1706 | |
|
1707 | 0 | return true; |
1708 | 0 | } |
1709 | | |
1710 | | void cmGlobalGenerator::Generate() |
1711 | 0 | { |
1712 | | // Create a map from local generator to the complete set of targets |
1713 | | // it builds by default. |
1714 | 0 | this->InitializeProgressMarks(); |
1715 | |
|
1716 | 0 | this->ProcessEvaluationFiles(); |
1717 | |
|
1718 | 0 | this->CMakeInstance->UpdateProgress("Generating", 0.1f); |
1719 | |
|
1720 | 0 | #ifndef CMAKE_BOOTSTRAP |
1721 | 0 | if (!this->QtAutoGen->SetupCustomTargets()) { |
1722 | 0 | if (!cmSystemTools::GetErrorOccurredFlag()) { |
1723 | 0 | this->GetCMakeInstance()->IssueMessage( |
1724 | 0 | MessageType::FATAL_ERROR, |
1725 | 0 | "Problem setting up custom targets for QtAutoGen"); |
1726 | 0 | } |
1727 | 0 | return; |
1728 | 0 | } |
1729 | 0 | #endif |
1730 | | |
1731 | | // Generate project files |
1732 | 0 | for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { |
1733 | 0 | this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile()); |
1734 | 0 | this->LocalGenerators[i]->Generate(); |
1735 | 0 | if (!this->LocalGenerators[i]->GetMakefile()->IsOn( |
1736 | 0 | "CMAKE_SKIP_INSTALL_RULES")) { |
1737 | 0 | this->LocalGenerators[i]->GenerateInstallRules(); |
1738 | 0 | } |
1739 | 0 | this->LocalGenerators[i]->GenerateTestFiles(); |
1740 | 0 | this->CMakeInstance->UpdateProgress( |
1741 | 0 | "Generating", |
1742 | 0 | 0.1f + |
1743 | 0 | 0.9f * (static_cast<float>(i) + 1.0f) / |
1744 | 0 | static_cast<float>(this->LocalGenerators.size())); |
1745 | 0 | } |
1746 | 0 | this->SetCurrentMakefile(nullptr); |
1747 | |
|
1748 | 0 | if (!this->GenerateCPackPropertiesFile()) { |
1749 | 0 | this->GetCMakeInstance()->IssueMessage( |
1750 | 0 | MessageType::FATAL_ERROR, "Could not write CPack properties file."); |
1751 | 0 | } |
1752 | |
|
1753 | 0 | for (auto& buildExpSet : this->BuildExportSets) { |
1754 | 0 | if (!buildExpSet.second->GenerateImportFile()) { |
1755 | 0 | if (!cmSystemTools::GetErrorOccurredFlag()) { |
1756 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, |
1757 | 0 | "Could not write export file."); |
1758 | 0 | } |
1759 | 0 | return; |
1760 | 0 | } |
1761 | 0 | } |
1762 | | // Update rule hashes. |
1763 | 0 | this->CheckRuleHashes(); |
1764 | |
|
1765 | 0 | this->WriteSummary(); |
1766 | |
|
1767 | 0 | if (this->ExtraGenerator) { |
1768 | 0 | this->ExtraGenerator->Generate(); |
1769 | 0 | } |
1770 | | |
1771 | | // Perform validation checks on memoized link structures. |
1772 | 0 | this->CheckTargetLinkLibraries(); |
1773 | |
|
1774 | 0 | if (!this->CMP0068WarnTargets.empty()) { |
1775 | 0 | std::ostringstream w; |
1776 | | /* clang-format off */ |
1777 | 0 | w << |
1778 | 0 | cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n" |
1779 | 0 | "For compatibility with older versions of CMake, the install_name " |
1780 | 0 | "fields for the following targets are still affected by RPATH " |
1781 | 0 | "settings:\n" |
1782 | 0 | ; |
1783 | | /* clang-format on */ |
1784 | 0 | for (std::string const& t : this->CMP0068WarnTargets) { |
1785 | 0 | w << ' ' << t << '\n'; |
1786 | 0 | } |
1787 | 0 | this->GetCMakeInstance()->IssueDiagnostic(cmDiagnostics::CMD_AUTHOR, |
1788 | 0 | w.str()); |
1789 | 0 | } |
1790 | 0 | } |
1791 | | |
1792 | | #if !defined(CMAKE_BOOTSTRAP) |
1793 | | void cmGlobalGenerator::WriteJsonContent(std::string const& path, |
1794 | | Json::Value const& value) const |
1795 | 0 | { |
1796 | 0 | cmsys::ofstream ftmp(path.c_str()); |
1797 | 0 | this->JsonWriter->write(value, &ftmp); |
1798 | 0 | ftmp << '\n'; |
1799 | 0 | ftmp.close(); |
1800 | 0 | } |
1801 | | |
1802 | | void cmGlobalGenerator::WriteInstallJson() const |
1803 | 0 | { |
1804 | 0 | Json::Value index(Json::objectValue); |
1805 | 0 | index["InstallScripts"] = Json::arrayValue; |
1806 | 0 | for (auto const& file : this->InstallScripts) { |
1807 | 0 | index["InstallScripts"].append(file); |
1808 | 0 | } |
1809 | 0 | index["Parallel"] = |
1810 | 0 | this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool( |
1811 | 0 | "INSTALL_PARALLEL"); |
1812 | 0 | if (this->SupportsDefaultConfigs()) { |
1813 | 0 | index["Configs"] = Json::arrayValue; |
1814 | 0 | for (auto const& config : this->GetDefaultConfigs()) { |
1815 | 0 | index["Configs"].append(config); |
1816 | 0 | } |
1817 | 0 | } |
1818 | 0 | this->WriteJsonContent( |
1819 | 0 | cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), |
1820 | 0 | "/CMakeFiles/InstallScripts.json"), |
1821 | 0 | index); |
1822 | 0 | } |
1823 | | #endif |
1824 | | |
1825 | | bool cmGlobalGenerator::ComputeTargetDepends() |
1826 | 0 | { |
1827 | 0 | cmComputeTargetDepends ctd(this); |
1828 | 0 | if (!ctd.Compute()) { |
1829 | 0 | return false; |
1830 | 0 | } |
1831 | 0 | for (cmGeneratorTarget const* target : ctd.GetTargets()) { |
1832 | 0 | ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]); |
1833 | 0 | } |
1834 | 0 | return true; |
1835 | 0 | } |
1836 | | |
1837 | | std::vector<cmGeneratorTarget*> |
1838 | | cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const |
1839 | 0 | { |
1840 | 0 | std::vector<cmGeneratorTarget*> gts; |
1841 | 0 | cm::append(gts, lg->GetGeneratorTargets()); |
1842 | 0 | std::sort(gts.begin(), gts.end(), |
1843 | 0 | [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) { |
1844 | 0 | return this->TargetOrderIndexLess(l, r); |
1845 | 0 | }); |
1846 | 0 | return gts; |
1847 | 0 | } |
1848 | | |
1849 | | void cmGlobalGenerator::ComputeTargetOrder() |
1850 | 0 | { |
1851 | 0 | size_t index = 0; |
1852 | 0 | auto const& lgens = this->GetLocalGenerators(); |
1853 | 0 | for (auto const& lgen : lgens) { |
1854 | 0 | auto const& targets = lgen->GetGeneratorTargets(); |
1855 | 0 | for (auto const& gt : targets) { |
1856 | 0 | this->ComputeTargetOrder(gt.get(), index); |
1857 | 0 | } |
1858 | 0 | } |
1859 | 0 | assert(index == this->TargetOrderIndex.size()); |
1860 | 0 | } |
1861 | | |
1862 | | void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt, |
1863 | | size_t& index) |
1864 | 0 | { |
1865 | 0 | std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0); |
1866 | 0 | auto insertion = this->TargetOrderIndex.insert(value); |
1867 | 0 | if (!insertion.second) { |
1868 | 0 | return; |
1869 | 0 | } |
1870 | 0 | auto entry = insertion.first; |
1871 | |
|
1872 | 0 | auto const& deps = this->GetTargetDirectDepends(gt); |
1873 | 0 | for (auto const& d : deps) { |
1874 | 0 | this->ComputeTargetOrder(d, index); |
1875 | 0 | } |
1876 | |
|
1877 | 0 | entry->second = index++; |
1878 | 0 | } |
1879 | | |
1880 | | bool cmGlobalGenerator::ApplyCXXStdTargets() |
1881 | 0 | { |
1882 | 0 | for (auto const& gen : this->LocalGenerators) { |
1883 | | |
1884 | | // tgt->ApplyCXXStd can create targets itself, so we need iterators which |
1885 | | // won't be invalidated by that target creation |
1886 | 0 | auto const& genTgts = gen->GetGeneratorTargets(); |
1887 | 0 | std::vector<cmGeneratorTarget*> existingTgts; |
1888 | 0 | existingTgts.reserve(genTgts.size()); |
1889 | 0 | for (auto const& tgt : genTgts) { |
1890 | 0 | existingTgts.push_back(tgt.get()); |
1891 | 0 | } |
1892 | |
|
1893 | 0 | for (auto const& tgt : existingTgts) { |
1894 | 0 | if (!tgt->ApplyCXXStdTargets()) { |
1895 | 0 | return false; |
1896 | 0 | } |
1897 | 0 | } |
1898 | 0 | } |
1899 | | |
1900 | 0 | return true; |
1901 | 0 | } |
1902 | | |
1903 | | bool cmGlobalGenerator::DiscoverSyntheticTargets() |
1904 | 0 | { |
1905 | 0 | cmSyntheticTargetCache cache; |
1906 | |
|
1907 | 0 | for (auto const& gen : this->LocalGenerators) { |
1908 | | // Because DiscoverSyntheticTargets() adds generator targets, we need to |
1909 | | // cache the existing list of generator targets before starting. |
1910 | 0 | std::vector<cmGeneratorTarget*> genTargets; |
1911 | 0 | genTargets.reserve(gen->GetGeneratorTargets().size()); |
1912 | 0 | for (auto const& tgt : gen->GetGeneratorTargets()) { |
1913 | 0 | genTargets.push_back(tgt.get()); |
1914 | 0 | } |
1915 | |
|
1916 | 0 | for (auto* tgt : genTargets) { |
1917 | 0 | std::vector<std::string> const& configs = |
1918 | 0 | tgt->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
1919 | |
|
1920 | 0 | for (auto const& config : configs) { |
1921 | 0 | if (!tgt->DiscoverSyntheticTargets(cache, config)) { |
1922 | 0 | return false; |
1923 | 0 | } |
1924 | 0 | } |
1925 | 0 | } |
1926 | 0 | } |
1927 | | |
1928 | 0 | return true; |
1929 | 0 | } |
1930 | | |
1931 | | bool cmGlobalGenerator::AddHeaderSetVerification() |
1932 | 0 | { |
1933 | 0 | for (auto const& gen : this->LocalGenerators) { |
1934 | | // Because AddHeaderSetVerification() adds generator targets, we need to |
1935 | | // cache the existing list of generator targets before starting. |
1936 | 0 | std::vector<cmGeneratorTarget*> genTargets; |
1937 | 0 | genTargets.reserve(gen->GetGeneratorTargets().size()); |
1938 | 0 | for (auto const& tgt : gen->GetGeneratorTargets()) { |
1939 | 0 | genTargets.push_back(tgt.get()); |
1940 | 0 | } |
1941 | |
|
1942 | 0 | for (auto* tgt : genTargets) { |
1943 | 0 | if (!tgt->AddHeaderSetVerification()) { |
1944 | 0 | return false; |
1945 | 0 | } |
1946 | 0 | } |
1947 | 0 | } |
1948 | | |
1949 | 0 | cmTarget* allVerifyInterfaceTarget = |
1950 | 0 | this->Makefiles.front()->FindTargetToUse( |
1951 | 0 | "all_verify_interface_header_sets", |
1952 | 0 | { cmStateEnums::TargetDomain::NATIVE }); |
1953 | 0 | if (allVerifyInterfaceTarget) { |
1954 | 0 | this->LocalGenerators.front()->AddGeneratorTarget( |
1955 | 0 | cm::make_unique<cmGeneratorTarget>(allVerifyInterfaceTarget, |
1956 | 0 | this->LocalGenerators.front().get())); |
1957 | 0 | } |
1958 | 0 | cmTarget* allVerifyPrivateTarget = this->Makefiles.front()->FindTargetToUse( |
1959 | 0 | "all_verify_private_header_sets", { cmStateEnums::TargetDomain::NATIVE }); |
1960 | 0 | if (allVerifyPrivateTarget) { |
1961 | 0 | this->LocalGenerators.front()->AddGeneratorTarget( |
1962 | 0 | cm::make_unique<cmGeneratorTarget>(allVerifyPrivateTarget, |
1963 | 0 | this->LocalGenerators.front().get())); |
1964 | 0 | } |
1965 | |
|
1966 | 0 | if (allVerifyInterfaceTarget || allVerifyPrivateTarget) { |
1967 | 0 | cmTarget* allVerifyTarget = |
1968 | 0 | this->GetMakefiles().front()->AddNewUtilityTarget( |
1969 | 0 | "all_verify_header_sets", true); |
1970 | 0 | this->LocalGenerators.front()->AddGeneratorTarget( |
1971 | 0 | cm::make_unique<cmGeneratorTarget>(allVerifyTarget, |
1972 | 0 | this->LocalGenerators.front().get())); |
1973 | 0 | if (allVerifyInterfaceTarget) { |
1974 | 0 | allVerifyTarget->AddUtility(allVerifyInterfaceTarget->GetName(), false); |
1975 | 0 | } |
1976 | 0 | if (allVerifyPrivateTarget) { |
1977 | 0 | allVerifyTarget->AddUtility(allVerifyPrivateTarget->GetName(), false); |
1978 | 0 | } |
1979 | 0 | } |
1980 | |
|
1981 | 0 | return true; |
1982 | 0 | } |
1983 | | |
1984 | | void cmGlobalGenerator::CreateFileGenerateOutputs() |
1985 | 0 | { |
1986 | 0 | for (auto const& lg : this->LocalGenerators) { |
1987 | 0 | lg->CreateEvaluationFileOutputs(); |
1988 | 0 | } |
1989 | 0 | } |
1990 | | |
1991 | | bool cmGlobalGenerator::AddAutomaticSources() |
1992 | 0 | { |
1993 | 0 | for (auto const& lg : this->LocalGenerators) { |
1994 | 0 | for (auto const& gt : lg->GetGeneratorTargets()) { |
1995 | 0 | if (!gt->CanCompileSources()) { |
1996 | 0 | continue; |
1997 | 0 | } |
1998 | 0 | lg->AddUnityBuild(gt.get()); |
1999 | 0 | lg->AddISPCDependencies(gt.get()); |
2000 | | // Targets that reuse a PCH are handled below. |
2001 | 0 | if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) { |
2002 | 0 | lg->AddPchDependencies(gt.get()); |
2003 | 0 | } |
2004 | 0 | lg->AddXCConfigSources(gt.get()); |
2005 | 0 | } |
2006 | 0 | } |
2007 | 0 | for (auto const& lg : this->LocalGenerators) { |
2008 | 0 | for (auto const& gt : lg->GetGeneratorTargets()) { |
2009 | 0 | if (!gt->CanCompileSources()) { |
2010 | 0 | continue; |
2011 | 0 | } |
2012 | | // Handle targets that reuse a PCH from an above-handled target. |
2013 | 0 | if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) { |
2014 | 0 | lg->AddPchDependencies(gt.get()); |
2015 | 0 | } |
2016 | 0 | } |
2017 | 0 | } |
2018 | | // The above transformations may have changed the classification of sources, |
2019 | | // e.g., sources that go into unity builds become SourceKindUnityBatched. |
2020 | | // Clear the source list and classification cache (KindedSources) of all |
2021 | | // targets so that it will be recomputed correctly by the generators later |
2022 | | // now that the above transformations are done for all targets. |
2023 | | // Also clear the link interface cache to support $<TARGET_OBJECTS:objlib> |
2024 | | // in INTERFACE_LINK_LIBRARIES because the list of object files may have |
2025 | | // been changed by conversion to a unity build or addition of a PCH source. |
2026 | 0 | for (auto const& lg : this->LocalGenerators) { |
2027 | 0 | for (auto const& gt : lg->GetGeneratorTargets()) { |
2028 | 0 | gt->ClearSourcesCache(); |
2029 | 0 | gt->ClearLinkInterfaceCache(); |
2030 | 0 | } |
2031 | 0 | } |
2032 | 0 | return true; |
2033 | 0 | } |
2034 | | |
2035 | | std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer( |
2036 | | cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const |
2037 | 0 | { |
2038 | 0 | return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir); |
2039 | 0 | } |
2040 | | |
2041 | | std::unique_ptr<cmLinkLineComputer> |
2042 | | cmGlobalGenerator::CreateMSVC60LinkLineComputer( |
2043 | | cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const |
2044 | 0 | { |
2045 | 0 | return std::unique_ptr<cmLinkLineComputer>( |
2046 | 0 | cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir)); |
2047 | 0 | } |
2048 | | |
2049 | | void cmGlobalGenerator::FinalizeTargetConfiguration() |
2050 | 0 | { |
2051 | 0 | std::vector<std::string> const langs = |
2052 | 0 | this->CMakeInstance->GetState()->GetEnabledLanguages(); |
2053 | | |
2054 | | // Construct per-target generator information. |
2055 | 0 | for (auto const& mf : this->Makefiles) { |
2056 | 0 | cmBTStringRange const compileDefinitions = |
2057 | 0 | mf->GetCompileDefinitionsEntries(); |
2058 | 0 | for (auto& target : mf->GetTargets()) { |
2059 | 0 | cmTarget* t = &target.second; |
2060 | 0 | t->FinalizeTargetConfiguration(compileDefinitions); |
2061 | 0 | } |
2062 | | |
2063 | | // The standard include directories for each language |
2064 | | // should be treated as system include directories. |
2065 | 0 | std::set<std::string> standardIncludesSet; |
2066 | 0 | for (std::string const& li : langs) { |
2067 | 0 | std::string const standardIncludesVar = |
2068 | 0 | cmStrCat("CMAKE_", li, "_STANDARD_INCLUDE_DIRECTORIES"); |
2069 | 0 | std::string const& standardIncludesStr = |
2070 | 0 | mf->GetSafeDefinition(standardIncludesVar); |
2071 | 0 | cmList standardIncludesList{ standardIncludesStr }; |
2072 | 0 | standardIncludesSet.insert(standardIncludesList.begin(), |
2073 | 0 | standardIncludesList.end()); |
2074 | 0 | } |
2075 | 0 | mf->AddSystemIncludeDirectories(standardIncludesSet); |
2076 | 0 | } |
2077 | 0 | } |
2078 | | |
2079 | | void cmGlobalGenerator::CreateGeneratorTargets( |
2080 | | TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg, |
2081 | | std::map<cmTarget*, cmGeneratorTarget*> const& importedMap) |
2082 | 0 | { |
2083 | 0 | if (targetTypes == AllTargets) { |
2084 | 0 | for (cmTarget* target : mf->GetOrderedTargets()) { |
2085 | 0 | lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg)); |
2086 | 0 | } |
2087 | 0 | } |
2088 | |
|
2089 | 0 | for (cmTarget* t : mf->GetImportedTargets()) { |
2090 | 0 | lg->AddImportedGeneratorTarget(importedMap.find(t)->second); |
2091 | 0 | } |
2092 | 0 | } |
2093 | | |
2094 | | void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes) |
2095 | 0 | { |
2096 | 0 | std::map<cmTarget*, cmGeneratorTarget*> importedMap; |
2097 | 0 | for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { |
2098 | 0 | auto& mf = this->Makefiles[i]; |
2099 | 0 | for (auto const& ownedImpTgt : mf->GetOwnedImportedTargets()) { |
2100 | 0 | cmLocalGenerator* lg = this->LocalGenerators[i].get(); |
2101 | 0 | auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg); |
2102 | 0 | importedMap[ownedImpTgt.get()] = gt.get(); |
2103 | 0 | lg->AddOwnedImportedGeneratorTarget(std::move(gt)); |
2104 | 0 | } |
2105 | 0 | } |
2106 | | |
2107 | | // Construct per-target generator information. |
2108 | 0 | for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { |
2109 | 0 | this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(), |
2110 | 0 | this->LocalGenerators[i].get(), importedMap); |
2111 | 0 | } |
2112 | 0 | } |
2113 | | |
2114 | | void cmGlobalGenerator::ClearGeneratorMembers() |
2115 | 1 | { |
2116 | 1 | this->BuildExportSets.clear(); |
2117 | | |
2118 | 1 | this->Makefiles.clear(); |
2119 | | |
2120 | 1 | this->LocalGenerators.clear(); |
2121 | | |
2122 | 1 | this->AliasTargets.clear(); |
2123 | 1 | this->ExportSets.clear(); |
2124 | 1 | this->InstallComponents.clear(); |
2125 | 1 | this->TargetDependencies.clear(); |
2126 | 1 | this->TargetSearchIndex.clear(); |
2127 | 1 | this->GeneratorTargetSearchIndex.clear(); |
2128 | 1 | this->MakefileSearchIndex.clear(); |
2129 | 1 | this->LocalGeneratorSearchIndex.clear(); |
2130 | 1 | this->TargetOrderIndex.clear(); |
2131 | 1 | this->ProjectMap.clear(); |
2132 | 1 | this->RuleHashes.clear(); |
2133 | 1 | this->DirectoryContentMap.clear(); |
2134 | 1 | this->XcFrameworkPListContentMap.clear(); |
2135 | 1 | this->BinaryDirectories.clear(); |
2136 | 1 | this->GeneratedFiles.clear(); |
2137 | 1 | this->RuntimeDependencySets.clear(); |
2138 | 1 | this->RuntimeDependencySetsByName.clear(); |
2139 | 1 | this->WarnedExperimental.clear(); |
2140 | 1 | this->WarnedCMP0210Languages.clear(); |
2141 | 1 | } |
2142 | | |
2143 | | bool cmGlobalGenerator::SupportsShortObjectNames() const |
2144 | 0 | { |
2145 | 0 | return false; |
2146 | 0 | } |
2147 | | |
2148 | | bool cmGlobalGenerator::UseShortObjectNames( |
2149 | | cmStateEnums::IntermediateDirKind kind) const |
2150 | 0 | { |
2151 | 0 | IntermediateDirStrategy strategy = IntermediateDirStrategy::Full; |
2152 | 0 | switch (kind) { |
2153 | 0 | case cmStateEnums::IntermediateDirKind::ObjectFiles: |
2154 | 0 | strategy = this->IntDirStrategy; |
2155 | 0 | break; |
2156 | 0 | case cmStateEnums::IntermediateDirKind::QtAutogenMetadata: |
2157 | 0 | strategy = this->QtAutogenIntDirStrategy; |
2158 | 0 | break; |
2159 | 0 | default: |
2160 | 0 | assert(false); |
2161 | 0 | break; |
2162 | 0 | } |
2163 | 0 | return this->SupportsShortObjectNames() && |
2164 | 0 | strategy == IntermediateDirStrategy::Short; |
2165 | 0 | } |
2166 | | |
2167 | | std::string cmGlobalGenerator::GetShortBinaryOutputDir() const |
2168 | 0 | { |
2169 | 0 | return ".o"; |
2170 | 0 | } |
2171 | | |
2172 | | std::string cmGlobalGenerator::ComputeTargetShortName( |
2173 | | std::string const& bindir, std::string const& targetName) const |
2174 | 0 | { |
2175 | 0 | auto const& rcwbd = |
2176 | 0 | this->LocalGenerators[0]->MaybeRelativeToTopBinDir(bindir); |
2177 | 0 | cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); |
2178 | 0 | constexpr size_t HASH_TRUNCATION = 4; |
2179 | 0 | auto dirHash = hasher.HashString(rcwbd).substr(0, HASH_TRUNCATION); |
2180 | 0 | auto tgtHash = hasher.HashString(targetName).substr(0, HASH_TRUNCATION); |
2181 | 0 | return cmStrCat(tgtHash, dirHash); |
2182 | 0 | } |
2183 | | |
2184 | | cmGlobalGenerator::TargetDirectoryRegistration& |
2185 | | cmGlobalGenerator::RegisterTargetDirectory(cmGeneratorTarget const* tgt, |
2186 | | std::string const& targetDir) const |
2187 | 0 | { |
2188 | 0 | if (!tgt->IsNormal() || tgt->GetType() == cmStateEnums::GLOBAL_TARGET || |
2189 | 0 | tgt->Target->IsForTryCompile()) { |
2190 | 0 | static TargetDirectoryRegistration utilityRegistration(nullptr, true); |
2191 | 0 | return utilityRegistration; |
2192 | 0 | } |
2193 | | |
2194 | | // Get the registration instance for the target. |
2195 | 0 | #if __cplusplus >= 201703L |
2196 | 0 | auto registration = this->TargetDirectoryRegistrations.try_emplace(tgt); |
2197 | | #else |
2198 | | auto registration = this->TargetDirectoryRegistrations.insert( |
2199 | | std::make_pair(tgt, TargetDirectoryRegistration())); |
2200 | | #endif |
2201 | | // If it was just inserted, search for a `CollidesWith` possibility. |
2202 | 0 | if (registration.second) { |
2203 | 0 | auto& otherTargets = this->TargetDirectories[targetDir]; |
2204 | 0 | if (!otherTargets.empty()) { |
2205 | 0 | registration.first->second.CollidesWith = *otherTargets.begin(); |
2206 | 0 | } |
2207 | 0 | otherTargets.insert(tgt); |
2208 | 0 | } |
2209 | |
|
2210 | 0 | return registration.first->second; |
2211 | 0 | } |
2212 | | |
2213 | | void cmGlobalGenerator::ComputeTargetObjectDirectory( |
2214 | | cmGeneratorTarget* /*unused*/) const |
2215 | 0 | { |
2216 | 0 | } |
2217 | | |
2218 | | void cmGlobalGenerator::CheckTargetProperties() |
2219 | 0 | { |
2220 | | // check for link libraries and include directories containing "NOTFOUND" |
2221 | | // and for infinite loops |
2222 | 0 | std::map<std::string, std::string> notFoundMap; |
2223 | 0 | cmState* state = this->GetCMakeInstance()->GetState(); |
2224 | 0 | for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { |
2225 | 0 | this->Makefiles[i]->Generate(*this->LocalGenerators[i]); |
2226 | 0 | for (auto const& target : this->Makefiles[i]->GetTargets()) { |
2227 | 0 | if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) { |
2228 | 0 | continue; |
2229 | 0 | } |
2230 | 0 | for (auto const& lib : target.second.GetOriginalLinkLibraries()) { |
2231 | 0 | if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) { |
2232 | 0 | std::string varName = lib.first.substr(0, lib.first.size() - 9); |
2233 | 0 | if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) { |
2234 | 0 | varName += " (ADVANCED)"; |
2235 | 0 | } |
2236 | 0 | std::string text = |
2237 | 0 | cmStrCat(notFoundMap[varName], "\n linked by target \"", |
2238 | 0 | target.second.GetName(), "\" in directory ", |
2239 | 0 | this->Makefiles[i]->GetCurrentSourceDirectory()); |
2240 | 0 | notFoundMap[varName] = text; |
2241 | 0 | } |
2242 | 0 | } |
2243 | 0 | cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES"); |
2244 | 0 | if (!incDirProp) { |
2245 | 0 | continue; |
2246 | 0 | } |
2247 | | |
2248 | 0 | std::string incDirs = cmGeneratorExpression::Preprocess( |
2249 | 0 | *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); |
2250 | |
|
2251 | 0 | cmList incs(incDirs); |
2252 | |
|
2253 | 0 | for (std::string const& incDir : incs) { |
2254 | 0 | if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) { |
2255 | 0 | std::string varName = incDir.substr(0, incDir.size() - 9); |
2256 | 0 | if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) { |
2257 | 0 | varName += " (ADVANCED)"; |
2258 | 0 | } |
2259 | 0 | std::string text = |
2260 | 0 | cmStrCat(notFoundMap[varName], |
2261 | 0 | "\n used as include directory in directory ", |
2262 | 0 | this->Makefiles[i]->GetCurrentSourceDirectory()); |
2263 | 0 | notFoundMap[varName] = text; |
2264 | 0 | } |
2265 | 0 | } |
2266 | 0 | } |
2267 | 0 | } |
2268 | |
|
2269 | 0 | if (!notFoundMap.empty()) { |
2270 | 0 | std::string notFoundVars; |
2271 | 0 | for (auto const& notFound : notFoundMap) { |
2272 | 0 | notFoundVars += notFound.first; |
2273 | 0 | notFoundVars += notFound.second; |
2274 | 0 | notFoundVars += '\n'; |
2275 | 0 | } |
2276 | 0 | cmSystemTools::Error( |
2277 | 0 | cmStrCat("The following variables are used in this project, " |
2278 | 0 | "but they are set to NOTFOUND.\n" |
2279 | 0 | "Please set them or make sure they are set and " |
2280 | 0 | "tested correctly in the CMake files:\n", |
2281 | 0 | notFoundVars)); |
2282 | 0 | } |
2283 | 0 | } |
2284 | | |
2285 | | int cmGlobalGenerator::TryCompile(int jobs, std::string const& bindir, |
2286 | | std::string const& projectName, |
2287 | | std::string const& target, bool fast, |
2288 | | std::string& output, cmMakefile* mf) |
2289 | 0 | { |
2290 | 0 | cmBuildArgs buildArgs; |
2291 | 0 | buildArgs.jobs = jobs; |
2292 | 0 | buildArgs.binaryDir = bindir; |
2293 | 0 | buildArgs.projectName = projectName; |
2294 | 0 | buildArgs.verbose = true; |
2295 | | |
2296 | | // if this is not set, then this is a first time configure |
2297 | | // and there is a good chance that the try compile stuff will |
2298 | | // take the bulk of the time, so try and guess some progress |
2299 | | // by getting closer and closer to 100 without actually getting there. |
2300 | 0 | if (!this->CMakeInstance->GetState()->GetInitializedCacheValue( |
2301 | 0 | "CMAKE_NUMBER_OF_MAKEFILES")) { |
2302 | | // If CMAKE_NUMBER_OF_MAKEFILES is not set |
2303 | | // we are in the first time progress and we have no |
2304 | | // idea how long it will be. So, just move 1/10th of the way |
2305 | | // there each time, and don't go over 95% |
2306 | 0 | this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f); |
2307 | 0 | if (this->FirstTimeProgress > 0.95f) { |
2308 | 0 | this->FirstTimeProgress = 0.95f; |
2309 | 0 | } |
2310 | 0 | this->CMakeInstance->UpdateProgress("Configuring", |
2311 | 0 | this->FirstTimeProgress); |
2312 | 0 | } |
2313 | |
|
2314 | 0 | std::vector<std::string> newTarget = {}; |
2315 | 0 | if (!target.empty()) { |
2316 | 0 | newTarget = { target }; |
2317 | 0 | } |
2318 | 0 | std::string config = |
2319 | 0 | mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); |
2320 | 0 | cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable); |
2321 | |
|
2322 | 0 | std::stringstream ostr; |
2323 | 0 | auto ret = this->Build(buildArgs, newTarget, ostr, "", config, |
2324 | 0 | defaultBuildOptions, this->TryCompileTimeout, |
2325 | 0 | cmSystemTools::OUTPUT_NONE, {}, BuildTryCompile::Yes); |
2326 | 0 | output = ostr.str(); |
2327 | 0 | return ret; |
2328 | 0 | } |
2329 | | |
2330 | | std::vector<cmGlobalGenerator::GeneratedMakeCommand> |
2331 | | cmGlobalGenerator::GenerateBuildCommand( |
2332 | | std::string const& /*unused*/, std::string const& /*unused*/, |
2333 | | std::string const& /*unused*/, std::vector<std::string> const& /*unused*/, |
2334 | | std::string const& /*unused*/, int /*unused*/, bool /*unused*/, |
2335 | | cmBuildOptions /*unused*/, std::vector<std::string> const& /*unused*/, |
2336 | | BuildTryCompile /*unused*/) |
2337 | 0 | { |
2338 | 0 | GeneratedMakeCommand makeCommand; |
2339 | 0 | makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented"); |
2340 | 0 | return { std::move(makeCommand) }; |
2341 | 0 | } |
2342 | | |
2343 | | void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/, |
2344 | | int /*jobs*/) const |
2345 | 0 | { |
2346 | | // Subclasses override this method if they e.g want to give a warning that |
2347 | | // they do not support certain build command line options |
2348 | 0 | } |
2349 | | |
2350 | | int cmGlobalGenerator::Build(cmBuildArgs const& buildArgs, |
2351 | | std::vector<std::string> const& targets, |
2352 | | std::ostream& ostr, |
2353 | | std::string const& makeCommandCSTR, |
2354 | | std::string const& config, |
2355 | | cmBuildOptions buildOptions, cmDuration timeout, |
2356 | | cmSystemTools::OutputOption outputMode, |
2357 | | std::vector<std::string> const& nativeOptions, |
2358 | | BuildTryCompile isInTryCompile) |
2359 | 0 | { |
2360 | 0 | bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); |
2361 | | |
2362 | | /** |
2363 | | * Run an executable command and put the stdout in output. |
2364 | | */ |
2365 | 0 | cmWorkingDirectory workdir(buildArgs.binaryDir); |
2366 | 0 | ostr << "Change Dir: '" << buildArgs.binaryDir << '\'' << std::endl; |
2367 | 0 | if (workdir.Failed()) { |
2368 | 0 | cmSystemTools::SetRunCommandHideConsole(hideconsole); |
2369 | 0 | std::string const& err = workdir.GetError(); |
2370 | 0 | cmSystemTools::Error(err); |
2371 | 0 | ostr << err << std::endl; |
2372 | 0 | return 1; |
2373 | 0 | } |
2374 | 0 | std::string realConfig = config; |
2375 | 0 | if (realConfig.empty()) { |
2376 | 0 | realConfig = this->GetDefaultBuildConfig(); |
2377 | 0 | } |
2378 | |
|
2379 | 0 | int retVal = 0; |
2380 | 0 | cmSystemTools::SetRunCommandHideConsole(true); |
2381 | | |
2382 | | // Capture build command output when outputMode == OUTPUT_NONE. |
2383 | 0 | std::string outputBuf; |
2384 | |
|
2385 | 0 | std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand( |
2386 | 0 | makeCommandCSTR, buildArgs.projectName, buildArgs.binaryDir, targets, |
2387 | 0 | realConfig, buildArgs.jobs, buildArgs.verbose, buildOptions, nativeOptions, |
2388 | 0 | isInTryCompile); |
2389 | | |
2390 | | // Workaround to convince some commands to produce output. |
2391 | 0 | if (outputMode == cmSystemTools::OUTPUT_PASSTHROUGH && |
2392 | 0 | makeCommand.back().RequiresOutputForward) { |
2393 | 0 | outputMode = cmSystemTools::OUTPUT_FORWARD; |
2394 | 0 | } |
2395 | | |
2396 | | // should we do a clean first? |
2397 | 0 | if (buildOptions.Clean) { |
2398 | 0 | std::vector<GeneratedMakeCommand> cleanCommand = |
2399 | 0 | this->GenerateBuildCommand(makeCommandCSTR, buildArgs.projectName, |
2400 | 0 | buildArgs.binaryDir, { "clean" }, realConfig, |
2401 | 0 | buildArgs.jobs, buildArgs.verbose, |
2402 | 0 | buildOptions); |
2403 | 0 | ostr << "\nRun Clean Command: " << cleanCommand.front().QuotedPrintable() |
2404 | 0 | << std::endl; |
2405 | 0 | if (cleanCommand.size() != 1) { |
2406 | 0 | this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR, |
2407 | 0 | "The generator did not produce " |
2408 | 0 | "exactly one command for the " |
2409 | 0 | "'clean' target"); |
2410 | 0 | return 1; |
2411 | 0 | } |
2412 | 0 | if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand, |
2413 | 0 | &outputBuf, &outputBuf, &retVal, |
2414 | 0 | nullptr, outputMode, timeout)) { |
2415 | 0 | cmSystemTools::SetRunCommandHideConsole(hideconsole); |
2416 | 0 | cmSystemTools::Error("Generator: execution of make clean failed."); |
2417 | 0 | ostr << outputBuf << "\nGenerator: execution of make clean failed." |
2418 | 0 | << std::endl; |
2419 | |
|
2420 | 0 | return 1; |
2421 | 0 | } |
2422 | 0 | ostr << outputBuf; |
2423 | 0 | } |
2424 | | |
2425 | | // now build |
2426 | 0 | std::string makeCommandStr; |
2427 | 0 | std::string outputMakeCommandStr; |
2428 | 0 | bool isWatcomWMake = this->CMakeInstance->GetState()->UseWatcomWMake(); |
2429 | 0 | bool needBuildOutput = isWatcomWMake; |
2430 | 0 | std::string buildOutput; |
2431 | 0 | ostr << "\nRun Build Command(s): "; |
2432 | |
|
2433 | 0 | retVal = 0; |
2434 | 0 | for (auto command = makeCommand.begin(); |
2435 | 0 | command != makeCommand.end() && retVal == 0; ++command) { |
2436 | 0 | makeCommandStr = command->Printable(); |
2437 | 0 | outputMakeCommandStr = command->QuotedPrintable(); |
2438 | 0 | if ((command + 1) != makeCommand.end()) { |
2439 | 0 | makeCommandStr += " && "; |
2440 | 0 | outputMakeCommandStr += " && "; |
2441 | 0 | } |
2442 | |
|
2443 | 0 | ostr << outputMakeCommandStr << std::endl; |
2444 | 0 | if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, &outputBuf, |
2445 | 0 | &outputBuf, &retVal, nullptr, |
2446 | 0 | outputMode, timeout)) { |
2447 | 0 | cmSystemTools::SetRunCommandHideConsole(hideconsole); |
2448 | 0 | cmSystemTools::Error( |
2449 | 0 | cmStrCat("Generator: build tool execution failed, command was: ", |
2450 | 0 | makeCommandStr)); |
2451 | 0 | ostr << outputBuf |
2452 | 0 | << "\nGenerator: build tool execution failed, command was: " |
2453 | 0 | << outputMakeCommandStr << std::endl; |
2454 | |
|
2455 | 0 | return 1; |
2456 | 0 | } |
2457 | 0 | ostr << outputBuf << std::flush; |
2458 | 0 | if (needBuildOutput) { |
2459 | 0 | buildOutput += outputBuf; |
2460 | 0 | } |
2461 | 0 | } |
2462 | 0 | ostr << std::endl; |
2463 | 0 | cmSystemTools::SetRunCommandHideConsole(hideconsole); |
2464 | | |
2465 | | // The OpenWatcom tools do not return an error code when a link |
2466 | | // library is not found! |
2467 | 0 | if (isWatcomWMake && retVal == 0 && |
2468 | 0 | buildOutput.find("W1008: cannot open") != std::string::npos) { |
2469 | 0 | retVal = 1; |
2470 | 0 | } |
2471 | |
|
2472 | 0 | return retVal; |
2473 | 0 | } |
2474 | | |
2475 | | bool cmGlobalGenerator::Open(std::string const& bindir, |
2476 | | std::string const& projectName, bool dryRun) |
2477 | 0 | { |
2478 | 0 | if (this->ExtraGenerator) { |
2479 | 0 | return this->ExtraGenerator->Open(bindir, projectName, dryRun); |
2480 | 0 | } |
2481 | | |
2482 | 0 | return false; |
2483 | 0 | } |
2484 | | |
2485 | | std::string cmGlobalGenerator::GenerateCMakeBuildCommand( |
2486 | | std::string const& target, std::string const& config, |
2487 | | std::string const& parallel, std::string const& native, bool ignoreErrors) |
2488 | 0 | { |
2489 | 0 | std::string makeCommand = cmSystemTools::GetCMakeCommand(); |
2490 | 0 | makeCommand = |
2491 | 0 | cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build ."); |
2492 | 0 | if (!config.empty()) { |
2493 | 0 | makeCommand = cmStrCat(makeCommand, " --config \"", config, '"'); |
2494 | 0 | } |
2495 | 0 | if (!parallel.empty()) { |
2496 | 0 | makeCommand = cmStrCat(makeCommand, " --parallel \"", parallel, '"'); |
2497 | 0 | } |
2498 | 0 | if (!target.empty()) { |
2499 | 0 | makeCommand = cmStrCat(makeCommand, " --target \"", target, '"'); |
2500 | 0 | } |
2501 | 0 | char const* sep = " -- "; |
2502 | 0 | if (ignoreErrors) { |
2503 | 0 | char const* iflag = this->GetBuildIgnoreErrorsFlag(); |
2504 | 0 | if (iflag && *iflag) { |
2505 | 0 | makeCommand = cmStrCat(makeCommand, sep, iflag); |
2506 | 0 | sep = " "; |
2507 | 0 | } |
2508 | 0 | } |
2509 | 0 | if (!native.empty()) { |
2510 | 0 | makeCommand = cmStrCat(makeCommand, sep, native); |
2511 | 0 | } |
2512 | 0 | return makeCommand; |
2513 | 0 | } |
2514 | | |
2515 | | void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf) |
2516 | 0 | { |
2517 | 0 | this->IndexMakefile(mf.get()); |
2518 | 0 | this->Makefiles.push_back(std::move(mf)); |
2519 | | |
2520 | | // update progress |
2521 | | // estimate how many lg there will be |
2522 | 0 | cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue( |
2523 | 0 | "CMAKE_NUMBER_OF_MAKEFILES"); |
2524 | |
|
2525 | 0 | if (!numGenC) { |
2526 | | // If CMAKE_NUMBER_OF_MAKEFILES is not set |
2527 | | // we are in the first time progress and we have no |
2528 | | // idea how long it will be. So, just move half way |
2529 | | // there each time, and don't go over 95% |
2530 | 0 | this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f); |
2531 | 0 | if (this->FirstTimeProgress > 0.95f) { |
2532 | 0 | this->FirstTimeProgress = 0.95f; |
2533 | 0 | } |
2534 | 0 | this->CMakeInstance->UpdateProgress("Configuring", |
2535 | 0 | this->FirstTimeProgress); |
2536 | 0 | return; |
2537 | 0 | } |
2538 | | |
2539 | 0 | int numGen = atoi(numGenC->c_str()); |
2540 | 0 | float prog = |
2541 | 0 | static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen); |
2542 | 0 | if (prog > 1.0f) { |
2543 | 0 | prog = 1.0f; |
2544 | 0 | } |
2545 | 0 | this->CMakeInstance->UpdateProgress("Configuring", prog); |
2546 | 0 | } |
2547 | | |
2548 | | void cmGlobalGenerator::AddInstallComponent(std::string const& component) |
2549 | 0 | { |
2550 | 0 | if (!component.empty()) { |
2551 | 0 | this->InstallComponents.insert(component); |
2552 | 0 | } |
2553 | 0 | } |
2554 | | |
2555 | | void cmGlobalGenerator::MarkAsGeneratedFile(std::string const& filepath) |
2556 | 0 | { |
2557 | 0 | this->GeneratedFiles.insert(filepath); |
2558 | 0 | } |
2559 | | |
2560 | | bool cmGlobalGenerator::IsGeneratedFile(std::string const& filepath) |
2561 | 0 | { |
2562 | 0 | return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end(); |
2563 | 0 | } |
2564 | | |
2565 | | void cmGlobalGenerator::EnableInstallTarget() |
2566 | 0 | { |
2567 | 0 | this->InstallTargetEnabled = true; |
2568 | 0 | } |
2569 | | |
2570 | | std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator( |
2571 | | cmMakefile* mf) |
2572 | 0 | { |
2573 | 0 | return cm::make_unique<cmLocalGenerator>(this, mf); |
2574 | 0 | } |
2575 | | |
2576 | | void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen, |
2577 | | cmMakefile* mf) |
2578 | 0 | { |
2579 | 0 | this->SetConfiguredFilesPath(gen); |
2580 | 0 | this->TryCompileOuterMakefile = mf; |
2581 | 0 | cmValue make = |
2582 | 0 | gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM"); |
2583 | 0 | this->GetCMakeInstance()->AddCacheEntry( |
2584 | 0 | "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH); |
2585 | | // copy the enabled languages |
2586 | 0 | this->GetCMakeInstance()->GetState()->SetEnabledLanguages( |
2587 | 0 | gen->GetCMakeInstance()->GetState()->GetEnabledLanguages()); |
2588 | 0 | this->LanguagesReady = gen->LanguagesReady; |
2589 | 0 | this->ExtensionToLanguage = gen->ExtensionToLanguage; |
2590 | 0 | this->IgnoreExtensions = gen->IgnoreExtensions; |
2591 | 0 | this->LanguageToOutputExtension = gen->LanguageToOutputExtension; |
2592 | 0 | this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference; |
2593 | 0 | this->OutputExtensions = gen->OutputExtensions; |
2594 | 0 | } |
2595 | | |
2596 | | void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen) |
2597 | 0 | { |
2598 | 0 | if (!gen->ConfiguredFilesPath.empty()) { |
2599 | 0 | this->ConfiguredFilesPath = gen->ConfiguredFilesPath; |
2600 | 0 | } else { |
2601 | 0 | this->ConfiguredFilesPath = |
2602 | 0 | cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles"); |
2603 | 0 | } |
2604 | 0 | } |
2605 | | |
2606 | | bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp, |
2607 | | cmStateSnapshot const& snp_) const |
2608 | 0 | { |
2609 | 0 | cmStateSnapshot snp = snp_; |
2610 | 0 | while (snp.IsValid()) { |
2611 | 0 | if (snp == rootSnp) { |
2612 | | // No directory excludes itself. |
2613 | 0 | return false; |
2614 | 0 | } |
2615 | | |
2616 | 0 | if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) { |
2617 | | // This directory is excluded from its parent. |
2618 | 0 | return true; |
2619 | 0 | } |
2620 | 0 | snp = snp.GetBuildsystemDirectoryParent(); |
2621 | 0 | } |
2622 | 0 | return false; |
2623 | 0 | } |
2624 | | |
2625 | | bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root, |
2626 | | cmLocalGenerator const* gen) const |
2627 | 0 | { |
2628 | 0 | assert(gen); |
2629 | |
|
2630 | 0 | cmStateSnapshot rootSnp = root->GetStateSnapshot(); |
2631 | 0 | cmStateSnapshot snp = gen->GetStateSnapshot(); |
2632 | |
|
2633 | 0 | return this->IsExcluded(rootSnp, snp); |
2634 | 0 | } |
2635 | | |
2636 | | bool cmGlobalGenerator::IsExcluded(cmLocalGenerator const* root, |
2637 | | cmGeneratorTarget const* target) const |
2638 | 0 | { |
2639 | 0 | if (!target->IsInBuildSystem()) { |
2640 | 0 | return true; |
2641 | 0 | } |
2642 | 0 | cmMakefile* mf = root->GetMakefile(); |
2643 | 0 | std::string const EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL"; |
2644 | 0 | if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) { |
2645 | | // Expand the property value per configuration. |
2646 | 0 | unsigned int trueCount = 0; |
2647 | 0 | unsigned int falseCount = 0; |
2648 | 0 | std::vector<std::string> const& configs = |
2649 | 0 | mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); |
2650 | 0 | for (std::string const& config : configs) { |
2651 | 0 | cmGeneratorExpressionInterpreter genexInterpreter(root, config, target); |
2652 | 0 | if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) { |
2653 | 0 | ++trueCount; |
2654 | 0 | } else { |
2655 | 0 | ++falseCount; |
2656 | 0 | } |
2657 | 0 | } |
2658 | | |
2659 | | // Check whether the genex expansion of the property agrees in all |
2660 | | // configurations. |
2661 | 0 | if (trueCount > 0 && falseCount > 0) { |
2662 | 0 | std::ostringstream e; |
2663 | 0 | e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName() |
2664 | 0 | << "\" varies by configuration. This is not supported by the \"" |
2665 | 0 | << root->GetGlobalGenerator()->GetName() << "\" generator."; |
2666 | 0 | mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); |
2667 | 0 | } |
2668 | 0 | return trueCount; |
2669 | 0 | } |
2670 | | // This target is included in its directory. Check whether the |
2671 | | // directory is excluded. |
2672 | 0 | return this->IsExcluded(root, target->GetLocalGenerator()); |
2673 | 0 | } |
2674 | | |
2675 | | void cmGlobalGenerator::GetEnabledLanguages( |
2676 | | std::vector<std::string>& lang) const |
2677 | 0 | { |
2678 | 0 | lang = this->CMakeInstance->GetState()->GetEnabledLanguages(); |
2679 | 0 | } |
2680 | | |
2681 | | int cmGlobalGenerator::GetLinkerPreference(std::string const& lang) const |
2682 | 0 | { |
2683 | 0 | auto const it = this->LanguageToLinkerPreference.find(lang); |
2684 | 0 | if (it != this->LanguageToLinkerPreference.end()) { |
2685 | 0 | return it->second; |
2686 | 0 | } |
2687 | 0 | return 0; |
2688 | 0 | } |
2689 | | |
2690 | | void cmGlobalGenerator::FillProjectMap() |
2691 | 0 | { |
2692 | 0 | this->ProjectMap.clear(); // make sure we start with a clean map |
2693 | 0 | for (auto const& localGen : this->LocalGenerators) { |
2694 | | // for each local generator add all projects |
2695 | 0 | cmStateSnapshot snp = localGen->GetStateSnapshot(); |
2696 | 0 | std::string name; |
2697 | 0 | do { |
2698 | 0 | std::string snpProjName = snp.GetProjectName(); |
2699 | 0 | if (name != snpProjName) { |
2700 | 0 | name = snpProjName; |
2701 | 0 | this->ProjectMap[name].push_back(localGen.get()); |
2702 | 0 | } |
2703 | 0 | snp = snp.GetBuildsystemDirectoryParent(); |
2704 | 0 | } while (snp.IsValid()); |
2705 | 0 | } |
2706 | 0 | } |
2707 | | |
2708 | | cmMakefile* cmGlobalGenerator::FindMakefile(std::string const& start_dir) const |
2709 | 0 | { |
2710 | 0 | auto const it = this->MakefileSearchIndex.find(start_dir); |
2711 | 0 | if (it != this->MakefileSearchIndex.end()) { |
2712 | 0 | return it->second; |
2713 | 0 | } |
2714 | 0 | return nullptr; |
2715 | 0 | } |
2716 | | |
2717 | | cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator( |
2718 | | cmDirectoryId const& id) const |
2719 | 0 | { |
2720 | 0 | auto const it = this->LocalGeneratorSearchIndex.find(id.String); |
2721 | 0 | if (it != this->LocalGeneratorSearchIndex.end()) { |
2722 | 0 | return it->second; |
2723 | 0 | } |
2724 | 0 | return nullptr; |
2725 | 0 | } |
2726 | | |
2727 | | void cmGlobalGenerator::AddAlias(std::string const& name, |
2728 | | std::string const& tgtName) |
2729 | 0 | { |
2730 | 0 | this->AliasTargets[name] = tgtName; |
2731 | 0 | } |
2732 | | |
2733 | | bool cmGlobalGenerator::IsAlias(std::string const& name) const |
2734 | 0 | { |
2735 | 0 | return cm::contains(this->AliasTargets, name); |
2736 | 0 | } |
2737 | | |
2738 | | void cmGlobalGenerator::IndexTarget(cmTarget* t) |
2739 | 0 | { |
2740 | 0 | if (!t->IsImported() || t->IsImportedGloballyVisible()) { |
2741 | 0 | this->TargetSearchIndex[t->GetName()] = t; |
2742 | 0 | } |
2743 | 0 | } |
2744 | | |
2745 | | void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt) |
2746 | 0 | { |
2747 | 0 | if (!gt->IsImported() || gt->IsImportedGloballyVisible()) { |
2748 | 0 | this->GeneratorTargetSearchIndex[gt->GetName()] = gt; |
2749 | 0 | } |
2750 | 0 | } |
2751 | | |
2752 | | static char const hexDigits[] = "0123456789abcdef"; |
2753 | | |
2754 | | std::string cmGlobalGenerator::IndexGeneratorTargetUniquely( |
2755 | | cmGeneratorTarget const* gt) |
2756 | 0 | { |
2757 | | // Use the pointer value to uniquely identify the target instance. |
2758 | | // Use a ":" prefix to avoid conflict with project-defined targets. |
2759 | | // We must satisfy cmGeneratorExpression::IsValidTargetName so use no |
2760 | | // other special characters. |
2761 | 0 | constexpr size_t sizeof_ptr = |
2762 | 0 | sizeof(gt); // NOLINT(bugprone-sizeof-expression) |
2763 | 0 | char buf[1 + sizeof_ptr * 2]; |
2764 | 0 | char* b = buf; |
2765 | 0 | *b++ = ':'; |
2766 | 0 | for (size_t i = 0; i < sizeof_ptr; ++i) { |
2767 | 0 | unsigned char const c = reinterpret_cast<unsigned char const*>(>)[i]; |
2768 | 0 | *b++ = hexDigits[(c & 0xf0) >> 4]; |
2769 | 0 | *b++ = hexDigits[(c & 0x0f)]; |
2770 | 0 | } |
2771 | 0 | std::string id(buf, sizeof(buf)); |
2772 | | // We internally index pointers to non-const generator targets |
2773 | | // but our callers only have pointers to const generator targets. |
2774 | | // They will give up non-const privileges when looking up anyway. |
2775 | 0 | this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt); |
2776 | 0 | return id; |
2777 | 0 | } |
2778 | | |
2779 | | void cmGlobalGenerator::IndexMakefile(cmMakefile* mf) |
2780 | 0 | { |
2781 | | // We index by both source and binary directory. add_subdirectory |
2782 | | // supports multiple build directories sharing the same source directory. |
2783 | | // The source directory index will reference only the first time it is used. |
2784 | 0 | this->MakefileSearchIndex.insert( |
2785 | 0 | MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf)); |
2786 | 0 | this->MakefileSearchIndex.insert( |
2787 | 0 | MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf)); |
2788 | 0 | } |
2789 | | |
2790 | | void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg) |
2791 | 0 | { |
2792 | 0 | cmDirectoryId id = lg->GetMakefile()->GetDirectoryId(); |
2793 | 0 | this->LocalGeneratorSearchIndex[id.String] = lg; |
2794 | 0 | } |
2795 | | |
2796 | | cmTarget* cmGlobalGenerator::FindTargetImpl( |
2797 | | std::string const& name, cmStateEnums::TargetDomainSet domains) const |
2798 | 0 | { |
2799 | 0 | bool const useForeign = |
2800 | 0 | domains.contains(cmStateEnums::TargetDomain::FOREIGN); |
2801 | 0 | bool const useNative = domains.contains(cmStateEnums::TargetDomain::NATIVE); |
2802 | |
|
2803 | 0 | auto const it = this->TargetSearchIndex.find(name); |
2804 | 0 | if (it != this->TargetSearchIndex.end()) { |
2805 | 0 | if (it->second->IsForeign() ? useForeign : useNative) { |
2806 | 0 | return it->second; |
2807 | 0 | } |
2808 | 0 | } |
2809 | 0 | return nullptr; |
2810 | 0 | } |
2811 | | |
2812 | | cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl( |
2813 | | std::string const& name) const |
2814 | 0 | { |
2815 | 0 | auto const it = this->GeneratorTargetSearchIndex.find(name); |
2816 | 0 | if (it != this->GeneratorTargetSearchIndex.end()) { |
2817 | 0 | return it->second; |
2818 | 0 | } |
2819 | 0 | return nullptr; |
2820 | 0 | } |
2821 | | |
2822 | | cmTarget* cmGlobalGenerator::FindTarget( |
2823 | | std::string const& name, cmStateEnums::TargetDomainSet domains) const |
2824 | 0 | { |
2825 | 0 | if (domains.contains(cmStateEnums::TargetDomain::ALIAS)) { |
2826 | 0 | auto const ai = this->AliasTargets.find(name); |
2827 | 0 | if (ai != this->AliasTargets.end()) { |
2828 | 0 | return this->FindTargetImpl(ai->second, domains); |
2829 | 0 | } |
2830 | 0 | } |
2831 | 0 | return this->FindTargetImpl(name, domains); |
2832 | 0 | } |
2833 | | |
2834 | | cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget( |
2835 | | std::string const& name) const |
2836 | 0 | { |
2837 | 0 | auto const ai = this->AliasTargets.find(name); |
2838 | 0 | if (ai != this->AliasTargets.end()) { |
2839 | 0 | return this->FindGeneratorTargetImpl(ai->second); |
2840 | 0 | } |
2841 | 0 | return this->FindGeneratorTargetImpl(name); |
2842 | 0 | } |
2843 | | |
2844 | | bool cmGlobalGenerator::NameResolvesToFramework( |
2845 | | std::string const& libname) const |
2846 | 0 | { |
2847 | 0 | if (cmSystemTools::IsPathToFramework(libname)) { |
2848 | 0 | return true; |
2849 | 0 | } |
2850 | | |
2851 | 0 | if (cmTarget* tgt = this->FindTarget(libname)) { |
2852 | 0 | if (tgt->IsFrameworkOnApple()) { |
2853 | 0 | return true; |
2854 | 0 | } |
2855 | 0 | } |
2856 | | |
2857 | 0 | return false; |
2858 | 0 | } |
2859 | | |
2860 | | // If the file has no extension it's either a raw executable or might |
2861 | | // be a direct reference to a binary within a framework (bad practice!). |
2862 | | // This is where we change the path to point to the framework directory. |
2863 | | // .tbd files also can be located in SDK frameworks (they are |
2864 | | // placeholders for actual libraries shipped with the OS) |
2865 | | cm::optional<cmGlobalGenerator::FrameworkDescriptor> |
2866 | | cmGlobalGenerator::SplitFrameworkPath(std::string const& path, |
2867 | | FrameworkFormat format) const |
2868 | 0 | { |
2869 | | // Check for framework structure: |
2870 | | // (/path/to/)?FwName.framework |
2871 | | // or (/path/to/)?FwName.framework/FwName(.tbd)? |
2872 | | // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)? |
2873 | 0 | static cmsys::RegularExpression frameworkPath( |
2874 | 0 | "((.+)/)?([^/]+)\\.framework(/Versions/([^/]+))?(/(.+))?$"); |
2875 | |
|
2876 | 0 | auto ext = cmSystemTools::GetFilenameLastExtensionView(path); |
2877 | 0 | if ((ext.empty() || ext == ".tbd" || ext == ".framework") && |
2878 | 0 | frameworkPath.find(path)) { |
2879 | 0 | auto name = frameworkPath.match(3); |
2880 | 0 | auto libname = |
2881 | 0 | cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(7)); |
2882 | 0 | if (format == FrameworkFormat::Strict && libname.empty()) { |
2883 | 0 | return cm::nullopt; |
2884 | 0 | } |
2885 | 0 | if (!libname.empty() && !cmHasPrefix(libname, name)) { |
2886 | 0 | return cm::nullopt; |
2887 | 0 | } |
2888 | | |
2889 | 0 | if (libname.empty() || name.size() == libname.size()) { |
2890 | 0 | return FrameworkDescriptor{ frameworkPath.match(2), |
2891 | 0 | frameworkPath.match(5), name }; |
2892 | 0 | } |
2893 | | |
2894 | 0 | return FrameworkDescriptor{ frameworkPath.match(2), frameworkPath.match(5), |
2895 | 0 | name, libname.substr(name.size()) }; |
2896 | 0 | } |
2897 | | |
2898 | 0 | if (format == FrameworkFormat::Extended) { |
2899 | | // path format can be more flexible: (/path/to/)?fwName(.framework)? |
2900 | 0 | auto fwDir = cmSystemTools::GetParentDirectory(path); |
2901 | 0 | auto name = ext == ".framework" |
2902 | 0 | ? cmSystemTools::GetFilenameWithoutExtension(path) |
2903 | 0 | : cmSystemTools::GetFilenameName(path); |
2904 | |
|
2905 | 0 | return FrameworkDescriptor{ fwDir, name }; |
2906 | 0 | } |
2907 | | |
2908 | 0 | return cm::nullopt; |
2909 | 0 | } |
2910 | | |
2911 | | namespace { |
2912 | | void IssueReservedTargetNameError(cmake* cm, cmTarget* tgt, |
2913 | | std::string const& targetNameAsWritten, |
2914 | | std::string const& reason) |
2915 | 0 | { |
2916 | 0 | cm->IssueMessage(MessageType::FATAL_ERROR, |
2917 | 0 | cmStrCat("The target name \"", targetNameAsWritten, |
2918 | 0 | "\" is reserved ", reason, '.'), |
2919 | 0 | tgt->GetBacktrace()); |
2920 | 0 | } |
2921 | | } |
2922 | | |
2923 | | bool cmGlobalGenerator::CheckReservedTargetName( |
2924 | | std::string const& targetName, std::string const& reason) const |
2925 | 0 | { |
2926 | 0 | cmTarget* tgt = this->FindTarget(targetName); |
2927 | 0 | if (!tgt) { |
2928 | 0 | return true; |
2929 | 0 | } |
2930 | 0 | IssueReservedTargetNameError(this->GetCMakeInstance(), tgt, targetName, |
2931 | 0 | reason); |
2932 | 0 | return false; |
2933 | 0 | } |
2934 | | |
2935 | | bool cmGlobalGenerator::CheckReservedTargetNamePrefix( |
2936 | | std::string const& targetPrefix, std::string const& reason) const |
2937 | 0 | { |
2938 | 0 | bool ret = true; |
2939 | 0 | for (auto const& tgtPair : this->TargetSearchIndex) { |
2940 | 0 | if (cmHasPrefix(tgtPair.first, targetPrefix)) { |
2941 | 0 | IssueReservedTargetNameError(this->GetCMakeInstance(), tgtPair.second, |
2942 | 0 | tgtPair.first, reason); |
2943 | 0 | ret = false; |
2944 | 0 | } |
2945 | 0 | } |
2946 | 0 | return ret; |
2947 | 0 | } |
2948 | | |
2949 | | void cmGlobalGenerator::CreateDefaultGlobalTargets( |
2950 | | std::vector<GlobalTargetInfo>& targets) |
2951 | 0 | { |
2952 | 0 | this->AddGlobalTarget_Package(targets); |
2953 | 0 | this->AddGlobalTarget_PackageSource(targets); |
2954 | 0 | this->AddGlobalTarget_Test(targets); |
2955 | 0 | this->AddGlobalTarget_EditCache(targets); |
2956 | 0 | this->AddGlobalTarget_RebuildCache(targets); |
2957 | 0 | this->AddGlobalTarget_Install(targets); |
2958 | 0 | } |
2959 | | |
2960 | | void cmGlobalGenerator::AddGlobalTarget_Package( |
2961 | | std::vector<GlobalTargetInfo>& targets) |
2962 | 0 | { |
2963 | 0 | auto& mf = this->Makefiles[0]; |
2964 | 0 | std::string configFile = |
2965 | 0 | cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake"); |
2966 | 0 | if (!cmSystemTools::FileExists(configFile)) { |
2967 | 0 | return; |
2968 | 0 | } |
2969 | | |
2970 | 0 | static auto const reservedTargets = { "package", "PACKAGE" }; |
2971 | 0 | for (auto const& target : reservedTargets) { |
2972 | 0 | if (!this->CheckReservedTargetName(target, |
2973 | 0 | "when CPack packaging is enabled")) { |
2974 | 0 | return; |
2975 | 0 | } |
2976 | 0 | } |
2977 | | |
2978 | 0 | char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); |
2979 | 0 | GlobalTargetInfo gti; |
2980 | 0 | gti.Name = this->GetPackageTargetName(); |
2981 | 0 | gti.Message = "Run CPack packaging tool..."; |
2982 | 0 | gti.UsesTerminal = true; |
2983 | 0 | gti.WorkingDir = mf->GetCurrentBinaryDirectory(); |
2984 | 0 | cmCustomCommandLine singleLine; |
2985 | 0 | singleLine.push_back(cmSystemTools::GetCPackCommand()); |
2986 | 0 | if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { |
2987 | 0 | singleLine.push_back("-C"); |
2988 | 0 | singleLine.push_back(cmakeCfgIntDir); |
2989 | 0 | } |
2990 | 0 | singleLine.push_back("--config"); |
2991 | 0 | singleLine.push_back("./CPackConfig.cmake"); |
2992 | 0 | gti.CommandLines.push_back(std::move(singleLine)); |
2993 | 0 | if (this->GetPreinstallTargetName()) { |
2994 | 0 | gti.Depends.emplace_back(this->GetPreinstallTargetName()); |
2995 | 0 | } else { |
2996 | 0 | cmValue noPackageAll = |
2997 | 0 | mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY"); |
2998 | 0 | if (noPackageAll.IsOff()) { |
2999 | 0 | gti.Depends.emplace_back(this->GetAllTargetName()); |
3000 | 0 | } |
3001 | 0 | } |
3002 | 0 | targets.push_back(std::move(gti)); |
3003 | 0 | } |
3004 | | |
3005 | | void cmGlobalGenerator::AddGlobalTarget_PackageSource( |
3006 | | std::vector<GlobalTargetInfo>& targets) |
3007 | 0 | { |
3008 | 0 | char const* packageSourceTargetName = this->GetPackageSourceTargetName(); |
3009 | 0 | if (!packageSourceTargetName) { |
3010 | 0 | return; |
3011 | 0 | } |
3012 | | |
3013 | 0 | auto& mf = this->Makefiles[0]; |
3014 | 0 | std::string configFile = |
3015 | 0 | cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake"); |
3016 | 0 | if (!cmSystemTools::FileExists(configFile)) { |
3017 | 0 | return; |
3018 | 0 | } |
3019 | | |
3020 | 0 | static auto const reservedTargets = { "package_source" }; |
3021 | 0 | for (auto const& target : reservedTargets) { |
3022 | 0 | if (!this->CheckReservedTargetName( |
3023 | 0 | target, "when CPack source packaging is enabled")) { |
3024 | 0 | return; |
3025 | 0 | } |
3026 | 0 | } |
3027 | | |
3028 | 0 | GlobalTargetInfo gti; |
3029 | 0 | gti.Name = packageSourceTargetName; |
3030 | 0 | gti.Message = "Run CPack packaging tool for source..."; |
3031 | 0 | gti.WorkingDir = mf->GetCurrentBinaryDirectory(); |
3032 | 0 | gti.UsesTerminal = true; |
3033 | 0 | cmCustomCommandLine singleLine; |
3034 | 0 | singleLine.push_back(cmSystemTools::GetCPackCommand()); |
3035 | 0 | singleLine.push_back("--config"); |
3036 | 0 | singleLine.push_back("./CPackSourceConfig.cmake"); |
3037 | 0 | gti.CommandLines.push_back(std::move(singleLine)); |
3038 | 0 | targets.push_back(std::move(gti)); |
3039 | 0 | } |
3040 | | |
3041 | | void cmGlobalGenerator::AddGlobalTarget_Test( |
3042 | | std::vector<GlobalTargetInfo>& targets) |
3043 | 0 | { |
3044 | 0 | auto& mf = this->Makefiles[0]; |
3045 | 0 | if (!mf->IsOn("CMAKE_TESTING_ENABLED")) { |
3046 | 0 | return; |
3047 | 0 | } |
3048 | | |
3049 | 0 | static auto const reservedTargets = { "test", "RUN_TESTS" }; |
3050 | 0 | for (auto const& target : reservedTargets) { |
3051 | 0 | if (!this->CheckReservedTargetName(target, |
3052 | 0 | "when CTest testing is enabled")) { |
3053 | 0 | return; |
3054 | 0 | } |
3055 | 0 | } |
3056 | | |
3057 | 0 | char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); |
3058 | 0 | GlobalTargetInfo gti; |
3059 | 0 | gti.Name = this->GetTestTargetName(); |
3060 | 0 | gti.Message = "Running tests..."; |
3061 | 0 | gti.UsesTerminal = true; |
3062 | | // Unlike the 'install' target, the 'test' target does not depend on 'all' |
3063 | | // by default. Enable it only if CMAKE_SKIP_TEST_ALL_DEPENDENCY is |
3064 | | // explicitly set to OFF. |
3065 | 0 | if (cmValue noall = mf->GetDefinition("CMAKE_SKIP_TEST_ALL_DEPENDENCY")) { |
3066 | 0 | if (noall.IsOff()) { |
3067 | 0 | gti.Depends.emplace_back(this->GetAllTargetName()); |
3068 | 0 | } |
3069 | 0 | } |
3070 | 0 | cmCustomCommandLine singleLine; |
3071 | 0 | singleLine.push_back(cmSystemTools::GetCTestCommand()); |
3072 | 0 | cmList args(mf->GetDefinition("CMAKE_CTEST_ARGUMENTS")); |
3073 | 0 | for (auto const& arg : args) { |
3074 | 0 | singleLine.push_back(arg); |
3075 | 0 | } |
3076 | 0 | if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { |
3077 | 0 | singleLine.push_back("-C"); |
3078 | 0 | singleLine.push_back(cmakeCfgIntDir); |
3079 | 0 | } else // TODO: This is a hack. Should be something to do with the |
3080 | | // generator |
3081 | 0 | { |
3082 | 0 | singleLine.push_back("$(ARGS)"); |
3083 | 0 | } |
3084 | 0 | gti.CommandLines.push_back(std::move(singleLine)); |
3085 | 0 | targets.push_back(std::move(gti)); |
3086 | 0 | } |
3087 | | |
3088 | | void cmGlobalGenerator::ReserveGlobalTargetCodegen() |
3089 | 0 | { |
3090 | | // Read the policy value at the end of the top-level CMakeLists.txt file |
3091 | | // since it's a global policy that affects the whole project. |
3092 | 0 | auto& mf = this->Makefiles[0]; |
3093 | 0 | auto const policyStatus = mf->GetPolicyStatus(cmPolicies::CMP0171); |
3094 | |
|
3095 | 0 | this->AllowGlobalTargetCodegen = (policyStatus == cmPolicies::NEW); |
3096 | |
|
3097 | 0 | cmTarget* tgt = this->FindTarget("codegen"); |
3098 | 0 | if (!tgt) { |
3099 | 0 | return; |
3100 | 0 | } |
3101 | | |
3102 | 0 | switch (policyStatus) { |
3103 | 0 | case cmPolicies::WARN: |
3104 | 0 | this->GetCMakeInstance()->IssueDiagnostic( |
3105 | 0 | cmDiagnostics::CMD_AUTHOR, |
3106 | 0 | cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0171), '\n', |
3107 | 0 | "The target name \"codegen\" is reserved."), |
3108 | 0 | tgt->GetBacktrace()); |
3109 | 0 | break; |
3110 | 0 | case cmPolicies::OLD: |
3111 | 0 | break; |
3112 | 0 | case cmPolicies::NEW: |
3113 | 0 | this->GetCMakeInstance()->IssueMessage( |
3114 | 0 | MessageType::FATAL_ERROR, "The target name \"codegen\" is reserved.", |
3115 | 0 | tgt->GetBacktrace()); |
3116 | 0 | cmSystemTools::SetFatalErrorOccurred(); |
3117 | 0 | break; |
3118 | 0 | } |
3119 | 0 | } |
3120 | | |
3121 | | bool cmGlobalGenerator::CheckCMP0171() const |
3122 | 0 | { |
3123 | 0 | return this->AllowGlobalTargetCodegen; |
3124 | 0 | } |
3125 | | |
3126 | | void cmGlobalGenerator::AddGlobalTarget_EditCache( |
3127 | | std::vector<GlobalTargetInfo>& targets) const |
3128 | 0 | { |
3129 | 0 | char const* editCacheTargetName = this->GetEditCacheTargetName(); |
3130 | 0 | if (!editCacheTargetName) { |
3131 | 0 | return; |
3132 | 0 | } |
3133 | 0 | GlobalTargetInfo gti; |
3134 | 0 | gti.Name = editCacheTargetName; |
3135 | 0 | gti.PerConfig = cmTarget::PerConfig::No; |
3136 | 0 | cmCustomCommandLine singleLine; |
3137 | | |
3138 | | // Use generator preference for the edit_cache rule if it is defined. |
3139 | 0 | std::string edit_cmd = this->GetEditCacheCommand(); |
3140 | 0 | if (!edit_cmd.empty()) { |
3141 | 0 | singleLine.push_back(std::move(edit_cmd)); |
3142 | 0 | if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) { |
3143 | 0 | singleLine.push_back("--compile-no-warning-as-error"); |
3144 | 0 | } |
3145 | 0 | if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) { |
3146 | 0 | singleLine.push_back("--link-no-warning-as-error"); |
3147 | 0 | } |
3148 | 0 | singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); |
3149 | 0 | singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); |
3150 | 0 | gti.Message = "Running CMake cache editor..."; |
3151 | 0 | gti.UsesTerminal = true; |
3152 | 0 | } else { |
3153 | 0 | singleLine.push_back(cmSystemTools::GetCMakeCommand()); |
3154 | 0 | singleLine.push_back("-E"); |
3155 | 0 | singleLine.push_back("echo"); |
3156 | 0 | singleLine.push_back("No interactive CMake dialog available."); |
3157 | 0 | gti.Message = "No interactive CMake dialog available..."; |
3158 | 0 | gti.UsesTerminal = false; |
3159 | 0 | gti.StdPipesUTF8 = true; |
3160 | 0 | } |
3161 | 0 | gti.CommandLines.push_back(std::move(singleLine)); |
3162 | |
|
3163 | 0 | targets.push_back(std::move(gti)); |
3164 | 0 | } |
3165 | | |
3166 | | void cmGlobalGenerator::AddGlobalTarget_RebuildCache( |
3167 | | std::vector<GlobalTargetInfo>& targets) const |
3168 | 0 | { |
3169 | 0 | char const* rebuildCacheTargetName = this->GetRebuildCacheTargetName(); |
3170 | 0 | if (!rebuildCacheTargetName) { |
3171 | 0 | return; |
3172 | 0 | } |
3173 | 0 | GlobalTargetInfo gti; |
3174 | 0 | gti.Name = rebuildCacheTargetName; |
3175 | 0 | gti.Message = "Running CMake to regenerate build system..."; |
3176 | 0 | gti.UsesTerminal = true; |
3177 | 0 | gti.PerConfig = cmTarget::PerConfig::No; |
3178 | 0 | cmCustomCommandLine singleLine; |
3179 | 0 | singleLine.push_back(cmSystemTools::GetCMakeCommand()); |
3180 | 0 | singleLine.push_back("--regenerate-during-build"); |
3181 | 0 | if (this->GetCMakeInstance()->GetIgnoreCompileWarningAsError()) { |
3182 | 0 | singleLine.push_back("--compile-no-warning-as-error"); |
3183 | 0 | } |
3184 | 0 | if (this->GetCMakeInstance()->GetIgnoreLinkWarningAsError()) { |
3185 | 0 | singleLine.push_back("--link-no-warning-as-error"); |
3186 | 0 | } |
3187 | 0 | singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); |
3188 | 0 | singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); |
3189 | 0 | gti.CommandLines.push_back(std::move(singleLine)); |
3190 | 0 | gti.StdPipesUTF8 = true; |
3191 | 0 | targets.push_back(std::move(gti)); |
3192 | 0 | } |
3193 | | |
3194 | | void cmGlobalGenerator::AddGlobalTarget_Install( |
3195 | | std::vector<GlobalTargetInfo>& targets) |
3196 | 0 | { |
3197 | 0 | auto& mf = this->Makefiles[0]; |
3198 | 0 | char const* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); |
3199 | 0 | bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES"); |
3200 | 0 | if (this->InstallTargetEnabled && skipInstallRules) { |
3201 | 0 | this->CMakeInstance->IssueMessage( |
3202 | 0 | MessageType::WARNING, |
3203 | 0 | "CMAKE_SKIP_INSTALL_RULES was enabled even though " |
3204 | 0 | "installation rules have been specified", |
3205 | 0 | mf->GetBacktrace()); |
3206 | 0 | } else if (this->InstallTargetEnabled && !skipInstallRules) { |
3207 | 0 | if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) { |
3208 | 0 | std::set<std::string>* componentsSet = &this->InstallComponents; |
3209 | 0 | std::ostringstream ostr; |
3210 | 0 | if (!componentsSet->empty()) { |
3211 | 0 | ostr << "Available install components are: " |
3212 | 0 | << cmWrap('"', *componentsSet, '"', " "); |
3213 | 0 | } else { |
3214 | 0 | ostr << "Only default component available"; |
3215 | 0 | } |
3216 | 0 | GlobalTargetInfo gti; |
3217 | 0 | gti.Name = "list_install_components"; |
3218 | 0 | gti.Message = ostr.str(); |
3219 | 0 | gti.UsesTerminal = false; |
3220 | 0 | targets.push_back(std::move(gti)); |
3221 | 0 | } |
3222 | 0 | std::string cmd = cmSystemTools::GetCMakeCommand(); |
3223 | 0 | GlobalTargetInfo gti; |
3224 | 0 | gti.Name = this->GetInstallTargetName(); |
3225 | 0 | gti.Message = "Install the project..."; |
3226 | 0 | gti.UsesTerminal = true; |
3227 | 0 | gti.StdPipesUTF8 = true; |
3228 | 0 | gti.Role = "install"; |
3229 | 0 | cmCustomCommandLine singleLine; |
3230 | 0 | if (this->GetPreinstallTargetName()) { |
3231 | 0 | gti.Depends.emplace_back(this->GetPreinstallTargetName()); |
3232 | 0 | } else { |
3233 | 0 | cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY"); |
3234 | 0 | if (noall.IsOff()) { |
3235 | 0 | gti.Depends.emplace_back(this->GetAllTargetName()); |
3236 | 0 | } |
3237 | 0 | } |
3238 | 0 | if (mf->GetDefinition("CMake_BINARY_DIR") && |
3239 | 0 | !mf->IsOn("CMAKE_CROSSCOMPILING")) { |
3240 | | // We are building CMake itself. We cannot use the original |
3241 | | // executable to install over itself. The generator will |
3242 | | // automatically convert this name to the build-time location. |
3243 | 0 | cmd = "cmake"; |
3244 | 0 | } |
3245 | 0 | singleLine.push_back(cmd); |
3246 | 0 | if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { |
3247 | 0 | std::string cfgArg = "-DBUILD_TYPE="; |
3248 | 0 | bool useEPN = this->UseEffectivePlatformName(mf.get()); |
3249 | 0 | if (useEPN) { |
3250 | 0 | cfgArg += "$(CONFIGURATION)"; |
3251 | 0 | singleLine.push_back(cfgArg); |
3252 | 0 | cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)"; |
3253 | 0 | } else { |
3254 | 0 | cfgArg += this->GetCMakeCFGIntDir(); |
3255 | 0 | } |
3256 | 0 | singleLine.push_back(cfgArg); |
3257 | 0 | } |
3258 | 0 | singleLine.push_back("-P"); |
3259 | 0 | singleLine.push_back("cmake_install.cmake"); |
3260 | 0 | gti.CommandLines.push_back(singleLine); |
3261 | 0 | targets.push_back(gti); |
3262 | | |
3263 | | // install_local |
3264 | 0 | if (char const* install_local = this->GetInstallLocalTargetName()) { |
3265 | 0 | gti.Name = install_local; |
3266 | 0 | gti.Message = "Installing only the local directory..."; |
3267 | 0 | gti.Role = "install"; |
3268 | 0 | gti.UsesTerminal = |
3269 | 0 | !this->GetCMakeInstance()->GetState()->GetGlobalPropertyAsBool( |
3270 | 0 | "INSTALL_PARALLEL"); |
3271 | 0 | gti.CommandLines.clear(); |
3272 | |
|
3273 | 0 | cmCustomCommandLine localCmdLine = singleLine; |
3274 | |
|
3275 | 0 | localCmdLine.insert(localCmdLine.begin() + 1, |
3276 | 0 | "-DCMAKE_INSTALL_LOCAL_ONLY=1"); |
3277 | |
|
3278 | 0 | gti.CommandLines.push_back(std::move(localCmdLine)); |
3279 | 0 | targets.push_back(gti); |
3280 | 0 | } |
3281 | | |
3282 | | // install_strip |
3283 | 0 | char const* install_strip = this->GetInstallStripTargetName(); |
3284 | 0 | if (install_strip && mf->IsSet("CMAKE_STRIP")) { |
3285 | 0 | gti.Name = install_strip; |
3286 | 0 | gti.Message = "Installing the project stripped..."; |
3287 | 0 | gti.UsesTerminal = true; |
3288 | 0 | gti.Role = "install"; |
3289 | 0 | gti.CommandLines.clear(); |
3290 | |
|
3291 | 0 | cmCustomCommandLine stripCmdLine = singleLine; |
3292 | |
|
3293 | 0 | stripCmdLine.insert(stripCmdLine.begin() + 1, |
3294 | 0 | "-DCMAKE_INSTALL_DO_STRIP=1"); |
3295 | 0 | gti.CommandLines.push_back(std::move(stripCmdLine)); |
3296 | 0 | targets.push_back(gti); |
3297 | 0 | } |
3298 | 0 | } |
3299 | 0 | } |
3300 | | |
3301 | | class ModuleCompilationDatabaseCommandAction |
3302 | | { |
3303 | | public: |
3304 | | ModuleCompilationDatabaseCommandAction( |
3305 | | std::string output, std::function<std::vector<std::string>()> inputs) |
3306 | 0 | : Output(std::move(output)) |
3307 | 0 | , Inputs(std::move(inputs)) |
3308 | 0 | { |
3309 | 0 | } |
3310 | | void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
3311 | | std::unique_ptr<cmCustomCommand> cc); |
3312 | | |
3313 | | private: |
3314 | | std::string const Output; |
3315 | | std::function<std::vector<std::string>()> const Inputs; |
3316 | | }; |
3317 | | |
3318 | | void ModuleCompilationDatabaseCommandAction::operator()( |
3319 | | cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
3320 | | std::unique_ptr<cmCustomCommand> cc) |
3321 | 0 | { |
3322 | 0 | auto inputs = this->Inputs(); |
3323 | |
|
3324 | 0 | cmCustomCommandLines command_lines; |
3325 | 0 | cmCustomCommandLine command_line; |
3326 | 0 | { |
3327 | 0 | command_line.emplace_back(cmSystemTools::GetCMakeCommand()); |
3328 | 0 | command_line.emplace_back("-E"); |
3329 | 0 | command_line.emplace_back("cmake_module_compile_db"); |
3330 | 0 | command_line.emplace_back("merge"); |
3331 | 0 | command_line.emplace_back("-o"); |
3332 | 0 | command_line.emplace_back(this->Output); |
3333 | 0 | for (auto const& input : inputs) { |
3334 | 0 | command_line.emplace_back(input); |
3335 | 0 | } |
3336 | 0 | } |
3337 | 0 | command_lines.emplace_back(std::move(command_line)); |
3338 | |
|
3339 | 0 | cc->SetBacktrace(lfbt); |
3340 | 0 | cc->SetCommandLines(command_lines); |
3341 | 0 | cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str()); |
3342 | 0 | cc->SetDependsExplicitOnly(true); |
3343 | 0 | cc->SetOutputs(this->Output); |
3344 | 0 | if (!inputs.empty()) { |
3345 | 0 | cc->SetMainDependency(inputs[0]); |
3346 | 0 | } |
3347 | 0 | cc->SetDepends(inputs); |
3348 | 0 | detail::AddCustomCommandToOutput(lg, cmCommandOrigin::Generator, |
3349 | 0 | std::move(cc), false); |
3350 | 0 | } |
3351 | | |
3352 | | class ModuleCompilationDatabaseTargetAction |
3353 | | { |
3354 | | public: |
3355 | | ModuleCompilationDatabaseTargetAction(std::string output, cmTarget* target) |
3356 | 0 | : Output(std::move(output)) |
3357 | 0 | , Target(target) |
3358 | 0 | { |
3359 | 0 | } |
3360 | | void operator()(cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
3361 | | std::unique_ptr<cmCustomCommand> cc); |
3362 | | |
3363 | | private: |
3364 | | std::string const Output; |
3365 | | cmTarget* const Target; |
3366 | | }; |
3367 | | |
3368 | | void ModuleCompilationDatabaseTargetAction::operator()( |
3369 | | cmLocalGenerator& lg, cmListFileBacktrace const& lfbt, |
3370 | | std::unique_ptr<cmCustomCommand> cc) |
3371 | 0 | { |
3372 | 0 | cc->SetBacktrace(lfbt); |
3373 | 0 | cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str()); |
3374 | 0 | std::vector<std::string> target_inputs; |
3375 | 0 | target_inputs.emplace_back(this->Output); |
3376 | 0 | cc->SetDepends(target_inputs); |
3377 | 0 | detail::AddUtilityCommand(lg, cmCommandOrigin::Generator, this->Target, |
3378 | 0 | std::move(cc)); |
3379 | 0 | } |
3380 | | |
3381 | | void cmGlobalGenerator::AddBuildDatabaseFile(std::string const& lang, |
3382 | | std::string const& config, |
3383 | | std::string const& path) |
3384 | 0 | { |
3385 | 0 | if (!config.empty()) { |
3386 | 0 | this->PerConfigModuleDbs[config][lang].push_back(path); |
3387 | 0 | } |
3388 | 0 | this->PerLanguageModuleDbs[lang].push_back(path); |
3389 | 0 | } |
3390 | | |
3391 | | bool cmGlobalGenerator::AddBuildDatabaseTargets() |
3392 | 0 | { |
3393 | 0 | auto& mf = this->Makefiles[0]; |
3394 | 0 | if (!mf->IsOn("CMAKE_EXPORT_BUILD_DATABASE")) { |
3395 | 0 | return true; |
3396 | 0 | } |
3397 | 0 | if (!cmExperimental::HasSupportEnabled( |
3398 | 0 | *mf.get(), cmExperimental::Feature::ExportBuildDatabase)) { |
3399 | 0 | return {}; |
3400 | 0 | } |
3401 | | |
3402 | 0 | static auto const reservedTargets = { "cmake_build_database" }; |
3403 | 0 | for (auto const& target : reservedTargets) { |
3404 | 0 | if (!this->CheckReservedTargetName( |
3405 | 0 | target, "when exporting build databases are enabled")) { |
3406 | 0 | return false; |
3407 | 0 | } |
3408 | 0 | } |
3409 | 0 | static auto const reservedPrefixes = { "cmake_build_database-" }; |
3410 | 0 | for (auto const& prefix : reservedPrefixes) { |
3411 | 0 | if (!this->CheckReservedTargetNamePrefix( |
3412 | 0 | prefix, "when exporting build databases are enabled")) { |
3413 | 0 | return false; |
3414 | 0 | } |
3415 | 0 | } |
3416 | | |
3417 | 0 | if (!this->SupportsBuildDatabase()) { |
3418 | 0 | return true; |
3419 | 0 | } |
3420 | | |
3421 | 0 | auto configs = mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); |
3422 | |
|
3423 | 0 | static cm::static_string_view TargetPrefix = "cmake_build_database"_s; |
3424 | 0 | auto AddMergeTarget = |
3425 | 0 | [&mf](std::string const& name, char const* comment, |
3426 | 0 | std::string const& output, |
3427 | 0 | std::function<std::vector<std::string>()> inputs) { |
3428 | | // Add the custom command. |
3429 | 0 | { |
3430 | 0 | ModuleCompilationDatabaseCommandAction action{ output, |
3431 | 0 | std::move(inputs) }; |
3432 | 0 | auto cc = cm::make_unique<cmCustomCommand>(); |
3433 | 0 | cc->SetComment(comment); |
3434 | 0 | mf->AddGeneratorAction( |
3435 | 0 | std::move(cc), action, |
3436 | 0 | cmMakefile::GeneratorActionWhen::AfterGeneratorTargets); |
3437 | 0 | } |
3438 | | |
3439 | | // Add a custom target with the given name. |
3440 | 0 | { |
3441 | 0 | cmTarget* target = mf->AddNewUtilityTarget(name, true); |
3442 | 0 | ModuleCompilationDatabaseTargetAction action{ output, target }; |
3443 | 0 | auto cc = cm::make_unique<cmCustomCommand>(); |
3444 | 0 | mf->AddGeneratorAction(std::move(cc), action); |
3445 | 0 | } |
3446 | 0 | }; |
3447 | |
|
3448 | 0 | std::string module_languages[] = { "CXX" }; |
3449 | | |
3450 | | // Add per-configuration targets. |
3451 | 0 | for (auto const& config : configs) { |
3452 | | // Add per-language targets. |
3453 | 0 | std::vector<std::string> all_config_paths; |
3454 | 0 | for (auto const& lang : module_languages) { |
3455 | 0 | auto comment = cmStrCat("Combining module command databases for ", lang, |
3456 | 0 | " and ", config); |
3457 | 0 | auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_", |
3458 | 0 | lang, '_', config, ".json"); |
3459 | 0 | mf->GetOrCreateGeneratedSource(output); |
3460 | 0 | AddMergeTarget(cmStrCat(TargetPrefix, '-', lang, '-', config), |
3461 | 0 | comment.c_str(), output, [this, config, lang]() { |
3462 | 0 | return this->PerConfigModuleDbs[config][lang]; |
3463 | 0 | }); |
3464 | 0 | all_config_paths.emplace_back(std::move(output)); |
3465 | 0 | } |
3466 | | |
3467 | | // Add the overall target. |
3468 | 0 | auto comment = cmStrCat("Combining module command databases for ", config); |
3469 | 0 | auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_", |
3470 | 0 | config, ".json"); |
3471 | 0 | mf->GetOrCreateGeneratedSource(output); |
3472 | 0 | AddMergeTarget(cmStrCat(TargetPrefix, '-', config), comment.c_str(), |
3473 | 0 | output, [all_config_paths]() { return all_config_paths; }); |
3474 | 0 | } |
3475 | | |
3476 | | // NMC considerations |
3477 | | // Add per-language targets. |
3478 | 0 | std::vector<std::string> all_config_paths; |
3479 | 0 | for (auto const& lang : module_languages) { |
3480 | 0 | auto comment = cmStrCat("Combining module command databases for ", lang); |
3481 | 0 | auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_", |
3482 | 0 | lang, ".json"); |
3483 | 0 | mf->GetOrCreateGeneratedSource(output); |
3484 | 0 | AddMergeTarget( |
3485 | 0 | cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output, |
3486 | 0 | [this, lang]() { return this->PerLanguageModuleDbs[lang]; }); |
3487 | 0 | all_config_paths.emplace_back(std::move(output)); |
3488 | 0 | } |
3489 | | |
3490 | | // Add the overall target. |
3491 | 0 | auto const* comment = "Combining all module command databases"; |
3492 | 0 | auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json"); |
3493 | 0 | mf->GetOrCreateGeneratedSource(output); |
3494 | 0 | AddMergeTarget(std::string(TargetPrefix), comment, output, |
3495 | 0 | [all_config_paths]() { return all_config_paths; }); |
3496 | |
|
3497 | 0 | return true; |
3498 | 0 | } |
3499 | | |
3500 | | std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const |
3501 | 0 | { |
3502 | 0 | cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty( |
3503 | 0 | "PREDEFINED_TARGETS_FOLDER"); |
3504 | |
|
3505 | 0 | if (prop) { |
3506 | 0 | return *prop; |
3507 | 0 | } |
3508 | | |
3509 | 0 | return "CMakePredefinedTargets"; |
3510 | 0 | } |
3511 | | |
3512 | | bool cmGlobalGenerator::UseFolderProperty() const |
3513 | 0 | { |
3514 | 0 | cmValue const prop = |
3515 | 0 | this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS"); |
3516 | | |
3517 | | // If this property is defined, let the setter turn this on or off. |
3518 | 0 | if (prop) { |
3519 | 0 | return prop.IsOn(); |
3520 | 0 | } |
3521 | | |
3522 | | // If CMP0143 is NEW `treat` "USE_FOLDERS" as ON. Otherwise `treat` it as OFF |
3523 | 0 | assert(!this->Makefiles.empty()); |
3524 | 0 | return (this->Makefiles[0]->GetPolicyStatus(cmPolicies::CMP0143) == |
3525 | 0 | cmPolicies::NEW); |
3526 | 0 | } |
3527 | | |
3528 | | void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, |
3529 | | cmMakefile* mf) |
3530 | 0 | { |
3531 | | // Package |
3532 | 0 | auto tb = |
3533 | 0 | mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig); |
3534 | | |
3535 | | // Do nothing if gti.Name is already used |
3536 | 0 | if (!tb.second) { |
3537 | 0 | return; |
3538 | 0 | } |
3539 | | |
3540 | 0 | cmTarget& target = tb.first; |
3541 | 0 | target.SetProperty("EXCLUDE_FROM_ALL", "TRUE"); |
3542 | | |
3543 | | // Store the custom command in the target. |
3544 | 0 | cmCustomCommand cc; |
3545 | 0 | cc.SetCommandLines(gti.CommandLines); |
3546 | 0 | cc.SetWorkingDirectory(gti.WorkingDir.c_str()); |
3547 | 0 | cc.SetStdPipesUTF8(gti.StdPipesUTF8); |
3548 | 0 | cc.SetUsesTerminal(gti.UsesTerminal); |
3549 | 0 | cc.SetRole(gti.Role); |
3550 | 0 | target.AddPostBuildCommand(std::move(cc)); |
3551 | 0 | if (!gti.Message.empty()) { |
3552 | 0 | target.SetProperty("EchoString", gti.Message); |
3553 | 0 | } |
3554 | 0 | for (std::string const& d : gti.Depends) { |
3555 | 0 | target.AddUtility(d, false); |
3556 | 0 | } |
3557 | | |
3558 | | // Organize in the "predefined targets" folder: |
3559 | | // |
3560 | 0 | if (this->UseFolderProperty()) { |
3561 | 0 | target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder()); |
3562 | 0 | } |
3563 | 0 | } |
3564 | | |
3565 | | std::string cmGlobalGenerator::GenerateRuleFile( |
3566 | | std::string const& output) const |
3567 | 0 | { |
3568 | 0 | std::string ruleFile = cmStrCat(output, ".rule"); |
3569 | 0 | char const* dir = this->GetCMakeCFGIntDir(); |
3570 | 0 | if (dir && dir[0] == '$') { |
3571 | 0 | cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles"); |
3572 | 0 | } |
3573 | 0 | return ruleFile; |
3574 | 0 | } |
3575 | | |
3576 | | bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const |
3577 | 0 | { |
3578 | 0 | return mf->PlatformIsAppleEmbedded(); |
3579 | 0 | } |
3580 | | |
3581 | | void cmGlobalGenerator::AppendDirectoryForConfig(std::string const& /*unused*/, |
3582 | | std::string const& /*unused*/, |
3583 | | std::string const& /*unused*/, |
3584 | | std::string& /*unused*/) |
3585 | 0 | { |
3586 | | // Subclasses that support multiple configurations should implement |
3587 | | // this method to append the subdirectory for the given build |
3588 | | // configuration. |
3589 | 0 | } |
3590 | | |
3591 | | cmValue cmGlobalGenerator::GetDebuggerWorkingDirectory( |
3592 | | cmGeneratorTarget* gt) const |
3593 | 0 | { |
3594 | 0 | return gt->GetProperty("DEBUGGER_WORKING_DIRECTORY"); |
3595 | 0 | } |
3596 | | |
3597 | | cmGlobalGenerator::TargetDependSet const& |
3598 | | cmGlobalGenerator::GetTargetDirectDepends( |
3599 | | cmGeneratorTarget const* target) const |
3600 | 0 | { |
3601 | 0 | auto i = this->TargetDependencies.find(target); |
3602 | 0 | assert(i != this->TargetDependencies.end()); |
3603 | 0 | return i->second; |
3604 | 0 | } |
3605 | | |
3606 | | bool cmGlobalGenerator::TargetOrderIndexLess(cmGeneratorTarget const* l, |
3607 | | cmGeneratorTarget const* r) const |
3608 | 0 | { |
3609 | 0 | return this->TargetOrderIndex.at(l) < this->TargetOrderIndex.at(r); |
3610 | 0 | } |
3611 | | |
3612 | | bool cmGlobalGenerator::IsReservedTarget(std::string const& name) |
3613 | 0 | { |
3614 | | // The following is a list of targets reserved |
3615 | | // by one or more of the cmake generators. |
3616 | | |
3617 | | // Adding additional targets to this list will require a policy! |
3618 | 0 | static cm::static_string_view const reservedTargets[] = { |
3619 | 0 | "all"_s, "ALL_BUILD"_s, "help"_s, "install"_s, |
3620 | 0 | "INSTALL"_s, "preinstall"_s, "clean"_s, "edit_cache"_s, |
3621 | 0 | "rebuild_cache"_s, "ZERO_CHECK"_s |
3622 | 0 | }; |
3623 | |
|
3624 | 0 | return cm::contains(reservedTargets, name); |
3625 | 0 | } |
3626 | | |
3627 | | void cmGlobalGenerator::SetExternalMakefileProjectGenerator( |
3628 | | std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator) |
3629 | 0 | { |
3630 | 0 | this->ExtraGenerator = std::move(extraGenerator); |
3631 | 0 | if (this->ExtraGenerator) { |
3632 | 0 | this->ExtraGenerator->SetGlobalGenerator(this); |
3633 | 0 | } |
3634 | 0 | } |
3635 | | |
3636 | | std::string cmGlobalGenerator::GetExtraGeneratorName() const |
3637 | 0 | { |
3638 | 0 | return this->ExtraGenerator ? this->ExtraGenerator->GetName() |
3639 | 0 | : std::string(); |
3640 | 0 | } |
3641 | | |
3642 | | void cmGlobalGenerator::FileReplacedDuringGenerate(std::string const& filename) |
3643 | 0 | { |
3644 | 0 | this->FilesReplacedDuringGenerate.push_back(filename); |
3645 | 0 | } |
3646 | | |
3647 | | void cmGlobalGenerator::GetFilesReplacedDuringGenerate( |
3648 | | std::vector<std::string>& filenames) |
3649 | 0 | { |
3650 | 0 | filenames.clear(); |
3651 | 0 | std::copy(this->FilesReplacedDuringGenerate.begin(), |
3652 | 0 | this->FilesReplacedDuringGenerate.end(), |
3653 | 0 | std::back_inserter(filenames)); |
3654 | 0 | } |
3655 | | |
3656 | | cmGlobalGenerator::TargetDependSet cmGlobalGenerator::GetTargetsForProject( |
3657 | | cmLocalGenerator const* root, |
3658 | | std::vector<cmLocalGenerator*> const& generators) const |
3659 | 0 | { |
3660 | 0 | TargetDependSet projectTargets; |
3661 | | // loop over all local generators |
3662 | 0 | for (auto* generator : generators) { |
3663 | | // check to make sure generator is not excluded |
3664 | 0 | if (this->IsExcluded(root, generator)) { |
3665 | 0 | continue; |
3666 | 0 | } |
3667 | | // loop over all the generator targets in the makefile |
3668 | 0 | for (auto const& target : generator->GetGeneratorTargets()) { |
3669 | 0 | if (this->IsRootOnlyTarget(target.get()) && |
3670 | 0 | target->GetLocalGenerator() != root) { |
3671 | 0 | continue; |
3672 | 0 | } |
3673 | | // Get the set of targets that depend on target |
3674 | 0 | this->AddTargetDepends(target.get(), projectTargets); |
3675 | 0 | } |
3676 | 0 | } |
3677 | 0 | return projectTargets; |
3678 | 0 | } |
3679 | | |
3680 | | bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const |
3681 | 0 | { |
3682 | 0 | return (target->GetType() == cmStateEnums::GLOBAL_TARGET || |
3683 | 0 | target->GetName() == this->GetAllTargetName()); |
3684 | 0 | } |
3685 | | |
3686 | | void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target, |
3687 | | TargetDependSet& projectTargets) const |
3688 | 0 | { |
3689 | | // add the target itself |
3690 | 0 | if (projectTargets.insert(target).second) { |
3691 | | // This is the first time we have encountered the target. |
3692 | | // Recursively follow its dependencies. |
3693 | 0 | for (auto const& t : this->GetTargetDirectDepends(target)) { |
3694 | 0 | this->AddTargetDepends(t, projectTargets); |
3695 | 0 | } |
3696 | 0 | } |
3697 | 0 | } |
3698 | | |
3699 | | void cmGlobalGenerator::AddToManifest(std::string const& f) |
3700 | 0 | { |
3701 | | // Add to the content listing for the file's directory. |
3702 | 0 | std::string dir = cmSystemTools::GetFilenamePath(f); |
3703 | 0 | std::string file = cmSystemTools::GetFilenameName(f); |
3704 | 0 | DirectoryContent& dc = this->DirectoryContentMap[dir]; |
3705 | 0 | dc.Generated.insert(file); |
3706 | 0 | dc.All.insert(file); |
3707 | 0 | } |
3708 | | |
3709 | | std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent( |
3710 | | std::string const& dir, bool needDisk) |
3711 | 0 | { |
3712 | 0 | DirectoryContent& dc = this->DirectoryContentMap[dir]; |
3713 | 0 | if (needDisk) { |
3714 | 0 | long mt = cmSystemTools::ModifiedTime(dir); |
3715 | 0 | if (mt != dc.LastDiskTime) { |
3716 | | // Reset to non-loaded directory content. |
3717 | 0 | dc.All = dc.Generated; |
3718 | | |
3719 | | // Load the directory content from disk. |
3720 | 0 | cmsys::Directory d; |
3721 | 0 | if (d.Load(dir)) { |
3722 | 0 | unsigned long n = d.GetNumberOfFiles(); |
3723 | 0 | for (unsigned long i = 0; i < n; ++i) { |
3724 | 0 | std::string const& f = d.GetFileName(i); |
3725 | 0 | if (f != "." && f != "..") { |
3726 | 0 | dc.All.insert(f); |
3727 | 0 | } |
3728 | 0 | } |
3729 | 0 | } |
3730 | 0 | dc.LastDiskTime = mt; |
3731 | 0 | } |
3732 | 0 | } |
3733 | 0 | return dc.All; |
3734 | 0 | } |
3735 | | |
3736 | | void cmGlobalGenerator::AddRuleHash(std::vector<std::string> const& outputs, |
3737 | | std::string const& content) |
3738 | 0 | { |
3739 | | // Ignore if there are no outputs. |
3740 | 0 | if (outputs.empty()) { |
3741 | 0 | return; |
3742 | 0 | } |
3743 | | |
3744 | | // Compute a hash of the rule. |
3745 | 0 | RuleHash hash; |
3746 | 0 | { |
3747 | 0 | cmCryptoHash md5(cmCryptoHash::AlgoMD5); |
3748 | 0 | std::string const md5_hex = md5.HashString(content); |
3749 | 0 | memcpy(hash.Data, md5_hex.c_str(), 32); |
3750 | 0 | } |
3751 | | |
3752 | | // Shorten the output name (in expected use case). |
3753 | 0 | std::string fname = |
3754 | 0 | this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]); |
3755 | | |
3756 | | // Associate the hash with this output. |
3757 | 0 | this->RuleHashes[fname] = hash; |
3758 | 0 | } |
3759 | | |
3760 | | void cmGlobalGenerator::CheckRuleHashes() |
3761 | 0 | { |
3762 | 0 | std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory(); |
3763 | 0 | std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt"); |
3764 | 0 | this->CheckRuleHashes(pfile, home); |
3765 | 0 | this->WriteRuleHashes(pfile); |
3766 | 0 | } |
3767 | | |
3768 | | void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile, |
3769 | | std::string const& home) |
3770 | 0 | { |
3771 | | #if defined(_WIN32) || defined(__CYGWIN__) |
3772 | | cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary); |
3773 | | #else |
3774 | 0 | cmsys::ifstream fin(pfile.c_str()); |
3775 | 0 | #endif |
3776 | 0 | if (!fin) { |
3777 | 0 | return; |
3778 | 0 | } |
3779 | 0 | std::string line; |
3780 | 0 | std::string fname; |
3781 | 0 | while (cmSystemTools::GetLineFromStream(fin, line)) { |
3782 | | // Line format is a 32-byte hex string followed by a space |
3783 | | // followed by a file name (with no escaping). |
3784 | | |
3785 | | // Skip blank and comment lines. |
3786 | 0 | if (line.size() < 34 || line[0] == '#') { |
3787 | 0 | continue; |
3788 | 0 | } |
3789 | | |
3790 | | // Get the filename. |
3791 | 0 | fname = line.substr(33); |
3792 | | |
3793 | | // Look for a hash for this file's rule. |
3794 | 0 | auto const rhi = this->RuleHashes.find(fname); |
3795 | 0 | if (rhi != this->RuleHashes.end()) { |
3796 | | // Compare the rule hash in the file to that we were given. |
3797 | 0 | if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) { |
3798 | | // The rule has changed. Delete the output so it will be |
3799 | | // built again. |
3800 | 0 | fname = cmSystemTools::CollapseFullPath(fname, home); |
3801 | 0 | cmSystemTools::RemoveFile(fname); |
3802 | 0 | } |
3803 | 0 | } else { |
3804 | | // We have no hash for a rule previously listed. This may be a |
3805 | | // case where a user has turned off a build option and might |
3806 | | // want to turn it back on later, so do not delete the file. |
3807 | | // Instead, we keep the rule hash as long as the file exists so |
3808 | | // that if the feature is turned back on and the rule has |
3809 | | // changed the file is still rebuilt. |
3810 | 0 | std::string fpath = cmSystemTools::CollapseFullPath(fname, home); |
3811 | 0 | if (cmSystemTools::FileExists(fpath)) { |
3812 | 0 | RuleHash hash; |
3813 | 0 | memcpy(hash.Data, line.c_str(), 32); |
3814 | 0 | this->RuleHashes[fname] = hash; |
3815 | 0 | } |
3816 | 0 | } |
3817 | 0 | } |
3818 | 0 | } |
3819 | | |
3820 | | void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile) |
3821 | 0 | { |
3822 | | // Now generate a new persistence file with the current hashes. |
3823 | 0 | if (this->RuleHashes.empty()) { |
3824 | 0 | cmSystemTools::RemoveFile(pfile); |
3825 | 0 | } else { |
3826 | 0 | cmGeneratedFileStream fout(pfile); |
3827 | 0 | fout << "# Hashes of file build rules.\n"; |
3828 | 0 | for (auto const& rh : this->RuleHashes) { |
3829 | 0 | fout.write(rh.second.Data, 32); |
3830 | 0 | fout << ' ' << rh.first << '\n'; |
3831 | 0 | } |
3832 | 0 | } |
3833 | 0 | } |
3834 | | |
3835 | | void cmGlobalGenerator::WriteSummary() |
3836 | 0 | { |
3837 | | // Record all target directories in a central location. |
3838 | 0 | std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), |
3839 | 0 | "/CMakeFiles/TargetDirectories.txt"); |
3840 | 0 | cmGeneratedFileStream fout(fname); |
3841 | |
|
3842 | 0 | for (auto const& lg : this->LocalGenerators) { |
3843 | 0 | for (auto const& tgt : lg->GetGeneratorTargets()) { |
3844 | 0 | if (!tgt->IsInBuildSystem()) { |
3845 | 0 | continue; |
3846 | 0 | } |
3847 | 0 | this->WriteSummary(tgt.get()); |
3848 | 0 | fout << tgt->GetCMFSupportDirectory() << '\n'; |
3849 | 0 | } |
3850 | 0 | } |
3851 | 0 | } |
3852 | | |
3853 | | void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) |
3854 | 0 | { |
3855 | | // Place the labels file in a per-target support directory. |
3856 | 0 | std::string dir = target->GetCMFSupportDirectory(); |
3857 | 0 | std::string file = cmStrCat(dir, "/Labels.txt"); |
3858 | 0 | std::string json_file = cmStrCat(dir, "/Labels.json"); |
3859 | |
|
3860 | 0 | #ifndef CMAKE_BOOTSTRAP |
3861 | | // Check whether labels are enabled for this target. |
3862 | 0 | cmValue targetLabels = target->GetProperty("LABELS"); |
3863 | 0 | cmValue directoryLabels = |
3864 | 0 | target->Target->GetMakefile()->GetProperty("LABELS"); |
3865 | 0 | cmValue cmakeDirectoryLabels = |
3866 | 0 | target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS"); |
3867 | 0 | if (targetLabels || directoryLabels || cmakeDirectoryLabels) { |
3868 | 0 | Json::Value lj_root(Json::objectValue); |
3869 | 0 | Json::Value& lj_target = lj_root["target"] = Json::objectValue; |
3870 | 0 | lj_target["name"] = target->GetName(); |
3871 | 0 | Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue; |
3872 | 0 | Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue; |
3873 | |
|
3874 | 0 | cmSystemTools::MakeDirectory(dir); |
3875 | 0 | cmGeneratedFileStream fout(file); |
3876 | |
|
3877 | 0 | cmList labels; |
3878 | | |
3879 | | // List the target-wide labels. All sources in the target get |
3880 | | // these labels. |
3881 | 0 | if (targetLabels) { |
3882 | 0 | labels.assign(*targetLabels); |
3883 | 0 | if (!labels.empty()) { |
3884 | 0 | fout << "# Target labels\n"; |
3885 | 0 | for (std::string const& l : labels) { |
3886 | 0 | fout << ' ' << l << '\n'; |
3887 | 0 | lj_target_labels.append(l); |
3888 | 0 | } |
3889 | 0 | } |
3890 | 0 | } |
3891 | | |
3892 | | // List directory labels |
3893 | 0 | cmList directoryLabelsList; |
3894 | 0 | cmList cmakeDirectoryLabelsList; |
3895 | |
|
3896 | 0 | if (directoryLabels) { |
3897 | 0 | directoryLabelsList.assign(*directoryLabels); |
3898 | 0 | } |
3899 | |
|
3900 | 0 | if (cmakeDirectoryLabels) { |
3901 | 0 | cmakeDirectoryLabelsList.assign(*cmakeDirectoryLabels); |
3902 | 0 | } |
3903 | |
|
3904 | 0 | if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) { |
3905 | 0 | fout << "# Directory labels\n"; |
3906 | 0 | } |
3907 | |
|
3908 | 0 | for (auto const& li : directoryLabelsList) { |
3909 | 0 | fout << ' ' << li << '\n'; |
3910 | 0 | lj_target_labels.append(li); |
3911 | 0 | } |
3912 | |
|
3913 | 0 | for (auto const& li : cmakeDirectoryLabelsList) { |
3914 | 0 | fout << ' ' << li << '\n'; |
3915 | 0 | lj_target_labels.append(li); |
3916 | 0 | } |
3917 | | |
3918 | | // List the source files with any per-source labels. |
3919 | 0 | fout << "# Source files and their labels\n"; |
3920 | 0 | std::vector<cmSourceFile*> sources; |
3921 | 0 | std::vector<std::string> const& configs = |
3922 | 0 | target->Target->GetMakefile()->GetGeneratorConfigs( |
3923 | 0 | cmMakefile::IncludeEmptyConfig); |
3924 | 0 | for (std::string const& c : configs) { |
3925 | 0 | target->GetSourceFiles(sources, c); |
3926 | 0 | } |
3927 | 0 | auto const sourcesEnd = cmRemoveDuplicates(sources); |
3928 | 0 | for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) { |
3929 | 0 | Json::Value& lj_source = lj_sources.append(Json::objectValue); |
3930 | 0 | std::string const& sfp = sf->ResolveFullPath(); |
3931 | 0 | fout << sfp << '\n'; |
3932 | 0 | lj_source["file"] = sfp; |
3933 | 0 | if (cmValue svalue = sf->GetProperty("LABELS")) { |
3934 | 0 | Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue; |
3935 | 0 | labels.assign(*svalue); |
3936 | 0 | for (auto const& label : labels) { |
3937 | 0 | fout << ' ' << label << '\n'; |
3938 | 0 | lj_source_labels.append(label); |
3939 | 0 | } |
3940 | 0 | } |
3941 | 0 | } |
3942 | 0 | cmGeneratedFileStream json_fout(json_file); |
3943 | 0 | json_fout << lj_root; |
3944 | 0 | } else |
3945 | 0 | #endif |
3946 | 0 | { |
3947 | 0 | cmSystemTools::RemoveFile(file); |
3948 | 0 | cmSystemTools::RemoveFile(json_file); |
3949 | 0 | } |
3950 | 0 | } |
3951 | | |
3952 | | // static |
3953 | | std::string cmGlobalGenerator::EscapeJSON(std::string const& s) |
3954 | 0 | { |
3955 | 0 | std::string result; |
3956 | 0 | result.reserve(s.size()); |
3957 | 0 | for (char i : s) { |
3958 | 0 | switch (i) { |
3959 | 0 | case '"': |
3960 | 0 | case '\\': |
3961 | 0 | result += '\\'; |
3962 | 0 | result += i; |
3963 | 0 | break; |
3964 | 0 | case '\n': |
3965 | 0 | result += "\\n"; |
3966 | 0 | break; |
3967 | 0 | case '\t': |
3968 | 0 | result += "\\t"; |
3969 | 0 | break; |
3970 | 0 | default: |
3971 | 0 | result += i; |
3972 | 0 | } |
3973 | 0 | } |
3974 | 0 | return result; |
3975 | 0 | } |
3976 | | |
3977 | | void cmGlobalGenerator::SetFilenameTargetDepends( |
3978 | | cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts) |
3979 | 0 | { |
3980 | 0 | this->FilenameTargetDepends[sf] = tgts; |
3981 | 0 | } |
3982 | | |
3983 | | std::set<cmGeneratorTarget const*> const& |
3984 | | cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const |
3985 | 0 | { |
3986 | 0 | return this->FilenameTargetDepends[sf]; |
3987 | 0 | } |
3988 | | |
3989 | | std::string const& cmGlobalGenerator::GetRealPath(std::string const& dir) |
3990 | 0 | { |
3991 | 0 | auto i = this->RealPaths.lower_bound(dir); |
3992 | 0 | if (i == this->RealPaths.end() || |
3993 | 0 | this->RealPaths.key_comp()(dir, i->first)) { |
3994 | 0 | i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir)); |
3995 | 0 | } |
3996 | 0 | return i->second; |
3997 | 0 | } |
3998 | | |
3999 | | std::string cmGlobalGenerator::NewDeferId() |
4000 | 0 | { |
4001 | 0 | return cmStrCat("__", this->NextDeferId++); |
4002 | 0 | } |
4003 | | |
4004 | | void cmGlobalGenerator::ProcessEvaluationFiles() |
4005 | 0 | { |
4006 | 0 | std::vector<std::string> generatedFiles; |
4007 | 0 | for (auto& localGen : this->LocalGenerators) { |
4008 | 0 | localGen->ProcessEvaluationFiles(generatedFiles); |
4009 | 0 | } |
4010 | 0 | } |
4011 | | |
4012 | | std::string cmGlobalGenerator::ExpandCFGIntDir( |
4013 | | std::string const& str, std::string const& /*config*/) const |
4014 | 0 | { |
4015 | 0 | return str; |
4016 | 0 | } |
4017 | | |
4018 | | bool cmGlobalGenerator::GenerateCPackPropertiesFile() |
4019 | 0 | { |
4020 | 0 | cmake::InstalledFilesMap const& installedFiles = |
4021 | 0 | this->CMakeInstance->GetInstalledFiles(); |
4022 | |
|
4023 | 0 | auto const& lg = this->LocalGenerators[0]; |
4024 | 0 | cmMakefile* mf = lg->GetMakefile(); |
4025 | |
|
4026 | 0 | std::vector<std::string> configs = |
4027 | 0 | mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); |
4028 | 0 | std::string config = mf->GetDefaultConfiguration(); |
4029 | |
|
4030 | 0 | std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), |
4031 | 0 | "/CPackProperties.cmake"); |
4032 | |
|
4033 | 0 | if (!cmSystemTools::FileExists(path) && installedFiles.empty()) { |
4034 | 0 | return true; |
4035 | 0 | } |
4036 | | |
4037 | 0 | cmGeneratedFileStream file(path); |
4038 | 0 | file << "# CPack properties\n"; |
4039 | |
|
4040 | 0 | for (auto const& i : installedFiles) { |
4041 | 0 | cmInstalledFile const& installedFile = i.second; |
4042 | |
|
4043 | 0 | cmCPackPropertiesGenerator cpackPropertiesGenerator( |
4044 | 0 | lg.get(), installedFile, configs); |
4045 | |
|
4046 | 0 | cpackPropertiesGenerator.Generate(file, config, configs); |
4047 | 0 | } |
4048 | |
|
4049 | 0 | return true; |
4050 | 0 | } |
4051 | | |
4052 | | cmInstallRuntimeDependencySet* |
4053 | | cmGlobalGenerator::CreateAnonymousRuntimeDependencySet() |
4054 | 0 | { |
4055 | 0 | auto set = cm::make_unique<cmInstallRuntimeDependencySet>(); |
4056 | 0 | auto* retval = set.get(); |
4057 | 0 | this->RuntimeDependencySets.push_back(std::move(set)); |
4058 | 0 | return retval; |
4059 | 0 | } |
4060 | | |
4061 | | cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet( |
4062 | | std::string const& name) |
4063 | 0 | { |
4064 | 0 | auto it = this->RuntimeDependencySetsByName.find(name); |
4065 | 0 | if (it == this->RuntimeDependencySetsByName.end()) { |
4066 | 0 | auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name); |
4067 | 0 | it = |
4068 | 0 | this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get())) |
4069 | 0 | .first; |
4070 | 0 | this->RuntimeDependencySets.push_back(std::move(set)); |
4071 | 0 | } |
4072 | 0 | return it->second; |
4073 | 0 | } |
4074 | | |
4075 | | cmGlobalGenerator::StripCommandStyle cmGlobalGenerator::GetStripCommandStyle( |
4076 | | std::string const& strip) |
4077 | 0 | { |
4078 | | #ifdef __APPLE__ |
4079 | | auto i = this->StripCommandStyleMap.find(strip); |
4080 | | if (i == this->StripCommandStyleMap.end()) { |
4081 | | StripCommandStyle style = StripCommandStyle::Default; |
4082 | | |
4083 | | // Try running strip tool with Apple-specific options. |
4084 | | std::vector<std::string> cmd{ strip, "-u", "-r" }; |
4085 | | std::string out; |
4086 | | std::string err; |
4087 | | int ret; |
4088 | | if (cmSystemTools::RunSingleCommand(cmd, &out, &err, &ret, nullptr, |
4089 | | cmSystemTools::OUTPUT_NONE) && |
4090 | | // Check for Apple-specific output. |
4091 | | ret != 0 && cmHasLiteralPrefix(err, "fatal error: /") && |
4092 | | err.find("/usr/bin/strip: no files specified") != std::string::npos) { |
4093 | | style = StripCommandStyle::Apple; |
4094 | | } |
4095 | | i = this->StripCommandStyleMap.emplace(strip, style).first; |
4096 | | } |
4097 | | return i->second; |
4098 | | #else |
4099 | 0 | static_cast<void>(strip); |
4100 | 0 | return StripCommandStyle::Default; |
4101 | 0 | #endif |
4102 | 0 | } |
4103 | | |
4104 | | std::string cmGlobalGenerator::GetEncodedLiteral(std::string const& lit) |
4105 | 0 | { |
4106 | 0 | std::string result = lit; |
4107 | 0 | return this->EncodeLiteral(result); |
4108 | 0 | } |
4109 | | |
4110 | | void cmGlobalGenerator::AddInstallScript(std::string const& file) |
4111 | 0 | { |
4112 | 0 | this->InstallScripts.push_back(file); |
4113 | 0 | } |
4114 | | |
4115 | | void cmGlobalGenerator::AddTestFile(std::string const& file) |
4116 | 0 | { |
4117 | 0 | this->TestFiles.push_back(file); |
4118 | 0 | } |
4119 | | |
4120 | | void cmGlobalGenerator::AddCMakeFilesToRebuild( |
4121 | | std::vector<std::string>& files) const |
4122 | 0 | { |
4123 | 0 | files.insert(files.end(), this->InstallScripts.begin(), |
4124 | 0 | this->InstallScripts.end()); |
4125 | 0 | files.insert(files.end(), this->TestFiles.begin(), this->TestFiles.end()); |
4126 | 0 | } |
4127 | | |
4128 | | bool cmGlobalGenerator::ShouldWarnExperimental(cm::string_view featureName, |
4129 | | cm::string_view featureUuid) |
4130 | 0 | { |
4131 | 0 | return this->WarnedExperimental |
4132 | 0 | .emplace(cmStrCat(featureName, '-', featureUuid)) |
4133 | 0 | .second; |
4134 | 0 | } |
4135 | | |
4136 | | cm::optional<cmXcFrameworkPlist> cmGlobalGenerator::GetXcFrameworkPListContent( |
4137 | | std::string const& path) const |
4138 | 0 | { |
4139 | 0 | cm::optional<cmXcFrameworkPlist> result; |
4140 | 0 | auto i = this->XcFrameworkPListContentMap.find(path); |
4141 | 0 | if (i != this->XcFrameworkPListContentMap.end()) { |
4142 | 0 | result = i->second; |
4143 | 0 | } |
4144 | 0 | return result; |
4145 | 0 | } |
4146 | | |
4147 | | void cmGlobalGenerator::SetXcFrameworkPListContent( |
4148 | | std::string const& path, cmXcFrameworkPlist const& content) |
4149 | 0 | { |
4150 | 0 | this->XcFrameworkPListContentMap.emplace(path, content); |
4151 | 0 | } |