1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt 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 <cmext/algorithm>
18 #include <cmext/string_view>
19 
20 #include "cmsys/Directory.hxx"
21 #include "cmsys/FStream.hxx"
22 
23 #if defined(_WIN32) && !defined(__CYGWIN__)
24 #  include <windows.h>
25 #endif
26 
27 #include "cmAlgorithms.h"
28 #include "cmCPackPropertiesGenerator.h"
29 #include "cmComputeTargetDepends.h"
30 #include "cmCustomCommand.h"
31 #include "cmCustomCommandLines.h"
32 #include "cmDuration.h"
33 #include "cmExportBuildFileGenerator.h"
34 #include "cmExternalMakefileProjectGenerator.h"
35 #include "cmGeneratedFileStream.h"
36 #include "cmGeneratorExpression.h"
37 #include "cmGeneratorTarget.h"
38 #include "cmInstallGenerator.h"
39 #include "cmInstallRuntimeDependencySet.h"
40 #include "cmLinkLineComputer.h"
41 #include "cmListFileCache.h"
42 #include "cmLocalGenerator.h"
43 #include "cmMSVC60LinkLineComputer.h"
44 #include "cmMakefile.h"
45 #include "cmMessageType.h"
46 #include "cmPolicies.h"
47 #include "cmRange.h"
48 #include "cmSourceFile.h"
49 #include "cmState.h"
50 #include "cmStateDirectory.h"
51 #include "cmStateTypes.h"
52 #include "cmValue.h"
53 #include "cmVersion.h"
54 #include "cmWorkingDirectory.h"
55 #include "cmake.h"
56 
57 #if !defined(CMAKE_BOOTSTRAP)
58 #  include <cm3p/json/value.h>
59 #  include <cm3p/json/writer.h>
60 
61 #  include "cmCryptoHash.h"
62 #  include "cmQtAutoGenGlobalInitializer.h"
63 #endif
64 
65 #if defined(_MSC_VER) && _MSC_VER >= 1800
66 #  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
67 #endif
68 
69 const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
70   "CMAKE_PLATFORM_INFO_INITIALIZED";
71 
72 class cmInstalledFile;
73 
operator ()(cmTarget const * t1,cmTarget const * t2) const74 bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1,
75                                                   cmTarget const* t2) const
76 {
77   int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
78   if (nameResult == 0) {
79     return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory().c_str(),
80                   t2->GetMakefile()->GetCurrentBinaryDirectory().c_str()) < 0;
81   }
82   return nameResult < 0;
83 }
84 
cmGlobalGenerator(cmake * cm)85 cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
86   : CMakeInstance(cm)
87 {
88   // By default the .SYMBOLIC dependency is not needed on symbolic rules.
89   this->NeedSymbolicMark = false;
90 
91   // by default use the native paths
92   this->ForceUnixPaths = false;
93 
94   // By default do not try to support color.
95   this->ToolSupportsColor = false;
96 
97   // By default do not use link scripts.
98   this->UseLinkScript = false;
99 
100   // Whether an install target is needed.
101   this->InstallTargetEnabled = false;
102 
103   // how long to let try compiles run
104   this->TryCompileTimeout = cmDuration::zero();
105 
106   this->CurrentConfigureMakefile = nullptr;
107   this->TryCompileOuterMakefile = nullptr;
108 
109   this->ConfigureDoneCMP0026AndCMP0024 = false;
110   this->FirstTimeProgress = 0.0f;
111 
112   this->RecursionDepth = 0;
113 
114   cm->GetState()->SetIsGeneratorMultiConfig(false);
115   cm->GetState()->SetMinGWMake(false);
116   cm->GetState()->SetMSYSShell(false);
117   cm->GetState()->SetNMake(false);
118   cm->GetState()->SetWatcomWMake(false);
119   cm->GetState()->SetWindowsShell(false);
120   cm->GetState()->SetWindowsVSIDE(false);
121 }
122 
~cmGlobalGenerator()123 cmGlobalGenerator::~cmGlobalGenerator()
124 {
125   this->ClearGeneratorMembers();
126 }
127 
128 #if !defined(CMAKE_BOOTSTRAP)
GetJson() const129 Json::Value cmGlobalGenerator::GetJson() const
130 {
131   Json::Value generator = Json::objectValue;
132   generator["name"] = this->GetName();
133   generator["multiConfig"] = this->IsMultiConfig();
134   return generator;
135 }
136 #endif
137 
SetGeneratorInstance(std::string const & i,cmMakefile * mf)138 bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i,
139                                              cmMakefile* mf)
140 {
141   if (i.empty()) {
142     return true;
143   }
144 
145   std::ostringstream e;
146   /* clang-format off */
147   e <<
148     "Generator\n"
149     "  " << this->GetName() << "\n"
150     "does not support instance specification, but instance\n"
151     "  " << i << "\n"
152     "was specified.";
153   /* clang-format on */
154   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
155   return false;
156 }
157 
SetGeneratorPlatform(std::string const & p,cmMakefile * mf)158 bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p,
159                                              cmMakefile* mf)
160 {
161   if (p.empty()) {
162     return true;
163   }
164 
165   std::ostringstream e;
166   /* clang-format off */
167   e <<
168     "Generator\n"
169     "  " << this->GetName() << "\n"
170     "does not support platform specification, but platform\n"
171     "  " << p << "\n"
172     "was specified.";
173   /* clang-format on */
174   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
175   return false;
176 }
177 
SetGeneratorToolset(std::string const & ts,bool,cmMakefile * mf)178 bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool,
179                                             cmMakefile* mf)
180 {
181   if (ts.empty()) {
182     return true;
183   }
184   std::ostringstream e;
185   /* clang-format off */
186   e <<
187     "Generator\n"
188     "  " << this->GetName() << "\n"
189     "does not support toolset specification, but toolset\n"
190     "  " << ts << "\n"
191     "was specified.";
192   /* clang-format on */
193   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
194   return false;
195 }
196 
SelectMakeProgram(const std::string & inMakeProgram,const std::string & makeDefault) const197 std::string cmGlobalGenerator::SelectMakeProgram(
198   const std::string& inMakeProgram, const std::string& makeDefault) const
199 {
200   std::string makeProgram = inMakeProgram;
201   if (cmIsOff(makeProgram)) {
202     cmValue makeProgramCSTR =
203       this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
204     if (cmIsOff(makeProgramCSTR)) {
205       makeProgram = makeDefault;
206     } else {
207       makeProgram = *makeProgramCSTR;
208     }
209     if (cmIsOff(makeProgram) && !makeProgram.empty()) {
210       makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
211     }
212   }
213   return makeProgram;
214 }
215 
ResolveLanguageCompiler(const std::string & lang,cmMakefile * mf,bool optional) const216 void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
217                                                 cmMakefile* mf,
218                                                 bool optional) const
219 {
220   std::string langComp = cmStrCat("CMAKE_", lang, "_COMPILER");
221 
222   if (!mf->GetDefinition(langComp)) {
223     if (!optional) {
224       cmSystemTools::Error(langComp + " not set, after EnableLanguage");
225     }
226     return;
227   }
228   std::string const& name = mf->GetRequiredDefinition(langComp);
229   std::string path;
230   if (!cmSystemTools::FileIsFullPath(name)) {
231     path = cmSystemTools::FindProgram(name);
232   } else {
233     path = name;
234   }
235   if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
236     return;
237   }
238   cmValue cname =
239     this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
240 
241   // Split compiler from arguments
242   std::vector<std::string> cnameArgVec;
243   if (cname && !cname->empty()) {
244     cmExpandList(*cname, cnameArgVec);
245     cname = cmValue(cnameArgVec.front());
246   }
247 
248   std::string changeVars;
249   if (cname && !optional) {
250     std::string cnameString;
251     if (!cmSystemTools::FileIsFullPath(*cname)) {
252       cnameString = cmSystemTools::FindProgram(*cname);
253     } else {
254       cnameString = *cname;
255     }
256     std::string pathString = path;
257     // get rid of potentially multiple slashes:
258     cmSystemTools::ConvertToUnixSlashes(cnameString);
259     cmSystemTools::ConvertToUnixSlashes(pathString);
260     if (cnameString != pathString) {
261       cmValue cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
262         "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
263       if (cvars) {
264         changeVars += *cvars;
265         changeVars += ";";
266       }
267       changeVars += langComp;
268       changeVars += ";";
269       changeVars += *cname;
270       this->GetCMakeInstance()->GetState()->SetGlobalProperty(
271         "__CMAKE_DELETE_CACHE_CHANGE_VARS_", changeVars.c_str());
272     }
273   }
274 }
275 
AddBuildExportSet(cmExportBuildFileGenerator * gen)276 void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
277 {
278   this->BuildExportSets[gen->GetMainExportFileName()] = gen;
279 }
280 
AddBuildExportExportSet(cmExportBuildFileGenerator * gen)281 void cmGlobalGenerator::AddBuildExportExportSet(
282   cmExportBuildFileGenerator* gen)
283 {
284   this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
285   this->AddBuildExportSet(gen);
286 }
287 
GenerateImportFile(const std::string & file)288 bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
289 {
290   auto const it = this->BuildExportSets.find(file);
291   if (it != this->BuildExportSets.end()) {
292     bool result = it->second->GenerateImportFile();
293 
294     if (!this->ConfigureDoneCMP0026AndCMP0024) {
295       for (const auto& m : this->Makefiles) {
296         m->RemoveExportBuildFileGeneratorCMP0024(it->second);
297       }
298     }
299 
300     this->BuildExportSets.erase(it);
301     return result;
302   }
303   return false;
304 }
305 
ForceLinkerLanguages()306 void cmGlobalGenerator::ForceLinkerLanguages()
307 {
308 }
309 
CheckTargetsForMissingSources() const310 bool cmGlobalGenerator::CheckTargetsForMissingSources() const
311 {
312   bool failed = false;
313   for (const auto& localGen : this->LocalGenerators) {
314     for (const auto& target : localGen->GetGeneratorTargets()) {
315       if (!target->CanCompileSources() ||
316           cmIsOn(target->GetProperty("ghs_integrity_app"))) {
317         continue;
318       }
319 
320       if (target->GetAllConfigSources().empty()) {
321         std::ostringstream e;
322         e << "No SOURCES given to target: " << target->GetName();
323         this->GetCMakeInstance()->IssueMessage(
324           MessageType::FATAL_ERROR, e.str(), target->GetBacktrace());
325         failed = true;
326       }
327     }
328   }
329   return failed;
330 }
331 
CheckTargetsForType() const332 bool cmGlobalGenerator::CheckTargetsForType() const
333 {
334   if (!this->GetLanguageEnabled("Swift")) {
335     return false;
336   }
337   bool failed = false;
338   for (const auto& generator : this->LocalGenerators) {
339     for (const auto& target : generator->GetGeneratorTargets()) {
340       if (target->GetType() == cmStateEnums::EXECUTABLE) {
341         std::vector<std::string> const& configs =
342           target->Makefile->GetGeneratorConfigs(
343             cmMakefile::IncludeEmptyConfig);
344         for (std::string const& config : configs) {
345           if (target->IsWin32Executable(config) &&
346               target->GetLinkerLanguage(config) == "Swift") {
347             this->GetCMakeInstance()->IssueMessage(
348               MessageType::FATAL_ERROR,
349               "WIN32_EXECUTABLE property is not supported on Swift "
350               "executables",
351               target->GetBacktrace());
352             failed = true;
353           }
354         }
355       }
356     }
357   }
358   return failed;
359 }
360 
CheckTargetsForPchCompilePdb() const361 bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const
362 {
363   if (!this->GetLanguageEnabled("C") && !this->GetLanguageEnabled("CXX")) {
364     return false;
365   }
366   bool failed = false;
367   for (const auto& generator : this->LocalGenerators) {
368     for (const auto& target : generator->GetGeneratorTargets()) {
369       if (!target->CanCompileSources() ||
370           cmIsOn(target->GetProperty("ghs_integrity_app"))) {
371         continue;
372       }
373 
374       std::string const& reuseFrom =
375         target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM");
376       std::string const& compilePdb =
377         target->GetSafeProperty("COMPILE_PDB_NAME");
378 
379       if (!reuseFrom.empty() && reuseFrom != compilePdb) {
380         const std::string e = cmStrCat(
381           "PRECOMPILE_HEADERS_REUSE_FROM property is set on target (\"",
382           target->GetName(),
383           "\"). Reusable precompile headers requires the COMPILE_PDB_NAME"
384           " property to have the value \"",
385           reuseFrom, "\"\n");
386         this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
387                                                target->GetBacktrace());
388         failed = true;
389       }
390     }
391   }
392   return failed;
393 }
394 
IsExportedTargetsFile(const std::string & filename) const395 bool cmGlobalGenerator::IsExportedTargetsFile(
396   const std::string& filename) const
397 {
398   auto const it = this->BuildExportSets.find(filename);
399   if (it == this->BuildExportSets.end()) {
400     return false;
401   }
402   return !cm::contains(this->BuildExportExportSets, filename);
403 }
404 
405 // Find the make program for the generator, required for try compiles
FindMakeProgram(cmMakefile * mf)406 bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
407 {
408   if (this->FindMakeProgramFile.empty()) {
409     cmSystemTools::Error(
410       "Generator implementation error, "
411       "all generators must specify this->FindMakeProgramFile");
412     return false;
413   }
414   if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
415     std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile);
416     if (!setMakeProgram.empty()) {
417       mf->ReadListFile(setMakeProgram);
418     }
419   }
420   if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
421     std::ostringstream err;
422     err << "CMake was unable to find a build program corresponding to \""
423         << this->GetName() << "\".  CMAKE_MAKE_PROGRAM is not set.  You "
424         << "probably need to select a different build tool.";
425     cmSystemTools::Error(err.str());
426     cmSystemTools::SetFatalErrorOccured();
427     return false;
428   }
429   std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
430   // if there are spaces in the make program use short path
431   // but do not short path the actual program name, as
432   // this can cause trouble with VSExpress
433   if (makeProgram.find(' ') != std::string::npos) {
434     std::string dir;
435     std::string file;
436     cmSystemTools::SplitProgramPath(makeProgram, dir, file);
437     std::string saveFile = file;
438     cmSystemTools::GetShortPath(makeProgram, makeProgram);
439     cmSystemTools::SplitProgramPath(makeProgram, dir, file);
440     makeProgram = cmStrCat(dir, '/', saveFile);
441     mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program",
442                            cmStateEnums::FILEPATH);
443   }
444   return true;
445 }
446 
CheckLanguages(std::vector<std::string> const &,cmMakefile *) const447 bool cmGlobalGenerator::CheckLanguages(
448   std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const
449 {
450   return true;
451 }
452 
453 // enable the given language
454 //
455 // The following files are loaded in this order:
456 //
457 // First figure out what OS we are running on:
458 //
459 // CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
460 //   CMakeDetermineSystem.cmake - figure out os info and create
461 //                                CMakeSystem.cmake IF CMAKE_SYSTEM
462 //                                not set
463 //   CMakeSystem.cmake - configured file created by
464 //                       CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
465 
466 // CMakeSystemSpecificInitialize.cmake
467 //   - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake
468 
469 // Next try and enable all languages found in the languages vector
470 //
471 // FOREACH LANG in languages
472 //   CMake(LANG)Compiler.cmake - configured file create by
473 //                               CMakeDetermine(LANG)Compiler.cmake
474 //     CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
475 //                                          creates CMake(LANG)Compiler.cmake
476 //     CMake(LANG)Compiler.cmake - configured file created by
477 //                                 CMakeDetermine(LANG)Compiler.cmake
478 //
479 // CMakeSystemSpecificInformation.cmake
480 //   - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
481 //     may use compiler stuff
482 
483 // FOREACH LANG in languages
484 //   CMake(LANG)Information.cmake
485 //     - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
486 //   CMakeTest(LANG)Compiler.cmake
487 //     - Make sure the compiler works with a try compile if
488 //       CMakeDetermine(LANG) was loaded
489 //
490 // Now load a few files that can override values set in any of the above
491 // (PROJECTNAME)Compatibility.cmake
492 //   - load any backwards compatibility stuff for current project
493 // ${CMAKE_USER_MAKE_RULES_OVERRIDE}
494 //   - allow users a chance to override system variables
495 //
496 //
497 
EnableLanguage(std::vector<std::string> const & languages,cmMakefile * mf,bool optional)498 void cmGlobalGenerator::EnableLanguage(
499   std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
500 {
501   if (!this->IsMultiConfig() &&
502       !this->GetCMakeInstance()->GetIsInTryCompile()) {
503     std::string envBuildType;
504     if (!mf->GetDefinition("CMAKE_BUILD_TYPE") &&
505         cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) {
506       mf->AddCacheDefinition(
507         "CMAKE_BUILD_TYPE", envBuildType,
508         "Choose the type of build.  Options include: empty, "
509         "Debug, Release, RelWithDebInfo, MinSizeRel.",
510         cmStateEnums::STRING);
511     }
512   }
513 
514   if (languages.empty()) {
515     cmSystemTools::Error("EnableLanguage must have a lang specified!");
516     cmSystemTools::SetFatalErrorOccured();
517     return;
518   }
519 
520   std::set<std::string> cur_languages(languages.begin(), languages.end());
521   for (std::string const& li : cur_languages) {
522     if (!this->LanguagesInProgress.insert(li).second) {
523       std::ostringstream e;
524       e << "Language '" << li
525         << "' is currently being enabled.  "
526            "Recursive call not allowed.";
527       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
528       cmSystemTools::SetFatalErrorOccured();
529       return;
530     }
531   }
532 
533   if (this->TryCompileOuterMakefile) {
534     // In a try-compile we can only enable languages provided by caller.
535     for (std::string const& lang : languages) {
536       if (lang == "NONE") {
537         this->SetLanguageEnabled("NONE", mf);
538       } else {
539         if (!cm::contains(this->LanguagesReady, lang)) {
540           std::ostringstream e;
541           e << "The test project needs language " << lang
542             << " which is not enabled.";
543           this->TryCompileOuterMakefile->IssueMessage(MessageType::FATAL_ERROR,
544                                                       e.str());
545           cmSystemTools::SetFatalErrorOccured();
546           return;
547         }
548       }
549     }
550   }
551 
552   bool fatalError = false;
553 
554   mf->AddDefinitionBool("RUN_CONFIGURE", true);
555   std::string rootBin =
556     cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
557 
558   // If the configuration files path has been set,
559   // then we are in a try compile and need to copy the enable language
560   // files from the parent cmake bin dir, into the try compile bin dir
561   if (!this->ConfiguredFilesPath.empty()) {
562     rootBin = this->ConfiguredFilesPath;
563   }
564   rootBin += '/';
565   rootBin += cmVersion::GetCMakeVersion();
566 
567   // set the dir for parent files so they can be used by modules
568   mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin);
569 
570   if (!this->CMakeInstance->GetIsInTryCompile()) {
571     // Keep a mark in the cache to indicate that we've initialized the
572     // platform information directory.  If the platform information
573     // directory exists but the mark is missing then CMakeCache.txt
574     // has been removed or replaced without also removing the CMakeFiles/
575     // directory.  In this case remove the platform information directory
576     // so that it will be re-initialized and the relevant information
577     // restored in the cache.
578     if (cmSystemTools::FileIsDirectory(rootBin) &&
579         !mf->IsOn(kCMAKE_PLATFORM_INFO_INITIALIZED)) {
580       cmSystemTools::RemoveADirectory(rootBin);
581     }
582     this->GetCMakeInstance()->AddCacheEntry(
583       kCMAKE_PLATFORM_INFO_INITIALIZED, "1",
584       "Platform information initialized", cmStateEnums::INTERNAL);
585   }
586 
587   // try and load the CMakeSystem.cmake if it is there
588   std::string fpath = rootBin;
589   bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
590   if (readCMakeSystem) {
591     fpath += "/CMakeSystem.cmake";
592     if (cmSystemTools::FileExists(fpath)) {
593       mf->ReadListFile(fpath);
594     }
595   }
596 
597   //  Load the CMakeDetermineSystem.cmake file and find out
598   // what platform we are running on
599   if (!mf->GetDefinition("CMAKE_SYSTEM")) {
600 #if defined(_WIN32) && !defined(__CYGWIN__)
601     /* Windows version number data.  */
602     OSVERSIONINFOEXW osviex;
603     ZeroMemory(&osviex, sizeof(osviex));
604     osviex.dwOSVersionInfoSize = sizeof(osviex);
605 
606 #  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
607 #    pragma warning(push)
608 #    ifdef __INTEL_COMPILER
609 #      pragma warning(disable : 1478)
610 #    elif defined __clang__
611 #      pragma clang diagnostic push
612 #      pragma clang diagnostic ignored "-Wdeprecated-declarations"
613 #    else
614 #      pragma warning(disable : 4996)
615 #    endif
616 #  endif
617     GetVersionExW((OSVERSIONINFOW*)&osviex);
618 #  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
619 #    ifdef __clang__
620 #      pragma clang diagnostic pop
621 #    else
622 #      pragma warning(pop)
623 #    endif
624 #  endif
625     std::ostringstream windowsVersionString;
626     windowsVersionString << osviex.dwMajorVersion << "."
627                          << osviex.dwMinorVersion << "."
628                          << osviex.dwBuildNumber;
629     mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
630 #endif
631     // Read the DetermineSystem file
632     std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
633     mf->ReadListFile(systemFile);
634     // load the CMakeSystem.cmake from the binary directory
635     // this file is configured by the CMakeDetermineSystem.cmake file
636     fpath = cmStrCat(rootBin, "/CMakeSystem.cmake");
637     mf->ReadListFile(fpath);
638   }
639 
640   if (readCMakeSystem) {
641     // Tell the generator about the instance, if any.
642     std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
643     if (!this->SetGeneratorInstance(instance, mf)) {
644       cmSystemTools::SetFatalErrorOccured();
645       return;
646     }
647 
648     // Tell the generator about the target system.
649     std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
650     if (!this->SetSystemName(system, mf)) {
651       cmSystemTools::SetFatalErrorOccured();
652       return;
653     }
654 
655     // Tell the generator about the platform, if any.
656     std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM");
657     if (!this->SetGeneratorPlatform(platform, mf)) {
658       cmSystemTools::SetFatalErrorOccured();
659       return;
660     }
661 
662     // Tell the generator about the toolset, if any.
663     std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
664     if (!this->SetGeneratorToolset(toolset, false, mf)) {
665       cmSystemTools::SetFatalErrorOccured();
666       return;
667     }
668 
669     // Find the native build tool for this generator.
670     if (!this->FindMakeProgram(mf)) {
671       return;
672     }
673   }
674 
675   // Check that the languages are supported by the generator and its
676   // native build tool found above.
677   if (!this->CheckLanguages(languages, mf)) {
678     return;
679   }
680 
681   // **** Load the system specific initialization if not yet loaded
682   if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) {
683     fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake");
684     if (!mf->ReadListFile(fpath)) {
685       cmSystemTools::Error("Could not find cmake module file: "
686                            "CMakeSystemSpecificInitialize.cmake");
687     }
688   }
689 
690   std::map<std::string, bool> needTestLanguage;
691   std::map<std::string, bool> needSetLanguageEnabledMaps;
692   // foreach language
693   // load the CMakeDetermine(LANG)Compiler.cmake file to find
694   // the compiler
695 
696   for (std::string const& lang : languages) {
697     needSetLanguageEnabledMaps[lang] = false;
698     if (lang == "NONE") {
699       this->SetLanguageEnabled("NONE", mf);
700       continue;
701     }
702     std::string loadedLang = cmStrCat("CMAKE_", lang, "_COMPILER_LOADED");
703     if (!mf->GetDefinition(loadedLang)) {
704       fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
705 
706       // If the existing build tree was already configured with this
707       // version of CMake then try to load the configured file first
708       // to avoid duplicate compiler tests.
709       if (cmSystemTools::FileExists(fpath)) {
710         if (!mf->ReadListFile(fpath)) {
711           cmSystemTools::Error("Could not find cmake module file: " + fpath);
712         }
713         // if this file was found then the language was already determined
714         // to be working
715         needTestLanguage[lang] = false;
716         this->SetLanguageEnabledFlag(lang, mf);
717         needSetLanguageEnabledMaps[lang] = true;
718         // this can only be called after loading CMake(LANG)Compiler.cmake
719       }
720     }
721 
722     if (!this->GetLanguageEnabled(lang)) {
723       if (this->CMakeInstance->GetIsInTryCompile()) {
724         cmSystemTools::Error("This should not have happened. "
725                              "If you see this message, you are probably "
726                              "using a broken CMakeLists.txt file or a "
727                              "problematic release of CMake");
728       }
729       // if the CMake(LANG)Compiler.cmake file was not found then
730       // load CMakeDetermine(LANG)Compiler.cmake
731       std::string determineCompiler =
732         cmStrCat("CMakeDetermine", lang, "Compiler.cmake");
733       std::string determineFile = mf->GetModulesFile(determineCompiler);
734       if (!mf->ReadListFile(determineFile)) {
735         cmSystemTools::Error("Could not find cmake module file: " +
736                              determineCompiler);
737       }
738       if (cmSystemTools::GetFatalErrorOccured()) {
739         return;
740       }
741       needTestLanguage[lang] = true;
742       // Some generators like visual studio should not use the env variables
743       // So the global generator can specify that in this variable
744       if (!mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) {
745         // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
746         // into the environment, in case user scripts want to run
747         // configure, or sub cmakes
748         std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
749         std::string compilerEnv =
750           cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
751         const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
752         const std::string& envVarValue =
753           mf->GetRequiredDefinition(compilerName);
754         std::string env = cmStrCat(envVar, '=', envVarValue);
755         cmSystemTools::PutEnv(env);
756       }
757 
758       // if determineLanguage was called then load the file it
759       // configures CMake(LANG)Compiler.cmake
760       fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
761       if (!mf->ReadListFile(fpath)) {
762         cmSystemTools::Error("Could not find cmake module file: " + fpath);
763       }
764       this->SetLanguageEnabledFlag(lang, mf);
765       needSetLanguageEnabledMaps[lang] = true;
766       // this can only be called after loading CMake(LANG)Compiler.cmake
767       // the language must be enabled for try compile to work, but we do
768       // not know if it is a working compiler yet so set the test language
769       // flag
770       needTestLanguage[lang] = true;
771     } // end if(!this->GetLanguageEnabled(lang) )
772   }   // end loop over languages
773 
774   // **** Load the system specific information if not yet loaded
775   if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) {
776     fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
777     if (!mf->ReadListFile(fpath)) {
778       cmSystemTools::Error("Could not find cmake module file: "
779                            "CMakeSystemSpecificInformation.cmake");
780     }
781   }
782   // loop over languages again loading CMake(LANG)Information.cmake
783   //
784   for (std::string const& lang : languages) {
785     if (lang == "NONE") {
786       this->SetLanguageEnabled("NONE", mf);
787       continue;
788     }
789 
790     // Check that the compiler was found.
791     std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
792     std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
793     std::ostringstream noCompiler;
794     cmValue compilerFile = mf->GetDefinition(compilerName);
795     if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) {
796       /* clang-format off */
797       noCompiler <<
798         "No " << compilerName << " could be found.\n"
799         ;
800       /* clang-format on */
801     } else if ((lang != "RC") && (lang != "ASM_MASM")) {
802       if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
803         /* clang-format off */
804         noCompiler <<
805           "The " << compilerName << ":\n"
806           "  " << *compilerFile << "\n"
807           "is not a full path and was not found in the PATH.\n"
808           ;
809         /* clang-format on */
810       } else if (!cmSystemTools::FileExists(*compilerFile)) {
811         /* clang-format off */
812         noCompiler <<
813           "The " << compilerName << ":\n"
814           "  " << *compilerFile << "\n"
815           "is not a full path to an existing compiler tool.\n"
816           ;
817         /* clang-format on */
818       }
819     }
820     if (!noCompiler.str().empty()) {
821       // Skip testing this language since the compiler is not found.
822       needTestLanguage[lang] = false;
823       if (!optional) {
824         // The compiler was not found and it is not optional.  Remove
825         // CMake(LANG)Compiler.cmake so we try again next time CMake runs.
826         std::string compilerLangFile =
827           cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
828         cmSystemTools::RemoveFile(compilerLangFile);
829         if (!this->CMakeInstance->GetIsInTryCompile()) {
830           this->PrintCompilerAdvice(noCompiler, lang,
831                                     mf->GetDefinition(compilerEnv));
832           mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str());
833           fatalError = true;
834         }
835       }
836     }
837 
838     std::string langLoadedVar =
839       cmStrCat("CMAKE_", lang, "_INFORMATION_LOADED");
840     if (!mf->GetDefinition(langLoadedVar)) {
841       fpath = cmStrCat("CMake", lang, "Information.cmake");
842       std::string informationFile = mf->GetModulesFile(fpath);
843       if (informationFile.empty()) {
844         cmSystemTools::Error("Could not find cmake module file: " + fpath);
845       } else if (!mf->ReadListFile(informationFile)) {
846         cmSystemTools::Error("Could not process cmake module file: " +
847                              informationFile);
848       }
849     }
850     if (needSetLanguageEnabledMaps[lang]) {
851       this->SetLanguageEnabledMaps(lang, mf);
852     }
853     this->LanguagesReady.insert(lang);
854 
855     // Test the compiler for the language just setup
856     // (but only if a compiler has been actually found)
857     // At this point we should have enough info for a try compile
858     // which is used in the backward stuff
859     // If the language is untested then test it now with a try compile.
860     if (needTestLanguage[lang]) {
861       if (!this->CMakeInstance->GetIsInTryCompile()) {
862         std::string testLang = cmStrCat("CMakeTest", lang, "Compiler.cmake");
863         std::string ifpath = mf->GetModulesFile(testLang);
864         if (!mf->ReadListFile(ifpath)) {
865           cmSystemTools::Error("Could not find cmake module file: " +
866                                testLang);
867         }
868         std::string compilerWorks =
869           cmStrCat("CMAKE_", lang, "_COMPILER_WORKS");
870         // if the compiler did not work, then remove the
871         // CMake(LANG)Compiler.cmake file so that it will get tested the
872         // next time cmake is run
873         if (!mf->IsOn(compilerWorks)) {
874           std::string compilerLangFile =
875             cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
876           cmSystemTools::RemoveFile(compilerLangFile);
877         }
878       } // end if in try compile
879     }   // end need test language
880     // Store the shared library flags so that we can satisfy CMP0018
881     std::string sharedLibFlagsVar =
882       cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS");
883     this->LanguageToOriginalSharedLibFlags[lang] =
884       mf->GetSafeDefinition(sharedLibFlagsVar);
885 
886     // Translate compiler ids for compatibility.
887     this->CheckCompilerIdCompatibility(mf, lang);
888   } // end for each language
889 
890   // Now load files that can override any settings on the platform or for
891   // the project First load the project compatibility file if it is in
892   // cmake
893   std::string projectCompatibility =
894     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/",
895              mf->GetSafeDefinition("PROJECT_NAME"), "Compatibility.cmake");
896   if (cmSystemTools::FileExists(projectCompatibility)) {
897     mf->ReadListFile(projectCompatibility);
898   }
899   // Inform any extra generator of the new language.
900   if (this->ExtraGenerator) {
901     this->ExtraGenerator->EnableLanguage(languages, mf, false);
902   }
903 
904   if (fatalError) {
905     cmSystemTools::SetFatalErrorOccured();
906   }
907 
908   for (std::string const& lang : cur_languages) {
909     this->LanguagesInProgress.erase(lang);
910   }
911 }
912 
PrintCompilerAdvice(std::ostream & os,std::string const & lang,cmValue envVar) const913 void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
914                                             std::string const& lang,
915                                             cmValue envVar) const
916 {
917   // Subclasses override this method if they do not support this advice.
918   os << "Tell CMake where to find the compiler by setting ";
919   if (envVar) {
920     os << "either the environment variable \"" << envVar << "\" or ";
921   }
922   os << "the CMake cache entry CMAKE_" << lang
923      << "_COMPILER "
924         "to the full path to the compiler, or to the compiler name "
925         "if it is in the PATH.";
926 }
927 
CheckCompilerIdCompatibility(cmMakefile * mf,std::string const & lang) const928 void cmGlobalGenerator::CheckCompilerIdCompatibility(
929   cmMakefile* mf, std::string const& lang) const
930 {
931   std::string compilerIdVar = "CMAKE_" + lang + "_COMPILER_ID";
932   std::string const compilerId = mf->GetSafeDefinition(compilerIdVar);
933 
934   if (compilerId == "AppleClang") {
935     switch (mf->GetPolicyStatus(cmPolicies::CMP0025)) {
936       case cmPolicies::WARN:
937         if (!this->CMakeInstance->GetIsInTryCompile() &&
938             mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0025")) {
939           std::ostringstream w;
940           /* clang-format off */
941           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
942             "Converting " << lang <<
943             R"( compiler id "AppleClang" to "Clang" for compatibility.)"
944             ;
945           /* clang-format on */
946           mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
947         }
948         CM_FALLTHROUGH;
949       case cmPolicies::OLD:
950         // OLD behavior is to convert AppleClang to Clang.
951         mf->AddDefinition(compilerIdVar, "Clang");
952         break;
953       case cmPolicies::REQUIRED_IF_USED:
954       case cmPolicies::REQUIRED_ALWAYS:
955         mf->IssueMessage(
956           MessageType::FATAL_ERROR,
957           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025));
958         break;
959       case cmPolicies::NEW:
960         // NEW behavior is to keep AppleClang.
961         break;
962     }
963   }
964 
965   if (compilerId == "QCC") {
966     switch (mf->GetPolicyStatus(cmPolicies::CMP0047)) {
967       case cmPolicies::WARN:
968         if (!this->CMakeInstance->GetIsInTryCompile() &&
969             mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0047")) {
970           std::ostringstream w;
971           /* clang-format off */
972           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
973             "Converting " << lang <<
974             R"( compiler id "QCC" to "GNU" for compatibility.)"
975             ;
976           /* clang-format on */
977           mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
978         }
979         CM_FALLTHROUGH;
980       case cmPolicies::OLD:
981         // OLD behavior is to convert QCC to GNU.
982         mf->AddDefinition(compilerIdVar, "GNU");
983         if (lang == "C") {
984           mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
985         } else if (lang == "CXX") {
986           mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
987         }
988         break;
989       case cmPolicies::REQUIRED_IF_USED:
990       case cmPolicies::REQUIRED_ALWAYS:
991         mf->IssueMessage(
992           MessageType::FATAL_ERROR,
993           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0047));
994         CM_FALLTHROUGH;
995       case cmPolicies::NEW:
996         // NEW behavior is to keep QCC.
997         break;
998     }
999   }
1000 
1001   if (compilerId == "XLClang") {
1002     switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
1003       case cmPolicies::WARN:
1004         if (!this->CMakeInstance->GetIsInTryCompile() &&
1005             mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
1006           std::ostringstream w;
1007           /* clang-format off */
1008           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
1009             "Converting " << lang <<
1010             R"( compiler id "XLClang" to "XL" for compatibility.)"
1011             ;
1012           /* clang-format on */
1013           mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
1014         }
1015         CM_FALLTHROUGH;
1016       case cmPolicies::OLD:
1017         // OLD behavior is to convert XLClang to XL.
1018         mf->AddDefinition(compilerIdVar, "XL");
1019         break;
1020       case cmPolicies::REQUIRED_IF_USED:
1021       case cmPolicies::REQUIRED_ALWAYS:
1022         mf->IssueMessage(
1023           MessageType::FATAL_ERROR,
1024           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
1025         break;
1026       case cmPolicies::NEW:
1027         // NEW behavior is to keep AppleClang.
1028         break;
1029     }
1030   }
1031 }
1032 
GetLanguageOutputExtension(cmSourceFile const & source) const1033 std::string cmGlobalGenerator::GetLanguageOutputExtension(
1034   cmSourceFile const& source) const
1035 {
1036   const std::string& lang = source.GetLanguage();
1037   if (!lang.empty()) {
1038     auto const it = this->LanguageToOutputExtension.find(lang);
1039     if (it != this->LanguageToOutputExtension.end()) {
1040       return it->second;
1041     }
1042   } else {
1043     // if no language is found then check to see if it is already an
1044     // output extension for some language.  In that case it should be ignored
1045     // and in this map, so it will not be compiled but will just be used.
1046     std::string const& ext = source.GetExtension();
1047     if (!ext.empty()) {
1048       if (this->OutputExtensions.count(ext)) {
1049         return ext;
1050       }
1051     }
1052   }
1053   return "";
1054 }
1055 
GetLanguageFromExtension(const char * ext) const1056 std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
1057 {
1058   // if there is an extension and it starts with . then move past the
1059   // . because the extensions are not stored with a .  in the map
1060   if (ext && *ext == '.') {
1061     ++ext;
1062   }
1063   auto const it = this->ExtensionToLanguage.find(ext);
1064   if (it != this->ExtensionToLanguage.end()) {
1065     return it->second;
1066   }
1067   return "";
1068 }
1069 
1070 /* SetLanguageEnabled() is now split in two parts:
1071 at first the enabled-flag is set. This can then be used in EnabledLanguage()
1072 for checking whether the language is already enabled. After setting this
1073 flag still the values from the cmake variables have to be copied into the
1074 internal maps, this is done in SetLanguageEnabledMaps() which is called
1075 after the system- and compiler specific files have been loaded.
1076 
1077 This split was done originally so that compiler-specific configuration
1078 files could change the object file extension
1079 (CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
1080 to the C++ maps.
1081 */
SetLanguageEnabled(const std::string & l,cmMakefile * mf)1082 void cmGlobalGenerator::SetLanguageEnabled(const std::string& l,
1083                                            cmMakefile* mf)
1084 {
1085   this->SetLanguageEnabledFlag(l, mf);
1086   this->SetLanguageEnabledMaps(l, mf);
1087 }
1088 
SetLanguageEnabledFlag(const std::string & l,cmMakefile * mf)1089 void cmGlobalGenerator::SetLanguageEnabledFlag(const std::string& l,
1090                                                cmMakefile* mf)
1091 {
1092   this->CMakeInstance->GetState()->SetLanguageEnabled(l);
1093 
1094   // Fill the language-to-extension map with the current variable
1095   // settings to make sure it is available for the try_compile()
1096   // command source file signature.  In SetLanguageEnabledMaps this
1097   // will be done again to account for any compiler- or
1098   // platform-specific entries.
1099   this->FillExtensionToLanguageMap(l, mf);
1100 }
1101 
SetLanguageEnabledMaps(const std::string & l,cmMakefile * mf)1102 void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
1103                                                cmMakefile* mf)
1104 {
1105   // use LanguageToLinkerPreference to detect whether this functions has
1106   // run before
1107   if (cm::contains(this->LanguageToLinkerPreference, l)) {
1108     return;
1109   }
1110 
1111   std::string linkerPrefVar = "CMAKE_" + l + "_LINKER_PREFERENCE";
1112   cmValue linkerPref = mf->GetDefinition(linkerPrefVar);
1113   int preference = 0;
1114   if (cmNonempty(linkerPref)) {
1115     if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) {
1116       // backward compatibility: before 2.6 LINKER_PREFERENCE
1117       // was either "None" or "Preferred", and only the first character was
1118       // tested. So if there is a custom language out there and it is
1119       // "Preferred", set its preference high
1120       if ((*linkerPref)[0] == 'P') {
1121         preference = 100;
1122       } else {
1123         preference = 0;
1124       }
1125     }
1126   }
1127 
1128   if (preference < 0) {
1129     std::string msg =
1130       cmStrCat(linkerPrefVar, " is negative, adjusting it to 0");
1131     cmSystemTools::Message(msg, "Warning");
1132     preference = 0;
1133   }
1134 
1135   this->LanguageToLinkerPreference[l] = preference;
1136 
1137   std::string outputExtensionVar = "CMAKE_" + l + "_OUTPUT_EXTENSION";
1138   if (cmValue p = mf->GetDefinition(outputExtensionVar)) {
1139     std::string outputExtension = *p;
1140     this->LanguageToOutputExtension[l] = outputExtension;
1141     this->OutputExtensions[outputExtension] = outputExtension;
1142     if (cmHasPrefix(outputExtension, ".")) {
1143       outputExtension = outputExtension.substr(1);
1144       this->OutputExtensions[outputExtension] = outputExtension;
1145     }
1146   }
1147 
1148   // The map was originally filled by SetLanguageEnabledFlag, but
1149   // since then the compiler- and platform-specific files have been
1150   // loaded which might have added more entries.
1151   this->FillExtensionToLanguageMap(l, mf);
1152 
1153   std::string ignoreExtensionsVar =
1154     std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS");
1155   std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
1156   std::vector<std::string> extensionList = cmExpandedList(ignoreExts);
1157   for (std::string const& i : extensionList) {
1158     this->IgnoreExtensions[i] = true;
1159   }
1160 }
1161 
FillExtensionToLanguageMap(const std::string & l,cmMakefile * mf)1162 void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l,
1163                                                    cmMakefile* mf)
1164 {
1165   std::string extensionsVar = std::string("CMAKE_") + std::string(l) +
1166     std::string("_SOURCE_FILE_EXTENSIONS");
1167   const std::string& exts = mf->GetSafeDefinition(extensionsVar);
1168   std::vector<std::string> extensionList = cmExpandedList(exts);
1169   for (std::string const& i : extensionList) {
1170     this->ExtensionToLanguage[i] = l;
1171   }
1172 }
1173 
GetGlobalSetting(std::string const & name) const1174 cmValue cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
1175 {
1176   assert(!this->Makefiles.empty());
1177   return this->Makefiles[0]->GetDefinition(name);
1178 }
1179 
GlobalSettingIsOn(std::string const & name) const1180 bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const
1181 {
1182   assert(!this->Makefiles.empty());
1183   return this->Makefiles[0]->IsOn(name);
1184 }
1185 
GetSafeGlobalSetting(std::string const & name) const1186 std::string cmGlobalGenerator::GetSafeGlobalSetting(
1187   std::string const& name) const
1188 {
1189   assert(!this->Makefiles.empty());
1190   return this->Makefiles[0]->GetDefinition(name);
1191 }
1192 
IgnoreFile(const char * ext) const1193 bool cmGlobalGenerator::IgnoreFile(const char* ext) const
1194 {
1195   if (!this->GetLanguageFromExtension(ext).empty()) {
1196     return false;
1197   }
1198   return (this->IgnoreExtensions.count(ext) > 0);
1199 }
1200 
GetLanguageEnabled(const std::string & l) const1201 bool cmGlobalGenerator::GetLanguageEnabled(const std::string& l) const
1202 {
1203   return this->CMakeInstance->GetState()->GetLanguageEnabled(l);
1204 }
1205 
ClearEnabledLanguages()1206 void cmGlobalGenerator::ClearEnabledLanguages()
1207 {
1208   this->CMakeInstance->GetState()->ClearEnabledLanguages();
1209 }
1210 
CreateLocalGenerators()1211 void cmGlobalGenerator::CreateLocalGenerators()
1212 {
1213   this->LocalGeneratorSearchIndex.clear();
1214   this->LocalGenerators.clear();
1215   this->LocalGenerators.reserve(this->Makefiles.size());
1216   for (const auto& m : this->Makefiles) {
1217     auto lg = this->CreateLocalGenerator(m.get());
1218     this->IndexLocalGenerator(lg.get());
1219     this->LocalGenerators.push_back(std::move(lg));
1220   }
1221 }
1222 
Configure()1223 void cmGlobalGenerator::Configure()
1224 {
1225   this->FirstTimeProgress = 0.0f;
1226   this->ClearGeneratorMembers();
1227   this->NextDeferId = 0;
1228 
1229   cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
1230 
1231   snapshot.GetDirectory().SetCurrentSource(
1232     this->CMakeInstance->GetHomeDirectory());
1233   snapshot.GetDirectory().SetCurrentBinary(
1234     this->CMakeInstance->GetHomeOutputDirectory());
1235 
1236   auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
1237   auto* dirMf = dirMfu.get();
1238   this->Makefiles.push_back(std::move(dirMfu));
1239   dirMf->SetRecursionDepth(this->RecursionDepth);
1240   this->IndexMakefile(dirMf);
1241 
1242   this->BinaryDirectories.insert(
1243     this->CMakeInstance->GetHomeOutputDirectory());
1244 
1245   // now do it
1246   this->ConfigureDoneCMP0026AndCMP0024 = false;
1247   dirMf->Configure();
1248   dirMf->EnforceDirectoryLevelRules();
1249 
1250   this->ConfigureDoneCMP0026AndCMP0024 = true;
1251 
1252   // Put a copy of each global target in every directory.
1253   {
1254     std::vector<GlobalTargetInfo> globalTargets;
1255     this->CreateDefaultGlobalTargets(globalTargets);
1256 
1257     for (const auto& mf : this->Makefiles) {
1258       for (GlobalTargetInfo const& globalTarget : globalTargets) {
1259         this->CreateGlobalTarget(globalTarget, mf.get());
1260       }
1261     }
1262   }
1263 
1264   // update the cache entry for the number of local generators, this is used
1265   // for progress
1266   char num[100];
1267   sprintf(num, "%d", static_cast<int>(this->Makefiles.size()));
1268   this->GetCMakeInstance()->AddCacheEntry("CMAKE_NUMBER_OF_MAKEFILES", num,
1269                                           "number of local generators",
1270                                           cmStateEnums::INTERNAL);
1271 
1272   if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
1273     std::ostringstream msg;
1274     if (cmSystemTools::GetErrorOccuredFlag()) {
1275       msg << "Configuring incomplete, errors occurred!";
1276       const char* logs[] = { "CMakeOutput.log", "CMakeError.log", nullptr };
1277       for (const char** log = logs; *log; ++log) {
1278         std::string f = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
1279                                  "/CMakeFiles/", *log);
1280         if (cmSystemTools::FileExists(f)) {
1281           msg << "\nSee also \"" << f << "\".";
1282         }
1283       }
1284     } else {
1285       msg << "Configuring done";
1286     }
1287     this->CMakeInstance->UpdateProgress(msg.str(), -1);
1288   }
1289 }
1290 
CreateGenerationObjects(TargetTypes targetTypes)1291 void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
1292 {
1293   this->CreateLocalGenerators();
1294   // Commit side effects only if we are actually generating
1295   if (this->GetConfigureDoneCMP0026()) {
1296     this->CheckTargetProperties();
1297   }
1298   this->CreateGeneratorTargets(targetTypes);
1299   this->ComputeBuildFileGenerators();
1300 }
1301 
CreateImportedGenerationObjects(cmMakefile * mf,const std::vector<std::string> & targets,std::vector<const cmGeneratorTarget * > & exports)1302 void cmGlobalGenerator::CreateImportedGenerationObjects(
1303   cmMakefile* mf, const std::vector<std::string>& targets,
1304   std::vector<const cmGeneratorTarget*>& exports)
1305 {
1306   this->CreateGenerationObjects(ImportedOnly);
1307   auto const mfit =
1308     std::find_if(this->Makefiles.begin(), this->Makefiles.end(),
1309                  [mf](const std::unique_ptr<cmMakefile>& item) {
1310                    return item.get() == mf;
1311                  });
1312   auto& lg =
1313     this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
1314   for (std::string const& t : targets) {
1315     cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
1316     if (gt) {
1317       exports.push_back(gt);
1318     }
1319   }
1320 }
1321 
GetExportedTargetsFile(const std::string & filename) const1322 cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
1323   const std::string& filename) const
1324 {
1325   auto const it = this->BuildExportSets.find(filename);
1326   return it == this->BuildExportSets.end() ? nullptr : it->second;
1327 }
1328 
AddCMP0042WarnTarget(const std::string & target)1329 void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target)
1330 {
1331   this->CMP0042WarnTargets.insert(target);
1332 }
1333 
AddCMP0068WarnTarget(const std::string & target)1334 void cmGlobalGenerator::AddCMP0068WarnTarget(const std::string& target)
1335 {
1336   this->CMP0068WarnTargets.insert(target);
1337 }
1338 
CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const1339 bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
1340 {
1341   // If the property is not enabled then okay.
1342   if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1343         "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
1344     return true;
1345   }
1346 
1347   // This generator does not support duplicate custom targets.
1348   std::ostringstream e;
1349   e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
1350     << "global property.  "
1351     << "The \"" << this->GetName() << "\" generator does not support "
1352     << "duplicate custom targets.  "
1353     << "Consider using a Makefiles generator or fix the project to not "
1354     << "use duplicate target names.";
1355   cmSystemTools::Error(e.str());
1356   return false;
1357 }
1358 
ComputeBuildFileGenerators()1359 void cmGlobalGenerator::ComputeBuildFileGenerators()
1360 {
1361   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1362     std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
1363       this->Makefiles[i]->GetExportBuildFileGenerators();
1364     for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
1365       g->Compute(this->LocalGenerators[i].get());
1366     }
1367   }
1368 }
1369 
UnsupportedVariableIsDefined(const std::string & name,bool supported) const1370 bool cmGlobalGenerator::UnsupportedVariableIsDefined(const std::string& name,
1371                                                      bool supported) const
1372 {
1373   if (!supported && this->Makefiles.front()->GetDefinition(name)) {
1374     std::ostringstream e;
1375     /* clang-format off */
1376     e <<
1377       "Generator\n"
1378       "  " << this->GetName() << "\n"
1379       "does not support variable\n"
1380       "  " << name << "\n"
1381       "but it has been specified."
1382       ;
1383     /* clang-format on */
1384     this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
1385     return true;
1386   }
1387 
1388   return false;
1389 }
1390 
Compute()1391 bool cmGlobalGenerator::Compute()
1392 {
1393   // Make sure unsupported variables are not used.
1394   if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
1395                                          this->SupportsDefaultBuildType())) {
1396     return false;
1397   }
1398   if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
1399                                          this->SupportsCrossConfigs())) {
1400     return false;
1401   }
1402   if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
1403                                          this->SupportsDefaultConfigs())) {
1404     return false;
1405   }
1406   if (!this->InspectConfigTypeVariables()) {
1407     return false;
1408   }
1409 
1410   // Some generators track files replaced during the Generate.
1411   // Start with an empty vector:
1412   this->FilesReplacedDuringGenerate.clear();
1413 
1414   // clear targets to issue warning CMP0042 for
1415   this->CMP0042WarnTargets.clear();
1416   // clear targets to issue warning CMP0068 for
1417   this->CMP0068WarnTargets.clear();
1418 
1419   // Check whether this generator is allowed to run.
1420   if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
1421     return false;
1422   }
1423   this->FinalizeTargetCompileInfo();
1424 
1425   this->CreateGenerationObjects();
1426 
1427   // at this point this->LocalGenerators has been filled,
1428   // so create the map from project name to vector of local generators
1429   this->FillProjectMap();
1430 
1431   // Add automatically generated sources (e.g. unity build).
1432   if (!this->AddAutomaticSources()) {
1433     return false;
1434   }
1435 
1436   // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC
1437   if (!this->QtAutoGen()) {
1438     return false;
1439   }
1440 
1441   // Add generator specific helper commands
1442   for (const auto& localGen : this->LocalGenerators) {
1443     localGen->AddHelperCommands();
1444   }
1445 
1446   // Perform up-front computation in order to handle errors (such as unknown
1447   // features) at this point. While processing the compile features we also
1448   // calculate and cache the language standard required by the compile
1449   // features.
1450   for (const auto& localGen : this->LocalGenerators) {
1451     if (!localGen->ComputeTargetCompileFeatures()) {
1452       return false;
1453     }
1454   }
1455 
1456   for (const auto& localGen : this->LocalGenerators) {
1457     cmMakefile* mf = localGen->GetMakefile();
1458     for (const auto& g : mf->GetInstallGenerators()) {
1459       if (!g->Compute(localGen.get())) {
1460         return false;
1461       }
1462     }
1463   }
1464 
1465   this->AddExtraIDETargets();
1466 
1467   // Trace the dependencies, after that no custom commands should be added
1468   // because their dependencies might not be handled correctly
1469   for (const auto& localGen : this->LocalGenerators) {
1470     localGen->TraceDependencies();
1471   }
1472 
1473   // Make sure that all (non-imported) targets have source files added!
1474   if (this->CheckTargetsForMissingSources()) {
1475     return false;
1476   }
1477 
1478   this->ForceLinkerLanguages();
1479 
1480   // Compute the manifest of main targets generated.
1481   for (const auto& localGen : this->LocalGenerators) {
1482     localGen->ComputeTargetManifest();
1483   }
1484 
1485   // Compute the inter-target dependencies.
1486   if (!this->ComputeTargetDepends()) {
1487     return false;
1488   }
1489   this->ComputeTargetOrder();
1490 
1491   if (this->CheckTargetsForType()) {
1492     return false;
1493   }
1494 
1495   if (this->CheckTargetsForPchCompilePdb()) {
1496     return false;
1497   }
1498 
1499   for (const auto& localGen : this->LocalGenerators) {
1500     localGen->ComputeHomeRelativeOutputPath();
1501   }
1502 
1503   return true;
1504 }
1505 
Generate()1506 void cmGlobalGenerator::Generate()
1507 {
1508   // Create a map from local generator to the complete set of targets
1509   // it builds by default.
1510   this->InitializeProgressMarks();
1511 
1512   this->ProcessEvaluationFiles();
1513 
1514   this->CMakeInstance->UpdateProgress("Generating", 0.1f);
1515 
1516   // Generate project files
1517   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1518     this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
1519     this->LocalGenerators[i]->Generate();
1520     if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
1521           "CMAKE_SKIP_INSTALL_RULES")) {
1522       this->LocalGenerators[i]->GenerateInstallRules();
1523     }
1524     this->LocalGenerators[i]->GenerateTestFiles();
1525     this->CMakeInstance->UpdateProgress(
1526       "Generating",
1527       0.1f +
1528         0.9f * (static_cast<float>(i) + 1.0f) /
1529           static_cast<float>(this->LocalGenerators.size()));
1530   }
1531   this->SetCurrentMakefile(nullptr);
1532 
1533   if (!this->GenerateCPackPropertiesFile()) {
1534     this->GetCMakeInstance()->IssueMessage(
1535       MessageType::FATAL_ERROR, "Could not write CPack properties file.");
1536   }
1537 
1538   for (auto& buildExpSet : this->BuildExportSets) {
1539     if (!buildExpSet.second->GenerateImportFile()) {
1540       if (!cmSystemTools::GetErrorOccuredFlag()) {
1541         this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
1542                                                "Could not write export file.");
1543       }
1544       return;
1545     }
1546   }
1547   // Update rule hashes.
1548   this->CheckRuleHashes();
1549 
1550   this->WriteSummary();
1551 
1552   if (this->ExtraGenerator) {
1553     this->ExtraGenerator->Generate();
1554   }
1555 
1556   if (!this->CMP0042WarnTargets.empty()) {
1557     std::ostringstream w;
1558     w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";
1559     w << "MACOSX_RPATH is not specified for"
1560          " the following targets:\n";
1561     for (std::string const& t : this->CMP0042WarnTargets) {
1562       w << " " << t << "\n";
1563     }
1564     this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
1565                                            w.str());
1566   }
1567 
1568   if (!this->CMP0068WarnTargets.empty()) {
1569     std::ostringstream w;
1570     /* clang-format off */
1571     w <<
1572       cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n"
1573       "For compatibility with older versions of CMake, the install_name "
1574       "fields for the following targets are still affected by RPATH "
1575       "settings:\n"
1576       ;
1577     /* clang-format on */
1578     for (std::string const& t : this->CMP0068WarnTargets) {
1579       w << " " << t << "\n";
1580     }
1581     this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
1582                                            w.str());
1583   }
1584 
1585   this->CMakeInstance->UpdateProgress("Generating done", -1);
1586 }
1587 
ComputeTargetDepends()1588 bool cmGlobalGenerator::ComputeTargetDepends()
1589 {
1590   cmComputeTargetDepends ctd(this);
1591   if (!ctd.Compute()) {
1592     return false;
1593   }
1594   for (cmGeneratorTarget const* target : ctd.GetTargets()) {
1595     ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
1596   }
1597   return true;
1598 }
1599 
1600 std::vector<cmGeneratorTarget*>
GetLocalGeneratorTargetsInOrder(cmLocalGenerator * lg) const1601 cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const
1602 {
1603   std::vector<cmGeneratorTarget*> gts;
1604   cm::append(gts, lg->GetGeneratorTargets());
1605   std::sort(gts.begin(), gts.end(),
1606             [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
1607               return this->TargetOrderIndex.at(l) <
1608                 this->TargetOrderIndex.at(r);
1609             });
1610   return gts;
1611 }
1612 
ComputeTargetOrder()1613 void cmGlobalGenerator::ComputeTargetOrder()
1614 {
1615   size_t index = 0;
1616   auto const& lgens = this->GetLocalGenerators();
1617   for (auto const& lgen : lgens) {
1618     const auto& targets = lgen->GetGeneratorTargets();
1619     for (const auto& gt : targets) {
1620       this->ComputeTargetOrder(gt.get(), index);
1621     }
1622   }
1623   assert(index == this->TargetOrderIndex.size());
1624 }
1625 
ComputeTargetOrder(cmGeneratorTarget const * gt,size_t & index)1626 void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
1627                                            size_t& index)
1628 {
1629   std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
1630   auto insertion = this->TargetOrderIndex.insert(value);
1631   if (!insertion.second) {
1632     return;
1633   }
1634   auto entry = insertion.first;
1635 
1636   const auto& deps = this->GetTargetDirectDepends(gt);
1637   for (const auto& d : deps) {
1638     this->ComputeTargetOrder(d, index);
1639   }
1640 
1641   entry->second = index++;
1642 }
1643 
QtAutoGen()1644 bool cmGlobalGenerator::QtAutoGen()
1645 {
1646 #ifndef CMAKE_BOOTSTRAP
1647   cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators);
1648   return initializer.generate();
1649 #else
1650   return true;
1651 #endif
1652 }
1653 
AddAutomaticSources()1654 bool cmGlobalGenerator::AddAutomaticSources()
1655 {
1656   for (const auto& lg : this->LocalGenerators) {
1657     lg->CreateEvaluationFileOutputs();
1658   }
1659   for (const auto& lg : this->LocalGenerators) {
1660     for (const auto& gt : lg->GetGeneratorTargets()) {
1661       if (!gt->CanCompileSources()) {
1662         continue;
1663       }
1664       lg->AddUnityBuild(gt.get());
1665       lg->AddISPCDependencies(gt.get());
1666       // Targets that re-use a PCH are handled below.
1667       if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1668         lg->AddPchDependencies(gt.get());
1669       }
1670     }
1671   }
1672   for (const auto& lg : this->LocalGenerators) {
1673     for (const auto& gt : lg->GetGeneratorTargets()) {
1674       if (!gt->CanCompileSources()) {
1675         continue;
1676       }
1677       // Handle targets that re-use a PCH from an above-handled target.
1678       if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1679         lg->AddPchDependencies(gt.get());
1680       }
1681     }
1682   }
1683   // The above transformations may have changed the classification of sources.
1684   // Clear the source list and classification cache (KindedSources) of all
1685   // targets so that it will be recomputed correctly by the generators later
1686   // now that the above transformations are done for all targets.
1687   for (const auto& lg : this->LocalGenerators) {
1688     for (const auto& gt : lg->GetGeneratorTargets()) {
1689       gt->ClearSourcesCache();
1690     }
1691   }
1692   return true;
1693 }
1694 
CreateLinkLineComputer(cmOutputConverter * outputConverter,cmStateDirectory const & stateDir) const1695 std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
1696   cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
1697 {
1698   return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
1699 }
1700 
1701 std::unique_ptr<cmLinkLineComputer>
CreateMSVC60LinkLineComputer(cmOutputConverter * outputConverter,cmStateDirectory const & stateDir) const1702 cmGlobalGenerator::CreateMSVC60LinkLineComputer(
1703   cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
1704 {
1705   return std::unique_ptr<cmLinkLineComputer>(
1706     cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
1707 }
1708 
FinalizeTargetCompileInfo()1709 void cmGlobalGenerator::FinalizeTargetCompileInfo()
1710 {
1711   std::vector<std::string> const langs =
1712     this->CMakeInstance->GetState()->GetEnabledLanguages();
1713 
1714   // Construct per-target generator information.
1715   for (const auto& mf : this->Makefiles) {
1716     const cmBTStringRange noconfig_compile_definitions =
1717       mf->GetCompileDefinitionsEntries();
1718 
1719     for (auto& target : mf->GetTargets()) {
1720       cmTarget* t = &target.second;
1721       if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
1722         continue;
1723       }
1724 
1725       t->AppendBuildInterfaceIncludes();
1726 
1727       if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1728         continue;
1729       }
1730 
1731       for (auto const& def : noconfig_compile_definitions) {
1732         t->InsertCompileDefinition(def);
1733       }
1734 
1735       cmPolicies::PolicyStatus polSt =
1736         mf->GetPolicyStatus(cmPolicies::CMP0043);
1737       if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
1738         std::vector<std::string> configs =
1739           mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
1740 
1741         for (std::string const& c : configs) {
1742           std::string defPropName =
1743             cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
1744           if (cmValue val = mf->GetProperty(defPropName)) {
1745             t->AppendProperty(defPropName, *val);
1746           }
1747         }
1748       }
1749     }
1750 
1751     // The standard include directories for each language
1752     // should be treated as system include directories.
1753     std::set<std::string> standardIncludesSet;
1754     for (std::string const& li : langs) {
1755       std::string const standardIncludesVar =
1756         "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES";
1757       std::string const& standardIncludesStr =
1758         mf->GetSafeDefinition(standardIncludesVar);
1759       std::vector<std::string> standardIncludesVec =
1760         cmExpandedList(standardIncludesStr);
1761       standardIncludesSet.insert(standardIncludesVec.begin(),
1762                                  standardIncludesVec.end());
1763     }
1764     mf->AddSystemIncludeDirectories(standardIncludesSet);
1765   }
1766 }
1767 
CreateGeneratorTargets(TargetTypes targetTypes,cmMakefile * mf,cmLocalGenerator * lg,std::map<cmTarget *,cmGeneratorTarget * > const & importedMap)1768 void cmGlobalGenerator::CreateGeneratorTargets(
1769   TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
1770   std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
1771 {
1772   if (targetTypes == AllTargets) {
1773     for (cmTarget* target : mf->GetOrderedTargets()) {
1774       lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg));
1775     }
1776   }
1777 
1778   for (cmTarget* t : mf->GetImportedTargets()) {
1779     lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
1780   }
1781 }
1782 
CreateGeneratorTargets(TargetTypes targetTypes)1783 void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
1784 {
1785   std::map<cmTarget*, cmGeneratorTarget*> importedMap;
1786   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1787     auto& mf = this->Makefiles[i];
1788     for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) {
1789       cmLocalGenerator* lg = this->LocalGenerators[i].get();
1790       auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
1791       importedMap[ownedImpTgt.get()] = gt.get();
1792       lg->AddOwnedImportedGeneratorTarget(std::move(gt));
1793     }
1794   }
1795 
1796   // Construct per-target generator information.
1797   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1798     this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
1799                                  this->LocalGenerators[i].get(), importedMap);
1800   }
1801 }
1802 
ClearGeneratorMembers()1803 void cmGlobalGenerator::ClearGeneratorMembers()
1804 {
1805   this->BuildExportSets.clear();
1806 
1807   this->Makefiles.clear();
1808 
1809   this->LocalGenerators.clear();
1810 
1811   this->AliasTargets.clear();
1812   this->ExportSets.clear();
1813   this->InstallComponents.clear();
1814   this->TargetDependencies.clear();
1815   this->TargetSearchIndex.clear();
1816   this->GeneratorTargetSearchIndex.clear();
1817   this->MakefileSearchIndex.clear();
1818   this->LocalGeneratorSearchIndex.clear();
1819   this->TargetOrderIndex.clear();
1820   this->ProjectMap.clear();
1821   this->RuleHashes.clear();
1822   this->DirectoryContentMap.clear();
1823   this->BinaryDirectories.clear();
1824   this->GeneratedFiles.clear();
1825 }
1826 
ComputeTargetObjectDirectory(cmGeneratorTarget *) const1827 void cmGlobalGenerator::ComputeTargetObjectDirectory(
1828   cmGeneratorTarget* /*unused*/) const
1829 {
1830 }
1831 
CheckTargetProperties()1832 void cmGlobalGenerator::CheckTargetProperties()
1833 {
1834   // check for link libraries and include directories containing "NOTFOUND"
1835   // and for infinite loops
1836   std::map<std::string, std::string> notFoundMap;
1837   cmState* state = this->GetCMakeInstance()->GetState();
1838   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1839     this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
1840     for (auto const& target : this->Makefiles[i]->GetTargets()) {
1841       if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1842         continue;
1843       }
1844       for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
1845         if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) {
1846           std::string varName = lib.first.substr(0, lib.first.size() - 9);
1847           if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
1848             varName += " (ADVANCED)";
1849           }
1850           std::string text =
1851             cmStrCat(notFoundMap[varName], "\n    linked by target \"",
1852                      target.second.GetName(), "\" in directory ",
1853                      this->Makefiles[i]->GetCurrentSourceDirectory());
1854           notFoundMap[varName] = text;
1855         }
1856       }
1857       std::vector<std::string> incs;
1858       cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
1859       if (!incDirProp) {
1860         continue;
1861       }
1862 
1863       std::string incDirs = cmGeneratorExpression::Preprocess(
1864         *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
1865 
1866       cmExpandList(incDirs, incs);
1867 
1868       for (std::string const& incDir : incs) {
1869         if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) {
1870           std::string varName = incDir.substr(0, incDir.size() - 9);
1871           if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
1872             varName += " (ADVANCED)";
1873           }
1874           std::string text =
1875             cmStrCat(notFoundMap[varName],
1876                      "\n   used as include directory in directory ",
1877                      this->Makefiles[i]->GetCurrentSourceDirectory());
1878           notFoundMap[varName] = text;
1879         }
1880       }
1881     }
1882   }
1883 
1884   if (!notFoundMap.empty()) {
1885     std::string notFoundVars;
1886     for (auto const& notFound : notFoundMap) {
1887       notFoundVars += notFound.first;
1888       notFoundVars += notFound.second;
1889       notFoundVars += "\n";
1890     }
1891     cmSystemTools::Error("The following variables are used in this project, "
1892                          "but they are set to NOTFOUND.\n"
1893                          "Please set them or make sure they are set and "
1894                          "tested correctly in the CMake files:\n" +
1895                          notFoundVars);
1896   }
1897 }
1898 
TryCompile(int jobs,const std::string & srcdir,const std::string & bindir,const std::string & projectName,const std::string & target,bool fast,std::string & output,cmMakefile * mf)1899 int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
1900                                   const std::string& bindir,
1901                                   const std::string& projectName,
1902                                   const std::string& target, bool fast,
1903                                   std::string& output, cmMakefile* mf)
1904 {
1905   // if this is not set, then this is a first time configure
1906   // and there is a good chance that the try compile stuff will
1907   // take the bulk of the time, so try and guess some progress
1908   // by getting closer and closer to 100 without actually getting there.
1909   if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
1910         "CMAKE_NUMBER_OF_MAKEFILES")) {
1911     // If CMAKE_NUMBER_OF_MAKEFILES is not set
1912     // we are in the first time progress and we have no
1913     // idea how long it will be.  So, just move 1/10th of the way
1914     // there each time, and don't go over 95%
1915     this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
1916     if (this->FirstTimeProgress > 0.95f) {
1917       this->FirstTimeProgress = 0.95f;
1918     }
1919     this->CMakeInstance->UpdateProgress("Configuring",
1920                                         this->FirstTimeProgress);
1921   }
1922 
1923   std::vector<std::string> newTarget = {};
1924   if (!target.empty()) {
1925     newTarget = { target };
1926   }
1927   std::string config =
1928     mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
1929   return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
1930                      config, false, fast, false, this->TryCompileTimeout);
1931 }
1932 
1933 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
GenerateBuildCommand(const std::string &,const std::string &,const std::string &,std::vector<std::string> const &,const std::string &,bool,int,bool,std::vector<std::string> const &)1934 cmGlobalGenerator::GenerateBuildCommand(
1935   const std::string& /*unused*/, const std::string& /*unused*/,
1936   const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
1937   const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
1938   bool /*unused*/, std::vector<std::string> const& /*unused*/)
1939 {
1940   GeneratedMakeCommand makeCommand;
1941   makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
1942   return { std::move(makeCommand) };
1943 }
1944 
PrintBuildCommandAdvice(std::ostream &,int) const1945 void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
1946                                                 int /*jobs*/) const
1947 {
1948   // Subclasses override this method if they e.g want to give a warning that
1949   // they do not support certain build command line options
1950 }
1951 
Build(int jobs,const std::string &,const std::string & bindir,const std::string & projectName,const std::vector<std::string> & targets,std::string & output,const std::string & makeCommandCSTR,const std::string & config,bool clean,bool fast,bool verbose,cmDuration timeout,cmSystemTools::OutputOption outputflag,std::vector<std::string> const & nativeOptions)1952 int cmGlobalGenerator::Build(
1953   int jobs, const std::string& /*unused*/, const std::string& bindir,
1954   const std::string& projectName, const std::vector<std::string>& targets,
1955   std::string& output, const std::string& makeCommandCSTR,
1956   const std::string& config, bool clean, bool fast, bool verbose,
1957   cmDuration timeout, cmSystemTools::OutputOption outputflag,
1958   std::vector<std::string> const& nativeOptions)
1959 {
1960   bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
1961 
1962   /**
1963    * Run an executable command and put the stdout in output.
1964    */
1965   cmWorkingDirectory workdir(bindir);
1966   output += "Change Dir: ";
1967   output += bindir;
1968   output += "\n";
1969   if (workdir.Failed()) {
1970     cmSystemTools::SetRunCommandHideConsole(hideconsole);
1971     std::string err = cmStrCat("Failed to change directory: ",
1972                                std::strerror(workdir.GetLastResult()));
1973     cmSystemTools::Error(err);
1974     output += err;
1975     output += "\n";
1976     return 1;
1977   }
1978   std::string realConfig = config;
1979   if (realConfig.empty()) {
1980     realConfig = this->GetDefaultBuildConfig();
1981   }
1982 
1983   int retVal = 0;
1984   cmSystemTools::SetRunCommandHideConsole(true);
1985   std::string outputBuffer;
1986   std::string* outputPtr = &outputBuffer;
1987 
1988   std::vector<GeneratedMakeCommand> makeCommand =
1989     this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
1990                                realConfig, fast, jobs, verbose, nativeOptions);
1991 
1992   // Workaround to convince some commands to produce output.
1993   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
1994       makeCommand.back().RequiresOutputForward) {
1995     outputflag = cmSystemTools::OUTPUT_FORWARD;
1996   }
1997 
1998   // should we do a clean first?
1999   if (clean) {
2000     std::vector<GeneratedMakeCommand> cleanCommand =
2001       this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
2002                                  { "clean" }, realConfig, fast, jobs, verbose);
2003     output += "\nRun Clean Command:";
2004     output += cleanCommand.front().Printable();
2005     output += "\n";
2006     if (cleanCommand.size() != 1) {
2007       this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
2008                                              "The generator did not produce "
2009                                              "exactly one command for the "
2010                                              "'clean' target");
2011       return 1;
2012     }
2013     if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
2014                                          outputPtr, outputPtr, &retVal,
2015                                          nullptr, outputflag, timeout)) {
2016       cmSystemTools::SetRunCommandHideConsole(hideconsole);
2017       cmSystemTools::Error("Generator: execution of make clean failed.");
2018       output += *outputPtr;
2019       output += "\nGenerator: execution of make clean failed.\n";
2020 
2021       return 1;
2022     }
2023     output += *outputPtr;
2024   }
2025 
2026   // now build
2027   std::string makeCommandStr;
2028   output += "\nRun Build Command(s):";
2029 
2030   retVal = 0;
2031   for (auto command = makeCommand.begin();
2032        command != makeCommand.end() && retVal == 0; ++command) {
2033     makeCommandStr = command->Printable();
2034     if (command != makeCommand.end()) {
2035       makeCommandStr += " && ";
2036     }
2037 
2038     output += makeCommandStr;
2039     if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
2040                                          outputPtr, &retVal, nullptr,
2041                                          outputflag, timeout)) {
2042       cmSystemTools::SetRunCommandHideConsole(hideconsole);
2043       cmSystemTools::Error(
2044         "Generator: execution of make failed. Make command was: " +
2045         makeCommandStr);
2046       output += *outputPtr;
2047       output += "\nGenerator: execution of make failed. Make command was: " +
2048         makeCommandStr + "\n";
2049 
2050       return 1;
2051     }
2052     output += *outputPtr;
2053   }
2054   output += "\n";
2055   cmSystemTools::SetRunCommandHideConsole(hideconsole);
2056 
2057   // The OpenWatcom tools do not return an error code when a link
2058   // library is not found!
2059   if (this->CMakeInstance->GetState()->UseWatcomWMake() && retVal == 0 &&
2060       output.find("W1008: cannot open") != std::string::npos) {
2061     retVal = 1;
2062   }
2063 
2064   return retVal;
2065 }
2066 
Open(const std::string & bindir,const std::string & projectName,bool dryRun)2067 bool cmGlobalGenerator::Open(const std::string& bindir,
2068                              const std::string& projectName, bool dryRun)
2069 {
2070   if (this->ExtraGenerator) {
2071     return this->ExtraGenerator->Open(bindir, projectName, dryRun);
2072   }
2073 
2074   return false;
2075 }
2076 
GenerateCMakeBuildCommand(const std::string & target,const std::string & config,const std::string & parallel,const std::string & native,bool ignoreErrors)2077 std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
2078   const std::string& target, const std::string& config,
2079   const std::string& parallel, const std::string& native, bool ignoreErrors)
2080 {
2081   std::string makeCommand = cmSystemTools::GetCMakeCommand();
2082   makeCommand =
2083     cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build .");
2084   if (!config.empty()) {
2085     makeCommand += " --config \"";
2086     makeCommand += config;
2087     makeCommand += "\"";
2088   }
2089   if (!parallel.empty()) {
2090     makeCommand += " --parallel \"";
2091     makeCommand += parallel;
2092     makeCommand += "\"";
2093   }
2094   if (!target.empty()) {
2095     makeCommand += " --target \"";
2096     makeCommand += target;
2097     makeCommand += "\"";
2098   }
2099   const char* sep = " -- ";
2100   if (ignoreErrors) {
2101     const char* iflag = this->GetBuildIgnoreErrorsFlag();
2102     if (iflag && *iflag) {
2103       makeCommand += sep;
2104       makeCommand += iflag;
2105       sep = " ";
2106     }
2107   }
2108   if (!native.empty()) {
2109     makeCommand += sep;
2110     makeCommand += native;
2111   }
2112   return makeCommand;
2113 }
2114 
AddMakefile(std::unique_ptr<cmMakefile> mf)2115 void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
2116 {
2117   this->IndexMakefile(mf.get());
2118   this->Makefiles.push_back(std::move(mf));
2119 
2120   // update progress
2121   // estimate how many lg there will be
2122   cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
2123     "CMAKE_NUMBER_OF_MAKEFILES");
2124 
2125   if (!numGenC) {
2126     // If CMAKE_NUMBER_OF_MAKEFILES is not set
2127     // we are in the first time progress and we have no
2128     // idea how long it will be.  So, just move half way
2129     // there each time, and don't go over 95%
2130     this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2131     if (this->FirstTimeProgress > 0.95f) {
2132       this->FirstTimeProgress = 0.95f;
2133     }
2134     this->CMakeInstance->UpdateProgress("Configuring",
2135                                         this->FirstTimeProgress);
2136     return;
2137   }
2138 
2139   int numGen = atoi(numGenC->c_str());
2140   float prog =
2141     static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
2142   if (prog > 1.0f) {
2143     prog = 1.0f;
2144   }
2145   this->CMakeInstance->UpdateProgress("Configuring", prog);
2146 }
2147 
AddInstallComponent(const std::string & component)2148 void cmGlobalGenerator::AddInstallComponent(const std::string& component)
2149 {
2150   if (!component.empty()) {
2151     this->InstallComponents.insert(component);
2152   }
2153 }
2154 
MarkAsGeneratedFile(const std::string & filepath)2155 void cmGlobalGenerator::MarkAsGeneratedFile(const std::string& filepath)
2156 {
2157   this->GeneratedFiles.insert(filepath);
2158 }
2159 
IsGeneratedFile(const std::string & filepath)2160 bool cmGlobalGenerator::IsGeneratedFile(const std::string& filepath)
2161 {
2162   return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
2163 }
2164 
EnableInstallTarget()2165 void cmGlobalGenerator::EnableInstallTarget()
2166 {
2167   this->InstallTargetEnabled = true;
2168 }
2169 
CreateLocalGenerator(cmMakefile * mf)2170 std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
2171   cmMakefile* mf)
2172 {
2173   return cm::make_unique<cmLocalGenerator>(this, mf);
2174 }
2175 
EnableLanguagesFromGenerator(cmGlobalGenerator * gen,cmMakefile * mf)2176 void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
2177                                                      cmMakefile* mf)
2178 {
2179   this->SetConfiguredFilesPath(gen);
2180   this->TryCompileOuterMakefile = mf;
2181   cmValue make =
2182     gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
2183   this->GetCMakeInstance()->AddCacheEntry(
2184     "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
2185   // copy the enabled languages
2186   this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
2187     gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
2188   this->LanguagesReady = gen->LanguagesReady;
2189   this->ExtensionToLanguage = gen->ExtensionToLanguage;
2190   this->IgnoreExtensions = gen->IgnoreExtensions;
2191   this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
2192   this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
2193   this->OutputExtensions = gen->OutputExtensions;
2194 }
2195 
SetConfiguredFilesPath(cmGlobalGenerator * gen)2196 void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
2197 {
2198   if (!gen->ConfiguredFilesPath.empty()) {
2199     this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
2200   } else {
2201     this->ConfiguredFilesPath =
2202       cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
2203   }
2204 }
2205 
IsExcluded(cmStateSnapshot const & rootSnp,cmStateSnapshot const & snp_) const2206 bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp,
2207                                    cmStateSnapshot const& snp_) const
2208 {
2209   cmStateSnapshot snp = snp_;
2210   while (snp.IsValid()) {
2211     if (snp == rootSnp) {
2212       // No directory excludes itself.
2213       return false;
2214     }
2215 
2216     if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
2217       // This directory is excluded from its parent.
2218       return true;
2219     }
2220     snp = snp.GetBuildsystemDirectoryParent();
2221   }
2222   return false;
2223 }
2224 
IsExcluded(cmLocalGenerator * root,cmLocalGenerator * gen) const2225 bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
2226                                    cmLocalGenerator* gen) const
2227 {
2228   assert(gen);
2229 
2230   cmStateSnapshot rootSnp = root->GetStateSnapshot();
2231   cmStateSnapshot snp = gen->GetStateSnapshot();
2232 
2233   return this->IsExcluded(rootSnp, snp);
2234 }
2235 
IsExcluded(cmLocalGenerator * root,const cmGeneratorTarget * target) const2236 bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
2237                                    const cmGeneratorTarget* target) const
2238 {
2239   if (!target->IsInBuildSystem()) {
2240     return true;
2241   }
2242   cmMakefile* mf = root->GetMakefile();
2243   const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
2244   if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
2245     // Expand the property value per configuration.
2246     unsigned int trueCount = 0;
2247     unsigned int falseCount = 0;
2248     const std::vector<std::string>& configs =
2249       mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2250     for (const std::string& config : configs) {
2251       cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
2252       if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
2253         ++trueCount;
2254       } else {
2255         ++falseCount;
2256       }
2257     }
2258 
2259     // Check whether the genex expansion of the property agrees in all
2260     // configurations.
2261     if (trueCount > 0 && falseCount > 0) {
2262       std::ostringstream e;
2263       e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName()
2264         << "\" varies by configuration. This is not supported by the \""
2265         << root->GetGlobalGenerator()->GetName() << "\" generator.";
2266       mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
2267     }
2268     return trueCount;
2269   }
2270   // This target is included in its directory.  Check whether the
2271   // directory is excluded.
2272   return this->IsExcluded(root, target->GetLocalGenerator());
2273 }
2274 
GetEnabledLanguages(std::vector<std::string> & lang) const2275 void cmGlobalGenerator::GetEnabledLanguages(
2276   std::vector<std::string>& lang) const
2277 {
2278   lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
2279 }
2280 
GetLinkerPreference(const std::string & lang) const2281 int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
2282 {
2283   auto const it = this->LanguageToLinkerPreference.find(lang);
2284   if (it != this->LanguageToLinkerPreference.end()) {
2285     return it->second;
2286   }
2287   return 0;
2288 }
2289 
FillProjectMap()2290 void cmGlobalGenerator::FillProjectMap()
2291 {
2292   this->ProjectMap.clear(); // make sure we start with a clean map
2293   for (const auto& localGen : this->LocalGenerators) {
2294     // for each local generator add all projects
2295     cmStateSnapshot snp = localGen->GetStateSnapshot();
2296     std::string name;
2297     do {
2298       std::string snpProjName = snp.GetProjectName();
2299       if (name != snpProjName) {
2300         name = snpProjName;
2301         this->ProjectMap[name].push_back(localGen.get());
2302       }
2303       snp = snp.GetBuildsystemDirectoryParent();
2304     } while (snp.IsValid());
2305   }
2306 }
2307 
FindMakefile(const std::string & start_dir) const2308 cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
2309 {
2310   auto const it = this->MakefileSearchIndex.find(start_dir);
2311   if (it != this->MakefileSearchIndex.end()) {
2312     return it->second;
2313   }
2314   return nullptr;
2315 }
2316 
FindLocalGenerator(cmDirectoryId const & id) const2317 cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
2318   cmDirectoryId const& id) const
2319 {
2320   auto const it = this->LocalGeneratorSearchIndex.find(id.String);
2321   if (it != this->LocalGeneratorSearchIndex.end()) {
2322     return it->second;
2323   }
2324   return nullptr;
2325 }
2326 
AddAlias(const std::string & name,std::string const & tgtName)2327 void cmGlobalGenerator::AddAlias(const std::string& name,
2328                                  std::string const& tgtName)
2329 {
2330   this->AliasTargets[name] = tgtName;
2331 }
2332 
IsAlias(const std::string & name) const2333 bool cmGlobalGenerator::IsAlias(const std::string& name) const
2334 {
2335   return cm::contains(this->AliasTargets, name);
2336 }
2337 
IndexTarget(cmTarget * t)2338 void cmGlobalGenerator::IndexTarget(cmTarget* t)
2339 {
2340   if (!t->IsImported() || t->IsImportedGloballyVisible()) {
2341     this->TargetSearchIndex[t->GetName()] = t;
2342   }
2343 }
2344 
IndexGeneratorTarget(cmGeneratorTarget * gt)2345 void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
2346 {
2347   if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
2348     this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
2349   }
2350 }
2351 
2352 static char const hexDigits[] = "0123456789abcdef";
2353 
IndexGeneratorTargetUniquely(cmGeneratorTarget const * gt)2354 std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
2355   cmGeneratorTarget const* gt)
2356 {
2357   // Use the pointer value to uniquely identify the target instance.
2358   // Use a ":" prefix to avoid conflict with project-defined targets.
2359   // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
2360   // other special characters.
2361   constexpr size_t sizeof_ptr =
2362     sizeof(gt); // NOLINT(bugprone-sizeof-expression)
2363   char buf[1 + sizeof_ptr * 2];
2364   char* b = buf;
2365   *b++ = ':';
2366   for (size_t i = 0; i < sizeof_ptr; ++i) {
2367     unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
2368     *b++ = hexDigits[(c & 0xf0) >> 4];
2369     *b++ = hexDigits[(c & 0x0f)];
2370   }
2371   std::string id(buf, sizeof(buf));
2372   // We internally index pointers to non-const generator targets
2373   // but our callers only have pointers to const generator targets.
2374   // They will give up non-const privileges when looking up anyway.
2375   this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
2376   return id;
2377 }
2378 
IndexMakefile(cmMakefile * mf)2379 void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
2380 {
2381   // We index by both source and binary directory.  add_subdirectory
2382   // supports multiple build directories sharing the same source directory.
2383   // The source directory index will reference only the first time it is used.
2384   this->MakefileSearchIndex.insert(
2385     MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
2386   this->MakefileSearchIndex.insert(
2387     MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf));
2388 }
2389 
IndexLocalGenerator(cmLocalGenerator * lg)2390 void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
2391 {
2392   cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
2393   this->LocalGeneratorSearchIndex[id.String] = lg;
2394 }
2395 
FindTargetImpl(std::string const & name) const2396 cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
2397 {
2398   auto const it = this->TargetSearchIndex.find(name);
2399   if (it != this->TargetSearchIndex.end()) {
2400     return it->second;
2401   }
2402   return nullptr;
2403 }
2404 
FindGeneratorTargetImpl(std::string const & name) const2405 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
2406   std::string const& name) const
2407 {
2408   auto const it = this->GeneratorTargetSearchIndex.find(name);
2409   if (it != this->GeneratorTargetSearchIndex.end()) {
2410     return it->second;
2411   }
2412   return nullptr;
2413 }
2414 
FindTarget(const std::string & name,bool excludeAliases) const2415 cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
2416                                         bool excludeAliases) const
2417 {
2418   if (!excludeAliases) {
2419     auto const ai = this->AliasTargets.find(name);
2420     if (ai != this->AliasTargets.end()) {
2421       return this->FindTargetImpl(ai->second);
2422     }
2423   }
2424   return this->FindTargetImpl(name);
2425 }
2426 
FindGeneratorTarget(const std::string & name) const2427 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
2428   const std::string& name) const
2429 {
2430   auto const ai = this->AliasTargets.find(name);
2431   if (ai != this->AliasTargets.end()) {
2432     return this->FindGeneratorTargetImpl(ai->second);
2433   }
2434   return this->FindGeneratorTargetImpl(name);
2435 }
2436 
NameResolvesToFramework(const std::string & libname) const2437 bool cmGlobalGenerator::NameResolvesToFramework(
2438   const std::string& libname) const
2439 {
2440   if (cmSystemTools::IsPathToFramework(libname)) {
2441     return true;
2442   }
2443 
2444   if (cmTarget* tgt = this->FindTarget(libname)) {
2445     if (tgt->IsFrameworkOnApple()) {
2446       return true;
2447     }
2448   }
2449 
2450   return false;
2451 }
2452 
CheckCMP0037(std::string const & targetName,std::string const & reason) const2453 bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
2454                                      std::string const& reason) const
2455 {
2456   cmTarget* tgt = this->FindTarget(targetName);
2457   if (!tgt) {
2458     return true;
2459   }
2460   MessageType messageType = MessageType::AUTHOR_WARNING;
2461   std::ostringstream e;
2462   bool issueMessage = false;
2463   switch (tgt->GetPolicyStatusCMP0037()) {
2464     case cmPolicies::WARN:
2465       e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
2466       issueMessage = true;
2467       CM_FALLTHROUGH;
2468     case cmPolicies::OLD:
2469       break;
2470     case cmPolicies::NEW:
2471     case cmPolicies::REQUIRED_IF_USED:
2472     case cmPolicies::REQUIRED_ALWAYS:
2473       issueMessage = true;
2474       messageType = MessageType::FATAL_ERROR;
2475       break;
2476   }
2477   if (issueMessage) {
2478     e << "The target name \"" << targetName << "\" is reserved " << reason
2479       << ".";
2480     if (messageType == MessageType::AUTHOR_WARNING) {
2481       e << "  It may result in undefined behavior.";
2482     }
2483     this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
2484                                            tgt->GetBacktrace());
2485     if (messageType == MessageType::FATAL_ERROR) {
2486       return false;
2487     }
2488   }
2489   return true;
2490 }
2491 
CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo> & targets)2492 void cmGlobalGenerator::CreateDefaultGlobalTargets(
2493   std::vector<GlobalTargetInfo>& targets)
2494 {
2495   this->AddGlobalTarget_Package(targets);
2496   this->AddGlobalTarget_PackageSource(targets);
2497   this->AddGlobalTarget_Test(targets);
2498   this->AddGlobalTarget_EditCache(targets);
2499   this->AddGlobalTarget_RebuildCache(targets);
2500   this->AddGlobalTarget_Install(targets);
2501 }
2502 
AddGlobalTarget_Package(std::vector<GlobalTargetInfo> & targets)2503 void cmGlobalGenerator::AddGlobalTarget_Package(
2504   std::vector<GlobalTargetInfo>& targets)
2505 {
2506   auto& mf = this->Makefiles[0];
2507   std::string configFile =
2508     cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
2509   if (!cmSystemTools::FileExists(configFile)) {
2510     return;
2511   }
2512 
2513   static const auto reservedTargets = { "package", "PACKAGE" };
2514   for (auto const& target : reservedTargets) {
2515     if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
2516       return;
2517     }
2518   }
2519 
2520   const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2521   GlobalTargetInfo gti;
2522   gti.Name = this->GetPackageTargetName();
2523   gti.Message = "Run CPack packaging tool...";
2524   gti.UsesTerminal = true;
2525   gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2526   cmCustomCommandLine singleLine;
2527   singleLine.push_back(cmSystemTools::GetCPackCommand());
2528   if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2529     singleLine.push_back("-C");
2530     singleLine.push_back(cmakeCfgIntDir);
2531   }
2532   singleLine.push_back("--config");
2533   singleLine.push_back("./CPackConfig.cmake");
2534   gti.CommandLines.push_back(std::move(singleLine));
2535   if (this->GetPreinstallTargetName()) {
2536     gti.Depends.emplace_back(this->GetPreinstallTargetName());
2537   } else {
2538     cmValue noPackageAll =
2539       mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
2540     if (cmIsOff(noPackageAll)) {
2541       gti.Depends.emplace_back(this->GetAllTargetName());
2542     }
2543   }
2544   targets.push_back(std::move(gti));
2545 }
2546 
AddGlobalTarget_PackageSource(std::vector<GlobalTargetInfo> & targets)2547 void cmGlobalGenerator::AddGlobalTarget_PackageSource(
2548   std::vector<GlobalTargetInfo>& targets)
2549 {
2550   const char* packageSourceTargetName = this->GetPackageSourceTargetName();
2551   if (!packageSourceTargetName) {
2552     return;
2553   }
2554 
2555   auto& mf = this->Makefiles[0];
2556   std::string configFile =
2557     cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
2558   if (!cmSystemTools::FileExists(configFile)) {
2559     return;
2560   }
2561 
2562   static const auto reservedTargets = { "package_source" };
2563   for (auto const& target : reservedTargets) {
2564     if (!this->CheckCMP0037(target,
2565                             "when CPack source packaging is enabled")) {
2566       return;
2567     }
2568   }
2569 
2570   GlobalTargetInfo gti;
2571   gti.Name = packageSourceTargetName;
2572   gti.Message = "Run CPack packaging tool for source...";
2573   gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2574   gti.UsesTerminal = true;
2575   cmCustomCommandLine singleLine;
2576   singleLine.push_back(cmSystemTools::GetCPackCommand());
2577   singleLine.push_back("--config");
2578   singleLine.push_back("./CPackSourceConfig.cmake");
2579   singleLine.push_back(std::move(configFile));
2580   gti.CommandLines.push_back(std::move(singleLine));
2581   targets.push_back(std::move(gti));
2582 }
2583 
AddGlobalTarget_Test(std::vector<GlobalTargetInfo> & targets)2584 void cmGlobalGenerator::AddGlobalTarget_Test(
2585   std::vector<GlobalTargetInfo>& targets)
2586 {
2587   auto& mf = this->Makefiles[0];
2588   if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
2589     return;
2590   }
2591 
2592   static const auto reservedTargets = { "test", "RUN_TESTS" };
2593   for (auto const& target : reservedTargets) {
2594     if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
2595       return;
2596     }
2597   }
2598 
2599   const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2600   GlobalTargetInfo gti;
2601   gti.Name = this->GetTestTargetName();
2602   gti.Message = "Running tests...";
2603   gti.UsesTerminal = true;
2604   cmCustomCommandLine singleLine;
2605   singleLine.push_back(cmSystemTools::GetCTestCommand());
2606   singleLine.push_back("--force-new-ctest-process");
2607   std::vector<std::string> args;
2608   if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) {
2609     for (auto const& arg : args) {
2610       singleLine.push_back(arg);
2611     }
2612   }
2613   if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2614     singleLine.push_back("-C");
2615     singleLine.push_back(cmakeCfgIntDir);
2616   } else // TODO: This is a hack. Should be something to do with the
2617          // generator
2618   {
2619     singleLine.push_back("$(ARGS)");
2620   }
2621   gti.CommandLines.push_back(std::move(singleLine));
2622   targets.push_back(std::move(gti));
2623 }
2624 
AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo> & targets) const2625 void cmGlobalGenerator::AddGlobalTarget_EditCache(
2626   std::vector<GlobalTargetInfo>& targets) const
2627 {
2628   const char* editCacheTargetName = this->GetEditCacheTargetName();
2629   if (!editCacheTargetName) {
2630     return;
2631   }
2632   GlobalTargetInfo gti;
2633   gti.Name = editCacheTargetName;
2634   gti.PerConfig = cmTarget::PerConfig::No;
2635   cmCustomCommandLine singleLine;
2636 
2637   // Use generator preference for the edit_cache rule if it is defined.
2638   std::string edit_cmd = this->GetEditCacheCommand();
2639   if (!edit_cmd.empty()) {
2640     singleLine.push_back(std::move(edit_cmd));
2641     singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2642     singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2643     gti.Message = "Running CMake cache editor...";
2644     gti.UsesTerminal = true;
2645   } else {
2646     singleLine.push_back(cmSystemTools::GetCMakeCommand());
2647     singleLine.push_back("-E");
2648     singleLine.push_back("echo");
2649     singleLine.push_back("No interactive CMake dialog available.");
2650     gti.Message = "No interactive CMake dialog available...";
2651     gti.UsesTerminal = false;
2652     gti.StdPipesUTF8 = true;
2653   }
2654   gti.CommandLines.push_back(std::move(singleLine));
2655 
2656   targets.push_back(std::move(gti));
2657 }
2658 
AddGlobalTarget_RebuildCache(std::vector<GlobalTargetInfo> & targets) const2659 void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
2660   std::vector<GlobalTargetInfo>& targets) const
2661 {
2662   const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
2663   if (!rebuildCacheTargetName) {
2664     return;
2665   }
2666   GlobalTargetInfo gti;
2667   gti.Name = rebuildCacheTargetName;
2668   gti.Message = "Running CMake to regenerate build system...";
2669   gti.UsesTerminal = true;
2670   gti.PerConfig = cmTarget::PerConfig::No;
2671   cmCustomCommandLine singleLine;
2672   singleLine.push_back(cmSystemTools::GetCMakeCommand());
2673   singleLine.push_back("--regenerate-during-build");
2674   singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2675   singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2676   gti.CommandLines.push_back(std::move(singleLine));
2677   gti.StdPipesUTF8 = true;
2678   targets.push_back(std::move(gti));
2679 }
2680 
AddGlobalTarget_Install(std::vector<GlobalTargetInfo> & targets)2681 void cmGlobalGenerator::AddGlobalTarget_Install(
2682   std::vector<GlobalTargetInfo>& targets)
2683 {
2684   auto& mf = this->Makefiles[0];
2685   const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2686   bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
2687   if (this->InstallTargetEnabled && skipInstallRules) {
2688     this->CMakeInstance->IssueMessage(
2689       MessageType::WARNING,
2690       "CMAKE_SKIP_INSTALL_RULES was enabled even though "
2691       "installation rules have been specified",
2692       mf->GetBacktrace());
2693   } else if (this->InstallTargetEnabled && !skipInstallRules) {
2694     if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
2695       std::set<std::string>* componentsSet = &this->InstallComponents;
2696       std::ostringstream ostr;
2697       if (!componentsSet->empty()) {
2698         ostr << "Available install components are: ";
2699         ostr << cmWrap('"', *componentsSet, '"', " ");
2700       } else {
2701         ostr << "Only default component available";
2702       }
2703       GlobalTargetInfo gti;
2704       gti.Name = "list_install_components";
2705       gti.Message = ostr.str();
2706       gti.UsesTerminal = false;
2707       targets.push_back(std::move(gti));
2708     }
2709     std::string cmd = cmSystemTools::GetCMakeCommand();
2710     GlobalTargetInfo gti;
2711     gti.Name = this->GetInstallTargetName();
2712     gti.Message = "Install the project...";
2713     gti.UsesTerminal = true;
2714     gti.StdPipesUTF8 = true;
2715     cmCustomCommandLine singleLine;
2716     if (this->GetPreinstallTargetName()) {
2717       gti.Depends.emplace_back(this->GetPreinstallTargetName());
2718     } else {
2719       cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
2720       if (cmIsOff(noall)) {
2721         gti.Depends.emplace_back(this->GetAllTargetName());
2722       }
2723     }
2724     if (mf->GetDefinition("CMake_BINARY_DIR") &&
2725         !mf->IsOn("CMAKE_CROSSCOMPILING")) {
2726       // We are building CMake itself.  We cannot use the original
2727       // executable to install over itself.  The generator will
2728       // automatically convert this name to the build-time location.
2729       cmd = "cmake";
2730     }
2731     singleLine.push_back(cmd);
2732     if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2733       std::string cfgArg = "-DBUILD_TYPE=";
2734       bool useEPN = this->UseEffectivePlatformName(mf.get());
2735       if (useEPN) {
2736         cfgArg += "$(CONFIGURATION)";
2737         singleLine.push_back(cfgArg);
2738         cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
2739       } else {
2740         cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR");
2741       }
2742       singleLine.push_back(cfgArg);
2743     }
2744     singleLine.push_back("-P");
2745     singleLine.push_back("cmake_install.cmake");
2746     gti.CommandLines.push_back(singleLine);
2747     targets.push_back(gti);
2748 
2749     // install_local
2750     if (const char* install_local = this->GetInstallLocalTargetName()) {
2751       gti.Name = install_local;
2752       gti.Message = "Installing only the local directory...";
2753       gti.UsesTerminal = true;
2754       gti.CommandLines.clear();
2755 
2756       cmCustomCommandLine localCmdLine = singleLine;
2757 
2758       localCmdLine.insert(localCmdLine.begin() + 1,
2759                           "-DCMAKE_INSTALL_LOCAL_ONLY=1");
2760 
2761       gti.CommandLines.push_back(std::move(localCmdLine));
2762       targets.push_back(gti);
2763     }
2764 
2765     // install_strip
2766     const char* install_strip = this->GetInstallStripTargetName();
2767     if ((install_strip != nullptr) && (mf->IsSet("CMAKE_STRIP"))) {
2768       gti.Name = install_strip;
2769       gti.Message = "Installing the project stripped...";
2770       gti.UsesTerminal = true;
2771       gti.CommandLines.clear();
2772 
2773       cmCustomCommandLine stripCmdLine = singleLine;
2774 
2775       stripCmdLine.insert(stripCmdLine.begin() + 1,
2776                           "-DCMAKE_INSTALL_DO_STRIP=1");
2777       gti.CommandLines.push_back(std::move(stripCmdLine));
2778       targets.push_back(gti);
2779     }
2780   }
2781 }
2782 
GetPredefinedTargetsFolder() const2783 std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
2784 {
2785   cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
2786     "PREDEFINED_TARGETS_FOLDER");
2787 
2788   if (prop) {
2789     return *prop;
2790   }
2791 
2792   return "CMakePredefinedTargets";
2793 }
2794 
UseFolderProperty() const2795 bool cmGlobalGenerator::UseFolderProperty() const
2796 {
2797   cmValue prop =
2798     this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
2799 
2800   // If this property is defined, let the setter turn this on or off...
2801   //
2802   if (prop) {
2803     return cmIsOn(*prop);
2804   }
2805 
2806   // By default, this feature is OFF, since it is not supported in the
2807   // Visual Studio Express editions until VS11:
2808   //
2809   return false;
2810 }
2811 
CreateGlobalTarget(GlobalTargetInfo const & gti,cmMakefile * mf)2812 void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
2813                                            cmMakefile* mf)
2814 {
2815   // Package
2816   auto tb =
2817     mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig);
2818 
2819   // Do nothing if gti.Name is already used
2820   if (!tb.second) {
2821     return;
2822   }
2823 
2824   cmTarget& target = tb.first;
2825   target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2826 
2827   std::vector<std::string> no_outputs;
2828   std::vector<std::string> no_byproducts;
2829   std::vector<std::string> no_depends;
2830   // Store the custom command in the target.
2831   cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines,
2832                      cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str(),
2833                      gti.StdPipesUTF8);
2834   cc.SetUsesTerminal(gti.UsesTerminal);
2835   target.AddPostBuildCommand(std::move(cc));
2836   if (!gti.Message.empty()) {
2837     target.SetProperty("EchoString", gti.Message);
2838   }
2839   for (std::string const& d : gti.Depends) {
2840     target.AddUtility(d, false);
2841   }
2842 
2843   // Organize in the "predefined targets" folder:
2844   //
2845   if (this->UseFolderProperty()) {
2846     target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
2847   }
2848 }
2849 
GenerateRuleFile(std::string const & output) const2850 std::string cmGlobalGenerator::GenerateRuleFile(
2851   std::string const& output) const
2852 {
2853   std::string ruleFile = cmStrCat(output, ".rule");
2854   const char* dir = this->GetCMakeCFGIntDir();
2855   if (dir && dir[0] == '$') {
2856     cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
2857   }
2858   return ruleFile;
2859 }
2860 
ShouldStripResourcePath(cmMakefile * mf) const2861 bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
2862 {
2863   return mf->PlatformIsAppleEmbedded();
2864 }
2865 
GetSharedLibFlagsForLanguage(std::string const & l) const2866 std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
2867   std::string const& l) const
2868 {
2869   auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
2870   if (it != this->LanguageToOriginalSharedLibFlags.end()) {
2871     return it->second;
2872   }
2873   return "";
2874 }
2875 
AppendDirectoryForConfig(const std::string &,const std::string &,const std::string &,std::string &)2876 void cmGlobalGenerator::AppendDirectoryForConfig(const std::string& /*unused*/,
2877                                                  const std::string& /*unused*/,
2878                                                  const std::string& /*unused*/,
2879                                                  std::string& /*unused*/)
2880 {
2881   // Subclasses that support multiple configurations should implement
2882   // this method to append the subdirectory for the given build
2883   // configuration.
2884 }
2885 
2886 cmGlobalGenerator::TargetDependSet const&
GetTargetDirectDepends(cmGeneratorTarget const * target)2887 cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target)
2888 {
2889   return this->TargetDependencies[target];
2890 }
2891 
IsReservedTarget(std::string const & name)2892 bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
2893 {
2894   // The following is a list of targets reserved
2895   // by one or more of the cmake generators.
2896 
2897   // Adding additional targets to this list will require a policy!
2898   const char* reservedTargets[] = { "all",       "ALL_BUILD",  "help",
2899                                     "install",   "INSTALL",    "preinstall",
2900                                     "clean",     "edit_cache", "rebuild_cache",
2901                                     "ZERO_CHECK" };
2902 
2903   return cm::contains(reservedTargets, name);
2904 }
2905 
SetExternalMakefileProjectGenerator(std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)2906 void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
2907   std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
2908 {
2909   this->ExtraGenerator = std::move(extraGenerator);
2910   if (this->ExtraGenerator) {
2911     this->ExtraGenerator->SetGlobalGenerator(this);
2912   }
2913 }
2914 
GetExtraGeneratorName() const2915 std::string cmGlobalGenerator::GetExtraGeneratorName() const
2916 {
2917   return this->ExtraGenerator ? this->ExtraGenerator->GetName()
2918                               : std::string();
2919 }
2920 
FileReplacedDuringGenerate(const std::string & filename)2921 void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
2922 {
2923   this->FilesReplacedDuringGenerate.push_back(filename);
2924 }
2925 
GetFilesReplacedDuringGenerate(std::vector<std::string> & filenames)2926 void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
2927   std::vector<std::string>& filenames)
2928 {
2929   filenames.clear();
2930   std::copy(this->FilesReplacedDuringGenerate.begin(),
2931             this->FilesReplacedDuringGenerate.end(),
2932             std::back_inserter(filenames));
2933 }
2934 
GetTargetSets(TargetDependSet & projectTargets,TargetDependSet & originalTargets,cmLocalGenerator * root,std::vector<cmLocalGenerator * > & generators)2935 void cmGlobalGenerator::GetTargetSets(
2936   TargetDependSet& projectTargets, TargetDependSet& originalTargets,
2937   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
2938 {
2939   // loop over all local generators
2940   for (auto* generator : generators) {
2941     // check to make sure generator is not excluded
2942     if (this->IsExcluded(root, generator)) {
2943       continue;
2944     }
2945     // loop over all the generator targets in the makefile
2946     for (const auto& target : generator->GetGeneratorTargets()) {
2947       if (this->IsRootOnlyTarget(target.get()) &&
2948           target->GetLocalGenerator() != root) {
2949         continue;
2950       }
2951       // put the target in the set of original targets
2952       originalTargets.insert(target.get());
2953       // Get the set of targets that depend on target
2954       this->AddTargetDepends(target.get(), projectTargets);
2955     }
2956   }
2957 }
2958 
IsRootOnlyTarget(cmGeneratorTarget * target) const2959 bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
2960 {
2961   return (target->GetType() == cmStateEnums::GLOBAL_TARGET ||
2962           target->GetName() == this->GetAllTargetName());
2963 }
2964 
AddTargetDepends(cmGeneratorTarget const * target,TargetDependSet & projectTargets)2965 void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
2966                                          TargetDependSet& projectTargets)
2967 {
2968   // add the target itself
2969   if (projectTargets.insert(target).second) {
2970     // This is the first time we have encountered the target.
2971     // Recursively follow its dependencies.
2972     for (auto const& t : this->GetTargetDirectDepends(target)) {
2973       this->AddTargetDepends(t, projectTargets);
2974     }
2975   }
2976 }
2977 
AddToManifest(std::string const & f)2978 void cmGlobalGenerator::AddToManifest(std::string const& f)
2979 {
2980   // Add to the content listing for the file's directory.
2981   std::string dir = cmSystemTools::GetFilenamePath(f);
2982   std::string file = cmSystemTools::GetFilenameName(f);
2983   DirectoryContent& dc = this->DirectoryContentMap[dir];
2984   dc.Generated.insert(file);
2985   dc.All.insert(file);
2986 }
2987 
GetDirectoryContent(std::string const & dir,bool needDisk)2988 std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
2989   std::string const& dir, bool needDisk)
2990 {
2991   DirectoryContent& dc = this->DirectoryContentMap[dir];
2992   if (needDisk) {
2993     long mt = cmSystemTools::ModifiedTime(dir);
2994     if (mt != dc.LastDiskTime) {
2995       // Reset to non-loaded directory content.
2996       dc.All = dc.Generated;
2997 
2998       // Load the directory content from disk.
2999       cmsys::Directory d;
3000       if (d.Load(dir)) {
3001         unsigned long n = d.GetNumberOfFiles();
3002         for (unsigned long i = 0; i < n; ++i) {
3003           const char* f = d.GetFile(i);
3004           if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
3005             dc.All.insert(f);
3006           }
3007         }
3008       }
3009       dc.LastDiskTime = mt;
3010     }
3011   }
3012   return dc.All;
3013 }
3014 
AddRuleHash(const std::vector<std::string> & outputs,std::string const & content)3015 void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
3016                                     std::string const& content)
3017 {
3018 #if !defined(CMAKE_BOOTSTRAP)
3019   // Ignore if there are no outputs.
3020   if (outputs.empty()) {
3021     return;
3022   }
3023 
3024   // Compute a hash of the rule.
3025   RuleHash hash;
3026   {
3027     cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3028     std::string const md5_hex = md5.HashString(content);
3029     memcpy(hash.Data, md5_hex.c_str(), 32);
3030   }
3031 
3032   // Shorten the output name (in expected use case).
3033   std::string fname =
3034     this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]);
3035 
3036   // Associate the hash with this output.
3037   this->RuleHashes[fname] = hash;
3038 #else
3039   (void)outputs;
3040   (void)content;
3041 #endif
3042 }
3043 
CheckRuleHashes()3044 void cmGlobalGenerator::CheckRuleHashes()
3045 {
3046 #if !defined(CMAKE_BOOTSTRAP)
3047   std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
3048   std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
3049   this->CheckRuleHashes(pfile, home);
3050   this->WriteRuleHashes(pfile);
3051 #endif
3052 }
3053 
CheckRuleHashes(std::string const & pfile,std::string const & home)3054 void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
3055                                         std::string const& home)
3056 {
3057 #if defined(_WIN32) || defined(__CYGWIN__)
3058   cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
3059 #else
3060   cmsys::ifstream fin(pfile.c_str());
3061 #endif
3062   if (!fin) {
3063     return;
3064   }
3065   std::string line;
3066   std::string fname;
3067   while (cmSystemTools::GetLineFromStream(fin, line)) {
3068     // Line format is a 32-byte hex string followed by a space
3069     // followed by a file name (with no escaping).
3070 
3071     // Skip blank and comment lines.
3072     if (line.size() < 34 || line[0] == '#') {
3073       continue;
3074     }
3075 
3076     // Get the filename.
3077     fname = line.substr(33);
3078 
3079     // Look for a hash for this file's rule.
3080     auto const rhi = this->RuleHashes.find(fname);
3081     if (rhi != this->RuleHashes.end()) {
3082       // Compare the rule hash in the file to that we were given.
3083       if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
3084         // The rule has changed.  Delete the output so it will be
3085         // built again.
3086         fname = cmSystemTools::CollapseFullPath(fname, home);
3087         cmSystemTools::RemoveFile(fname);
3088       }
3089     } else {
3090       // We have no hash for a rule previously listed.  This may be a
3091       // case where a user has turned off a build option and might
3092       // want to turn it back on later, so do not delete the file.
3093       // Instead, we keep the rule hash as long as the file exists so
3094       // that if the feature is turned back on and the rule has
3095       // changed the file is still rebuilt.
3096       std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
3097       if (cmSystemTools::FileExists(fpath)) {
3098         RuleHash hash;
3099         memcpy(hash.Data, line.c_str(), 32);
3100         this->RuleHashes[fname] = hash;
3101       }
3102     }
3103   }
3104 }
3105 
WriteRuleHashes(std::string const & pfile)3106 void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
3107 {
3108   // Now generate a new persistence file with the current hashes.
3109   if (this->RuleHashes.empty()) {
3110     cmSystemTools::RemoveFile(pfile);
3111   } else {
3112     cmGeneratedFileStream fout(pfile);
3113     fout << "# Hashes of file build rules.\n";
3114     for (auto const& rh : this->RuleHashes) {
3115       fout.write(rh.second.Data, 32);
3116       fout << " " << rh.first << "\n";
3117     }
3118   }
3119 }
3120 
WriteSummary()3121 void cmGlobalGenerator::WriteSummary()
3122 {
3123   // Record all target directories in a central location.
3124   std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3125                                "/CMakeFiles/TargetDirectories.txt");
3126   cmGeneratedFileStream fout(fname);
3127 
3128   for (const auto& lg : this->LocalGenerators) {
3129     for (const auto& tgt : lg->GetGeneratorTargets()) {
3130       if (!tgt->IsInBuildSystem()) {
3131         continue;
3132       }
3133       this->WriteSummary(tgt.get());
3134       fout << tgt->GetSupportDirectory() << "\n";
3135     }
3136   }
3137 }
3138 
WriteSummary(cmGeneratorTarget * target)3139 void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
3140 {
3141   // Place the labels file in a per-target support directory.
3142   std::string dir = target->GetSupportDirectory();
3143   std::string file = cmStrCat(dir, "/Labels.txt");
3144   std::string json_file = dir + "/Labels.json";
3145 
3146 #ifndef CMAKE_BOOTSTRAP
3147   // Check whether labels are enabled for this target.
3148   cmValue targetLabels = target->GetProperty("LABELS");
3149   cmValue directoryLabels =
3150     target->Target->GetMakefile()->GetProperty("LABELS");
3151   cmValue cmakeDirectoryLabels =
3152     target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
3153   if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
3154     Json::Value lj_root(Json::objectValue);
3155     Json::Value& lj_target = lj_root["target"] = Json::objectValue;
3156     lj_target["name"] = target->GetName();
3157     Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
3158     Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
3159 
3160     cmSystemTools::MakeDirectory(dir);
3161     cmGeneratedFileStream fout(file);
3162 
3163     std::vector<std::string> labels;
3164 
3165     // List the target-wide labels.  All sources in the target get
3166     // these labels.
3167     if (targetLabels) {
3168       cmExpandList(*targetLabels, labels);
3169       if (!labels.empty()) {
3170         fout << "# Target labels\n";
3171         for (std::string const& l : labels) {
3172           fout << " " << l << "\n";
3173           lj_target_labels.append(l);
3174         }
3175       }
3176     }
3177 
3178     // List directory labels
3179     std::vector<std::string> directoryLabelsList;
3180     std::vector<std::string> cmakeDirectoryLabelsList;
3181 
3182     if (directoryLabels) {
3183       cmExpandList(*directoryLabels, directoryLabelsList);
3184     }
3185 
3186     if (cmakeDirectoryLabels) {
3187       cmExpandList(*cmakeDirectoryLabels, cmakeDirectoryLabelsList);
3188     }
3189 
3190     if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
3191       fout << "# Directory labels\n";
3192     }
3193 
3194     for (std::string const& li : directoryLabelsList) {
3195       fout << " " << li << "\n";
3196       lj_target_labels.append(li);
3197     }
3198 
3199     for (std::string const& li : cmakeDirectoryLabelsList) {
3200       fout << " " << li << "\n";
3201       lj_target_labels.append(li);
3202     }
3203 
3204     // List the source files with any per-source labels.
3205     fout << "# Source files and their labels\n";
3206     std::vector<cmSourceFile*> sources;
3207     std::vector<std::string> const& configs =
3208       target->Target->GetMakefile()->GetGeneratorConfigs(
3209         cmMakefile::IncludeEmptyConfig);
3210     for (std::string const& c : configs) {
3211       target->GetSourceFiles(sources, c);
3212     }
3213     auto const sourcesEnd = cmRemoveDuplicates(sources);
3214     for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
3215       Json::Value& lj_source = lj_sources.append(Json::objectValue);
3216       std::string const& sfp = sf->ResolveFullPath();
3217       fout << sfp << "\n";
3218       lj_source["file"] = sfp;
3219       if (cmValue svalue = sf->GetProperty("LABELS")) {
3220         labels.clear();
3221         Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
3222         cmExpandList(*svalue, labels);
3223         for (std::string const& label : labels) {
3224           fout << " " << label << "\n";
3225           lj_source_labels.append(label);
3226         }
3227       }
3228     }
3229     cmGeneratedFileStream json_fout(json_file);
3230     json_fout << lj_root;
3231   } else
3232 #endif
3233   {
3234     cmSystemTools::RemoveFile(file);
3235     cmSystemTools::RemoveFile(json_file);
3236   }
3237 }
3238 
3239 // static
EscapeJSON(const std::string & s)3240 std::string cmGlobalGenerator::EscapeJSON(const std::string& s)
3241 {
3242   std::string result;
3243   result.reserve(s.size());
3244   for (char i : s) {
3245     switch (i) {
3246       case '"':
3247       case '\\':
3248         result += '\\';
3249         result += i;
3250         break;
3251       case '\n':
3252         result += "\\n";
3253         break;
3254       case '\t':
3255         result += "\\t";
3256         break;
3257       default:
3258         result += i;
3259     }
3260   }
3261   return result;
3262 }
3263 
SetFilenameTargetDepends(cmSourceFile * sf,std::set<cmGeneratorTarget const * > const & tgts)3264 void cmGlobalGenerator::SetFilenameTargetDepends(
3265   cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
3266 {
3267   this->FilenameTargetDepends[sf] = tgts;
3268 }
3269 
3270 std::set<cmGeneratorTarget const*> const&
GetFilenameTargetDepends(cmSourceFile * sf) const3271 cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
3272 {
3273   return this->FilenameTargetDepends[sf];
3274 }
3275 
GetRealPath(const std::string & dir)3276 const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
3277 {
3278   auto i = this->RealPaths.lower_bound(dir);
3279   if (i == this->RealPaths.end() ||
3280       this->RealPaths.key_comp()(dir, i->first)) {
3281     i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
3282   }
3283   return i->second;
3284 }
3285 
NewDeferId()3286 std::string cmGlobalGenerator::NewDeferId()
3287 {
3288   return cmStrCat("__"_s, std::to_string(this->NextDeferId++));
3289 }
3290 
ProcessEvaluationFiles()3291 void cmGlobalGenerator::ProcessEvaluationFiles()
3292 {
3293   std::vector<std::string> generatedFiles;
3294   for (auto& localGen : this->LocalGenerators) {
3295     localGen->ProcessEvaluationFiles(generatedFiles);
3296   }
3297 }
3298 
ExpandCFGIntDir(const std::string & str,const std::string &) const3299 std::string cmGlobalGenerator::ExpandCFGIntDir(
3300   const std::string& str, const std::string& /*config*/) const
3301 {
3302   return str;
3303 }
3304 
GenerateCPackPropertiesFile()3305 bool cmGlobalGenerator::GenerateCPackPropertiesFile()
3306 {
3307   cmake::InstalledFilesMap const& installedFiles =
3308     this->CMakeInstance->GetInstalledFiles();
3309 
3310   const auto& lg = this->LocalGenerators[0];
3311   cmMakefile* mf = lg->GetMakefile();
3312 
3313   std::vector<std::string> configs =
3314     mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
3315   std::string config = mf->GetDefaultConfiguration();
3316 
3317   std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3318                               "/CPackProperties.cmake");
3319 
3320   if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
3321     return true;
3322   }
3323 
3324   cmGeneratedFileStream file(path);
3325   file << "# CPack properties\n";
3326 
3327   for (auto const& i : installedFiles) {
3328     cmInstalledFile const& installedFile = i.second;
3329 
3330     cmCPackPropertiesGenerator cpackPropertiesGenerator(
3331       lg.get(), installedFile, configs);
3332 
3333     cpackPropertiesGenerator.Generate(file, config, configs);
3334   }
3335 
3336   return true;
3337 }
3338 
3339 cmInstallRuntimeDependencySet*
CreateAnonymousRuntimeDependencySet()3340 cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
3341 {
3342   auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
3343   auto* retval = set.get();
3344   this->RuntimeDependencySets.push_back(std::move(set));
3345   return retval;
3346 }
3347 
GetNamedRuntimeDependencySet(const std::string & name)3348 cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
3349   const std::string& name)
3350 {
3351   auto it = this->RuntimeDependencySetsByName.find(name);
3352   if (it == this->RuntimeDependencySetsByName.end()) {
3353     auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
3354     it =
3355       this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
3356         .first;
3357     this->RuntimeDependencySets.push_back(std::move(set));
3358   }
3359   return it->second;
3360 }
3361