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