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"
11 #include <initializer_list>
17 #include <cm/optional>
18 #include <cmext/algorithm>
19 #include <cmext/string_view>
21 #include "cmsys/Directory.hxx"
22 #include "cmsys/FStream.hxx"
23 #include "cmsys/RegularExpression.hxx"
25 #if defined(_WIN32) && !defined(__CYGWIN__)
29 #include "cmAlgorithms.h"
30 #include "cmCPackPropertiesGenerator.h"
31 #include "cmComputeTargetDepends.h"
32 #include "cmCustomCommand.h"
33 #include "cmCustomCommandLines.h"
34 #include "cmDuration.h"
35 #include "cmExportBuildFileGenerator.h"
36 #include "cmExternalMakefileProjectGenerator.h"
37 #include "cmGeneratedFileStream.h"
38 #include "cmGeneratorExpression.h"
39 #include "cmGeneratorTarget.h"
40 #include "cmInstallGenerator.h"
41 #include "cmInstallRuntimeDependencySet.h"
42 #include "cmLinkLineComputer.h"
43 #include "cmLocalGenerator.h"
44 #include "cmMSVC60LinkLineComputer.h"
45 #include "cmMakefile.h"
46 #include "cmMessageType.h"
47 #include "cmPolicies.h"
49 #include "cmSourceFile.h"
51 #include "cmStateDirectory.h"
52 #include "cmStateTypes.h"
53 #include "cmStringAlgorithms.h"
54 #include "cmSystemTools.h"
56 #include "cmVersion.h"
57 #include "cmWorkingDirectory.h"
60 #if !defined(CMAKE_BOOTSTRAP)
61 # include <cm3p/json/value.h>
62 # include <cm3p/json/writer.h>
64 # include "cmCryptoHash.h"
65 # include "cmQtAutoGenGlobalInitializer.h"
68 const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
69 "CMAKE_PLATFORM_INFO_INITIALIZED";
71 class cmInstalledFile;
73 bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1,
74 cmTarget const* t2) const
76 int nameResult = strcmp(t1->GetName().c_str(), t2->GetName().c_str());
77 if (nameResult == 0) {
78 return strcmp(t1->GetMakefile()->GetCurrentBinaryDirectory().c_str(),
79 t2->GetMakefile()->GetCurrentBinaryDirectory().c_str()) < 0;
81 return nameResult < 0;
84 cmGlobalGenerator::cmGlobalGenerator(cmake* cm)
87 // By default the .SYMBOLIC dependency is not needed on symbolic rules.
88 this->NeedSymbolicMark = false;
90 // by default use the native paths
91 this->ForceUnixPaths = false;
93 // By default do not try to support color.
94 this->ToolSupportsColor = false;
96 // By default do not use link scripts.
97 this->UseLinkScript = false;
99 // Whether an install target is needed.
100 this->InstallTargetEnabled = false;
102 // how long to let try compiles run
103 this->TryCompileTimeout = cmDuration::zero();
105 this->CurrentConfigureMakefile = nullptr;
106 this->TryCompileOuterMakefile = nullptr;
108 this->ConfigureDoneCMP0026AndCMP0024 = false;
109 this->FirstTimeProgress = 0.0f;
111 this->RecursionDepth = 0;
113 cm->GetState()->SetIsGeneratorMultiConfig(false);
114 cm->GetState()->SetMinGWMake(false);
115 cm->GetState()->SetMSYSShell(false);
116 cm->GetState()->SetNMake(false);
117 cm->GetState()->SetWatcomWMake(false);
118 cm->GetState()->SetWindowsShell(false);
119 cm->GetState()->SetWindowsVSIDE(false);
122 cmGlobalGenerator::~cmGlobalGenerator()
124 this->ClearGeneratorMembers();
127 #if !defined(CMAKE_BOOTSTRAP)
128 Json::Value cmGlobalGenerator::GetJson() const
130 Json::Value generator = Json::objectValue;
131 generator["name"] = this->GetName();
132 generator["multiConfig"] = this->IsMultiConfig();
137 bool cmGlobalGenerator::SetGeneratorInstance(std::string const& i,
144 std::ostringstream e;
145 /* clang-format off */
148 " " << this->GetName() << "\n"
149 "does not support instance specification, but instance\n"
152 /* clang-format on */
153 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
157 bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p,
164 std::ostringstream e;
165 /* clang-format off */
168 " " << this->GetName() << "\n"
169 "does not support platform specification, but platform\n"
172 /* clang-format on */
173 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
177 bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool,
183 std::ostringstream e;
184 /* clang-format off */
187 " " << this->GetName() << "\n"
188 "does not support toolset specification, but toolset\n"
191 /* clang-format on */
192 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
196 std::string cmGlobalGenerator::SelectMakeProgram(
197 const std::string& inMakeProgram, const std::string& makeDefault) const
199 std::string makeProgram = inMakeProgram;
200 if (cmIsOff(makeProgram)) {
201 cmValue makeProgramCSTR =
202 this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
203 if (cmIsOff(makeProgramCSTR)) {
204 makeProgram = makeDefault;
206 makeProgram = *makeProgramCSTR;
208 if (cmIsOff(makeProgram) && !makeProgram.empty()) {
209 makeProgram = "CMAKE_MAKE_PROGRAM-NOTFOUND";
215 void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
219 std::string langComp = cmStrCat("CMAKE_", lang, "_COMPILER");
221 if (!mf->GetDefinition(langComp)) {
223 cmSystemTools::Error(langComp + " not set, after EnableLanguage");
227 std::string const& name = mf->GetRequiredDefinition(langComp);
229 if (!cmSystemTools::FileIsFullPath(name)) {
230 path = cmSystemTools::FindProgram(name);
234 if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) {
238 this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp);
240 // Split compiler from arguments
241 std::vector<std::string> cnameArgVec;
242 if (cname && !cname->empty()) {
243 cmExpandList(*cname, cnameArgVec);
244 cname = cmValue(cnameArgVec.front());
247 std::string changeVars;
248 if (cname && !optional) {
249 std::string cnameString;
250 if (!cmSystemTools::FileIsFullPath(*cname)) {
251 cnameString = cmSystemTools::FindProgram(*cname);
253 cnameString = *cname;
255 std::string pathString = path;
256 // get rid of potentially multiple slashes:
257 cmSystemTools::ConvertToUnixSlashes(cnameString);
258 cmSystemTools::ConvertToUnixSlashes(pathString);
259 if (cnameString != pathString) {
260 cmValue cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
261 "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
263 changeVars += *cvars;
266 changeVars += langComp;
268 changeVars += *cname;
269 this->GetCMakeInstance()->GetState()->SetGlobalProperty(
270 "__CMAKE_DELETE_CACHE_CHANGE_VARS_", changeVars.c_str());
275 void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
277 this->BuildExportSets[gen->GetMainExportFileName()] = gen;
280 void cmGlobalGenerator::AddBuildExportExportSet(
281 cmExportBuildFileGenerator* gen)
283 this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
284 this->AddBuildExportSet(gen);
287 bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
289 auto const it = this->BuildExportSets.find(file);
290 if (it != this->BuildExportSets.end()) {
291 bool result = it->second->GenerateImportFile();
293 if (!this->ConfigureDoneCMP0026AndCMP0024) {
294 for (const auto& m : this->Makefiles) {
295 m->RemoveExportBuildFileGeneratorCMP0024(it->second);
299 this->BuildExportSets.erase(it);
305 void cmGlobalGenerator::ForceLinkerLanguages()
309 bool cmGlobalGenerator::CheckTargetsForMissingSources() const
312 for (const auto& localGen : this->LocalGenerators) {
313 for (const auto& target : localGen->GetGeneratorTargets()) {
314 if (!target->CanCompileSources() ||
315 cmIsOn(target->GetProperty("ghs_integrity_app"))) {
319 if (target->GetAllConfigSources().empty()) {
320 std::ostringstream e;
321 e << "No SOURCES given to target: " << target->GetName();
322 this->GetCMakeInstance()->IssueMessage(
323 MessageType::FATAL_ERROR, e.str(), target->GetBacktrace());
331 void cmGlobalGenerator::CheckTargetLinkLibraries() const
333 for (const auto& generator : this->LocalGenerators) {
334 for (const auto& gt : generator->GetGeneratorTargets()) {
335 gt->CheckLinkLibraries();
337 for (const auto& gt : generator->GetOwnedImportedGeneratorTargets()) {
338 gt->CheckLinkLibraries();
343 bool cmGlobalGenerator::CheckTargetsForType() const
345 if (!this->GetLanguageEnabled("Swift")) {
349 for (const auto& generator : this->LocalGenerators) {
350 for (const auto& target : generator->GetGeneratorTargets()) {
351 std::string systemName =
352 target->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
353 if (systemName.find("Windows") == std::string::npos) {
357 if (target->GetType() == cmStateEnums::EXECUTABLE) {
358 std::vector<std::string> const& configs =
359 target->Makefile->GetGeneratorConfigs(
360 cmMakefile::IncludeEmptyConfig);
361 for (std::string const& config : configs) {
362 if (target->IsWin32Executable(config) &&
363 target->GetLinkerLanguage(config) == "Swift") {
364 this->GetCMakeInstance()->IssueMessage(
365 MessageType::FATAL_ERROR,
366 "WIN32_EXECUTABLE property is not supported on Swift "
368 target->GetBacktrace());
378 bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const
380 if (!this->GetLanguageEnabled("C") && !this->GetLanguageEnabled("CXX")) {
384 for (const auto& generator : this->LocalGenerators) {
385 for (const auto& target : generator->GetGeneratorTargets()) {
386 if (!target->CanCompileSources() ||
387 cmIsOn(target->GetProperty("ghs_integrity_app"))) {
391 std::string const& reuseFrom =
392 target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM");
393 std::string const& compilePdb =
394 target->GetSafeProperty("COMPILE_PDB_NAME");
396 if (!reuseFrom.empty() && reuseFrom != compilePdb) {
397 const std::string e = cmStrCat(
398 "PRECOMPILE_HEADERS_REUSE_FROM property is set on target (\"",
400 "\"). Reusable precompile headers requires the COMPILE_PDB_NAME"
401 " property to have the value \"",
403 this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
404 target->GetBacktrace());
412 bool cmGlobalGenerator::IsExportedTargetsFile(
413 const std::string& filename) const
415 auto const it = this->BuildExportSets.find(filename);
416 if (it == this->BuildExportSets.end()) {
419 return !cm::contains(this->BuildExportExportSets, filename);
422 // Find the make program for the generator, required for try compiles
423 bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
425 if (this->FindMakeProgramFile.empty()) {
426 cmSystemTools::Error(
427 "Generator implementation error, "
428 "all generators must specify this->FindMakeProgramFile");
431 if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
432 std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile);
433 if (!setMakeProgram.empty()) {
434 mf->ReadListFile(setMakeProgram);
437 if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
438 std::ostringstream err;
439 err << "CMake was unable to find a build program corresponding to \""
440 << this->GetName() << "\". CMAKE_MAKE_PROGRAM is not set. You "
441 << "probably need to select a different build tool.";
442 cmSystemTools::Error(err.str());
443 cmSystemTools::SetFatalErrorOccurred();
446 std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
447 // if there are spaces in the make program use short path
448 // but do not short path the actual program name, as
449 // this can cause trouble with VSExpress
450 if (makeProgram.find(' ') != std::string::npos) {
453 cmSystemTools::SplitProgramPath(makeProgram, dir, file);
454 std::string saveFile = file;
455 cmSystemTools::GetShortPath(makeProgram, makeProgram);
456 cmSystemTools::SplitProgramPath(makeProgram, dir, file);
457 makeProgram = cmStrCat(dir, '/', saveFile);
458 mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program",
459 cmStateEnums::FILEPATH);
464 bool cmGlobalGenerator::CheckLanguages(
465 std::vector<std::string> const& /* languages */, cmMakefile* /* mf */) const
470 // enable the given language
472 // The following files are loaded in this order:
474 // First figure out what OS we are running on:
476 // CMakeSystem.cmake - configured file created by CMakeDetermineSystem.cmake
477 // CMakeDetermineSystem.cmake - figure out os info and create
478 // CMakeSystem.cmake IF CMAKE_SYSTEM
480 // CMakeSystem.cmake - configured file created by
481 // CMakeDetermineSystem.cmake IF CMAKE_SYSTEM_LOADED
483 // CMakeSystemSpecificInitialize.cmake
484 // - includes Platform/${CMAKE_SYSTEM_NAME}-Initialize.cmake
486 // Next try and enable all languages found in the languages vector
488 // FOREACH LANG in languages
489 // CMake(LANG)Compiler.cmake - configured file create by
490 // CMakeDetermine(LANG)Compiler.cmake
491 // CMakeDetermine(LANG)Compiler.cmake - Finds compiler for LANG and
492 // creates CMake(LANG)Compiler.cmake
493 // CMake(LANG)Compiler.cmake - configured file created by
494 // CMakeDetermine(LANG)Compiler.cmake
496 // CMakeSystemSpecificInformation.cmake
497 // - includes Platform/${CMAKE_SYSTEM_NAME}.cmake
498 // may use compiler stuff
500 // FOREACH LANG in languages
501 // CMake(LANG)Information.cmake
502 // - loads Platform/${CMAKE_SYSTEM_NAME}-${COMPILER}.cmake
503 // CMakeTest(LANG)Compiler.cmake
504 // - Make sure the compiler works with a try compile if
505 // CMakeDetermine(LANG) was loaded
507 // Now load a few files that can override values set in any of the above
508 // (PROJECTNAME)Compatibility.cmake
509 // - load any backwards compatibility stuff for current project
510 // ${CMAKE_USER_MAKE_RULES_OVERRIDE}
511 // - allow users a chance to override system variables
515 void cmGlobalGenerator::EnableLanguage(
516 std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
518 if (!this->IsMultiConfig() &&
519 !this->GetCMakeInstance()->GetIsInTryCompile()) {
520 std::string envBuildType;
521 if (!mf->GetDefinition("CMAKE_BUILD_TYPE") &&
522 cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) {
523 mf->AddCacheDefinition(
524 "CMAKE_BUILD_TYPE", envBuildType,
525 "Choose the type of build. Options include: empty, "
526 "Debug, Release, RelWithDebInfo, MinSizeRel.",
527 cmStateEnums::STRING);
531 if (languages.empty()) {
532 cmSystemTools::Error("EnableLanguage must have a lang specified!");
533 cmSystemTools::SetFatalErrorOccurred();
537 std::set<std::string> cur_languages(languages.begin(), languages.end());
538 for (std::string const& li : cur_languages) {
539 if (!this->LanguagesInProgress.insert(li).second) {
540 std::ostringstream e;
541 e << "Language '" << li
542 << "' is currently being enabled. "
543 "Recursive call not allowed.";
544 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
545 cmSystemTools::SetFatalErrorOccurred();
550 if (this->TryCompileOuterMakefile) {
551 // In a try-compile we can only enable languages provided by caller.
552 for (std::string const& lang : languages) {
553 if (lang == "NONE") {
554 this->SetLanguageEnabled("NONE", mf);
556 if (!cm::contains(this->LanguagesReady, lang)) {
557 std::ostringstream e;
558 e << "The test project needs language " << lang
559 << " which is not enabled.";
560 this->TryCompileOuterMakefile->IssueMessage(MessageType::FATAL_ERROR,
562 cmSystemTools::SetFatalErrorOccurred();
569 bool fatalError = false;
571 mf->AddDefinitionBool("RUN_CONFIGURE", true);
572 std::string rootBin =
573 cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
575 // If the configuration files path has been set,
576 // then we are in a try compile and need to copy the enable language
577 // files from the parent cmake bin dir, into the try compile bin dir
578 if (!this->ConfiguredFilesPath.empty()) {
579 rootBin = this->ConfiguredFilesPath;
582 rootBin += cmVersion::GetCMakeVersion();
584 // set the dir for parent files so they can be used by modules
585 mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin);
587 if (!this->CMakeInstance->GetIsInTryCompile()) {
588 // Keep a mark in the cache to indicate that we've initialized the
589 // platform information directory. If the platform information
590 // directory exists but the mark is missing then CMakeCache.txt
591 // has been removed or replaced without also removing the CMakeFiles/
592 // directory. In this case remove the platform information directory
593 // so that it will be re-initialized and the relevant information
594 // restored in the cache.
595 if (cmSystemTools::FileIsDirectory(rootBin) &&
596 !mf->IsOn(kCMAKE_PLATFORM_INFO_INITIALIZED)) {
597 cmSystemTools::RemoveADirectory(rootBin);
599 this->GetCMakeInstance()->AddCacheEntry(
600 kCMAKE_PLATFORM_INFO_INITIALIZED, "1",
601 "Platform information initialized", cmStateEnums::INTERNAL);
604 // try and load the CMakeSystem.cmake if it is there
605 std::string fpath = rootBin;
606 bool const readCMakeSystem = !mf->GetDefinition("CMAKE_SYSTEM_LOADED");
607 if (readCMakeSystem) {
608 fpath += "/CMakeSystem.cmake";
609 if (cmSystemTools::FileExists(fpath)) {
610 mf->ReadListFile(fpath);
614 // Load the CMakeDetermineSystem.cmake file and find out
615 // what platform we are running on
616 if (!mf->GetDefinition("CMAKE_SYSTEM")) {
617 #if defined(_WIN32) && !defined(__CYGWIN__)
618 cmSystemTools::WindowsVersion windowsVersion =
619 cmSystemTools::GetWindowsVersion();
620 std::ostringstream windowsVersionString;
621 windowsVersionString << windowsVersion.dwMajorVersion << "."
622 << windowsVersion.dwMinorVersion << "."
623 << windowsVersion.dwBuildNumber;
624 mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
626 // Read the DetermineSystem file
627 std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
628 mf->ReadListFile(systemFile);
629 // load the CMakeSystem.cmake from the binary directory
630 // this file is configured by the CMakeDetermineSystem.cmake file
631 fpath = cmStrCat(rootBin, "/CMakeSystem.cmake");
632 mf->ReadListFile(fpath);
635 if (readCMakeSystem) {
636 // Tell the generator about the instance, if any.
637 std::string instance = mf->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE");
638 if (!this->SetGeneratorInstance(instance, mf)) {
639 cmSystemTools::SetFatalErrorOccurred();
643 // Tell the generator about the target system.
644 std::string system = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
645 if (!this->SetSystemName(system, mf)) {
646 cmSystemTools::SetFatalErrorOccurred();
650 // Tell the generator about the platform, if any.
651 std::string platform = mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM");
652 if (!this->SetGeneratorPlatform(platform, mf)) {
653 cmSystemTools::SetFatalErrorOccurred();
657 // Tell the generator about the toolset, if any.
658 std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
659 if (!this->SetGeneratorToolset(toolset, false, mf)) {
660 cmSystemTools::SetFatalErrorOccurred();
664 // Find the native build tool for this generator.
665 if (!this->FindMakeProgram(mf)) {
669 // One-time includes of user-provided project setup files
670 mf->GetState()->SetInTopLevelIncludes(true);
671 std::string includes =
672 mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES");
673 std::vector<std::string> includesList = cmExpandedList(includes);
674 for (std::string const& setupFile : includesList) {
675 std::string absSetupFile = cmSystemTools::CollapseFullPath(
676 setupFile, mf->GetCurrentSourceDirectory());
677 if (!cmSystemTools::FileExists(absSetupFile)) {
678 cmSystemTools::Error(
679 "CMAKE_PROJECT_TOP_LEVEL_INCLUDES file does not exist: " +
681 mf->GetState()->SetInTopLevelIncludes(false);
684 if (cmSystemTools::FileIsDirectory(absSetupFile)) {
685 cmSystemTools::Error(
686 "CMAKE_PROJECT_TOP_LEVEL_INCLUDES file is a directory: " +
688 mf->GetState()->SetInTopLevelIncludes(false);
691 if (!mf->ReadListFile(absSetupFile)) {
692 cmSystemTools::Error(
693 "Failed reading CMAKE_PROJECT_TOP_LEVEL_INCLUDES file: " +
695 mf->GetState()->SetInTopLevelIncludes(false);
700 mf->GetState()->SetInTopLevelIncludes(false);
702 // Check that the languages are supported by the generator and its
703 // native build tool found above.
704 if (!this->CheckLanguages(languages, mf)) {
708 // **** Load the system specific initialization if not yet loaded
709 if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INITIALIZE_LOADED")) {
710 fpath = mf->GetModulesFile("CMakeSystemSpecificInitialize.cmake");
711 if (!mf->ReadListFile(fpath)) {
712 cmSystemTools::Error("Could not find cmake module file: "
713 "CMakeSystemSpecificInitialize.cmake");
717 std::map<std::string, bool> needTestLanguage;
718 std::map<std::string, bool> needSetLanguageEnabledMaps;
720 // load the CMakeDetermine(LANG)Compiler.cmake file to find
723 for (std::string const& lang : languages) {
724 needSetLanguageEnabledMaps[lang] = false;
725 if (lang == "NONE") {
726 this->SetLanguageEnabled("NONE", mf);
729 std::string loadedLang = cmStrCat("CMAKE_", lang, "_COMPILER_LOADED");
730 if (!mf->GetDefinition(loadedLang)) {
731 fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
733 // If the existing build tree was already configured with this
734 // version of CMake then try to load the configured file first
735 // to avoid duplicate compiler tests.
736 if (cmSystemTools::FileExists(fpath)) {
737 if (!mf->ReadListFile(fpath)) {
738 cmSystemTools::Error("Could not find cmake module file: " + fpath);
740 // if this file was found then the language was already determined
742 needTestLanguage[lang] = false;
743 this->SetLanguageEnabledFlag(lang, mf);
744 needSetLanguageEnabledMaps[lang] = true;
745 // this can only be called after loading CMake(LANG)Compiler.cmake
749 if (!this->GetLanguageEnabled(lang)) {
750 if (this->CMakeInstance->GetIsInTryCompile()) {
751 cmSystemTools::Error("This should not have happened. "
752 "If you see this message, you are probably "
753 "using a broken CMakeLists.txt file or a "
754 "problematic release of CMake");
756 // if the CMake(LANG)Compiler.cmake file was not found then
757 // load CMakeDetermine(LANG)Compiler.cmake
758 std::string determineCompiler =
759 cmStrCat("CMakeDetermine", lang, "Compiler.cmake");
760 std::string determineFile = mf->GetModulesFile(determineCompiler);
761 if (!mf->ReadListFile(determineFile)) {
762 cmSystemTools::Error("Could not find cmake module file: " +
765 if (cmSystemTools::GetFatalErrorOccurred()) {
768 needTestLanguage[lang] = true;
769 // Some generators like visual studio should not use the env variables
770 // So the global generator can specify that in this variable
771 if ((mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::OLD ||
772 mf->GetPolicyStatus(cmPolicies::CMP0132) == cmPolicies::WARN) &&
773 !mf->GetDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV")) {
774 // put ${CMake_(LANG)_COMPILER_ENV_VAR}=${CMAKE_(LANG)_COMPILER
775 // into the environment, in case user scripts want to run
776 // configure, or sub cmakes
777 std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
778 std::string compilerEnv =
779 cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
780 const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
781 const std::string& envVarValue =
782 mf->GetRequiredDefinition(compilerName);
783 std::string env = cmStrCat(envVar, '=', envVarValue);
784 cmSystemTools::PutEnv(env);
787 // if determineLanguage was called then load the file it
788 // configures CMake(LANG)Compiler.cmake
789 fpath = cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
790 if (!mf->ReadListFile(fpath)) {
791 cmSystemTools::Error("Could not find cmake module file: " + fpath);
793 this->SetLanguageEnabledFlag(lang, mf);
794 needSetLanguageEnabledMaps[lang] = true;
795 // this can only be called after loading CMake(LANG)Compiler.cmake
796 // the language must be enabled for try compile to work, but we do
797 // not know if it is a working compiler yet so set the test language
799 needTestLanguage[lang] = true;
800 } // end if(!this->GetLanguageEnabled(lang) )
801 } // end loop over languages
803 // **** Load the system specific information if not yet loaded
804 if (!mf->GetDefinition("CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED")) {
805 fpath = mf->GetModulesFile("CMakeSystemSpecificInformation.cmake");
806 if (!mf->ReadListFile(fpath)) {
807 cmSystemTools::Error("Could not find cmake module file: "
808 "CMakeSystemSpecificInformation.cmake");
811 // loop over languages again loading CMake(LANG)Information.cmake
813 for (std::string const& lang : languages) {
814 if (lang == "NONE") {
815 this->SetLanguageEnabled("NONE", mf);
819 // Check that the compiler was found.
820 std::string compilerName = cmStrCat("CMAKE_", lang, "_COMPILER");
821 std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR");
822 std::ostringstream noCompiler;
823 cmValue compilerFile = mf->GetDefinition(compilerName);
824 if (!cmNonempty(compilerFile) || cmIsNOTFOUND(*compilerFile)) {
825 /* clang-format off */
827 "No " << compilerName << " could be found.\n"
829 /* clang-format on */
830 } else if ((lang != "RC") && (lang != "ASM_MASM")) {
831 if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
832 /* clang-format off */
834 "The " << compilerName << ":\n"
835 " " << *compilerFile << "\n"
836 "is not a full path and was not found in the PATH.\n"
838 /* clang-format on */
839 } else if (!cmSystemTools::FileExists(*compilerFile)) {
840 /* clang-format off */
842 "The " << compilerName << ":\n"
843 " " << *compilerFile << "\n"
844 "is not a full path to an existing compiler tool.\n"
846 /* clang-format on */
849 if (!noCompiler.str().empty()) {
850 // Skip testing this language since the compiler is not found.
851 needTestLanguage[lang] = false;
853 // The compiler was not found and it is not optional. Remove
854 // CMake(LANG)Compiler.cmake so we try again next time CMake runs.
855 std::string compilerLangFile =
856 cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
857 cmSystemTools::RemoveFile(compilerLangFile);
858 if (!this->CMakeInstance->GetIsInTryCompile()) {
859 this->PrintCompilerAdvice(noCompiler, lang,
860 mf->GetDefinition(compilerEnv));
861 mf->IssueMessage(MessageType::FATAL_ERROR, noCompiler.str());
867 std::string langLoadedVar =
868 cmStrCat("CMAKE_", lang, "_INFORMATION_LOADED");
869 if (!mf->GetDefinition(langLoadedVar)) {
870 fpath = cmStrCat("CMake", lang, "Information.cmake");
871 std::string informationFile = mf->GetModulesFile(fpath);
872 if (informationFile.empty()) {
873 cmSystemTools::Error("Could not find cmake module file: " + fpath);
874 } else if (!mf->ReadListFile(informationFile)) {
875 cmSystemTools::Error("Could not process cmake module file: " +
879 if (needSetLanguageEnabledMaps[lang]) {
880 this->SetLanguageEnabledMaps(lang, mf);
882 this->LanguagesReady.insert(lang);
884 // Test the compiler for the language just setup
885 // (but only if a compiler has been actually found)
886 // At this point we should have enough info for a try compile
887 // which is used in the backward stuff
888 // If the language is untested then test it now with a try compile.
889 if (needTestLanguage[lang]) {
890 if (!this->CMakeInstance->GetIsInTryCompile()) {
891 std::string testLang = cmStrCat("CMakeTest", lang, "Compiler.cmake");
892 std::string ifpath = mf->GetModulesFile(testLang);
893 if (!mf->ReadListFile(ifpath)) {
894 cmSystemTools::Error("Could not find cmake module file: " +
897 std::string compilerWorks =
898 cmStrCat("CMAKE_", lang, "_COMPILER_WORKS");
899 // if the compiler did not work, then remove the
900 // CMake(LANG)Compiler.cmake file so that it will get tested the
901 // next time cmake is run
902 if (!mf->IsOn(compilerWorks)) {
903 std::string compilerLangFile =
904 cmStrCat(rootBin, "/CMake", lang, "Compiler.cmake");
905 cmSystemTools::RemoveFile(compilerLangFile);
907 } // end if in try compile
908 } // end need test language
909 // Store the shared library flags so that we can satisfy CMP0018
910 std::string sharedLibFlagsVar =
911 cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS");
912 this->LanguageToOriginalSharedLibFlags[lang] =
913 mf->GetSafeDefinition(sharedLibFlagsVar);
915 // Translate compiler ids for compatibility.
916 this->CheckCompilerIdCompatibility(mf, lang);
917 } // end for each language
919 // Now load files that can override any settings on the platform or for
920 // the project First load the project compatibility file if it is in
922 std::string projectCompatibility =
923 cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/",
924 mf->GetSafeDefinition("PROJECT_NAME"), "Compatibility.cmake");
925 if (cmSystemTools::FileExists(projectCompatibility)) {
926 mf->ReadListFile(projectCompatibility);
928 // Inform any extra generator of the new language.
929 if (this->ExtraGenerator) {
930 this->ExtraGenerator->EnableLanguage(languages, mf, false);
934 cmSystemTools::SetFatalErrorOccurred();
937 for (std::string const& lang : cur_languages) {
938 this->LanguagesInProgress.erase(lang);
942 void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
943 std::string const& lang,
944 cmValue envVar) const
946 // Subclasses override this method if they do not support this advice.
947 os << "Tell CMake where to find the compiler by setting ";
949 os << "either the environment variable \"" << envVar << "\" or ";
951 os << "the CMake cache entry CMAKE_" << lang
953 "to the full path to the compiler, or to the compiler name "
954 "if it is in the PATH.";
957 void cmGlobalGenerator::CheckCompilerIdCompatibility(
958 cmMakefile* mf, std::string const& lang) const
960 std::string compilerIdVar = "CMAKE_" + lang + "_COMPILER_ID";
961 std::string const compilerId = mf->GetSafeDefinition(compilerIdVar);
963 if (compilerId == "AppleClang") {
964 switch (mf->GetPolicyStatus(cmPolicies::CMP0025)) {
965 case cmPolicies::WARN:
966 if (!this->CMakeInstance->GetIsInTryCompile() &&
967 mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0025")) {
968 std::ostringstream w;
969 /* clang-format off */
970 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
971 "Converting " << lang <<
972 R"( compiler id "AppleClang" to "Clang" for compatibility.)"
974 /* clang-format on */
975 mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
978 case cmPolicies::OLD:
979 // OLD behavior is to convert AppleClang to Clang.
980 mf->AddDefinition(compilerIdVar, "Clang");
982 case cmPolicies::REQUIRED_IF_USED:
983 case cmPolicies::REQUIRED_ALWAYS:
985 MessageType::FATAL_ERROR,
986 cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0025));
988 case cmPolicies::NEW:
989 // NEW behavior is to keep AppleClang.
994 if (compilerId == "QCC") {
995 switch (mf->GetPolicyStatus(cmPolicies::CMP0047)) {
996 case cmPolicies::WARN:
997 if (!this->CMakeInstance->GetIsInTryCompile() &&
998 mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0047")) {
999 std::ostringstream w;
1000 /* clang-format off */
1001 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
1002 "Converting " << lang <<
1003 R"( compiler id "QCC" to "GNU" for compatibility.)"
1005 /* clang-format on */
1006 mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
1009 case cmPolicies::OLD:
1010 // OLD behavior is to convert QCC to GNU.
1011 mf->AddDefinition(compilerIdVar, "GNU");
1013 mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
1014 } else if (lang == "CXX") {
1015 mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
1018 case cmPolicies::REQUIRED_IF_USED:
1019 case cmPolicies::REQUIRED_ALWAYS:
1021 MessageType::FATAL_ERROR,
1022 cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0047));
1024 case cmPolicies::NEW:
1025 // NEW behavior is to keep QCC.
1030 if (compilerId == "XLClang") {
1031 switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
1032 case cmPolicies::WARN:
1033 if (!this->CMakeInstance->GetIsInTryCompile() &&
1034 mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
1035 std::ostringstream w;
1036 /* clang-format off */
1037 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
1038 "Converting " << lang <<
1039 R"( compiler id "XLClang" to "XL" for compatibility.)"
1041 /* clang-format on */
1042 mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
1045 case cmPolicies::OLD:
1046 // OLD behavior is to convert XLClang to XL.
1047 mf->AddDefinition(compilerIdVar, "XL");
1049 case cmPolicies::REQUIRED_IF_USED:
1050 case cmPolicies::REQUIRED_ALWAYS:
1052 MessageType::FATAL_ERROR,
1053 cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
1055 case cmPolicies::NEW:
1056 // NEW behavior is to keep AppleClang.
1061 if (compilerId == "LCC") {
1062 switch (mf->GetPolicyStatus(cmPolicies::CMP0129)) {
1063 case cmPolicies::WARN:
1064 if (!this->CMakeInstance->GetIsInTryCompile() &&
1065 mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0129")) {
1066 std::ostringstream w;
1067 /* clang-format off */
1068 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0129) << "\n"
1069 "Converting " << lang <<
1070 R"( compiler id "LCC" to "GNU" for compatibility.)"
1072 /* clang-format on */
1073 mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
1076 case cmPolicies::OLD:
1077 // OLD behavior is to convert LCC to GNU.
1078 mf->AddDefinition(compilerIdVar, "GNU");
1080 mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1");
1081 } else if (lang == "CXX") {
1082 mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1");
1083 } else if (lang == "Fortran") {
1084 mf->AddDefinition("CMAKE_COMPILER_IS_GNUG77", "1");
1087 // Fix compiler versions.
1088 std::string version = "CMAKE_" + lang + "_COMPILER_VERSION";
1089 std::string emulated = "CMAKE_" + lang + "_SIMULATE_VERSION";
1090 std::string emulatedId = "CMAKE_" + lang + "_SIMULATE_ID";
1091 std::string const& actual = mf->GetRequiredDefinition(emulated);
1092 mf->AddDefinition(version, actual);
1093 mf->RemoveDefinition(emulatedId);
1094 mf->RemoveDefinition(emulated);
1097 case cmPolicies::REQUIRED_IF_USED:
1098 case cmPolicies::REQUIRED_ALWAYS:
1100 MessageType::FATAL_ERROR,
1101 cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0129));
1103 case cmPolicies::NEW:
1104 // NEW behavior is to keep LCC.
1110 std::string cmGlobalGenerator::GetLanguageOutputExtension(
1111 cmSourceFile const& source) const
1113 const std::string& lang = source.GetLanguage();
1114 if (!lang.empty()) {
1115 auto const it = this->LanguageToOutputExtension.find(lang);
1116 if (it != this->LanguageToOutputExtension.end()) {
1120 // if no language is found then check to see if it is already an
1121 // output extension for some language. In that case it should be ignored
1122 // and in this map, so it will not be compiled but will just be used.
1123 std::string const& ext = source.GetExtension();
1125 if (this->OutputExtensions.count(ext)) {
1133 std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
1135 // if there is an extension and it starts with . then move past the
1136 // . because the extensions are not stored with a . in the map
1143 auto const it = this->ExtensionToLanguage.find(ext);
1144 if (it != this->ExtensionToLanguage.end()) {
1150 /* SetLanguageEnabled() is now split in two parts:
1151 at first the enabled-flag is set. This can then be used in EnabledLanguage()
1152 for checking whether the language is already enabled. After setting this
1153 flag still the values from the cmake variables have to be copied into the
1154 internal maps, this is done in SetLanguageEnabledMaps() which is called
1155 after the system- and compiler specific files have been loaded.
1157 This split was done originally so that compiler-specific configuration
1158 files could change the object file extension
1159 (CMAKE_<LANG>_OUTPUT_EXTENSION) before the CMake variables were copied
1162 void cmGlobalGenerator::SetLanguageEnabled(const std::string& l,
1165 this->SetLanguageEnabledFlag(l, mf);
1166 this->SetLanguageEnabledMaps(l, mf);
1169 void cmGlobalGenerator::SetLanguageEnabledFlag(const std::string& l,
1172 this->CMakeInstance->GetState()->SetLanguageEnabled(l);
1174 // Fill the language-to-extension map with the current variable
1175 // settings to make sure it is available for the try_compile()
1176 // command source file signature. In SetLanguageEnabledMaps this
1177 // will be done again to account for any compiler- or
1178 // platform-specific entries.
1179 this->FillExtensionToLanguageMap(l, mf);
1182 void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l,
1185 // use LanguageToLinkerPreference to detect whether this functions has
1187 if (cm::contains(this->LanguageToLinkerPreference, l)) {
1191 std::string linkerPrefVar = "CMAKE_" + l + "_LINKER_PREFERENCE";
1192 cmValue linkerPref = mf->GetDefinition(linkerPrefVar);
1194 if (cmNonempty(linkerPref)) {
1195 if (sscanf(linkerPref->c_str(), "%d", &preference) != 1) {
1196 // backward compatibility: before 2.6 LINKER_PREFERENCE
1197 // was either "None" or "Preferred", and only the first character was
1198 // tested. So if there is a custom language out there and it is
1199 // "Preferred", set its preference high
1200 if ((*linkerPref)[0] == 'P') {
1208 if (preference < 0) {
1210 cmStrCat(linkerPrefVar, " is negative, adjusting it to 0");
1211 cmSystemTools::Message(msg, "Warning");
1215 this->LanguageToLinkerPreference[l] = preference;
1217 std::string outputExtensionVar = "CMAKE_" + l + "_OUTPUT_EXTENSION";
1218 if (cmValue p = mf->GetDefinition(outputExtensionVar)) {
1219 std::string outputExtension = *p;
1220 this->LanguageToOutputExtension[l] = outputExtension;
1221 this->OutputExtensions[outputExtension] = outputExtension;
1222 if (cmHasPrefix(outputExtension, ".")) {
1223 outputExtension = outputExtension.substr(1);
1224 this->OutputExtensions[outputExtension] = outputExtension;
1228 // The map was originally filled by SetLanguageEnabledFlag, but
1229 // since then the compiler- and platform-specific files have been
1230 // loaded which might have added more entries.
1231 this->FillExtensionToLanguageMap(l, mf);
1233 std::string ignoreExtensionsVar =
1234 std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS");
1235 std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar);
1236 std::vector<std::string> extensionList = cmExpandedList(ignoreExts);
1237 for (std::string const& i : extensionList) {
1238 this->IgnoreExtensions[i] = true;
1242 void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l,
1245 std::string extensionsVar = std::string("CMAKE_") + std::string(l) +
1246 std::string("_SOURCE_FILE_EXTENSIONS");
1247 const std::string& exts = mf->GetSafeDefinition(extensionsVar);
1248 std::vector<std::string> extensionList = cmExpandedList(exts);
1249 for (std::string const& i : extensionList) {
1250 this->ExtensionToLanguage[i] = l;
1254 cmValue cmGlobalGenerator::GetGlobalSetting(std::string const& name) const
1256 assert(!this->Makefiles.empty());
1257 return this->Makefiles[0]->GetDefinition(name);
1260 bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const
1262 assert(!this->Makefiles.empty());
1263 return this->Makefiles[0]->IsOn(name);
1266 std::string cmGlobalGenerator::GetSafeGlobalSetting(
1267 std::string const& name) const
1269 assert(!this->Makefiles.empty());
1270 return this->Makefiles[0]->GetDefinition(name);
1273 bool cmGlobalGenerator::IgnoreFile(const char* ext) const
1275 if (!this->GetLanguageFromExtension(ext).empty()) {
1278 return (this->IgnoreExtensions.count(ext) > 0);
1281 bool cmGlobalGenerator::GetLanguageEnabled(const std::string& l) const
1283 return this->CMakeInstance->GetState()->GetLanguageEnabled(l);
1286 void cmGlobalGenerator::ClearEnabledLanguages()
1288 this->CMakeInstance->GetState()->ClearEnabledLanguages();
1291 void cmGlobalGenerator::CreateLocalGenerators()
1293 this->LocalGeneratorSearchIndex.clear();
1294 this->LocalGenerators.clear();
1295 this->LocalGenerators.reserve(this->Makefiles.size());
1296 for (const auto& m : this->Makefiles) {
1297 auto lg = this->CreateLocalGenerator(m.get());
1298 this->IndexLocalGenerator(lg.get());
1299 this->LocalGenerators.push_back(std::move(lg));
1303 void cmGlobalGenerator::Configure()
1305 this->FirstTimeProgress = 0.0f;
1306 this->ClearGeneratorMembers();
1307 this->NextDeferId = 0;
1309 cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
1311 snapshot.GetDirectory().SetCurrentSource(
1312 this->CMakeInstance->GetHomeDirectory());
1313 snapshot.GetDirectory().SetCurrentBinary(
1314 this->CMakeInstance->GetHomeOutputDirectory());
1316 auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
1317 auto* dirMf = dirMfu.get();
1318 this->Makefiles.push_back(std::move(dirMfu));
1319 dirMf->SetRecursionDepth(this->RecursionDepth);
1320 this->IndexMakefile(dirMf);
1322 this->BinaryDirectories.insert(
1323 this->CMakeInstance->GetHomeOutputDirectory());
1326 this->ConfigureDoneCMP0026AndCMP0024 = false;
1328 dirMf->EnforceDirectoryLevelRules();
1330 this->ConfigureDoneCMP0026AndCMP0024 = true;
1332 // Put a copy of each global target in every directory.
1334 std::vector<GlobalTargetInfo> globalTargets;
1335 this->CreateDefaultGlobalTargets(globalTargets);
1337 for (const auto& mf : this->Makefiles) {
1338 for (GlobalTargetInfo const& globalTarget : globalTargets) {
1339 this->CreateGlobalTarget(globalTarget, mf.get());
1344 // update the cache entry for the number of local generators, this is used
1347 snprintf(num, sizeof(num), "%d", static_cast<int>(this->Makefiles.size()));
1348 this->GetCMakeInstance()->AddCacheEntry("CMAKE_NUMBER_OF_MAKEFILES", num,
1349 "number of local generators",
1350 cmStateEnums::INTERNAL);
1352 if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
1353 std::ostringstream msg;
1354 if (cmSystemTools::GetErrorOccurredFlag()) {
1355 msg << "Configuring incomplete, errors occurred!";
1356 const char* logs[] = { "CMakeOutput.log", "CMakeError.log", nullptr };
1357 for (const char** log = logs; *log; ++log) {
1358 std::string f = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
1359 "/CMakeFiles/", *log);
1360 if (cmSystemTools::FileExists(f)) {
1361 msg << "\nSee also \"" << f << "\".";
1365 msg << "Configuring done";
1367 this->CMakeInstance->UpdateProgress(msg.str(), -1);
1371 void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
1373 this->CreateLocalGenerators();
1374 // Commit side effects only if we are actually generating
1375 if (this->GetConfigureDoneCMP0026()) {
1376 this->CheckTargetProperties();
1378 this->CreateGeneratorTargets(targetTypes);
1379 if (targetTypes == TargetTypes::AllTargets) {
1380 this->ComputeBuildFileGenerators();
1384 void cmGlobalGenerator::CreateImportedGenerationObjects(
1385 cmMakefile* mf, const std::vector<std::string>& targets,
1386 std::vector<const cmGeneratorTarget*>& exports)
1388 this->CreateGenerationObjects(ImportedOnly);
1390 std::find_if(this->Makefiles.begin(), this->Makefiles.end(),
1391 [mf](const std::unique_ptr<cmMakefile>& item) {
1392 return item.get() == mf;
1395 this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
1396 for (std::string const& t : targets) {
1397 cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
1399 exports.push_back(gt);
1404 cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
1405 const std::string& filename) const
1407 auto const it = this->BuildExportSets.find(filename);
1408 return it == this->BuildExportSets.end() ? nullptr : it->second;
1411 void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target)
1413 this->CMP0042WarnTargets.insert(target);
1416 void cmGlobalGenerator::AddCMP0068WarnTarget(const std::string& target)
1418 this->CMP0068WarnTargets.insert(target);
1421 bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
1423 // If the property is not enabled then okay.
1424 if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1425 "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
1429 // This generator does not support duplicate custom targets.
1430 std::ostringstream e;
1431 e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
1432 << "global property. "
1433 << "The \"" << this->GetName() << "\" generator does not support "
1434 << "duplicate custom targets. "
1435 << "Consider using a Makefiles generator or fix the project to not "
1436 << "use duplicate target names.";
1437 cmSystemTools::Error(e.str());
1441 void cmGlobalGenerator::ComputeBuildFileGenerators()
1443 for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1444 std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
1445 this->Makefiles[i]->GetExportBuildFileGenerators();
1446 for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
1447 g->Compute(this->LocalGenerators[i].get());
1452 bool cmGlobalGenerator::UnsupportedVariableIsDefined(const std::string& name,
1453 bool supported) const
1455 if (!supported && this->Makefiles.front()->GetDefinition(name)) {
1456 std::ostringstream e;
1457 /* clang-format off */
1460 " " << this->GetName() << "\n"
1461 "does not support variable\n"
1463 "but it has been specified."
1465 /* clang-format on */
1466 this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
1473 bool cmGlobalGenerator::Compute()
1475 // Make sure unsupported variables are not used.
1476 if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
1477 this->SupportsDefaultBuildType())) {
1480 if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
1481 this->SupportsCrossConfigs())) {
1484 if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
1485 this->SupportsDefaultConfigs())) {
1488 if (!this->InspectConfigTypeVariables()) {
1492 // Some generators track files replaced during the Generate.
1493 // Start with an empty vector:
1494 this->FilesReplacedDuringGenerate.clear();
1496 // clear targets to issue warning CMP0042 for
1497 this->CMP0042WarnTargets.clear();
1498 // clear targets to issue warning CMP0068 for
1499 this->CMP0068WarnTargets.clear();
1501 // Check whether this generator is allowed to run.
1502 if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
1505 this->FinalizeTargetConfiguration();
1507 this->CreateGenerationObjects();
1509 // at this point this->LocalGenerators has been filled,
1510 // so create the map from project name to vector of local generators
1511 this->FillProjectMap();
1513 // Add automatically generated sources (e.g. unity build).
1514 if (!this->AddAutomaticSources()) {
1518 // Iterate through all targets and add verification targets for header sets
1519 if (!this->AddHeaderSetVerification()) {
1523 // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC
1524 if (!this->QtAutoGen()) {
1528 // Add generator specific helper commands
1529 for (const auto& localGen : this->LocalGenerators) {
1530 localGen->AddHelperCommands();
1533 // Perform up-front computation in order to handle errors (such as unknown
1534 // features) at this point. While processing the compile features we also
1535 // calculate and cache the language standard required by the compile
1537 for (const auto& localGen : this->LocalGenerators) {
1538 if (!localGen->ComputeTargetCompileFeatures()) {
1543 for (const auto& localGen : this->LocalGenerators) {
1544 cmMakefile* mf = localGen->GetMakefile();
1545 for (const auto& g : mf->GetInstallGenerators()) {
1546 if (!g->Compute(localGen.get())) {
1552 this->AddExtraIDETargets();
1554 // Trace the dependencies, after that no custom commands should be added
1555 // because their dependencies might not be handled correctly
1556 for (const auto& localGen : this->LocalGenerators) {
1557 localGen->TraceDependencies();
1560 // Make sure that all (non-imported) targets have source files added!
1561 if (this->CheckTargetsForMissingSources()) {
1565 this->ForceLinkerLanguages();
1567 // Compute the manifest of main targets generated.
1568 for (const auto& localGen : this->LocalGenerators) {
1569 localGen->ComputeTargetManifest();
1572 // Compute the inter-target dependencies.
1573 if (!this->ComputeTargetDepends()) {
1576 this->ComputeTargetOrder();
1578 if (this->CheckTargetsForType()) {
1582 if (this->CheckTargetsForPchCompilePdb()) {
1586 for (const auto& localGen : this->LocalGenerators) {
1587 localGen->ComputeHomeRelativeOutputPath();
1593 void cmGlobalGenerator::Generate()
1595 // Create a map from local generator to the complete set of targets
1596 // it builds by default.
1597 this->InitializeProgressMarks();
1599 this->ProcessEvaluationFiles();
1601 this->CMakeInstance->UpdateProgress("Generating", 0.1f);
1603 // Generate project files
1604 for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1605 this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
1606 this->LocalGenerators[i]->Generate();
1607 if (!this->LocalGenerators[i]->GetMakefile()->IsOn(
1608 "CMAKE_SKIP_INSTALL_RULES")) {
1609 this->LocalGenerators[i]->GenerateInstallRules();
1611 this->LocalGenerators[i]->GenerateTestFiles();
1612 this->CMakeInstance->UpdateProgress(
1615 0.9f * (static_cast<float>(i) + 1.0f) /
1616 static_cast<float>(this->LocalGenerators.size()));
1618 this->SetCurrentMakefile(nullptr);
1620 if (!this->GenerateCPackPropertiesFile()) {
1621 this->GetCMakeInstance()->IssueMessage(
1622 MessageType::FATAL_ERROR, "Could not write CPack properties file.");
1625 for (auto& buildExpSet : this->BuildExportSets) {
1626 if (!buildExpSet.second->GenerateImportFile()) {
1627 if (!cmSystemTools::GetErrorOccurredFlag()) {
1628 this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
1629 "Could not write export file.");
1634 // Update rule hashes.
1635 this->CheckRuleHashes();
1637 this->WriteSummary();
1639 if (this->ExtraGenerator) {
1640 this->ExtraGenerator->Generate();
1643 // Perform validation checks on memoized link structures.
1644 this->CheckTargetLinkLibraries();
1646 if (!this->CMP0042WarnTargets.empty()) {
1647 std::ostringstream w;
1648 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";
1649 w << "MACOSX_RPATH is not specified for"
1650 " the following targets:\n";
1651 for (std::string const& t : this->CMP0042WarnTargets) {
1652 w << " " << t << "\n";
1654 this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
1658 if (!this->CMP0068WarnTargets.empty()) {
1659 std::ostringstream w;
1660 /* clang-format off */
1662 cmPolicies::GetPolicyWarning(cmPolicies::CMP0068) << "\n"
1663 "For compatibility with older versions of CMake, the install_name "
1664 "fields for the following targets are still affected by RPATH "
1667 /* clang-format on */
1668 for (std::string const& t : this->CMP0068WarnTargets) {
1669 w << " " << t << "\n";
1671 this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
1675 this->CMakeInstance->UpdateProgress("Generating done", -1);
1678 bool cmGlobalGenerator::ComputeTargetDepends()
1680 cmComputeTargetDepends ctd(this);
1681 if (!ctd.Compute()) {
1684 for (cmGeneratorTarget const* target : ctd.GetTargets()) {
1685 ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
1690 std::vector<cmGeneratorTarget*>
1691 cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const
1693 std::vector<cmGeneratorTarget*> gts;
1694 cm::append(gts, lg->GetGeneratorTargets());
1695 std::sort(gts.begin(), gts.end(),
1696 [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
1697 return this->TargetOrderIndex.at(l) <
1698 this->TargetOrderIndex.at(r);
1703 void cmGlobalGenerator::ComputeTargetOrder()
1706 auto const& lgens = this->GetLocalGenerators();
1707 for (auto const& lgen : lgens) {
1708 const auto& targets = lgen->GetGeneratorTargets();
1709 for (const auto& gt : targets) {
1710 this->ComputeTargetOrder(gt.get(), index);
1713 assert(index == this->TargetOrderIndex.size());
1716 void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
1719 std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
1720 auto insertion = this->TargetOrderIndex.insert(value);
1721 if (!insertion.second) {
1724 auto entry = insertion.first;
1726 const auto& deps = this->GetTargetDirectDepends(gt);
1727 for (const auto& d : deps) {
1728 this->ComputeTargetOrder(d, index);
1731 entry->second = index++;
1734 bool cmGlobalGenerator::QtAutoGen()
1736 #ifndef CMAKE_BOOTSTRAP
1737 cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators);
1738 return initializer.generate();
1744 bool cmGlobalGenerator::AddHeaderSetVerification()
1746 for (auto const& gen : this->LocalGenerators) {
1747 // Because AddHeaderSetVerification() adds generator targets, we need to
1748 // cache the existing list of generator targets before starting.
1749 std::vector<cmGeneratorTarget*> genTargets;
1750 genTargets.reserve(gen->GetGeneratorTargets().size());
1751 for (auto const& tgt : gen->GetGeneratorTargets()) {
1752 genTargets.push_back(tgt.get());
1755 for (auto* tgt : genTargets) {
1756 if (!tgt->AddHeaderSetVerification()) {
1762 cmTarget* allVerifyTarget = this->Makefiles.front()->FindTargetToUse(
1763 "all_verify_interface_header_sets", true);
1764 if (allVerifyTarget) {
1765 this->LocalGenerators.front()->AddGeneratorTarget(
1766 cm::make_unique<cmGeneratorTarget>(allVerifyTarget,
1767 this->LocalGenerators.front().get()));
1773 bool cmGlobalGenerator::AddAutomaticSources()
1775 for (const auto& lg : this->LocalGenerators) {
1776 lg->CreateEvaluationFileOutputs();
1778 for (const auto& lg : this->LocalGenerators) {
1779 for (const auto& gt : lg->GetGeneratorTargets()) {
1780 if (!gt->CanCompileSources()) {
1783 lg->AddUnityBuild(gt.get());
1784 lg->AddISPCDependencies(gt.get());
1785 // Targets that re-use a PCH are handled below.
1786 if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1787 lg->AddPchDependencies(gt.get());
1789 lg->AddXCConfigSources(gt.get());
1792 for (const auto& lg : this->LocalGenerators) {
1793 for (const auto& gt : lg->GetGeneratorTargets()) {
1794 if (!gt->CanCompileSources()) {
1797 // Handle targets that re-use a PCH from an above-handled target.
1798 if (gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
1799 lg->AddPchDependencies(gt.get());
1803 // The above transformations may have changed the classification of sources.
1804 // Clear the source list and classification cache (KindedSources) of all
1805 // targets so that it will be recomputed correctly by the generators later
1806 // now that the above transformations are done for all targets.
1807 for (const auto& lg : this->LocalGenerators) {
1808 for (const auto& gt : lg->GetGeneratorTargets()) {
1809 gt->ClearSourcesCache();
1815 std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
1816 cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
1818 return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
1821 std::unique_ptr<cmLinkLineComputer>
1822 cmGlobalGenerator::CreateMSVC60LinkLineComputer(
1823 cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
1825 return std::unique_ptr<cmLinkLineComputer>(
1826 cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
1829 void cmGlobalGenerator::FinalizeTargetConfiguration()
1831 std::vector<std::string> const langs =
1832 this->CMakeInstance->GetState()->GetEnabledLanguages();
1834 // Construct per-target generator information.
1835 for (const auto& mf : this->Makefiles) {
1836 const cmBTStringRange noConfigCompileDefinitions =
1837 mf->GetCompileDefinitionsEntries();
1838 cm::optional<std::map<std::string, cmValue>> perConfigCompileDefinitions;
1840 for (auto& target : mf->GetTargets()) {
1841 cmTarget* t = &target.second;
1842 t->FinalizeTargetConfiguration(noConfigCompileDefinitions,
1843 perConfigCompileDefinitions);
1846 // The standard include directories for each language
1847 // should be treated as system include directories.
1848 std::set<std::string> standardIncludesSet;
1849 for (std::string const& li : langs) {
1850 std::string const standardIncludesVar =
1851 "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES";
1852 std::string const& standardIncludesStr =
1853 mf->GetSafeDefinition(standardIncludesVar);
1854 std::vector<std::string> standardIncludesVec =
1855 cmExpandedList(standardIncludesStr);
1856 standardIncludesSet.insert(standardIncludesVec.begin(),
1857 standardIncludesVec.end());
1859 mf->AddSystemIncludeDirectories(standardIncludesSet);
1863 void cmGlobalGenerator::CreateGeneratorTargets(
1864 TargetTypes targetTypes, cmMakefile* mf, cmLocalGenerator* lg,
1865 std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
1867 if (targetTypes == AllTargets) {
1868 for (cmTarget* target : mf->GetOrderedTargets()) {
1869 lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg));
1873 for (cmTarget* t : mf->GetImportedTargets()) {
1874 lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
1878 void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes)
1880 std::map<cmTarget*, cmGeneratorTarget*> importedMap;
1881 for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1882 auto& mf = this->Makefiles[i];
1883 for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) {
1884 cmLocalGenerator* lg = this->LocalGenerators[i].get();
1885 auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
1886 importedMap[ownedImpTgt.get()] = gt.get();
1887 lg->AddOwnedImportedGeneratorTarget(std::move(gt));
1891 // Construct per-target generator information.
1892 for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
1893 this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
1894 this->LocalGenerators[i].get(), importedMap);
1898 void cmGlobalGenerator::ClearGeneratorMembers()
1900 this->BuildExportSets.clear();
1902 this->Makefiles.clear();
1904 this->LocalGenerators.clear();
1906 this->AliasTargets.clear();
1907 this->ExportSets.clear();
1908 this->InstallComponents.clear();
1909 this->TargetDependencies.clear();
1910 this->TargetSearchIndex.clear();
1911 this->GeneratorTargetSearchIndex.clear();
1912 this->MakefileSearchIndex.clear();
1913 this->LocalGeneratorSearchIndex.clear();
1914 this->TargetOrderIndex.clear();
1915 this->ProjectMap.clear();
1916 this->RuleHashes.clear();
1917 this->DirectoryContentMap.clear();
1918 this->BinaryDirectories.clear();
1919 this->GeneratedFiles.clear();
1922 void cmGlobalGenerator::ComputeTargetObjectDirectory(
1923 cmGeneratorTarget* /*unused*/) const
1927 void cmGlobalGenerator::CheckTargetProperties()
1929 // check for link libraries and include directories containing "NOTFOUND"
1930 // and for infinite loops
1931 std::map<std::string, std::string> notFoundMap;
1932 cmState* state = this->GetCMakeInstance()->GetState();
1933 for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
1934 this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
1935 for (auto const& target : this->Makefiles[i]->GetTargets()) {
1936 if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1939 for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
1940 if (lib.first.size() > 9 && cmIsNOTFOUND(lib.first)) {
1941 std::string varName = lib.first.substr(0, lib.first.size() - 9);
1942 if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
1943 varName += " (ADVANCED)";
1946 cmStrCat(notFoundMap[varName], "\n linked by target \"",
1947 target.second.GetName(), "\" in directory ",
1948 this->Makefiles[i]->GetCurrentSourceDirectory());
1949 notFoundMap[varName] = text;
1952 std::vector<std::string> incs;
1953 cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES");
1958 std::string incDirs = cmGeneratorExpression::Preprocess(
1959 *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions);
1961 cmExpandList(incDirs, incs);
1963 for (std::string const& incDir : incs) {
1964 if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) {
1965 std::string varName = incDir.substr(0, incDir.size() - 9);
1966 if (state->GetCacheEntryPropertyAsBool(varName, "ADVANCED")) {
1967 varName += " (ADVANCED)";
1970 cmStrCat(notFoundMap[varName],
1971 "\n used as include directory in directory ",
1972 this->Makefiles[i]->GetCurrentSourceDirectory());
1973 notFoundMap[varName] = text;
1979 if (!notFoundMap.empty()) {
1980 std::string notFoundVars;
1981 for (auto const& notFound : notFoundMap) {
1982 notFoundVars += notFound.first;
1983 notFoundVars += notFound.second;
1984 notFoundVars += "\n";
1986 cmSystemTools::Error("The following variables are used in this project, "
1987 "but they are set to NOTFOUND.\n"
1988 "Please set them or make sure they are set and "
1989 "tested correctly in the CMake files:\n" +
1994 int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
1995 const std::string& bindir,
1996 const std::string& projectName,
1997 const std::string& target, bool fast,
1998 std::string& output, cmMakefile* mf)
2000 // if this is not set, then this is a first time configure
2001 // and there is a good chance that the try compile stuff will
2002 // take the bulk of the time, so try and guess some progress
2003 // by getting closer and closer to 100 without actually getting there.
2004 if (!this->CMakeInstance->GetState()->GetInitializedCacheValue(
2005 "CMAKE_NUMBER_OF_MAKEFILES")) {
2006 // If CMAKE_NUMBER_OF_MAKEFILES is not set
2007 // we are in the first time progress and we have no
2008 // idea how long it will be. So, just move 1/10th of the way
2009 // there each time, and don't go over 95%
2010 this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2011 if (this->FirstTimeProgress > 0.95f) {
2012 this->FirstTimeProgress = 0.95f;
2014 this->CMakeInstance->UpdateProgress("Configuring",
2015 this->FirstTimeProgress);
2018 std::vector<std::string> newTarget = {};
2019 if (!target.empty()) {
2020 newTarget = { target };
2022 std::string config =
2023 mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
2024 cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
2026 return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
2027 config, defaultBuildOptions, false,
2028 this->TryCompileTimeout);
2031 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
2032 cmGlobalGenerator::GenerateBuildCommand(
2033 const std::string& /*unused*/, const std::string& /*unused*/,
2034 const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
2035 const std::string& /*unused*/, int /*unused*/, bool /*unused*/,
2036 const cmBuildOptions& /*unused*/, std::vector<std::string> const& /*unused*/)
2038 GeneratedMakeCommand makeCommand;
2039 makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
2040 return { std::move(makeCommand) };
2043 void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
2046 // Subclasses override this method if they e.g want to give a warning that
2047 // they do not support certain build command line options
2050 int cmGlobalGenerator::Build(
2051 int jobs, const std::string& /*unused*/, const std::string& bindir,
2052 const std::string& projectName, const std::vector<std::string>& targets,
2053 std::string& output, const std::string& makeCommandCSTR,
2054 const std::string& config, const cmBuildOptions& buildOptions, bool verbose,
2055 cmDuration timeout, cmSystemTools::OutputOption outputflag,
2056 std::vector<std::string> const& nativeOptions)
2058 bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
2061 * Run an executable command and put the stdout in output.
2063 cmWorkingDirectory workdir(bindir);
2064 output += "Change Dir: ";
2067 if (workdir.Failed()) {
2068 cmSystemTools::SetRunCommandHideConsole(hideconsole);
2069 std::string err = cmStrCat("Failed to change directory: ",
2070 std::strerror(workdir.GetLastResult()));
2071 cmSystemTools::Error(err);
2076 std::string realConfig = config;
2077 if (realConfig.empty()) {
2078 realConfig = this->GetDefaultBuildConfig();
2082 cmSystemTools::SetRunCommandHideConsole(true);
2083 std::string outputBuffer;
2084 std::string* outputPtr = &outputBuffer;
2086 std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
2087 makeCommandCSTR, projectName, bindir, targets, realConfig, jobs, verbose,
2088 buildOptions, nativeOptions);
2090 // Workaround to convince some commands to produce output.
2091 if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
2092 makeCommand.back().RequiresOutputForward) {
2093 outputflag = cmSystemTools::OUTPUT_FORWARD;
2096 // should we do a clean first?
2097 if (buildOptions.Clean) {
2098 std::vector<GeneratedMakeCommand> cleanCommand =
2099 this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
2100 { "clean" }, realConfig, jobs, verbose,
2102 output += "\nRun Clean Command:";
2103 output += cleanCommand.front().Printable();
2105 if (cleanCommand.size() != 1) {
2106 this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
2107 "The generator did not produce "
2108 "exactly one command for the "
2112 if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
2113 outputPtr, outputPtr, &retVal,
2114 nullptr, outputflag, timeout)) {
2115 cmSystemTools::SetRunCommandHideConsole(hideconsole);
2116 cmSystemTools::Error("Generator: execution of make clean failed.");
2117 output += *outputPtr;
2118 output += "\nGenerator: execution of make clean failed.\n";
2122 output += *outputPtr;
2126 std::string makeCommandStr;
2127 output += "\nRun Build Command(s):";
2130 for (auto command = makeCommand.begin();
2131 command != makeCommand.end() && retVal == 0; ++command) {
2132 makeCommandStr = command->Printable();
2133 if (command != makeCommand.end()) {
2134 makeCommandStr += " && ";
2137 output += makeCommandStr;
2138 if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
2139 outputPtr, &retVal, nullptr,
2140 outputflag, timeout)) {
2141 cmSystemTools::SetRunCommandHideConsole(hideconsole);
2142 cmSystemTools::Error(
2143 "Generator: execution of make failed. Make command was: " +
2145 output += *outputPtr;
2146 output += "\nGenerator: execution of make failed. Make command was: " +
2147 makeCommandStr + "\n";
2151 output += *outputPtr;
2154 cmSystemTools::SetRunCommandHideConsole(hideconsole);
2156 // The OpenWatcom tools do not return an error code when a link
2157 // library is not found!
2158 if (this->CMakeInstance->GetState()->UseWatcomWMake() && retVal == 0 &&
2159 output.find("W1008: cannot open") != std::string::npos) {
2166 bool cmGlobalGenerator::Open(const std::string& bindir,
2167 const std::string& projectName, bool dryRun)
2169 if (this->ExtraGenerator) {
2170 return this->ExtraGenerator->Open(bindir, projectName, dryRun);
2176 std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
2177 const std::string& target, const std::string& config,
2178 const std::string& parallel, const std::string& native, bool ignoreErrors)
2180 std::string makeCommand = cmSystemTools::GetCMakeCommand();
2182 cmStrCat(cmSystemTools::ConvertToOutputPath(makeCommand), " --build .");
2183 if (!config.empty()) {
2184 makeCommand += " --config \"";
2185 makeCommand += config;
2186 makeCommand += "\"";
2188 if (!parallel.empty()) {
2189 makeCommand += " --parallel \"";
2190 makeCommand += parallel;
2191 makeCommand += "\"";
2193 if (!target.empty()) {
2194 makeCommand += " --target \"";
2195 makeCommand += target;
2196 makeCommand += "\"";
2198 const char* sep = " -- ";
2200 const char* iflag = this->GetBuildIgnoreErrorsFlag();
2201 if (iflag && *iflag) {
2203 makeCommand += iflag;
2207 if (!native.empty()) {
2209 makeCommand += native;
2214 void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
2216 this->IndexMakefile(mf.get());
2217 this->Makefiles.push_back(std::move(mf));
2220 // estimate how many lg there will be
2221 cmValue numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue(
2222 "CMAKE_NUMBER_OF_MAKEFILES");
2225 // If CMAKE_NUMBER_OF_MAKEFILES is not set
2226 // we are in the first time progress and we have no
2227 // idea how long it will be. So, just move half way
2228 // there each time, and don't go over 95%
2229 this->FirstTimeProgress += ((1.0f - this->FirstTimeProgress) / 30.0f);
2230 if (this->FirstTimeProgress > 0.95f) {
2231 this->FirstTimeProgress = 0.95f;
2233 this->CMakeInstance->UpdateProgress("Configuring",
2234 this->FirstTimeProgress);
2238 int numGen = atoi(numGenC->c_str());
2240 static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
2244 this->CMakeInstance->UpdateProgress("Configuring", prog);
2247 void cmGlobalGenerator::AddInstallComponent(const std::string& component)
2249 if (!component.empty()) {
2250 this->InstallComponents.insert(component);
2254 void cmGlobalGenerator::MarkAsGeneratedFile(const std::string& filepath)
2256 this->GeneratedFiles.insert(filepath);
2259 bool cmGlobalGenerator::IsGeneratedFile(const std::string& filepath)
2261 return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
2264 void cmGlobalGenerator::EnableInstallTarget()
2266 this->InstallTargetEnabled = true;
2269 std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
2272 return cm::make_unique<cmLocalGenerator>(this, mf);
2275 void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
2278 this->SetConfiguredFilesPath(gen);
2279 this->TryCompileOuterMakefile = mf;
2281 gen->GetCMakeInstance()->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
2282 this->GetCMakeInstance()->AddCacheEntry(
2283 "CMAKE_MAKE_PROGRAM", make, "make program", cmStateEnums::FILEPATH);
2284 // copy the enabled languages
2285 this->GetCMakeInstance()->GetState()->SetEnabledLanguages(
2286 gen->GetCMakeInstance()->GetState()->GetEnabledLanguages());
2287 this->LanguagesReady = gen->LanguagesReady;
2288 this->ExtensionToLanguage = gen->ExtensionToLanguage;
2289 this->IgnoreExtensions = gen->IgnoreExtensions;
2290 this->LanguageToOutputExtension = gen->LanguageToOutputExtension;
2291 this->LanguageToLinkerPreference = gen->LanguageToLinkerPreference;
2292 this->OutputExtensions = gen->OutputExtensions;
2295 void cmGlobalGenerator::SetConfiguredFilesPath(cmGlobalGenerator* gen)
2297 if (!gen->ConfiguredFilesPath.empty()) {
2298 this->ConfiguredFilesPath = gen->ConfiguredFilesPath;
2300 this->ConfiguredFilesPath =
2301 cmStrCat(gen->CMakeInstance->GetHomeOutputDirectory(), "/CMakeFiles");
2305 bool cmGlobalGenerator::IsExcluded(cmStateSnapshot const& rootSnp,
2306 cmStateSnapshot const& snp_) const
2308 cmStateSnapshot snp = snp_;
2309 while (snp.IsValid()) {
2310 if (snp == rootSnp) {
2311 // No directory excludes itself.
2315 if (snp.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
2316 // This directory is excluded from its parent.
2319 snp = snp.GetBuildsystemDirectoryParent();
2324 bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
2325 cmLocalGenerator* gen) const
2329 cmStateSnapshot rootSnp = root->GetStateSnapshot();
2330 cmStateSnapshot snp = gen->GetStateSnapshot();
2332 return this->IsExcluded(rootSnp, snp);
2335 bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
2336 const cmGeneratorTarget* target) const
2338 if (!target->IsInBuildSystem()) {
2341 cmMakefile* mf = root->GetMakefile();
2342 const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
2343 if (cmValue exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
2344 // Expand the property value per configuration.
2345 unsigned int trueCount = 0;
2346 unsigned int falseCount = 0;
2347 const std::vector<std::string>& configs =
2348 mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
2349 for (const std::string& config : configs) {
2350 cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
2351 if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
2358 // Check whether the genex expansion of the property agrees in all
2360 if (trueCount > 0 && falseCount > 0) {
2361 std::ostringstream e;
2362 e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName()
2363 << "\" varies by configuration. This is not supported by the \""
2364 << root->GetGlobalGenerator()->GetName() << "\" generator.";
2365 mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
2369 // This target is included in its directory. Check whether the
2370 // directory is excluded.
2371 return this->IsExcluded(root, target->GetLocalGenerator());
2374 void cmGlobalGenerator::GetEnabledLanguages(
2375 std::vector<std::string>& lang) const
2377 lang = this->CMakeInstance->GetState()->GetEnabledLanguages();
2380 int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
2382 auto const it = this->LanguageToLinkerPreference.find(lang);
2383 if (it != this->LanguageToLinkerPreference.end()) {
2389 void cmGlobalGenerator::FillProjectMap()
2391 this->ProjectMap.clear(); // make sure we start with a clean map
2392 for (const auto& localGen : this->LocalGenerators) {
2393 // for each local generator add all projects
2394 cmStateSnapshot snp = localGen->GetStateSnapshot();
2397 std::string snpProjName = snp.GetProjectName();
2398 if (name != snpProjName) {
2400 this->ProjectMap[name].push_back(localGen.get());
2402 snp = snp.GetBuildsystemDirectoryParent();
2403 } while (snp.IsValid());
2407 cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
2409 auto const it = this->MakefileSearchIndex.find(start_dir);
2410 if (it != this->MakefileSearchIndex.end()) {
2416 cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
2417 cmDirectoryId const& id) const
2419 auto const it = this->LocalGeneratorSearchIndex.find(id.String);
2420 if (it != this->LocalGeneratorSearchIndex.end()) {
2426 void cmGlobalGenerator::AddAlias(const std::string& name,
2427 std::string const& tgtName)
2429 this->AliasTargets[name] = tgtName;
2432 bool cmGlobalGenerator::IsAlias(const std::string& name) const
2434 return cm::contains(this->AliasTargets, name);
2437 void cmGlobalGenerator::IndexTarget(cmTarget* t)
2439 if (!t->IsImported() || t->IsImportedGloballyVisible()) {
2440 this->TargetSearchIndex[t->GetName()] = t;
2444 void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
2446 if (!gt->IsImported() || gt->IsImportedGloballyVisible()) {
2447 this->GeneratorTargetSearchIndex[gt->GetName()] = gt;
2451 static char const hexDigits[] = "0123456789abcdef";
2453 std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
2454 cmGeneratorTarget const* gt)
2456 // Use the pointer value to uniquely identify the target instance.
2457 // Use a ":" prefix to avoid conflict with project-defined targets.
2458 // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
2459 // other special characters.
2460 constexpr size_t sizeof_ptr =
2461 sizeof(gt); // NOLINT(bugprone-sizeof-expression)
2462 char buf[1 + sizeof_ptr * 2];
2465 for (size_t i = 0; i < sizeof_ptr; ++i) {
2466 unsigned char const c = reinterpret_cast<unsigned char const*>(>)[i];
2467 *b++ = hexDigits[(c & 0xf0) >> 4];
2468 *b++ = hexDigits[(c & 0x0f)];
2470 std::string id(buf, sizeof(buf));
2471 // We internally index pointers to non-const generator targets
2472 // but our callers only have pointers to const generator targets.
2473 // They will give up non-const privileges when looking up anyway.
2474 this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
2478 void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
2480 // We index by both source and binary directory. add_subdirectory
2481 // supports multiple build directories sharing the same source directory.
2482 // The source directory index will reference only the first time it is used.
2483 this->MakefileSearchIndex.insert(
2484 MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
2485 this->MakefileSearchIndex.insert(
2486 MakefileMap::value_type(mf->GetCurrentBinaryDirectory(), mf));
2489 void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
2491 cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
2492 this->LocalGeneratorSearchIndex[id.String] = lg;
2495 cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
2497 auto const it = this->TargetSearchIndex.find(name);
2498 if (it != this->TargetSearchIndex.end()) {
2504 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
2505 std::string const& name) const
2507 auto const it = this->GeneratorTargetSearchIndex.find(name);
2508 if (it != this->GeneratorTargetSearchIndex.end()) {
2514 cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
2515 bool excludeAliases) const
2517 if (!excludeAliases) {
2518 auto const ai = this->AliasTargets.find(name);
2519 if (ai != this->AliasTargets.end()) {
2520 return this->FindTargetImpl(ai->second);
2523 return this->FindTargetImpl(name);
2526 cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
2527 const std::string& name) const
2529 auto const ai = this->AliasTargets.find(name);
2530 if (ai != this->AliasTargets.end()) {
2531 return this->FindGeneratorTargetImpl(ai->second);
2533 return this->FindGeneratorTargetImpl(name);
2536 bool cmGlobalGenerator::NameResolvesToFramework(
2537 const std::string& libname) const
2539 if (cmSystemTools::IsPathToFramework(libname)) {
2543 if (cmTarget* tgt = this->FindTarget(libname)) {
2544 if (tgt->IsFrameworkOnApple()) {
2552 // If the file has no extension it's either a raw executable or might
2553 // be a direct reference to a binary within a framework (bad practice!).
2554 // This is where we change the path to point to the framework directory.
2555 // .tbd files also can be located in SDK frameworks (they are
2556 // placeholders for actual libraries shipped with the OS)
2557 cm::optional<std::pair<std::string, std::string>>
2558 cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
2559 bool extendedFormat) const
2561 // Check for framework structure:
2562 // (/path/to/)?FwName.framework
2563 // or (/path/to/)?FwName.framework/FwName(.tbd)?
2564 // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)?
2565 static cmsys::RegularExpression frameworkPath(
2566 "((.+)/)?(.+)\\.framework(/Versions/[^/]+)?(/(.+))?$");
2568 auto ext = cmSystemTools::GetFilenameLastExtension(path);
2569 if ((ext.empty() || ext == ".tbd" || ext == ".framework") &&
2570 frameworkPath.find(path)) {
2571 auto name = frameworkPath.match(3);
2573 cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(6));
2574 if (!libname.empty() && !cmHasPrefix(libname, name)) {
2577 return std::pair<std::string, std::string>{ frameworkPath.match(2), name };
2580 if (extendedFormat) {
2581 // path format can be more flexible: (/path/to/)?fwName(.framework)?
2582 auto fwDir = cmSystemTools::GetParentDirectory(path);
2583 auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework"
2584 ? cmSystemTools::GetFilenameWithoutExtension(path)
2585 : cmSystemTools::GetFilenameName(path);
2587 return std::pair<std::string, std::string>{ fwDir, name };
2593 bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
2594 std::string const& reason) const
2596 cmTarget* tgt = this->FindTarget(targetName);
2600 MessageType messageType = MessageType::AUTHOR_WARNING;
2601 std::ostringstream e;
2602 bool issueMessage = false;
2603 switch (tgt->GetPolicyStatusCMP0037()) {
2604 case cmPolicies::WARN:
2605 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
2606 issueMessage = true;
2608 case cmPolicies::OLD:
2610 case cmPolicies::NEW:
2611 case cmPolicies::REQUIRED_IF_USED:
2612 case cmPolicies::REQUIRED_ALWAYS:
2613 issueMessage = true;
2614 messageType = MessageType::FATAL_ERROR;
2618 e << "The target name \"" << targetName << "\" is reserved " << reason
2620 if (messageType == MessageType::AUTHOR_WARNING) {
2621 e << " It may result in undefined behavior.";
2623 this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
2624 tgt->GetBacktrace());
2625 if (messageType == MessageType::FATAL_ERROR) {
2632 void cmGlobalGenerator::CreateDefaultGlobalTargets(
2633 std::vector<GlobalTargetInfo>& targets)
2635 this->AddGlobalTarget_Package(targets);
2636 this->AddGlobalTarget_PackageSource(targets);
2637 this->AddGlobalTarget_Test(targets);
2638 this->AddGlobalTarget_EditCache(targets);
2639 this->AddGlobalTarget_RebuildCache(targets);
2640 this->AddGlobalTarget_Install(targets);
2643 void cmGlobalGenerator::AddGlobalTarget_Package(
2644 std::vector<GlobalTargetInfo>& targets)
2646 auto& mf = this->Makefiles[0];
2647 std::string configFile =
2648 cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
2649 if (!cmSystemTools::FileExists(configFile)) {
2653 static const auto reservedTargets = { "package", "PACKAGE" };
2654 for (auto const& target : reservedTargets) {
2655 if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
2660 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2661 GlobalTargetInfo gti;
2662 gti.Name = this->GetPackageTargetName();
2663 gti.Message = "Run CPack packaging tool...";
2664 gti.UsesTerminal = true;
2665 gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2666 cmCustomCommandLine singleLine;
2667 singleLine.push_back(cmSystemTools::GetCPackCommand());
2668 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2669 singleLine.push_back("-C");
2670 singleLine.push_back(cmakeCfgIntDir);
2672 singleLine.push_back("--config");
2673 singleLine.push_back("./CPackConfig.cmake");
2674 gti.CommandLines.push_back(std::move(singleLine));
2675 if (this->GetPreinstallTargetName()) {
2676 gti.Depends.emplace_back(this->GetPreinstallTargetName());
2678 cmValue noPackageAll =
2679 mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
2680 if (cmIsOff(noPackageAll)) {
2681 gti.Depends.emplace_back(this->GetAllTargetName());
2684 targets.push_back(std::move(gti));
2687 void cmGlobalGenerator::AddGlobalTarget_PackageSource(
2688 std::vector<GlobalTargetInfo>& targets)
2690 const char* packageSourceTargetName = this->GetPackageSourceTargetName();
2691 if (!packageSourceTargetName) {
2695 auto& mf = this->Makefiles[0];
2696 std::string configFile =
2697 cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
2698 if (!cmSystemTools::FileExists(configFile)) {
2702 static const auto reservedTargets = { "package_source" };
2703 for (auto const& target : reservedTargets) {
2704 if (!this->CheckCMP0037(target,
2705 "when CPack source packaging is enabled")) {
2710 GlobalTargetInfo gti;
2711 gti.Name = packageSourceTargetName;
2712 gti.Message = "Run CPack packaging tool for source...";
2713 gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2714 gti.UsesTerminal = true;
2715 cmCustomCommandLine singleLine;
2716 singleLine.push_back(cmSystemTools::GetCPackCommand());
2717 singleLine.push_back("--config");
2718 singleLine.push_back("./CPackSourceConfig.cmake");
2719 singleLine.push_back(std::move(configFile));
2720 gti.CommandLines.push_back(std::move(singleLine));
2721 targets.push_back(std::move(gti));
2724 void cmGlobalGenerator::AddGlobalTarget_Test(
2725 std::vector<GlobalTargetInfo>& targets)
2727 auto& mf = this->Makefiles[0];
2728 if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
2732 static const auto reservedTargets = { "test", "RUN_TESTS" };
2733 for (auto const& target : reservedTargets) {
2734 if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
2739 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2740 GlobalTargetInfo gti;
2741 gti.Name = this->GetTestTargetName();
2742 gti.Message = "Running tests...";
2743 gti.UsesTerminal = true;
2744 cmCustomCommandLine singleLine;
2745 singleLine.push_back(cmSystemTools::GetCTestCommand());
2746 singleLine.push_back("--force-new-ctest-process");
2747 std::vector<std::string> args;
2748 if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) {
2749 for (auto const& arg : args) {
2750 singleLine.push_back(arg);
2753 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2754 singleLine.push_back("-C");
2755 singleLine.push_back(cmakeCfgIntDir);
2756 } else // TODO: This is a hack. Should be something to do with the
2759 singleLine.push_back("$(ARGS)");
2761 gti.CommandLines.push_back(std::move(singleLine));
2762 targets.push_back(std::move(gti));
2765 void cmGlobalGenerator::AddGlobalTarget_EditCache(
2766 std::vector<GlobalTargetInfo>& targets) const
2768 const char* editCacheTargetName = this->GetEditCacheTargetName();
2769 if (!editCacheTargetName) {
2772 GlobalTargetInfo gti;
2773 gti.Name = editCacheTargetName;
2774 gti.PerConfig = cmTarget::PerConfig::No;
2775 cmCustomCommandLine singleLine;
2777 // Use generator preference for the edit_cache rule if it is defined.
2778 std::string edit_cmd = this->GetEditCacheCommand();
2779 if (!edit_cmd.empty()) {
2780 singleLine.push_back(std::move(edit_cmd));
2781 singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2782 singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2783 gti.Message = "Running CMake cache editor...";
2784 gti.UsesTerminal = true;
2786 singleLine.push_back(cmSystemTools::GetCMakeCommand());
2787 singleLine.push_back("-E");
2788 singleLine.push_back("echo");
2789 singleLine.push_back("No interactive CMake dialog available.");
2790 gti.Message = "No interactive CMake dialog available...";
2791 gti.UsesTerminal = false;
2792 gti.StdPipesUTF8 = true;
2794 gti.CommandLines.push_back(std::move(singleLine));
2796 targets.push_back(std::move(gti));
2799 void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
2800 std::vector<GlobalTargetInfo>& targets) const
2802 const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
2803 if (!rebuildCacheTargetName) {
2806 GlobalTargetInfo gti;
2807 gti.Name = rebuildCacheTargetName;
2808 gti.Message = "Running CMake to regenerate build system...";
2809 gti.UsesTerminal = true;
2810 gti.PerConfig = cmTarget::PerConfig::No;
2811 cmCustomCommandLine singleLine;
2812 singleLine.push_back(cmSystemTools::GetCMakeCommand());
2813 singleLine.push_back("--regenerate-during-build");
2814 singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2815 singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2816 gti.CommandLines.push_back(std::move(singleLine));
2817 gti.StdPipesUTF8 = true;
2818 targets.push_back(std::move(gti));
2821 void cmGlobalGenerator::AddGlobalTarget_Install(
2822 std::vector<GlobalTargetInfo>& targets)
2824 auto& mf = this->Makefiles[0];
2825 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2826 bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
2827 if (this->InstallTargetEnabled && skipInstallRules) {
2828 this->CMakeInstance->IssueMessage(
2829 MessageType::WARNING,
2830 "CMAKE_SKIP_INSTALL_RULES was enabled even though "
2831 "installation rules have been specified",
2832 mf->GetBacktrace());
2833 } else if (this->InstallTargetEnabled && !skipInstallRules) {
2834 if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
2835 std::set<std::string>* componentsSet = &this->InstallComponents;
2836 std::ostringstream ostr;
2837 if (!componentsSet->empty()) {
2838 ostr << "Available install components are: ";
2839 ostr << cmWrap('"', *componentsSet, '"', " ");
2841 ostr << "Only default component available";
2843 GlobalTargetInfo gti;
2844 gti.Name = "list_install_components";
2845 gti.Message = ostr.str();
2846 gti.UsesTerminal = false;
2847 targets.push_back(std::move(gti));
2849 std::string cmd = cmSystemTools::GetCMakeCommand();
2850 GlobalTargetInfo gti;
2851 gti.Name = this->GetInstallTargetName();
2852 gti.Message = "Install the project...";
2853 gti.UsesTerminal = true;
2854 gti.StdPipesUTF8 = true;
2855 cmCustomCommandLine singleLine;
2856 if (this->GetPreinstallTargetName()) {
2857 gti.Depends.emplace_back(this->GetPreinstallTargetName());
2859 cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
2860 if (cmIsOff(noall)) {
2861 gti.Depends.emplace_back(this->GetAllTargetName());
2864 if (mf->GetDefinition("CMake_BINARY_DIR") &&
2865 !mf->IsOn("CMAKE_CROSSCOMPILING")) {
2866 // We are building CMake itself. We cannot use the original
2867 // executable to install over itself. The generator will
2868 // automatically convert this name to the build-time location.
2871 singleLine.push_back(cmd);
2872 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2873 std::string cfgArg = "-DBUILD_TYPE=";
2874 bool useEPN = this->UseEffectivePlatformName(mf.get());
2876 cfgArg += "$(CONFIGURATION)";
2877 singleLine.push_back(cfgArg);
2878 cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
2880 cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR");
2882 singleLine.push_back(cfgArg);
2884 singleLine.push_back("-P");
2885 singleLine.push_back("cmake_install.cmake");
2886 gti.CommandLines.push_back(singleLine);
2887 targets.push_back(gti);
2890 if (const char* install_local = this->GetInstallLocalTargetName()) {
2891 gti.Name = install_local;
2892 gti.Message = "Installing only the local directory...";
2893 gti.UsesTerminal = true;
2894 gti.CommandLines.clear();
2896 cmCustomCommandLine localCmdLine = singleLine;
2898 localCmdLine.insert(localCmdLine.begin() + 1,
2899 "-DCMAKE_INSTALL_LOCAL_ONLY=1");
2901 gti.CommandLines.push_back(std::move(localCmdLine));
2902 targets.push_back(gti);
2906 const char* install_strip = this->GetInstallStripTargetName();
2907 if ((install_strip != nullptr) && (mf->IsSet("CMAKE_STRIP"))) {
2908 gti.Name = install_strip;
2909 gti.Message = "Installing the project stripped...";
2910 gti.UsesTerminal = true;
2911 gti.CommandLines.clear();
2913 cmCustomCommandLine stripCmdLine = singleLine;
2915 stripCmdLine.insert(stripCmdLine.begin() + 1,
2916 "-DCMAKE_INSTALL_DO_STRIP=1");
2917 gti.CommandLines.push_back(std::move(stripCmdLine));
2918 targets.push_back(gti);
2923 std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
2925 cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
2926 "PREDEFINED_TARGETS_FOLDER");
2932 return "CMakePredefinedTargets";
2935 bool cmGlobalGenerator::UseFolderProperty() const
2938 this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
2940 // If this property is defined, let the setter turn this on or off...
2943 return cmIsOn(*prop);
2946 // By default, this feature is OFF, since it is not supported in the
2947 // Visual Studio Express editions until VS11:
2952 void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
2957 mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig);
2959 // Do nothing if gti.Name is already used
2964 cmTarget& target = tb.first;
2965 target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2967 // Store the custom command in the target.
2969 cc.SetCommandLines(gti.CommandLines);
2970 cc.SetWorkingDirectory(gti.WorkingDir.c_str());
2971 cc.SetStdPipesUTF8(gti.StdPipesUTF8);
2972 cc.SetUsesTerminal(gti.UsesTerminal);
2973 target.AddPostBuildCommand(std::move(cc));
2974 if (!gti.Message.empty()) {
2975 target.SetProperty("EchoString", gti.Message);
2977 for (std::string const& d : gti.Depends) {
2978 target.AddUtility(d, false);
2981 // Organize in the "predefined targets" folder:
2983 if (this->UseFolderProperty()) {
2984 target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
2988 std::string cmGlobalGenerator::GenerateRuleFile(
2989 std::string const& output) const
2991 std::string ruleFile = cmStrCat(output, ".rule");
2992 const char* dir = this->GetCMakeCFGIntDir();
2993 if (dir && dir[0] == '$') {
2994 cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
2999 bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
3001 return mf->PlatformIsAppleEmbedded();
3004 std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
3005 std::string const& l) const
3007 auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
3008 if (it != this->LanguageToOriginalSharedLibFlags.end()) {
3014 void cmGlobalGenerator::AppendDirectoryForConfig(const std::string& /*unused*/,
3015 const std::string& /*unused*/,
3016 const std::string& /*unused*/,
3017 std::string& /*unused*/)
3019 // Subclasses that support multiple configurations should implement
3020 // this method to append the subdirectory for the given build
3024 cmGlobalGenerator::TargetDependSet const&
3025 cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target)
3027 return this->TargetDependencies[target];
3030 bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
3032 // The following is a list of targets reserved
3033 // by one or more of the cmake generators.
3035 // Adding additional targets to this list will require a policy!
3036 const char* reservedTargets[] = { "all", "ALL_BUILD", "help",
3037 "install", "INSTALL", "preinstall",
3038 "clean", "edit_cache", "rebuild_cache",
3041 return cm::contains(reservedTargets, name);
3044 void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
3045 std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
3047 this->ExtraGenerator = std::move(extraGenerator);
3048 if (this->ExtraGenerator) {
3049 this->ExtraGenerator->SetGlobalGenerator(this);
3053 std::string cmGlobalGenerator::GetExtraGeneratorName() const
3055 return this->ExtraGenerator ? this->ExtraGenerator->GetName()
3059 void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
3061 this->FilesReplacedDuringGenerate.push_back(filename);
3064 void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
3065 std::vector<std::string>& filenames)
3068 std::copy(this->FilesReplacedDuringGenerate.begin(),
3069 this->FilesReplacedDuringGenerate.end(),
3070 std::back_inserter(filenames));
3073 void cmGlobalGenerator::GetTargetSets(
3074 TargetDependSet& projectTargets, TargetDependSet& originalTargets,
3075 cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
3077 // loop over all local generators
3078 for (auto* generator : generators) {
3079 // check to make sure generator is not excluded
3080 if (this->IsExcluded(root, generator)) {
3083 // loop over all the generator targets in the makefile
3084 for (const auto& target : generator->GetGeneratorTargets()) {
3085 if (this->IsRootOnlyTarget(target.get()) &&
3086 target->GetLocalGenerator() != root) {
3089 // put the target in the set of original targets
3090 originalTargets.insert(target.get());
3091 // Get the set of targets that depend on target
3092 this->AddTargetDepends(target.get(), projectTargets);
3097 bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
3099 return (target->GetType() == cmStateEnums::GLOBAL_TARGET ||
3100 target->GetName() == this->GetAllTargetName());
3103 void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
3104 TargetDependSet& projectTargets)
3106 // add the target itself
3107 if (projectTargets.insert(target).second) {
3108 // This is the first time we have encountered the target.
3109 // Recursively follow its dependencies.
3110 for (auto const& t : this->GetTargetDirectDepends(target)) {
3111 this->AddTargetDepends(t, projectTargets);
3116 void cmGlobalGenerator::AddToManifest(std::string const& f)
3118 // Add to the content listing for the file's directory.
3119 std::string dir = cmSystemTools::GetFilenamePath(f);
3120 std::string file = cmSystemTools::GetFilenameName(f);
3121 DirectoryContent& dc = this->DirectoryContentMap[dir];
3122 dc.Generated.insert(file);
3123 dc.All.insert(file);
3126 std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
3127 std::string const& dir, bool needDisk)
3129 DirectoryContent& dc = this->DirectoryContentMap[dir];
3131 long mt = cmSystemTools::ModifiedTime(dir);
3132 if (mt != dc.LastDiskTime) {
3133 // Reset to non-loaded directory content.
3134 dc.All = dc.Generated;
3136 // Load the directory content from disk.
3139 unsigned long n = d.GetNumberOfFiles();
3140 for (unsigned long i = 0; i < n; ++i) {
3141 const char* f = d.GetFile(i);
3142 if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
3147 dc.LastDiskTime = mt;
3153 void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
3154 std::string const& content)
3156 #if !defined(CMAKE_BOOTSTRAP)
3157 // Ignore if there are no outputs.
3158 if (outputs.empty()) {
3162 // Compute a hash of the rule.
3165 cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3166 std::string const md5_hex = md5.HashString(content);
3167 memcpy(hash.Data, md5_hex.c_str(), 32);
3170 // Shorten the output name (in expected use case).
3172 this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]);
3174 // Associate the hash with this output.
3175 this->RuleHashes[fname] = hash;
3182 void cmGlobalGenerator::CheckRuleHashes()
3184 #if !defined(CMAKE_BOOTSTRAP)
3185 std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
3186 std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
3187 this->CheckRuleHashes(pfile, home);
3188 this->WriteRuleHashes(pfile);
3192 void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
3193 std::string const& home)
3195 #if defined(_WIN32) || defined(__CYGWIN__)
3196 cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
3198 cmsys::ifstream fin(pfile.c_str());
3205 while (cmSystemTools::GetLineFromStream(fin, line)) {
3206 // Line format is a 32-byte hex string followed by a space
3207 // followed by a file name (with no escaping).
3209 // Skip blank and comment lines.
3210 if (line.size() < 34 || line[0] == '#') {
3214 // Get the filename.
3215 fname = line.substr(33);
3217 // Look for a hash for this file's rule.
3218 auto const rhi = this->RuleHashes.find(fname);
3219 if (rhi != this->RuleHashes.end()) {
3220 // Compare the rule hash in the file to that we were given.
3221 if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
3222 // The rule has changed. Delete the output so it will be
3224 fname = cmSystemTools::CollapseFullPath(fname, home);
3225 cmSystemTools::RemoveFile(fname);
3228 // We have no hash for a rule previously listed. This may be a
3229 // case where a user has turned off a build option and might
3230 // want to turn it back on later, so do not delete the file.
3231 // Instead, we keep the rule hash as long as the file exists so
3232 // that if the feature is turned back on and the rule has
3233 // changed the file is still rebuilt.
3234 std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
3235 if (cmSystemTools::FileExists(fpath)) {
3237 memcpy(hash.Data, line.c_str(), 32);
3238 this->RuleHashes[fname] = hash;
3244 void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
3246 // Now generate a new persistence file with the current hashes.
3247 if (this->RuleHashes.empty()) {
3248 cmSystemTools::RemoveFile(pfile);
3250 cmGeneratedFileStream fout(pfile);
3251 fout << "# Hashes of file build rules.\n";
3252 for (auto const& rh : this->RuleHashes) {
3253 fout.write(rh.second.Data, 32);
3254 fout << " " << rh.first << "\n";
3259 void cmGlobalGenerator::WriteSummary()
3261 // Record all target directories in a central location.
3262 std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3263 "/CMakeFiles/TargetDirectories.txt");
3264 cmGeneratedFileStream fout(fname);
3266 for (const auto& lg : this->LocalGenerators) {
3267 for (const auto& tgt : lg->GetGeneratorTargets()) {
3268 if (!tgt->IsInBuildSystem()) {
3271 this->WriteSummary(tgt.get());
3272 fout << tgt->GetSupportDirectory() << "\n";
3277 void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
3279 // Place the labels file in a per-target support directory.
3280 std::string dir = target->GetSupportDirectory();
3281 std::string file = cmStrCat(dir, "/Labels.txt");
3282 std::string json_file = dir + "/Labels.json";
3284 #ifndef CMAKE_BOOTSTRAP
3285 // Check whether labels are enabled for this target.
3286 cmValue targetLabels = target->GetProperty("LABELS");
3287 cmValue directoryLabels =
3288 target->Target->GetMakefile()->GetProperty("LABELS");
3289 cmValue cmakeDirectoryLabels =
3290 target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
3291 if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
3292 Json::Value lj_root(Json::objectValue);
3293 Json::Value& lj_target = lj_root["target"] = Json::objectValue;
3294 lj_target["name"] = target->GetName();
3295 Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
3296 Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
3298 cmSystemTools::MakeDirectory(dir);
3299 cmGeneratedFileStream fout(file);
3301 std::vector<std::string> labels;
3303 // List the target-wide labels. All sources in the target get
3306 cmExpandList(*targetLabels, labels);
3307 if (!labels.empty()) {
3308 fout << "# Target labels\n";
3309 for (std::string const& l : labels) {
3310 fout << " " << l << "\n";
3311 lj_target_labels.append(l);
3316 // List directory labels
3317 std::vector<std::string> directoryLabelsList;
3318 std::vector<std::string> cmakeDirectoryLabelsList;
3320 if (directoryLabels) {
3321 cmExpandList(*directoryLabels, directoryLabelsList);
3324 if (cmakeDirectoryLabels) {
3325 cmExpandList(*cmakeDirectoryLabels, cmakeDirectoryLabelsList);
3328 if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
3329 fout << "# Directory labels\n";
3332 for (std::string const& li : directoryLabelsList) {
3333 fout << " " << li << "\n";
3334 lj_target_labels.append(li);
3337 for (std::string const& li : cmakeDirectoryLabelsList) {
3338 fout << " " << li << "\n";
3339 lj_target_labels.append(li);
3342 // List the source files with any per-source labels.
3343 fout << "# Source files and their labels\n";
3344 std::vector<cmSourceFile*> sources;
3345 std::vector<std::string> const& configs =
3346 target->Target->GetMakefile()->GetGeneratorConfigs(
3347 cmMakefile::IncludeEmptyConfig);
3348 for (std::string const& c : configs) {
3349 target->GetSourceFiles(sources, c);
3351 auto const sourcesEnd = cmRemoveDuplicates(sources);
3352 for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
3353 Json::Value& lj_source = lj_sources.append(Json::objectValue);
3354 std::string const& sfp = sf->ResolveFullPath();
3355 fout << sfp << "\n";
3356 lj_source["file"] = sfp;
3357 if (cmValue svalue = sf->GetProperty("LABELS")) {
3359 Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
3360 cmExpandList(*svalue, labels);
3361 for (std::string const& label : labels) {
3362 fout << " " << label << "\n";
3363 lj_source_labels.append(label);
3367 cmGeneratedFileStream json_fout(json_file);
3368 json_fout << lj_root;
3372 cmSystemTools::RemoveFile(file);
3373 cmSystemTools::RemoveFile(json_file);
3378 std::string cmGlobalGenerator::EscapeJSON(const std::string& s)
3381 result.reserve(s.size());
3402 void cmGlobalGenerator::SetFilenameTargetDepends(
3403 cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
3405 this->FilenameTargetDepends[sf] = tgts;
3408 std::set<cmGeneratorTarget const*> const&
3409 cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
3411 return this->FilenameTargetDepends[sf];
3414 const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
3416 auto i = this->RealPaths.lower_bound(dir);
3417 if (i == this->RealPaths.end() ||
3418 this->RealPaths.key_comp()(dir, i->first)) {
3419 i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
3424 std::string cmGlobalGenerator::NewDeferId()
3426 return cmStrCat("__"_s, std::to_string(this->NextDeferId++));
3429 void cmGlobalGenerator::ProcessEvaluationFiles()
3431 std::vector<std::string> generatedFiles;
3432 for (auto& localGen : this->LocalGenerators) {
3433 localGen->ProcessEvaluationFiles(generatedFiles);
3437 std::string cmGlobalGenerator::ExpandCFGIntDir(
3438 const std::string& str, const std::string& /*config*/) const
3443 bool cmGlobalGenerator::GenerateCPackPropertiesFile()
3445 cmake::InstalledFilesMap const& installedFiles =
3446 this->CMakeInstance->GetInstalledFiles();
3448 const auto& lg = this->LocalGenerators[0];
3449 cmMakefile* mf = lg->GetMakefile();
3451 std::vector<std::string> configs =
3452 mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
3453 std::string config = mf->GetDefaultConfiguration();
3455 std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3456 "/CPackProperties.cmake");
3458 if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
3462 cmGeneratedFileStream file(path);
3463 file << "# CPack properties\n";
3465 for (auto const& i : installedFiles) {
3466 cmInstalledFile const& installedFile = i.second;
3468 cmCPackPropertiesGenerator cpackPropertiesGenerator(
3469 lg.get(), installedFile, configs);
3471 cpackPropertiesGenerator.Generate(file, config, configs);
3477 cmInstallRuntimeDependencySet*
3478 cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
3480 auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
3481 auto* retval = set.get();
3482 this->RuntimeDependencySets.push_back(std::move(set));
3486 cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
3487 const std::string& name)
3489 auto it = this->RuntimeDependencySetsByName.find(name);
3490 if (it == this->RuntimeDependencySetsByName.end()) {
3491 auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
3493 this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
3495 this->RuntimeDependencySets.push_back(std::move(set));