in Source/cmake.cxx [790:1336]
void cmake::SetArgs(const std::vector<std::string>& args)
{
bool haveToolset = false;
bool havePlatform = false;
bool haveBArg = false;
bool scriptMode = false;
std::string possibleUnknownArg;
#if !defined(CMAKE_BOOTSTRAP)
std::string profilingFormat;
std::string profilingOutput;
std::string presetName;
ListPresets listPresets = ListPresets::None;
#endif
auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool {
std::string path = cmSystemTools::CollapseFullPath(value);
cmSystemTools::ConvertToUnixSlashes(path);
state->SetHomeDirectory(path);
return true;
};
auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool {
std::string path = cmSystemTools::CollapseFullPath(value);
cmSystemTools::ConvertToUnixSlashes(path);
state->SetHomeOutputDirectory(path);
haveBArg = true;
return true;
};
auto PlatformLambda = [&](std::string const& value, cmake* state) -> bool {
if (havePlatform) {
cmSystemTools::Error("Multiple -A options not allowed");
return false;
}
state->SetGeneratorPlatform(value);
havePlatform = true;
return true;
};
auto ToolsetLamda = [&](std::string const& value, cmake* state) -> bool {
if (haveToolset) {
cmSystemTools::Error("Multiple -T options not allowed");
return false;
}
state->SetGeneratorToolset(value);
haveToolset = true;
return true;
};
std::vector<CommandArgument> arguments = {
CommandArgument{ "-S", "No source directory specified for -S",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, SourceArgLambda },
CommandArgument{ "-H", "No source directory specified for -H",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, SourceArgLambda },
CommandArgument{ "-O", CommandArgument::Values::Zero,
IgnoreAndTrueLambda },
CommandArgument{ "-B", "No build directory specified for -B",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, BuildArgLambda },
CommandArgument{ "-P", "-P must be followed by a file name.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
[&](std::string const&, cmake*) -> bool {
scriptMode = true;
return true;
} },
CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
IgnoreAndTrueLambda },
CommandArgument{ "-C", "-C must be followed by a file name.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
IgnoreAndTrueLambda },
CommandArgument{
"-U", "-U must be followed with VAR.", CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, IgnoreAndTrueLambda },
CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
IgnoreAndTrueLambda },
CommandArgument{ "-A", "No platform specified for -A",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, PlatformLambda },
CommandArgument{ "-T", "No toolset specified for -T",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No, ToolsetLamda },
CommandArgument{ "--toolchain", "No file specified for --toolchain",
CommandArgument::Values::One, IgnoreAndTrueLambda },
CommandArgument{ "--install-prefix",
"No install directory specified for --install-prefix",
CommandArgument::Values::One, IgnoreAndTrueLambda },
CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
[](std::string const& value, cmake* state) -> bool {
std::vector<std::string> values = cmExpandedList(value);
state->CheckBuildSystemArgument = values[0];
state->ClearBuildSystem = (atoi(values[1].c_str()) > 0);
return true;
} },
CommandArgument{ "--check-stamp-file", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
state->CheckStampFile = value;
return true;
} },
CommandArgument{ "--check-stamp-list", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
state->CheckStampList = value;
return true;
} },
CommandArgument{ "--regenerate-during-build",
CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
state->RegenerateDuringBuild = true;
return true;
} },
CommandArgument{ "--find-package", CommandArgument::Values::Zero,
IgnoreAndTrueLambda },
CommandArgument{ "--graphviz", "No file specified for --graphviz",
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
std::string path =
cmSystemTools::CollapseFullPath(value);
cmSystemTools::ConvertToUnixSlashes(path);
state->GraphVizFile = path;
return true;
} },
CommandArgument{ "--debug-trycompile", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "debug trycompile on\n";
state->DebugTryCompileOn();
return true;
} },
CommandArgument{ "--debug-output", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Running with debug output on.\n";
state->SetDebugOutputOn(true);
return true;
} },
CommandArgument{ "--log-level", "Invalid level specified for --log-level",
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
if (logLevel == LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --log-level");
return false;
}
state->SetLogLevel(logLevel);
state->LogLevelWasSetViaCLI = true;
return true;
} },
// This is supported for backward compatibility. This option only
// appeared in the 3.15.x release series and was renamed to
// --log-level in 3.16.0
CommandArgument{ "--loglevel", "Invalid level specified for --loglevel",
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
if (logLevel == LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --loglevel");
return false;
}
state->SetLogLevel(logLevel);
state->LogLevelWasSetViaCLI = true;
return true;
} },
CommandArgument{ "--log-context", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
state->SetShowLogContext(true);
return true;
} },
CommandArgument{
"--debug-find", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Running with debug output on for the `find` commands.\n";
state->SetDebugFindOutputOn(true);
return true;
} },
CommandArgument{ "--trace-expand", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Running with expanded trace output on.\n";
state->SetTrace(true);
state->SetTraceExpand(true);
return true;
} },
CommandArgument{ "--trace-format", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
state->SetTrace(true);
const auto traceFormat = StringToTraceFormat(value);
if (traceFormat == TraceFormat::TRACE_UNDEFINED) {
cmSystemTools::Error(
"Invalid format specified for --trace-format. "
"Valid formats are human, json-v1.");
return false;
}
state->SetTraceFormat(traceFormat);
return true;
} },
CommandArgument{ "--trace-source", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
std::string file(value);
cmSystemTools::ConvertToUnixSlashes(file);
state->AddTraceSource(file);
state->SetTrace(true);
return true;
} },
CommandArgument{ "--trace-redirect", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
std::string file(value);
cmSystemTools::ConvertToUnixSlashes(file);
state->SetTraceFile(file);
state->SetTrace(true);
return true;
} },
CommandArgument{ "--trace", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Running with trace output on.\n";
state->SetTrace(true);
state->SetTraceExpand(false);
return true;
} },
CommandArgument{ "--warn-uninitialized", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Warn about uninitialized values.\n";
state->SetWarnUninitialized(true);
return true;
} },
CommandArgument{ "--warn-unused-vars", CommandArgument::Values::Zero,
IgnoreAndTrueLambda }, // Option was removed.
CommandArgument{ "--no-warn-unused-cli", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout
<< "Not searching for unused variables given on the "
<< "command line.\n";
state->SetWarnUnusedCli(false);
return true;
} },
CommandArgument{
"--check-system-vars", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Also check system files when warning about unused and "
<< "uninitialized variables.\n";
state->SetCheckSystemVars(true);
return true;
} }
};
#if defined(CMAKE_HAVE_VS_GENERATORS)
arguments.emplace_back("--vs-solution-file", CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
state->VSSolutionFile = value;
return true;
});
#endif
#if !defined(CMAKE_BOOTSTRAP)
arguments.emplace_back("--profiling-format",
"No format specified for --profiling-format",
CommandArgument::Values::One,
[&](std::string const& value, cmake*) -> bool {
profilingFormat = value;
return true;
});
arguments.emplace_back(
"--profiling-output", "No path specified for --profiling-output",
CommandArgument::Values::One,
[&](std::string const& value, cmake*) -> bool {
profilingOutput = cmSystemTools::CollapseFullPath(value);
cmSystemTools::ConvertToUnixSlashes(profilingOutput);
return true;
});
arguments.emplace_back("--preset", "No preset specified for --preset",
CommandArgument::Values::One,
[&](std::string const& value, cmake*) -> bool {
presetName = value;
return true;
});
arguments.emplace_back(
"--list-presets", CommandArgument::Values::ZeroOrOne,
[&](std::string const& value, cmake*) -> bool {
if (value.empty() || value == "configure") {
listPresets = ListPresets::Configure;
} else if (value == "build") {
listPresets = ListPresets::Build;
} else if (value == "test") {
listPresets = ListPresets::Test;
} else if (value == "all") {
listPresets = ListPresets::All;
} else {
cmSystemTools::Error(
"Invalid value specified for --list-presets.\n"
"Valid values are configure, build, test, or all. "
"When no value is passed the default is configure.");
return false;
}
return true;
});
#endif
bool badGeneratorName = false;
CommandArgument generatorCommand(
"-G", "No generator specified for -G", CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
[&](std::string const& value, cmake* state) -> bool {
bool valid = state->CreateAndSetGlobalGenerator(value, true);
badGeneratorName = !valid;
return valid;
});
for (decltype(args.size()) i = 1; i < args.size(); ++i) {
// iterate each argument
std::string const& arg = args[i];
// Generator flag has special handling for when to print help
// so it becomes the exception
if (generatorCommand.matches(arg)) {
bool parsed = generatorCommand.parse(arg, i, args, this);
if (!parsed && !badGeneratorName) {
this->PrintGeneratorList();
return;
}
continue;
}
bool matched = false;
bool parsedCorrectly = true; // needs to be true so we can ignore
// arguments so as -E
for (auto const& m : arguments) {
if (m.matches(arg)) {
matched = true;
parsedCorrectly = m.parse(arg, i, args, this);
break;
}
}
// We have an issue where arguments to a "-P" script mode
// can be provided before the "-P" argument. This means
// that we need to lazily check this argument after checking
// all args.
// Additionally it can't be the source/binary tree location
if (!parsedCorrectly) {
cmSystemTools::Error("Run 'cmake --help' for all supported options.");
exit(1);
} else if (!matched && cmHasLiteralPrefix(arg, "-")) {
possibleUnknownArg = arg;
} else if (!matched) {
this->SetDirectoriesFromFile(arg);
}
}
if (!possibleUnknownArg.empty() && !scriptMode) {
cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
cmSystemTools::Error("Run 'cmake --help' for all supported options.");
exit(1);
}
// Empty instance, platform and toolset if only a generator is specified
if (this->GlobalGenerator) {
this->GeneratorInstance = "";
if (!this->GeneratorPlatformSet) {
this->GeneratorPlatform = "";
}
if (!this->GeneratorToolsetSet) {
this->GeneratorToolset = "";
}
}
#if !defined(CMAKE_BOOTSTRAP)
if (!profilingOutput.empty() || !profilingFormat.empty()) {
if (profilingOutput.empty()) {
cmSystemTools::Error(
"--profiling-format specified but no --profiling-output!");
return;
}
if (profilingFormat == "google-trace"_s) {
try {
this->ProfilingOutput =
cm::make_unique<cmMakefileProfilingData>(profilingOutput);
} catch (std::runtime_error& e) {
cmSystemTools::Error(
cmStrCat("Could not start profiling: ", e.what()));
return;
}
} else {
cmSystemTools::Error("Invalid format specified for --profiling-format");
return;
}
}
#endif
const bool haveSourceDir = !this->GetHomeDirectory().empty();
const bool haveBinaryDir = !this->GetHomeOutputDirectory().empty();
const bool havePreset =
#ifdef CMAKE_BOOTSTRAP
false;
#else
!presetName.empty();
#endif
if (this->CurrentWorkingMode == cmake::NORMAL_MODE && !haveSourceDir &&
!haveBinaryDir && !havePreset) {
this->IssueMessage(
MessageType::WARNING,
"No source or binary directory provided. Both will be assumed to be "
"the same as the current working directory, but note that this "
"warning will become a fatal error in future CMake releases.");
}
if (!haveSourceDir) {
this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
}
if (!haveBinaryDir) {
this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
}
#if !defined(CMAKE_BOOTSTRAP)
if (listPresets != ListPresets::None || !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 != ListPresets::None) {
if (listPresets == ListPresets::Configure) {
this->PrintPresetList(settingsFile);
} else if (listPresets == ListPresets::Build) {
settingsFile.PrintBuildPresetList();
} else if (listPresets == ListPresets::Test) {
settingsFile.PrintTestPresetList();
} else if (listPresets == ListPresets::All) {
settingsFile.PrintAllPresets();
}
this->SetWorkingMode(WorkingMode::HELP_MODE);
return;
}
auto preset = settingsFile.ConfigurePresets.find(presetName);
if (preset == settingsFile.ConfigurePresets.end()) {
cmSystemTools::Error(cmStrCat("No such preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
this->PrintPresetList(settingsFile);
return;
}
if (preset->second.Unexpanded.Hidden) {
cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ",
this->GetHomeDirectory(), ": \"",
presetName, '"'));
this->PrintPresetList(settingsFile);
return;
}
auto const& expandedPreset = preset->second.Expanded;
if (!expandedPreset) {
cmSystemTools::Error(cmStrCat("Could not evaluate preset \"",
preset->second.Unexpanded.Name,
"\": Invalid macro expansion"));
return;
}
if (!expandedPreset->ConditionResult) {
cmSystemTools::Error(cmStrCat("Could not use disabled preset \"",
preset->second.Unexpanded.Name, "\""));
return;
}
if (!this->State->IsCacheLoaded() && !haveBArg &&
!expandedPreset->BinaryDir.empty()) {
this->SetHomeOutputDirectory(expandedPreset->BinaryDir);
}
if (!this->GlobalGenerator && !expandedPreset->Generator.empty()) {
if (!this->CreateAndSetGlobalGenerator(expandedPreset->Generator,
false)) {
return;
}
}
this->UnprocessedPresetVariables = expandedPreset->CacheVariables;
this->UnprocessedPresetEnvironment = expandedPreset->Environment;
if (!expandedPreset->InstallDir.empty() &&
!this->State->GetInitializedCacheValue("CMAKE_INSTALL_PREFIX")) {
this->UnprocessedPresetVariables["CMAKE_INSTALL_PREFIX"] = {
"PATH", expandedPreset->InstallDir
};
}
if (!expandedPreset->ToolchainFile.empty() &&
!this->State->GetInitializedCacheValue("CMAKE_TOOLCHAIN_FILE")) {
this->UnprocessedPresetVariables["CMAKE_TOOLCHAIN_FILE"] = {
"FILEPATH", expandedPreset->ToolchainFile
};
}
if (!expandedPreset->ArchitectureStrategy ||
expandedPreset->ArchitectureStrategy ==
cmCMakePresetsFile::ArchToolsetStrategy::Set) {
if (!this->GeneratorPlatformSet) {
this->SetGeneratorPlatform(expandedPreset->Architecture);
}
}
if (!expandedPreset->ToolsetStrategy ||
expandedPreset->ToolsetStrategy ==
cmCMakePresetsFile::ArchToolsetStrategy::Set) {
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
}