diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2020-09-29 14:17:10 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2020-10-05 13:49:59 (GMT) |
commit | 8617479061039e2b357b7efc922f1b88648dce42 (patch) | |
tree | 41d37c685e178b73cf5122b5741fdcf9e4898d06 /Source/cmake.cxx | |
parent | 06128cf94964697279970a80ddfc1ce2ef7b4da5 (diff) | |
download | CMake-8617479061039e2b357b7efc922f1b88648dce42.zip CMake-8617479061039e2b357b7efc922f1b88648dce42.tar.gz CMake-8617479061039e2b357b7efc922f1b88648dce42.tar.bz2 |
CMake: Add presets functionality
Diffstat (limited to 'Source/cmake.cxx')
-rw-r--r-- | Source/cmake.cxx | 339 |
1 files changed, 306 insertions, 33 deletions
diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 9f84378..74701cf 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -13,6 +13,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) # include <cm/iterator> @@ -27,6 +28,7 @@ #include "cm_sys_stat.h" +#include "cmCMakePresetsFile.h" #include "cmCommands.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" @@ -286,6 +288,97 @@ void cmake::CleanupCommandsAndMacros() this->CurrentSnapshot.SetDefaultDefinitions(); } +#ifndef CMAKE_BOOTSTRAP +void cmake::SetWarningFromPreset(const std::string& name, + const cm::optional<bool>& warning, + const cm::optional<bool>& error) +{ + if (warning) { + if (*warning) { + this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN); + } else { + this->DiagLevels[name] = DIAG_IGNORE; + } + } + if (error) { + if (*error) { + this->DiagLevels[name] = DIAG_ERROR; + } else { + this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN); + } + } +} + +void cmake::ProcessPresetVariables() +{ + for (auto const& var : this->UnprocessedPresetVariables) { + if (!var.second) { + continue; + } + cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; + if (!var.second->Type.empty()) { + type = cmState::StringToCacheEntryType(var.second->Type); + } + this->ProcessCacheArg(var.first, var.second->Value, type); + } +} + +void cmake::PrintPresetVariables() +{ + bool first = true; + for (auto const& var : this->UnprocessedPresetVariables) { + if (!var.second) { + continue; + } + cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; + if (!var.second->Type.empty()) { + type = cmState::StringToCacheEntryType(var.second->Type); + } + if (first) { + std::cout << "Preset CMake variables:\n\n"; + first = false; + } + std::cout << " " << var.first; + if (type != cmStateEnums::UNINITIALIZED) { + std::cout << ':' << cmState::CacheEntryTypeToString(type); + } + std::cout << "=\"" << var.second->Value << "\"\n"; + } + if (!first) { + std::cout << '\n'; + } + this->UnprocessedPresetVariables.clear(); +} + +void cmake::ProcessPresetEnvironment() +{ + for (auto const& var : this->UnprocessedPresetEnvironment) { + if (var.second) { + cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second)); + } + } +} + +void cmake::PrintPresetEnvironment() +{ + bool first = true; + for (auto const& var : this->UnprocessedPresetEnvironment) { + if (!var.second) { + continue; + } + if (first) { + std::cout << "Preset environment variables:\n\n"; + first = false; + } + std::cout << " " << var.first << "=\"" << *var.second << "\"\n"; + } + if (!first) { + std::cout << '\n'; + } + this->UnprocessedPresetEnvironment.clear(); +} +#endif + // Parse the args bool cmake::SetCacheArgs(const std::vector<std::string>& args) { @@ -308,28 +401,10 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) std::string value; cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; if (cmState::ParseCacheEntry(entry, var, value, type)) { - // The value is transformed if it is a filepath for example, so - // we can't compare whether the value is already in the cache until - // after we call AddCacheEntry. - bool haveValue = false; - std::string cachedValue; - if (this->WarnUnusedCli) { - if (cmProp v = this->State->GetInitializedCacheValue(var)) { - haveValue = true; - cachedValue = *v; - } - } - - this->AddCacheEntry(var, value.c_str(), - "No help, variable specified on the command line.", - type); - - if (this->WarnUnusedCli) { - if (!haveValue || - cachedValue != *this->State->GetInitializedCacheValue(var)) { - this->WatchUnusedCli(var); - } - } +#ifndef CMAKE_BOOTSTRAP + this->UnprocessedPresetVariables.erase(var); +#endif + this->ProcessCacheArg(var, value, type); } else { cmSystemTools::Error("Parse error in command line argument: " + arg + "\n" + "Should be: VAR:type=value\n"); @@ -409,6 +484,9 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) // now remove them from the cache for (std::string const& currentEntry : entriesToDelete) { +#ifndef CMAKE_BOOTSTRAP + this->UnprocessedPresetVariables.erase(currentEntry); +#endif this->State->RemoveCacheEntry(currentEntry); } } else if (cmHasLiteralPrefix(arg, "-C")) { @@ -462,6 +540,33 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) return true; } +void cmake::ProcessCacheArg(const std::string& var, const std::string& value, + cmStateEnums::CacheEntryType type) +{ + // The value is transformed if it is a filepath for example, so + // we can't compare whether the value is already in the cache until + // after we call AddCacheEntry. + bool haveValue = false; + std::string cachedValue; + if (this->WarnUnusedCli) { + if (cmProp v = this->State->GetInitializedCacheValue(var)) { + haveValue = true; + cachedValue = *v; + } + } + + this->AddCacheEntry(var, value.c_str(), + "No help, variable specified on the command line.", + type); + + if (this->WarnUnusedCli) { + if (!haveValue || + cachedValue != *this->State->GetInitializedCacheValue(var)) { + this->WatchUnusedCli(var); + } + } +} + void cmake::ReadListFile(const std::vector<std::string>& args, const std::string& path) { @@ -625,6 +730,8 @@ void cmake::SetArgs(const std::vector<std::string>& args) #if !defined(CMAKE_BOOTSTRAP) std::string profilingFormat; std::string profilingOutput; + std::string presetName; + bool listPresets = false; #endif for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; @@ -830,19 +937,9 @@ void cmake::SetArgs(const std::vector<std::string>& args) } value = args[i]; } - auto gen = this->CreateGlobalGenerator(value); - if (!gen) { - std::string kdevError; - if (value.find("KDevelop3", 0) != std::string::npos) { - kdevError = "\nThe KDevelop3 generator is not supported anymore."; - } - - cmSystemTools::Error( - cmStrCat("Could not create named generator ", value, kdevError)); - this->PrintGeneratorList(); + if (!this->CreateAndSetGlobalGenerator(value, true)) { return; } - this->SetGlobalGenerator(std::move(gen)); #if !defined(CMAKE_BOOTSTRAP) } else if (cmHasLiteralPrefix(arg, "--profiling-format")) { profilingFormat = arg.substr(strlen("--profiling-format=")); @@ -856,6 +953,13 @@ void cmake::SetArgs(const std::vector<std::string>& args) if (profilingOutput.empty()) { cmSystemTools::Error("No path specified for --profiling-output"); } + } else if (cmHasLiteralPrefix(arg, "--preset")) { + presetName = arg.substr(strlen("--preset=")); + if (presetName.empty()) { + cmSystemTools::Error("No preset specified for --preset"); + } + } else if (cmHasLiteralPrefix(arg, "--list-presets")) { + listPresets = true; #endif } // no option assume it is the path to the source or an existing build @@ -915,6 +1019,91 @@ void cmake::SetArgs(const std::vector<std::string>& args) if (!haveBinaryDir) { this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); } + +#if !defined(CMAKE_BOOTSTRAP) + if (listPresets || !presetName.empty()) { + cmCMakePresetsFile settingsFile; + auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); + if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + cmSystemTools::Error( + cmStrCat("Could not read presets from ", this->GetHomeDirectory(), + ": ", cmCMakePresetsFile::ResultToString(result))); + return; + } + if (listPresets) { + this->PrintPresetList(settingsFile); + return; + } + auto preset = settingsFile.Presets.find(presetName); + if (preset == settingsFile.Presets.end()) { + cmSystemTools::Error(cmStrCat("No such preset in ", + this->GetHomeDirectory(), ": \"", + presetName, '"')); + this->PrintPresetList(settingsFile); + return; + } + if (preset->second.Hidden) { + cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ", + this->GetHomeDirectory(), ": \"", + presetName, '"')); + this->PrintPresetList(settingsFile); + return; + } + auto expandedPreset = settingsFile.ExpandMacros(preset->second); + if (!expandedPreset) { + cmSystemTools::Error(cmStrCat("Could not evaluate preset \"", + preset->second.Name, + "\": Invalid macro expansion")); + return; + } + + if (!haveBinaryDir) { + this->SetHomeOutputDirectory(expandedPreset->BinaryDir); + } + if (!this->GlobalGenerator) { + if (!this->CreateAndSetGlobalGenerator(expandedPreset->Generator, + false)) { + return; + } + } + this->UnprocessedPresetVariables = expandedPreset->CacheVariables; + this->UnprocessedPresetEnvironment = expandedPreset->Environment; + + if (!expandedPreset->GeneratorConfig || + expandedPreset->GeneratorConfig == + cmCMakePresetsFile::CMakeGeneratorConfig::Default) { + if (!this->GeneratorPlatformSet) { + this->SetGeneratorPlatform(expandedPreset->Architecture); + } + if (!this->GeneratorToolsetSet) { + this->SetGeneratorToolset(expandedPreset->Toolset); + } + } + + this->SetWarningFromPreset("dev", expandedPreset->WarnDev, + expandedPreset->ErrorDev); + this->SetWarningFromPreset("deprecated", expandedPreset->WarnDeprecated, + expandedPreset->ErrorDeprecated); + if (expandedPreset->WarnUninitialized == true) { + this->SetWarnUninitialized(true); + } + if (expandedPreset->WarnUnusedCli == false) { + this->SetWarnUnusedCli(false); + } + if (expandedPreset->WarnSystemVars == true) { + this->SetCheckSystemVars(true); + } + if (expandedPreset->DebugOutput == true) { + this->SetDebugOutputOn(true); + } + if (expandedPreset->DebugTryCompile == true) { + this->DebugTryCompileOn(); + } + if (expandedPreset->DebugFind == true) { + this->SetDebugFindOutputOn(true); + } + } +#endif } cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr) @@ -1240,6 +1429,79 @@ std::unique_ptr<cmGlobalGenerator> cmake::CreateGlobalGenerator( return generator; } +bool cmake::CreateAndSetGlobalGenerator(const std::string& name, + bool allowArch) +{ + auto gen = this->CreateGlobalGenerator(name, allowArch); + if (!gen) { + std::string kdevError; + std::string vsError; + if (name.find("KDevelop3", 0) != std::string::npos) { + kdevError = "\nThe KDevelop3 generator is not supported anymore."; + } + if (!allowArch && cmHasLiteralPrefix(name, "Visual Studio ") && + name.length() >= cmStrLen("Visual Studio xx xxxx ")) { + vsError = "\nUsing platforms in Visual Studio generator names is not " + "supported in CMakePresets.json."; + } + + cmSystemTools::Error( + cmStrCat("Could not create named generator ", name, kdevError, vsError)); + this->PrintGeneratorList(); + return false; + } + + this->SetGlobalGenerator(std::move(gen)); + return true; +} + +#ifndef CMAKE_BOOTSTRAP +void cmake::PrintPresetList(const cmCMakePresetsFile& file) const +{ + std::vector<GeneratorInfo> generators; + this->GetRegisteredGenerators(generators, false); + + std::vector<cmCMakePresetsFile::UnexpandedPreset> presets; + for (auto const& p : file.PresetOrder) { + auto const& preset = file.Presets.at(p); + if (!preset.Hidden && + std::find_if(generators.begin(), generators.end(), + [&preset](const GeneratorInfo& info) { + return info.name == preset.Generator; + }) != generators.end() && + file.ExpandMacros(preset)) { + presets.push_back(preset); + } + } + + if (presets.empty()) { + return; + } + + std::cout << "Available presets:\n\n"; + + auto longestPresetName = + std::max_element(presets.begin(), presets.end(), + [](const cmCMakePresetsFile::UnexpandedPreset& a, + const cmCMakePresetsFile::UnexpandedPreset& b) { + return a.Name.length() < b.Name.length(); + }); + auto longestLength = longestPresetName->Name.length(); + + for (auto const& preset : presets) { + std::cout << " \"" << preset.Name << '"'; + auto const& description = preset.DisplayName; + if (!description.empty()) { + for (std::size_t i = 0; i < longestLength - preset.Name.length(); ++i) { + std::cout << ' '; + } + std::cout << " - " << description; + } + std::cout << '\n'; + } +} +#endif + void cmake::SetHomeDirectory(const std::string& dir) { this->State->SetSourceDirectory(dir); @@ -1801,6 +2063,9 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) if (cmSystemTools::GetErrorOccuredFlag()) { return -1; } + if (this->GetWorkingMode() == HELP_MODE) { + return 0; + } // Log the trace format version to the desired output if (this->GetTrace()) { @@ -1829,11 +2094,19 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) this->AddCMakePaths(); } +#ifndef CMAKE_BOOTSTRAP + this->ProcessPresetVariables(); + this->ProcessPresetEnvironment(); +#endif // Add any cache args if (!this->SetCacheArgs(args)) { cmSystemTools::Error("Problem processing arguments. Aborting.\n"); return -1; } +#ifndef CMAKE_BOOTSTRAP + this->PrintPresetVariables(); + this->PrintPresetEnvironment(); +#endif // In script mode we terminate after running the script. if (this->GetWorkingMode() != NORMAL_MODE) { |