diff options
author | Brad King <brad.king@kitware.com> | 2021-05-20 13:19:06 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2021-05-20 13:19:14 (GMT) |
commit | 35ea23a618a83902a83659a1f422a0f3af90c249 (patch) | |
tree | 397a5ca2ce7a44cf9e623d9c9945587a817982b0 | |
parent | 34f9a551ce5631baef159076c697dd8f86daa8b8 (diff) | |
parent | 396e0a840e75afb3f5ed7b50892b93ce946fac2e (diff) | |
download | CMake-35ea23a618a83902a83659a1f422a0f3af90c249.zip CMake-35ea23a618a83902a83659a1f422a0f3af90c249.tar.gz CMake-35ea23a618a83902a83659a1f422a0f3af90c249.tar.bz2 |
Merge topic 'cmCommandLineArgument_understands_exact_versus_matching_variables'
396e0a840e cmCommandLineArgument: OneOrMore mode supports `=` separator
372bf1bcc4 cmCommandLineArgument: Understands which commands require partial matching
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !6142
-rw-r--r-- | Source/cmCommandLineArgument.h | 111 | ||||
-rw-r--r-- | Source/cmake.cxx | 66 | ||||
-rw-r--r-- | Source/cmakemain.cxx | 6 | ||||
-rw-r--r-- | Tests/RunCMake/CommandLine/build-invalid-target-syntax-stderr.txt | 3 | ||||
-rw-r--r-- | Tests/RunCMake/CommandLine/build-unknown-command-partial-match-stderr.txt | 2 |
5 files changed, 133 insertions, 55 deletions
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h index 5031c65..72ab045 100644 --- a/Source/cmCommandLineArgument.h +++ b/Source/cmCommandLineArgument.h @@ -17,10 +17,25 @@ struct cmCommandLineArgument OneOrMore }; + enum class RequiresSeparator + { + Yes, + No + }; + + enum class ParseMode + { + Valid, + Invalid, + SyntaxError, + ValueError + }; + std::string InvalidSyntaxMessage; std::string InvalidValueMessage; std::string Name; Values Type; + RequiresSeparator SeparatorNeeded; std::function<FunctionSignature> StoreCall; template <typename FunctionType> @@ -29,6 +44,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 +68,39 @@ 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); + bool matched = false; + if (this->Type == Values::Zero) { + matched = (input == this->Name); + } else if (this->SeparatorNeeded == RequiresSeparator::No) { + matched = cmHasPrefix(input, this->Name); + } else if (cmHasPrefix(input, this->Name)) { + if (input.size() == this->Name.size()) { + matched = true; + } else { + matched = + (input[this->Name.size()] == '=' || input[this->Name.size()] == ' '); + } + } + return matched; } template <typename T, typename... CallState> @@ -55,13 +108,6 @@ struct cmCommandLineArgument std::vector<std::string> const& allArgs, CallState&&... state) const { - enum class ParseMode - { - Valid, - Invalid, - SyntaxError, - ValueError - }; ParseMode parseState = ParseMode::Valid; if (this->Type == Values::Zero) { @@ -95,23 +141,10 @@ struct cmCommandLineArgument index = nextValueIndex; } } else { - // parse the string to get the value - auto possible_value = cm::string_view(input).substr(this->Name.size()); - if (possible_value.empty()) { - parseState = ParseMode::ValueError; - } else if (possible_value[0] == '=') { - possible_value.remove_prefix(1); - if (possible_value.empty()) { - parseState = ParseMode::ValueError; - } - } + auto value = this->extract_single_value(input, parseState); if (parseState == ParseMode::Valid) { - if (possible_value[0] == ' ') { - possible_value.remove_prefix(1); - } - - parseState = this->StoreCall(std::string(possible_value), - std::forward<CallState>(state)...) + parseState = + this->StoreCall(value, std::forward<CallState>(state)...) ? ParseMode::Valid : ParseMode::Invalid; } @@ -149,7 +182,13 @@ struct cmCommandLineArgument index = (nextValueIndex - 1); } } else { - parseState = ParseMode::SyntaxError; + auto value = this->extract_single_value(input, parseState); + if (parseState == ParseMode::Valid) { + parseState = + this->StoreCall(value, std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } } } @@ -161,4 +200,24 @@ struct cmCommandLineArgument } return (parseState == ParseMode::Valid); } + +private: + std::string extract_single_value(std::string const& input, + ParseMode& parseState) const + { + // parse the string to get the value + auto possible_value = cm::string_view(input).substr(this->Name.size()); + if (possible_value.empty()) { + parseState = ParseMode::ValueError; + } else if (possible_value[0] == '=') { + possible_value.remove_prefix(1); + if (possible_value.empty()) { + parseState = ParseMode::ValueError; + } + } + if (parseState == ParseMode::Valid && possible_value[0] == ' ') { + possible_value.remove_prefix(1); + } + return std::string(possible_value); + } }; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5440984..315bd20 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -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::Values::One, + CommandArgument::RequiresSeparator::No, DefineLambda }, CommandArgument{ "-W", "-W must be followed with [no-]<name>.", - CommandArgument::Values::One, WarningLambda }, + CommandArgument::Values::One, + CommandArgument::RequiresSeparator::No, 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, 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; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index ad64818..997d855 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -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 }, diff --git a/Tests/RunCMake/CommandLine/build-invalid-target-syntax-stderr.txt b/Tests/RunCMake/CommandLine/build-invalid-target-syntax-stderr.txt index 5fe2539..fa3adc8 100644 --- a/Tests/RunCMake/CommandLine/build-invalid-target-syntax-stderr.txt +++ b/Tests/RunCMake/CommandLine/build-invalid-target-syntax-stderr.txt @@ -1,2 +1 @@ -^CMake Error: '--target=invalid' is invalid syntax for --target -Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\] +^Error: could not load cache diff --git a/Tests/RunCMake/CommandLine/build-unknown-command-partial-match-stderr.txt b/Tests/RunCMake/CommandLine/build-unknown-command-partial-match-stderr.txt index d69338a..e4ad6b2 100644 --- a/Tests/RunCMake/CommandLine/build-unknown-command-partial-match-stderr.txt +++ b/Tests/RunCMake/CommandLine/build-unknown-command-partial-match-stderr.txt @@ -1,2 +1,2 @@ -^CMake Error: '--targetinvalid' is invalid syntax for --target +^Unknown argument --targetinvalid Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\] |