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