mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-04 04:40:56 -06:00
cmCommandLineArgument: Understands which commands require partial matching
Allows us to provide better error messages when commands such as `--target` are passed invalid input.
This commit is contained in:
@@ -17,10 +17,17 @@ struct cmCommandLineArgument
|
||||
OneOrMore
|
||||
};
|
||||
|
||||
enum class RequiresSeparator
|
||||
{
|
||||
Yes,
|
||||
No
|
||||
};
|
||||
|
||||
std::string InvalidSyntaxMessage;
|
||||
std::string InvalidValueMessage;
|
||||
std::string Name;
|
||||
Values Type;
|
||||
RequiresSeparator SeparatorNeeded;
|
||||
std::function<FunctionSignature> StoreCall;
|
||||
|
||||
template <typename FunctionType>
|
||||
@@ -29,6 +36,19 @@ struct cmCommandLineArgument
|
||||
, InvalidValueMessage(cmStrCat("Invalid value used with ", n))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, SeparatorNeeded(RequiresSeparator::Yes)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
cmCommandLineArgument(std::string n, Values t, RequiresSeparator s,
|
||||
FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
|
||||
, InvalidValueMessage(cmStrCat("Invalid value used with ", n))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, SeparatorNeeded(s)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
@@ -40,14 +60,38 @@ struct cmCommandLineArgument
|
||||
, InvalidValueMessage(std::move(failedMsg))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, SeparatorNeeded(RequiresSeparator::Yes)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
|
||||
RequiresSeparator s, FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
|
||||
, InvalidValueMessage(std::move(failedMsg))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, SeparatorNeeded(s)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
bool matches(std::string const& input) const
|
||||
{
|
||||
return (this->Type == Values::Zero) ? (input == this->Name)
|
||||
: cmHasPrefix(input, this->Name);
|
||||
if (this->Type == Values::Zero) {
|
||||
return input == this->Name;
|
||||
} else if (this->SeparatorNeeded == RequiresSeparator::No) {
|
||||
return cmHasPrefix(input, this->Name);
|
||||
} else if (cmHasPrefix(input, this->Name)) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
return true;
|
||||
} else {
|
||||
return (input[this->Name.size()] == '=' ||
|
||||
input[this->Name.size()] == ' ');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T, typename... CallState>
|
||||
|
||||
@@ -529,25 +529,29 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
|
||||
|
||||
std::vector<CommandArgument> arguments = {
|
||||
CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
|
||||
CommandArgument::Values::One, DefineLambda },
|
||||
CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
|
||||
CommandArgument::Values::One, WarningLambda },
|
||||
CommandArgument{ "-U", "-U must be followed with VAR.",
|
||||
CommandArgument::Values::One, UnSetLambda },
|
||||
CommandArgument{ "-C", "-C must be followed by a file name.",
|
||||
CommandArgument::Values::One,
|
||||
[&](std::string const& value, cmake* state) -> bool {
|
||||
cmSystemTools::Stdout("loading initial cache file " +
|
||||
value + "\n");
|
||||
// Resolve script path specified on command line
|
||||
// relative to $PWD.
|
||||
auto path = cmSystemTools::CollapseFullPath(value);
|
||||
state->ReadListFile(args, path);
|
||||
return true;
|
||||
} },
|
||||
CommandArgument::RequiresSeparator::No, DefineLambda },
|
||||
CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, WarningLambda },
|
||||
CommandArgument{ "-U", "-U must be followed with VAR.",
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, UnSetLambda },
|
||||
CommandArgument{
|
||||
"-C", "-C must be followed by a file name.",
|
||||
CommandArgument::Values::One, CommandArgument::RequiresSeparator::No,
|
||||
[&](std::string const& value, cmake* state) -> bool {
|
||||
cmSystemTools::Stdout("loading initial cache file " + value + "\n");
|
||||
// Resolve script path specified on command line
|
||||
// relative to $PWD.
|
||||
auto path = cmSystemTools::CollapseFullPath(value);
|
||||
state->ReadListFile(args, path);
|
||||
return true;
|
||||
} },
|
||||
|
||||
CommandArgument{ "-P", "-P must be followed by a file name.",
|
||||
CommandArgument::Values::One, ScriptLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, ScriptLambda },
|
||||
CommandArgument{ "--toolchain", "No file specified for --toolchain",
|
||||
CommandArgument::Values::One, ToolchainLambda },
|
||||
CommandArgument{ "--install-prefix",
|
||||
@@ -830,31 +834,44 @@ void cmake::SetArgs(const std::vector<std::string>& args)
|
||||
|
||||
std::vector<CommandArgument> arguments = {
|
||||
CommandArgument{ "-S", "No source directory specified for -S",
|
||||
CommandArgument::Values::One, SourceArgLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, SourceArgLambda },
|
||||
CommandArgument{ "-H", "No source directory specified for -H",
|
||||
CommandArgument::Values::One, SourceArgLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, SourceArgLambda },
|
||||
CommandArgument{ "-O", CommandArgument::Values::Zero,
|
||||
IgnoreAndTrueLambda },
|
||||
CommandArgument{ "-B", "No build directory specified for -B",
|
||||
CommandArgument::Values::One, BuildArgLambda },
|
||||
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, IgnoreAndTrueLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No,
|
||||
IgnoreAndTrueLambda },
|
||||
CommandArgument{ "-C", "-C must be followed by a file name.",
|
||||
CommandArgument::Values::One, IgnoreAndTrueLambda },
|
||||
CommandArgument{ "-U", "-U must be followed with VAR.",
|
||||
CommandArgument::Values::One, IgnoreAndTrueLambda },
|
||||
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, IgnoreAndTrueLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No,
|
||||
IgnoreAndTrueLambda },
|
||||
CommandArgument{ "-A", "No platform specified for -A",
|
||||
CommandArgument::Values::One, PlatformLambda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, PlatformLambda },
|
||||
CommandArgument{ "-T", "No toolset specified for -T",
|
||||
CommandArgument::Values::One, ToolsetLamda },
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No, ToolsetLamda },
|
||||
CommandArgument{ "--toolchain", "No file specified for --toolchain",
|
||||
CommandArgument::Values::One, IgnoreAndTrueLambda },
|
||||
CommandArgument{ "--install-prefix",
|
||||
@@ -1079,6 +1096,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
|
||||
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;
|
||||
|
||||
@@ -271,6 +271,7 @@ int do_cmake(int ac, char const* const* av)
|
||||
} },
|
||||
CommandArgument{ "-P", "No script specified for argument -P",
|
||||
CommandArgument::Values::One,
|
||||
CommandArgument::RequiresSeparator::No,
|
||||
[&](std::string const& value) -> bool {
|
||||
workingMode = cmake::SCRIPT_MODE;
|
||||
parsedArgs.emplace_back("-P");
|
||||
@@ -476,9 +477,10 @@ int do_build(int ac, char const* const* av)
|
||||
listPresets = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne, jLambda },
|
||||
CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne,
|
||||
CommandArgument::RequiresSeparator::No, jLambda },
|
||||
CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
|
||||
parallelLambda },
|
||||
CommandArgument::RequiresSeparator::No, parallelLambda },
|
||||
CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda },
|
||||
CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
|
||||
targetLambda },
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
^CMake Error: '--targetinvalid' is invalid syntax for --target
|
||||
^Unknown argument --targetinvalid
|
||||
Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
|
||||
|
||||
Reference in New Issue
Block a user