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<cmGlobalGenerator::FrameworkDescriptor>
2558 cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
2559 FrameworkFormat format) 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 (format == FrameworkFormat::Strict && libname.empty()) {
2577 if (!libname.empty() && !cmHasPrefix(libname, name)) {
2581 if (libname.empty() || name.size() == libname.size()) {
2582 return FrameworkDescriptor{ frameworkPath.match(2), name };
2585 return FrameworkDescriptor{ frameworkPath.match(2), name,
2586 libname.substr(name.size()) };
2589 if (format == FrameworkFormat::Extended) {
2590 // path format can be more flexible: (/path/to/)?fwName(.framework)?
2591 auto fwDir = cmSystemTools::GetParentDirectory(path);
2592 auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework"
2593 ? cmSystemTools::GetFilenameWithoutExtension(path)
2594 : cmSystemTools::GetFilenameName(path);
2596 return FrameworkDescriptor{ fwDir, name };
2602 bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
2603 std::string const& reason) const
2605 cmTarget* tgt = this->FindTarget(targetName);
2609 MessageType messageType = MessageType::AUTHOR_WARNING;
2610 std::ostringstream e;
2611 bool issueMessage = false;
2612 switch (tgt->GetPolicyStatusCMP0037()) {
2613 case cmPolicies::WARN:
2614 e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
2615 issueMessage = true;
2617 case cmPolicies::OLD:
2619 case cmPolicies::NEW:
2620 case cmPolicies::REQUIRED_IF_USED:
2621 case cmPolicies::REQUIRED_ALWAYS:
2622 issueMessage = true;
2623 messageType = MessageType::FATAL_ERROR;
2627 e << "The target name \"" << targetName << "\" is reserved " << reason
2629 if (messageType == MessageType::AUTHOR_WARNING) {
2630 e << " It may result in undefined behavior.";
2632 this->GetCMakeInstance()->IssueMessage(messageType, e.str(),
2633 tgt->GetBacktrace());
2634 if (messageType == MessageType::FATAL_ERROR) {
2641 void cmGlobalGenerator::CreateDefaultGlobalTargets(
2642 std::vector<GlobalTargetInfo>& targets)
2644 this->AddGlobalTarget_Package(targets);
2645 this->AddGlobalTarget_PackageSource(targets);
2646 this->AddGlobalTarget_Test(targets);
2647 this->AddGlobalTarget_EditCache(targets);
2648 this->AddGlobalTarget_RebuildCache(targets);
2649 this->AddGlobalTarget_Install(targets);
2652 void cmGlobalGenerator::AddGlobalTarget_Package(
2653 std::vector<GlobalTargetInfo>& targets)
2655 auto& mf = this->Makefiles[0];
2656 std::string configFile =
2657 cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
2658 if (!cmSystemTools::FileExists(configFile)) {
2662 static const auto reservedTargets = { "package", "PACKAGE" };
2663 for (auto const& target : reservedTargets) {
2664 if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
2669 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2670 GlobalTargetInfo gti;
2671 gti.Name = this->GetPackageTargetName();
2672 gti.Message = "Run CPack packaging tool...";
2673 gti.UsesTerminal = true;
2674 gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2675 cmCustomCommandLine singleLine;
2676 singleLine.push_back(cmSystemTools::GetCPackCommand());
2677 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2678 singleLine.push_back("-C");
2679 singleLine.push_back(cmakeCfgIntDir);
2681 singleLine.push_back("--config");
2682 singleLine.push_back("./CPackConfig.cmake");
2683 gti.CommandLines.push_back(std::move(singleLine));
2684 if (this->GetPreinstallTargetName()) {
2685 gti.Depends.emplace_back(this->GetPreinstallTargetName());
2687 cmValue noPackageAll =
2688 mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY");
2689 if (cmIsOff(noPackageAll)) {
2690 gti.Depends.emplace_back(this->GetAllTargetName());
2693 targets.push_back(std::move(gti));
2696 void cmGlobalGenerator::AddGlobalTarget_PackageSource(
2697 std::vector<GlobalTargetInfo>& targets)
2699 const char* packageSourceTargetName = this->GetPackageSourceTargetName();
2700 if (!packageSourceTargetName) {
2704 auto& mf = this->Makefiles[0];
2705 std::string configFile =
2706 cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
2707 if (!cmSystemTools::FileExists(configFile)) {
2711 static const auto reservedTargets = { "package_source" };
2712 for (auto const& target : reservedTargets) {
2713 if (!this->CheckCMP0037(target,
2714 "when CPack source packaging is enabled")) {
2719 GlobalTargetInfo gti;
2720 gti.Name = packageSourceTargetName;
2721 gti.Message = "Run CPack packaging tool for source...";
2722 gti.WorkingDir = mf->GetCurrentBinaryDirectory();
2723 gti.UsesTerminal = true;
2724 cmCustomCommandLine singleLine;
2725 singleLine.push_back(cmSystemTools::GetCPackCommand());
2726 singleLine.push_back("--config");
2727 singleLine.push_back("./CPackSourceConfig.cmake");
2728 singleLine.push_back(std::move(configFile));
2729 gti.CommandLines.push_back(std::move(singleLine));
2730 targets.push_back(std::move(gti));
2733 void cmGlobalGenerator::AddGlobalTarget_Test(
2734 std::vector<GlobalTargetInfo>& targets)
2736 auto& mf = this->Makefiles[0];
2737 if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
2741 static const auto reservedTargets = { "test", "RUN_TESTS" };
2742 for (auto const& target : reservedTargets) {
2743 if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
2748 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2749 GlobalTargetInfo gti;
2750 gti.Name = this->GetTestTargetName();
2751 gti.Message = "Running tests...";
2752 gti.UsesTerminal = true;
2753 cmCustomCommandLine singleLine;
2754 singleLine.push_back(cmSystemTools::GetCTestCommand());
2755 singleLine.push_back("--force-new-ctest-process");
2756 std::vector<std::string> args;
2757 if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) {
2758 for (auto const& arg : args) {
2759 singleLine.push_back(arg);
2762 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2763 singleLine.push_back("-C");
2764 singleLine.push_back(cmakeCfgIntDir);
2765 } else // TODO: This is a hack. Should be something to do with the
2768 singleLine.push_back("$(ARGS)");
2770 gti.CommandLines.push_back(std::move(singleLine));
2771 targets.push_back(std::move(gti));
2774 void cmGlobalGenerator::AddGlobalTarget_EditCache(
2775 std::vector<GlobalTargetInfo>& targets) const
2777 const char* editCacheTargetName = this->GetEditCacheTargetName();
2778 if (!editCacheTargetName) {
2781 GlobalTargetInfo gti;
2782 gti.Name = editCacheTargetName;
2783 gti.PerConfig = cmTarget::PerConfig::No;
2784 cmCustomCommandLine singleLine;
2786 // Use generator preference for the edit_cache rule if it is defined.
2787 std::string edit_cmd = this->GetEditCacheCommand();
2788 if (!edit_cmd.empty()) {
2789 singleLine.push_back(std::move(edit_cmd));
2790 singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2791 singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2792 gti.Message = "Running CMake cache editor...";
2793 gti.UsesTerminal = true;
2795 singleLine.push_back(cmSystemTools::GetCMakeCommand());
2796 singleLine.push_back("-E");
2797 singleLine.push_back("echo");
2798 singleLine.push_back("No interactive CMake dialog available.");
2799 gti.Message = "No interactive CMake dialog available...";
2800 gti.UsesTerminal = false;
2801 gti.StdPipesUTF8 = true;
2803 gti.CommandLines.push_back(std::move(singleLine));
2805 targets.push_back(std::move(gti));
2808 void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
2809 std::vector<GlobalTargetInfo>& targets) const
2811 const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
2812 if (!rebuildCacheTargetName) {
2815 GlobalTargetInfo gti;
2816 gti.Name = rebuildCacheTargetName;
2817 gti.Message = "Running CMake to regenerate build system...";
2818 gti.UsesTerminal = true;
2819 gti.PerConfig = cmTarget::PerConfig::No;
2820 cmCustomCommandLine singleLine;
2821 singleLine.push_back(cmSystemTools::GetCMakeCommand());
2822 singleLine.push_back("--regenerate-during-build");
2823 singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
2824 singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
2825 gti.CommandLines.push_back(std::move(singleLine));
2826 gti.StdPipesUTF8 = true;
2827 targets.push_back(std::move(gti));
2830 void cmGlobalGenerator::AddGlobalTarget_Install(
2831 std::vector<GlobalTargetInfo>& targets)
2833 auto& mf = this->Makefiles[0];
2834 const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
2835 bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
2836 if (this->InstallTargetEnabled && skipInstallRules) {
2837 this->CMakeInstance->IssueMessage(
2838 MessageType::WARNING,
2839 "CMAKE_SKIP_INSTALL_RULES was enabled even though "
2840 "installation rules have been specified",
2841 mf->GetBacktrace());
2842 } else if (this->InstallTargetEnabled && !skipInstallRules) {
2843 if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) {
2844 std::set<std::string>* componentsSet = &this->InstallComponents;
2845 std::ostringstream ostr;
2846 if (!componentsSet->empty()) {
2847 ostr << "Available install components are: ";
2848 ostr << cmWrap('"', *componentsSet, '"', " ");
2850 ostr << "Only default component available";
2852 GlobalTargetInfo gti;
2853 gti.Name = "list_install_components";
2854 gti.Message = ostr.str();
2855 gti.UsesTerminal = false;
2856 targets.push_back(std::move(gti));
2858 std::string cmd = cmSystemTools::GetCMakeCommand();
2859 GlobalTargetInfo gti;
2860 gti.Name = this->GetInstallTargetName();
2861 gti.Message = "Install the project...";
2862 gti.UsesTerminal = true;
2863 gti.StdPipesUTF8 = true;
2864 cmCustomCommandLine singleLine;
2865 if (this->GetPreinstallTargetName()) {
2866 gti.Depends.emplace_back(this->GetPreinstallTargetName());
2868 cmValue noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
2869 if (cmIsOff(noall)) {
2870 gti.Depends.emplace_back(this->GetAllTargetName());
2873 if (mf->GetDefinition("CMake_BINARY_DIR") &&
2874 !mf->IsOn("CMAKE_CROSSCOMPILING")) {
2875 // We are building CMake itself. We cannot use the original
2876 // executable to install over itself. The generator will
2877 // automatically convert this name to the build-time location.
2880 singleLine.push_back(cmd);
2881 if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') {
2882 std::string cfgArg = "-DBUILD_TYPE=";
2883 bool useEPN = this->UseEffectivePlatformName(mf.get());
2885 cfgArg += "$(CONFIGURATION)";
2886 singleLine.push_back(cfgArg);
2887 cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
2889 cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR");
2891 singleLine.push_back(cfgArg);
2893 singleLine.push_back("-P");
2894 singleLine.push_back("cmake_install.cmake");
2895 gti.CommandLines.push_back(singleLine);
2896 targets.push_back(gti);
2899 if (const char* install_local = this->GetInstallLocalTargetName()) {
2900 gti.Name = install_local;
2901 gti.Message = "Installing only the local directory...";
2902 gti.UsesTerminal = true;
2903 gti.CommandLines.clear();
2905 cmCustomCommandLine localCmdLine = singleLine;
2907 localCmdLine.insert(localCmdLine.begin() + 1,
2908 "-DCMAKE_INSTALL_LOCAL_ONLY=1");
2910 gti.CommandLines.push_back(std::move(localCmdLine));
2911 targets.push_back(gti);
2915 const char* install_strip = this->GetInstallStripTargetName();
2916 if ((install_strip != nullptr) && (mf->IsSet("CMAKE_STRIP"))) {
2917 gti.Name = install_strip;
2918 gti.Message = "Installing the project stripped...";
2919 gti.UsesTerminal = true;
2920 gti.CommandLines.clear();
2922 cmCustomCommandLine stripCmdLine = singleLine;
2924 stripCmdLine.insert(stripCmdLine.begin() + 1,
2925 "-DCMAKE_INSTALL_DO_STRIP=1");
2926 gti.CommandLines.push_back(std::move(stripCmdLine));
2927 targets.push_back(gti);
2932 std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
2934 cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
2935 "PREDEFINED_TARGETS_FOLDER");
2941 return "CMakePredefinedTargets";
2944 bool cmGlobalGenerator::UseFolderProperty() const
2947 this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
2949 // If this property is defined, let the setter turn this on or off...
2952 return cmIsOn(*prop);
2955 // By default, this feature is OFF, since it is not supported in the
2956 // Visual Studio Express editions until VS11:
2961 void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
2966 mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig);
2968 // Do nothing if gti.Name is already used
2973 cmTarget& target = tb.first;
2974 target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2976 // Store the custom command in the target.
2978 cc.SetCommandLines(gti.CommandLines);
2979 cc.SetWorkingDirectory(gti.WorkingDir.c_str());
2980 cc.SetStdPipesUTF8(gti.StdPipesUTF8);
2981 cc.SetUsesTerminal(gti.UsesTerminal);
2982 target.AddPostBuildCommand(std::move(cc));
2983 if (!gti.Message.empty()) {
2984 target.SetProperty("EchoString", gti.Message);
2986 for (std::string const& d : gti.Depends) {
2987 target.AddUtility(d, false);
2990 // Organize in the "predefined targets" folder:
2992 if (this->UseFolderProperty()) {
2993 target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
2997 std::string cmGlobalGenerator::GenerateRuleFile(
2998 std::string const& output) const
3000 std::string ruleFile = cmStrCat(output, ".rule");
3001 const char* dir = this->GetCMakeCFGIntDir();
3002 if (dir && dir[0] == '$') {
3003 cmSystemTools::ReplaceString(ruleFile, dir, "/CMakeFiles");
3008 bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
3010 return mf->PlatformIsAppleEmbedded();
3013 std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
3014 std::string const& l) const
3016 auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
3017 if (it != this->LanguageToOriginalSharedLibFlags.end()) {
3023 void cmGlobalGenerator::AppendDirectoryForConfig(const std::string& /*unused*/,
3024 const std::string& /*unused*/,
3025 const std::string& /*unused*/,
3026 std::string& /*unused*/)
3028 // Subclasses that support multiple configurations should implement
3029 // this method to append the subdirectory for the given build
3033 cmGlobalGenerator::TargetDependSet const&
3034 cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target)
3036 return this->TargetDependencies[target];
3039 bool cmGlobalGenerator::IsReservedTarget(std::string const& name)
3041 // The following is a list of targets reserved
3042 // by one or more of the cmake generators.
3044 // Adding additional targets to this list will require a policy!
3045 const char* reservedTargets[] = { "all", "ALL_BUILD", "help",
3046 "install", "INSTALL", "preinstall",
3047 "clean", "edit_cache", "rebuild_cache",
3050 return cm::contains(reservedTargets, name);
3053 void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
3054 std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
3056 this->ExtraGenerator = std::move(extraGenerator);
3057 if (this->ExtraGenerator) {
3058 this->ExtraGenerator->SetGlobalGenerator(this);
3062 std::string cmGlobalGenerator::GetExtraGeneratorName() const
3064 return this->ExtraGenerator ? this->ExtraGenerator->GetName()
3068 void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
3070 this->FilesReplacedDuringGenerate.push_back(filename);
3073 void cmGlobalGenerator::GetFilesReplacedDuringGenerate(
3074 std::vector<std::string>& filenames)
3077 std::copy(this->FilesReplacedDuringGenerate.begin(),
3078 this->FilesReplacedDuringGenerate.end(),
3079 std::back_inserter(filenames));
3082 void cmGlobalGenerator::GetTargetSets(
3083 TargetDependSet& projectTargets, TargetDependSet& originalTargets,
3084 cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
3086 // loop over all local generators
3087 for (auto* generator : generators) {
3088 // check to make sure generator is not excluded
3089 if (this->IsExcluded(root, generator)) {
3092 // loop over all the generator targets in the makefile
3093 for (const auto& target : generator->GetGeneratorTargets()) {
3094 if (this->IsRootOnlyTarget(target.get()) &&
3095 target->GetLocalGenerator() != root) {
3098 // put the target in the set of original targets
3099 originalTargets.insert(target.get());
3100 // Get the set of targets that depend on target
3101 this->AddTargetDepends(target.get(), projectTargets);
3106 bool cmGlobalGenerator::IsRootOnlyTarget(cmGeneratorTarget* target) const
3108 return (target->GetType() == cmStateEnums::GLOBAL_TARGET ||
3109 target->GetName() == this->GetAllTargetName());
3112 void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
3113 TargetDependSet& projectTargets)
3115 // add the target itself
3116 if (projectTargets.insert(target).second) {
3117 // This is the first time we have encountered the target.
3118 // Recursively follow its dependencies.
3119 for (auto const& t : this->GetTargetDirectDepends(target)) {
3120 this->AddTargetDepends(t, projectTargets);
3125 void cmGlobalGenerator::AddToManifest(std::string const& f)
3127 // Add to the content listing for the file's directory.
3128 std::string dir = cmSystemTools::GetFilenamePath(f);
3129 std::string file = cmSystemTools::GetFilenameName(f);
3130 DirectoryContent& dc = this->DirectoryContentMap[dir];
3131 dc.Generated.insert(file);
3132 dc.All.insert(file);
3135 std::set<std::string> const& cmGlobalGenerator::GetDirectoryContent(
3136 std::string const& dir, bool needDisk)
3138 DirectoryContent& dc = this->DirectoryContentMap[dir];
3140 long mt = cmSystemTools::ModifiedTime(dir);
3141 if (mt != dc.LastDiskTime) {
3142 // Reset to non-loaded directory content.
3143 dc.All = dc.Generated;
3145 // Load the directory content from disk.
3148 unsigned long n = d.GetNumberOfFiles();
3149 for (unsigned long i = 0; i < n; ++i) {
3150 const char* f = d.GetFile(i);
3151 if (strcmp(f, ".") != 0 && strcmp(f, "..") != 0) {
3156 dc.LastDiskTime = mt;
3162 void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
3163 std::string const& content)
3165 #if !defined(CMAKE_BOOTSTRAP)
3166 // Ignore if there are no outputs.
3167 if (outputs.empty()) {
3171 // Compute a hash of the rule.
3174 cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3175 std::string const md5_hex = md5.HashString(content);
3176 memcpy(hash.Data, md5_hex.c_str(), 32);
3179 // Shorten the output name (in expected use case).
3181 this->LocalGenerators[0]->MaybeRelativeToTopBinDir(outputs[0]);
3183 // Associate the hash with this output.
3184 this->RuleHashes[fname] = hash;
3191 void cmGlobalGenerator::CheckRuleHashes()
3193 #if !defined(CMAKE_BOOTSTRAP)
3194 std::string home = this->GetCMakeInstance()->GetHomeOutputDirectory();
3195 std::string pfile = cmStrCat(home, "/CMakeFiles/CMakeRuleHashes.txt");
3196 this->CheckRuleHashes(pfile, home);
3197 this->WriteRuleHashes(pfile);
3201 void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
3202 std::string const& home)
3204 #if defined(_WIN32) || defined(__CYGWIN__)
3205 cmsys::ifstream fin(pfile.c_str(), std::ios::in | std::ios::binary);
3207 cmsys::ifstream fin(pfile.c_str());
3214 while (cmSystemTools::GetLineFromStream(fin, line)) {
3215 // Line format is a 32-byte hex string followed by a space
3216 // followed by a file name (with no escaping).
3218 // Skip blank and comment lines.
3219 if (line.size() < 34 || line[0] == '#') {
3223 // Get the filename.
3224 fname = line.substr(33);
3226 // Look for a hash for this file's rule.
3227 auto const rhi = this->RuleHashes.find(fname);
3228 if (rhi != this->RuleHashes.end()) {
3229 // Compare the rule hash in the file to that we were given.
3230 if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
3231 // The rule has changed. Delete the output so it will be
3233 fname = cmSystemTools::CollapseFullPath(fname, home);
3234 cmSystemTools::RemoveFile(fname);
3237 // We have no hash for a rule previously listed. This may be a
3238 // case where a user has turned off a build option and might
3239 // want to turn it back on later, so do not delete the file.
3240 // Instead, we keep the rule hash as long as the file exists so
3241 // that if the feature is turned back on and the rule has
3242 // changed the file is still rebuilt.
3243 std::string fpath = cmSystemTools::CollapseFullPath(fname, home);
3244 if (cmSystemTools::FileExists(fpath)) {
3246 memcpy(hash.Data, line.c_str(), 32);
3247 this->RuleHashes[fname] = hash;
3253 void cmGlobalGenerator::WriteRuleHashes(std::string const& pfile)
3255 // Now generate a new persistence file with the current hashes.
3256 if (this->RuleHashes.empty()) {
3257 cmSystemTools::RemoveFile(pfile);
3259 cmGeneratedFileStream fout(pfile);
3260 fout << "# Hashes of file build rules.\n";
3261 for (auto const& rh : this->RuleHashes) {
3262 fout.write(rh.second.Data, 32);
3263 fout << " " << rh.first << "\n";
3268 void cmGlobalGenerator::WriteSummary()
3270 // Record all target directories in a central location.
3271 std::string fname = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3272 "/CMakeFiles/TargetDirectories.txt");
3273 cmGeneratedFileStream fout(fname);
3275 for (const auto& lg : this->LocalGenerators) {
3276 for (const auto& tgt : lg->GetGeneratorTargets()) {
3277 if (!tgt->IsInBuildSystem()) {
3280 this->WriteSummary(tgt.get());
3281 fout << tgt->GetSupportDirectory() << "\n";
3286 void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
3288 // Place the labels file in a per-target support directory.
3289 std::string dir = target->GetSupportDirectory();
3290 std::string file = cmStrCat(dir, "/Labels.txt");
3291 std::string json_file = dir + "/Labels.json";
3293 #ifndef CMAKE_BOOTSTRAP
3294 // Check whether labels are enabled for this target.
3295 cmValue targetLabels = target->GetProperty("LABELS");
3296 cmValue directoryLabels =
3297 target->Target->GetMakefile()->GetProperty("LABELS");
3298 cmValue cmakeDirectoryLabels =
3299 target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS");
3300 if (targetLabels || directoryLabels || cmakeDirectoryLabels) {
3301 Json::Value lj_root(Json::objectValue);
3302 Json::Value& lj_target = lj_root["target"] = Json::objectValue;
3303 lj_target["name"] = target->GetName();
3304 Json::Value& lj_target_labels = lj_target["labels"] = Json::arrayValue;
3305 Json::Value& lj_sources = lj_root["sources"] = Json::arrayValue;
3307 cmSystemTools::MakeDirectory(dir);
3308 cmGeneratedFileStream fout(file);
3310 std::vector<std::string> labels;
3312 // List the target-wide labels. All sources in the target get
3315 cmExpandList(*targetLabels, labels);
3316 if (!labels.empty()) {
3317 fout << "# Target labels\n";
3318 for (std::string const& l : labels) {
3319 fout << " " << l << "\n";
3320 lj_target_labels.append(l);
3325 // List directory labels
3326 std::vector<std::string> directoryLabelsList;
3327 std::vector<std::string> cmakeDirectoryLabelsList;
3329 if (directoryLabels) {
3330 cmExpandList(*directoryLabels, directoryLabelsList);
3333 if (cmakeDirectoryLabels) {
3334 cmExpandList(*cmakeDirectoryLabels, cmakeDirectoryLabelsList);
3337 if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) {
3338 fout << "# Directory labels\n";
3341 for (std::string const& li : directoryLabelsList) {
3342 fout << " " << li << "\n";
3343 lj_target_labels.append(li);
3346 for (std::string const& li : cmakeDirectoryLabelsList) {
3347 fout << " " << li << "\n";
3348 lj_target_labels.append(li);
3351 // List the source files with any per-source labels.
3352 fout << "# Source files and their labels\n";
3353 std::vector<cmSourceFile*> sources;
3354 std::vector<std::string> const& configs =
3355 target->Target->GetMakefile()->GetGeneratorConfigs(
3356 cmMakefile::IncludeEmptyConfig);
3357 for (std::string const& c : configs) {
3358 target->GetSourceFiles(sources, c);
3360 auto const sourcesEnd = cmRemoveDuplicates(sources);
3361 for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
3362 Json::Value& lj_source = lj_sources.append(Json::objectValue);
3363 std::string const& sfp = sf->ResolveFullPath();
3364 fout << sfp << "\n";
3365 lj_source["file"] = sfp;
3366 if (cmValue svalue = sf->GetProperty("LABELS")) {
3368 Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
3369 cmExpandList(*svalue, labels);
3370 for (std::string const& label : labels) {
3371 fout << " " << label << "\n";
3372 lj_source_labels.append(label);
3376 cmGeneratedFileStream json_fout(json_file);
3377 json_fout << lj_root;
3381 cmSystemTools::RemoveFile(file);
3382 cmSystemTools::RemoveFile(json_file);
3387 std::string cmGlobalGenerator::EscapeJSON(const std::string& s)
3390 result.reserve(s.size());
3411 void cmGlobalGenerator::SetFilenameTargetDepends(
3412 cmSourceFile* sf, std::set<cmGeneratorTarget const*> const& tgts)
3414 this->FilenameTargetDepends[sf] = tgts;
3417 std::set<cmGeneratorTarget const*> const&
3418 cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const
3420 return this->FilenameTargetDepends[sf];
3423 const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
3425 auto i = this->RealPaths.lower_bound(dir);
3426 if (i == this->RealPaths.end() ||
3427 this->RealPaths.key_comp()(dir, i->first)) {
3428 i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
3433 std::string cmGlobalGenerator::NewDeferId()
3435 return cmStrCat("__"_s, std::to_string(this->NextDeferId++));
3438 void cmGlobalGenerator::ProcessEvaluationFiles()
3440 std::vector<std::string> generatedFiles;
3441 for (auto& localGen : this->LocalGenerators) {
3442 localGen->ProcessEvaluationFiles(generatedFiles);
3446 std::string cmGlobalGenerator::ExpandCFGIntDir(
3447 const std::string& str, const std::string& /*config*/) const
3452 bool cmGlobalGenerator::GenerateCPackPropertiesFile()
3454 cmake::InstalledFilesMap const& installedFiles =
3455 this->CMakeInstance->GetInstalledFiles();
3457 const auto& lg = this->LocalGenerators[0];
3458 cmMakefile* mf = lg->GetMakefile();
3460 std::vector<std::string> configs =
3461 mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig);
3462 std::string config = mf->GetDefaultConfiguration();
3464 std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(),
3465 "/CPackProperties.cmake");
3467 if (!cmSystemTools::FileExists(path) && installedFiles.empty()) {
3471 cmGeneratedFileStream file(path);
3472 file << "# CPack properties\n";
3474 for (auto const& i : installedFiles) {
3475 cmInstalledFile const& installedFile = i.second;
3477 cmCPackPropertiesGenerator cpackPropertiesGenerator(
3478 lg.get(), installedFile, configs);
3480 cpackPropertiesGenerator.Generate(file, config, configs);
3486 cmInstallRuntimeDependencySet*
3487 cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
3489 auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
3490 auto* retval = set.get();
3491 this->RuntimeDependencySets.push_back(std::move(set));
3495 cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
3496 const std::string& name)
3498 auto it = this->RuntimeDependencySetsByName.find(name);
3499 if (it == this->RuntimeDependencySetsByName.end()) {
3500 auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
3502 this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
3504 this->RuntimeDependencySets.push_back(std::move(set));