diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 4 | ||||
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/CPack/bills-comments.txt | 68 | ||||
-rw-r--r-- | Source/QtDialog/CMakeSetup.cxx | 3 | ||||
-rw-r--r-- | Source/QtDialog/CMakeSetupDialog.cxx | 1 | ||||
-rw-r--r-- | Source/cmArgumentParser.cxx | 93 | ||||
-rw-r--r-- | Source/cmArgumentParser.h | 143 | ||||
-rw-r--r-- | Source/cmCommandArgumentsHelper.cxx | 233 | ||||
-rw-r--r-- | Source/cmCommandArgumentsHelper.h | 194 | ||||
-rw-r--r-- | Source/cmExecuteProcessCommand.cxx | 280 | ||||
-rw-r--r-- | Source/cmExportCommand.cxx | 102 | ||||
-rw-r--r-- | Source/cmExportCommand.h | 24 | ||||
-rw-r--r-- | Source/cmFileCommand.cxx | 155 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionNode.cxx | 164 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 163 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 14 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 41 | ||||
-rw-r--r-- | Source/cmInstallCommand.cxx | 175 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.cxx | 66 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.h | 35 | ||||
-rw-r--r-- | Source/cmParseArgumentsCommand.cxx | 159 | ||||
-rw-r--r-- | Source/cmSystemTools.cxx | 6 | ||||
-rw-r--r-- | Source/cmTargetPropertyComputer.cxx | 2 |
23 files changed, 996 insertions, 1131 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 3a12120..924d997 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -143,6 +143,8 @@ set(SRCS cmAffinity.cxx cmAffinity.h cmArchiveWrite.cxx + cmArgumentParser.cxx + cmArgumentParser.h cmBase32.cxx cmCacheManager.cxx cmCacheManager.h @@ -443,8 +445,6 @@ set(SRCS cmCMakeMinimumRequired.h cmCMakePolicyCommand.cxx cmCMakePolicyCommand.h - cmCommandArgumentsHelper.cxx - cmCommandArgumentsHelper.h cmConditionEvaluator.cxx cmConditionEvaluator.h cmConfigureFileCommand.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 9ff8d5c..4e7e400 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 14) -set(CMake_VERSION_PATCH 20190408) +set(CMake_VERSION_PATCH 20190415) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt deleted file mode 100644 index 1aaf9af..0000000 --- a/Source/CPack/bills-comments.txt +++ /dev/null @@ -1,68 +0,0 @@ -cpack.cxx - -cmCPackGenerators -- creates cmCPackGenericGenerator's via NewGenerator - - a cmCPackGenericGenerator factory - - -cmCPackGenericGenerator::Initialize - this->InitializeInternal - CPACK_INCLUDE_TOPLEVEL_DIRECTORY = 0 turns off - - -// binary package run -cmCPackGenericGenerator::ProcessGenerator // DoPackage - cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars - cmCPackGenericGenerator::InstallProject - run preinstall (make preinstall/fast) - call ReadListFile(cmake_install.cmake) - glob recurse in install directory to get list of files - this->CompressFiles with the list of files - - -// source package run -cmCPackGenericGenerator::ProcessGenerator // DoPackage - cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars - cmCPackGenericGenerator::InstallProject --> - if set CPACK_INSTALLED_DIRECTORIES - glob the files in that directory - copy those files to the tmp install directory _CPack something - glob recurse in install directory to get list of files - this->CompressFiles with the list of files - - -cmCPackGenericGenerator::InstallProject is used for both source and binary -packages. It is controlled based on values set in CPACK_ variables. - - -InstallProject - 1. CPACK_INSTALL_COMMANDS - a list of commands used to install the package - - 2. CPACK_INSTALLED_DIRECTORIES - copy this directory to CPACK_TEMPORARY_DIRECTORY - - 3. CPACK_INSTALL_CMAKE_PROJECTS - a cmake install script - - run make preinstall - - run cmake_install.cmake - - set CMAKE_INSTALL_PREFIX to the temp directory - - CPACK_BUILD_CONFIG check this and set the BUILD_TYPE to it - - ReadListFile on the install script cmake_install.cmake - - run strip on the executables and libraries if CPACK_STRIP_FILES is TRUE - -Recommendations: - -rename cmCPackGenerators to cmCPackGeneratorFactory - -rename cmCPackGenericGenerator --> cmCPackGenerator - -rename cmCPackGenericGenerator::ProcessGenerator -> cmCPackGenerator::DoPackage - - -break up cmCPackGenerator::InstallProject so it calls the following: - -// run user provided install commands - cmCPackGenerator::RunInstallCommands(); -// copy entire directories that need no processing like source trees - cmCPackGenerator::CopyPreInstalledDirectories(); -// run the cmake install scripts if provided - cmCPackGenerator::RunCMakeInstallScripts() - -- diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index cd30ad5..8d9a50c 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -48,6 +48,9 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #if defined(USE_QWindowsIntegrationPlugin) Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +# if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin); +# endif #endif int main(int argc, char** argv) diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 72cce9f..5f6ccca 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -303,7 +303,6 @@ void CMakeSetupDialog::initialize() #ifdef QT_WINEXTRAS this->TaskbarButton = new QWinTaskbarButton(this); this->TaskbarButton->setWindow(this->windowHandle()); - this->TaskbarButton->setOverlayIcon(QIcon(":/loading.png")); #endif } diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx new file mode 100644 index 0000000..751d117 --- /dev/null +++ b/Source/cmArgumentParser.cxx @@ -0,0 +1,93 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmArgumentParser.h" + +#include <algorithm> +#include <type_traits> + +namespace ArgumentParser { + +auto ActionMap::Emplace(cm::string_view name, Action action) + -> std::pair<iterator, bool> +{ + auto const it = + std::lower_bound(this->begin(), this->end(), name, + [](value_type const& elem, cm::string_view const& k) { + return elem.first < k; + }); + return (it != this->end() && it->first == name) + ? std::make_pair(it, false) + : std::make_pair(this->emplace(it, name, std::move(action)), true); +} + +auto ActionMap::Find(cm::string_view name) const -> const_iterator +{ + auto const it = + std::lower_bound(this->begin(), this->end(), name, + [](value_type const& elem, cm::string_view const& k) { + return elem.first < k; + }); + return (it != this->end() && it->first == name) ? it : this->end(); +} + +void Instance::Bind(bool& val) +{ + val = true; + this->CurrentString = nullptr; + this->CurrentList = nullptr; + this->ExpectValue = false; +} + +void Instance::Bind(std::string& val) +{ + this->CurrentString = &val; + this->CurrentList = nullptr; + this->ExpectValue = true; +} + +void Instance::Bind(StringList& val) +{ + this->CurrentString = nullptr; + this->CurrentList = &val; + this->ExpectValue = true; +} + +void Instance::Bind(MultiStringList& val) +{ + this->CurrentString = nullptr; + this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back()); + this->ExpectValue = false; +} + +void Instance::Consume(cm::string_view arg, void* result, + std::vector<std::string>* unparsedArguments, + std::vector<std::string>* keywordsMissingValue) +{ + auto const it = this->Bindings.Find(arg); + if (it != this->Bindings.end()) { + it->second(*this, result); + if (this->ExpectValue && keywordsMissingValue != nullptr) { + keywordsMissingValue->emplace_back(arg); + } + return; + } + + if (this->CurrentString != nullptr) { + this->CurrentString->assign(std::string(arg)); + this->CurrentString = nullptr; + this->CurrentList = nullptr; + } else if (this->CurrentList != nullptr) { + this->CurrentList->emplace_back(arg); + } else if (unparsedArguments != nullptr) { + unparsedArguments->emplace_back(arg); + } + + if (this->ExpectValue) { + if (keywordsMissingValue != nullptr) { + keywordsMissingValue->pop_back(); + } + this->ExpectValue = false; + } +} + +} // namespace ArgumentParser diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h new file mode 100644 index 0000000..6cfe946 --- /dev/null +++ b/Source/cmArgumentParser.h @@ -0,0 +1,143 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmArgumentParser_h +#define cmArgumentParser_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" + +#include <cassert> +#include <functional> +#include <string> +#include <utility> +#include <vector> + +namespace ArgumentParser { + +using StringList = std::vector<std::string>; +using MultiStringList = std::vector<StringList>; + +class Instance; +using Action = std::function<void(Instance&, void*)>; + +// using ActionMap = cm::flat_map<cm::string_view, Action>; +class ActionMap : public std::vector<std::pair<cm::string_view, Action>> +{ +public: + std::pair<iterator, bool> Emplace(cm::string_view name, Action action); + const_iterator Find(cm::string_view name) const; +}; + +class Instance +{ +public: + Instance(ActionMap const& bindings) + : Bindings(bindings) + { + } + + void Bind(bool& val); + void Bind(std::string& val); + void Bind(StringList& val); + void Bind(MultiStringList& val); + + void Consume(cm::string_view arg, void* result, + std::vector<std::string>* unparsedArguments, + std::vector<std::string>* keywordsMissingValue); + +private: + ActionMap const& Bindings; + std::string* CurrentString = nullptr; + StringList* CurrentList = nullptr; + bool ExpectValue = false; +}; + +} // namespace ArgumentParser + +template <typename Result> +class cmArgumentParser +{ +public: + // I *think* this function could be made `constexpr` when the code is + // compiled as C++20. This would allow building a parser at compile time. + template <typename T> + cmArgumentParser& Bind(cm::static_string_view name, T Result::*member) + { + bool const inserted = + this->Bindings + .Emplace(name, + [member](ArgumentParser::Instance& instance, void* result) { + instance.Bind(static_cast<Result*>(result)->*member); + }) + .second; + assert(inserted), (void)inserted; + return *this; + } + + template <typename Range> + void Parse(Result& result, Range const& args, + std::vector<std::string>* unparsedArguments = nullptr, + std::vector<std::string>* keywordsMissingValue = nullptr) const + { + ArgumentParser::Instance instance(this->Bindings); + for (cm::string_view arg : args) { + instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue); + } + } + + template <typename Range> + Result Parse(Range const& args, + std::vector<std::string>* unparsedArguments = nullptr, + std::vector<std::string>* keywordsMissingValue = nullptr) const + { + Result result; + this->Parse(result, args, unparsedArguments, keywordsMissingValue); + return result; + } + +private: + ArgumentParser::ActionMap Bindings; +}; + +template <> +class cmArgumentParser<void> +{ +public: + template <typename T> + cmArgumentParser& Bind(cm::static_string_view name, T& ref) + { + bool const inserted = this->Bind(cm::string_view(name), ref); + assert(inserted), (void)inserted; + return *this; + } + + template <typename Range> + void Parse(Range const& args, + std::vector<std::string>* unparsedArguments = nullptr, + std::vector<std::string>* keywordsMissingValue = nullptr) const + { + ArgumentParser::Instance instance(this->Bindings); + for (cm::string_view arg : args) { + instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue); + } + } + +protected: + template <typename T> + bool Bind(cm::string_view name, T& ref) + { + return this->Bindings + .Emplace(name, + [&ref](ArgumentParser::Instance& instance, void*) { + instance.Bind(ref); + }) + .second; + } + +private: + ArgumentParser::ActionMap Bindings; +}; + +#endif diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx deleted file mode 100644 index 968b17c..0000000 --- a/Source/cmCommandArgumentsHelper.cxx +++ /dev/null @@ -1,233 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCommandArgumentsHelper.h" - -cmCommandArgument::cmCommandArgument(cmCommandArgumentsHelper* args, - const char* key, - cmCommandArgumentGroup* group) - : Key(key) - , Group(group) - , WasActive(false) - , ArgumentsBeforeEmpty(true) - , CurrentIndex(0) -{ - if (args != nullptr) { - args->AddArgument(this); - } - - if (this->Group != nullptr) { - this->Group->ContainedArguments.push_back(this); - } -} - -void cmCommandArgument::Reset() -{ - this->WasActive = false; - this->CurrentIndex = 0; - this->DoReset(); -} - -void cmCommandArgument::Follows(const cmCommandArgument* arg) -{ - this->ArgumentsBeforeEmpty = false; - this->ArgumentsBefore.insert(arg); -} - -void cmCommandArgument::FollowsGroup(const cmCommandArgumentGroup* group) -{ - if (group != nullptr) { - this->ArgumentsBeforeEmpty = false; - this->ArgumentsBefore.insert(group->ContainedArguments.begin(), - group->ContainedArguments.end()); - } -} - -bool cmCommandArgument::MayFollow(const cmCommandArgument* current) const -{ - if (this->ArgumentsBeforeEmpty) { - return true; - } - return this->ArgumentsBefore.find(current) != this->ArgumentsBefore.end(); -} - -bool cmCommandArgument::KeyMatches(const std::string& key) const -{ - if ((this->Key == nullptr) || (this->Key[0] == '\0')) { - return true; - } - return (key == this->Key); -} - -void cmCommandArgument::ApplyOwnGroup() -{ - if (this->Group != nullptr) { - for (cmCommandArgument* cargs : this->Group->ContainedArguments) { - if (cargs != this) { - this->ArgumentsBefore.insert(cargs); - } - } - } -} - -void cmCommandArgument::Activate() -{ - this->WasActive = true; - this->CurrentIndex = 0; -} - -bool cmCommandArgument::Consume(const std::string& arg) -{ - bool res = this->DoConsume(arg, this->CurrentIndex); - this->CurrentIndex++; - return res; -} - -cmCAStringVector::cmCAStringVector(cmCommandArgumentsHelper* args, - const char* key, - cmCommandArgumentGroup* group) - : cmCommandArgument(args, key, group) - , Ignore(nullptr) -{ - if ((key == nullptr) || (*key == 0)) { - this->DataStart = 0; - } else { - this->DataStart = 1; - } -} - -bool cmCAStringVector::DoConsume(const std::string& arg, unsigned int index) -{ - if (index >= this->DataStart) { - if ((this->Ignore == nullptr) || (arg != this->Ignore)) { - this->Vector.push_back(arg); - } - } - - return false; -} - -void cmCAStringVector::DoReset() -{ - this->Vector.clear(); -} - -cmCAString::cmCAString(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group) - : cmCommandArgument(args, key, group) -{ - if ((key == nullptr) || (*key == 0)) { - this->DataStart = 0; - } else { - this->DataStart = 1; - } -} - -bool cmCAString::DoConsume(const std::string& arg, unsigned int index) -{ - if (index == this->DataStart) { - this->String = arg; - } - - return index >= this->DataStart; -} - -void cmCAString::DoReset() -{ - this->String.clear(); -} - -cmCAEnabler::cmCAEnabler(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group) - : cmCommandArgument(args, key, group) - , Enabled(false) -{ -} - -bool cmCAEnabler::DoConsume(const std::string&, unsigned int index) -{ - if (index == 0) { - this->Enabled = true; - } - return true; -} - -void cmCAEnabler::DoReset() -{ - this->Enabled = false; -} - -cmCADisabler::cmCADisabler(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group) - : cmCommandArgument(args, key, group) - , Enabled(true) -{ -} - -bool cmCADisabler::DoConsume(const std::string&, unsigned int index) -{ - if (index == 0) { - this->Enabled = false; - } - return true; -} - -void cmCADisabler::DoReset() -{ - this->Enabled = true; -} - -void cmCommandArgumentGroup::Follows(const cmCommandArgument* arg) -{ - for (cmCommandArgument* ca : this->ContainedArguments) { - ca->Follows(arg); - } -} - -void cmCommandArgumentGroup::FollowsGroup(const cmCommandArgumentGroup* group) -{ - for (cmCommandArgument* ca : this->ContainedArguments) { - ca->FollowsGroup(group); - } -} - -void cmCommandArgumentsHelper::Parse(const std::vector<std::string>* args, - std::vector<std::string>* unconsumedArgs) -{ - if (args == nullptr) { - return; - } - - for (cmCommandArgument* ca : this->Arguments) { - ca->ApplyOwnGroup(); - ca->Reset(); - } - - cmCommandArgument* activeArgument = nullptr; - const cmCommandArgument* previousArgument = nullptr; - for (std::string const& it : *args) { - for (cmCommandArgument* ca : this->Arguments) { - if (ca->KeyMatches(it) && (ca->MayFollow(previousArgument))) { - activeArgument = ca; - activeArgument->Activate(); - break; - } - } - - if (activeArgument) { - bool argDone = activeArgument->Consume(it); - previousArgument = activeArgument; - if (argDone) { - activeArgument = nullptr; - } - } else { - if (unconsumedArgs != nullptr) { - unconsumedArgs->push_back(it); - } - } - } -} - -void cmCommandArgumentsHelper::AddArgument(cmCommandArgument* arg) -{ - this->Arguments.push_back(arg); -} diff --git a/Source/cmCommandArgumentsHelper.h b/Source/cmCommandArgumentsHelper.h deleted file mode 100644 index dc934be..0000000 --- a/Source/cmCommandArgumentsHelper.h +++ /dev/null @@ -1,194 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmCommandArgumentsHelper_h -#define cmCommandArgumentsHelper_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <set> -#include <string> -#include <vector> - -class cmCommandArgumentGroup; -class cmCommandArgumentsHelper; - -/* cmCommandArgumentsHelper, cmCommandArgumentGroup and cmCommandArgument (i.e. -its derived classes cmCAXXX can be used to simplify the processing of -arguments to cmake commands. Maybe they can also be used to generate -documentation. - -For every argument supported by a command one cmCommandArgument is created -and added to cmCommandArgumentsHelper. cmCommand has a cmCommandArgumentsHelper -as member variable so this should be used. - -The order of the arguments is defined using the Follows(arg) method. It says -that this argument follows immediateley the given argument. It can be used -with multiple arguments if the argument can follow after different arguments. - -Arguments can be arranged in groups using cmCommandArgumentGroup. Every -member of a group can follow any other member of the group. These groups -can also be used to define the order. - -Once all arguments and groups are set up, cmCommandArgumentsHelper::Parse() -is called and afterwards the values of the arguments can be evaluated. - -For an example see cmExportCommand.cxx. -*/ -class cmCommandArgument -{ -public: - cmCommandArgument(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group = nullptr); - virtual ~cmCommandArgument() = default; - - /// this argument may follow after arg. 0 means it comes first. - void Follows(const cmCommandArgument* arg); - - /// this argument may follow after any of the arguments in the given group - void FollowsGroup(const cmCommandArgumentGroup* group); - - /// Returns true if the argument was found in the argument list - bool WasFound() const { return this->WasActive; } - - // The following methods are only called from - // cmCommandArgumentsHelper::Parse(), but making this a friend would - // give it access to everything - - /// Make the current argument the currently active argument - void Activate(); - /// Consume the current string - bool Consume(const std::string& arg); - - /// Return true if this argument may follow after the given argument. - bool MayFollow(const cmCommandArgument* current) const; - - /** Returns true if the given key matches the key for this argument. - If this argument has an empty key everything matches. */ - bool KeyMatches(const std::string& key) const; - - /// Make this argument follow all members of the own group - void ApplyOwnGroup(); - - /// Reset argument, so it's back to its initial state - void Reset(); - -private: - const char* Key; - std::set<const cmCommandArgument*> ArgumentsBefore; - cmCommandArgumentGroup* Group; - bool WasActive; - bool ArgumentsBeforeEmpty; - unsigned int CurrentIndex; - - virtual bool DoConsume(const std::string& arg, unsigned int index) = 0; - virtual void DoReset() = 0; -}; - -/** cmCAStringVector is to be used for arguments which can consist of more -than one string, e.g. the FILES argument in INSTALL(FILES f1 f2 f3 ...). */ -class cmCAStringVector : public cmCommandArgument -{ -public: - cmCAStringVector(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group = nullptr); - - /// Return the vector of strings - const std::vector<std::string>& GetVector() const { return this->Vector; } - - /** Is there a keyword which should be skipped in - the arguments (e.g. ARGS for ADD_CUSTOM_COMMAND) ? */ - void SetIgnore(const char* ignore) { this->Ignore = ignore; } - -private: - std::vector<std::string> Vector; - unsigned int DataStart; - const char* Ignore; - bool DoConsume(const std::string& arg, unsigned int index) override; - void DoReset() override; -}; - -/** cmCAString is to be used for arguments which consist of one value, -e.g. the executable name in ADD_EXECUTABLE(). */ -class cmCAString : public cmCommandArgument -{ -public: - cmCAString(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group = nullptr); - - /// Return the string - const std::string& GetString() const { return this->String; } - const char* GetCString() const { return this->String.c_str(); } - -private: - std::string String; - unsigned int DataStart; - bool DoConsume(const std::string& arg, unsigned int index) override; - void DoReset() override; -}; - -/** cmCAEnabler is to be used for options which are off by default and can be -enabled using a special argument, e.g. EXCLUDE_FROM_ALL in ADD_EXECUTABLE(). */ -class cmCAEnabler : public cmCommandArgument -{ -public: - cmCAEnabler(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group = nullptr); - - /// Has it been enabled ? - bool IsEnabled() const { return this->Enabled; } - -private: - bool Enabled; - bool DoConsume(const std::string& arg, unsigned int index) override; - void DoReset() override; -}; - -/** cmCADisable is to be used for options which are on by default and can be -disabled using a special argument.*/ -class cmCADisabler : public cmCommandArgument -{ -public: - cmCADisabler(cmCommandArgumentsHelper* args, const char* key, - cmCommandArgumentGroup* group = nullptr); - - /// Is it still enabled ? - bool IsEnabled() const { return this->Enabled; } - -private: - bool Enabled; - bool DoConsume(const std::string& arg, unsigned int index) override; - void DoReset() override; -}; - -/** Group of arguments, needed for ordering. E.g. WIN32, EXCLUDE_FROM_ALL and -MACSOX_BUNDLE from ADD_EXECUTABLE() are a group. -*/ -class cmCommandArgumentGroup -{ - friend class cmCommandArgument; - -public: - /// All members of this group may follow the given argument - void Follows(const cmCommandArgument* arg); - - /// All members of this group may follow all members of the given group - void FollowsGroup(const cmCommandArgumentGroup* group); - -private: - std::vector<cmCommandArgument*> ContainedArguments; -}; - -class cmCommandArgumentsHelper -{ -public: - /// Parse the argument list - void Parse(const std::vector<std::string>* args, - std::vector<std::string>* unconsumedArgs); - /// Add an argument. - void AddArgument(cmCommandArgument* arg); - -private: - std::vector<cmCommandArgument*> Arguments; -}; - -#endif diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 03eac5b..ff6340f 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -2,12 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExecuteProcessCommand.h" +#include "cm_static_string_view.hxx" #include "cmsys/Process.h" +#include <algorithm> #include <ctype.h> /* isspace */ -#include <sstream> #include <stdio.h> #include "cmAlgorithms.h" +#include "cmArgumentParser.h" #include "cmMakefile.h" #include "cmProcessOutput.h" #include "cmSystemTools.h" @@ -32,157 +34,85 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, this->SetError("called with incorrect number of arguments"); return false; } - std::vector<std::vector<const char*>> cmds; - std::string arguments; - bool doing_command = false; - size_t command_index = 0; - bool output_quiet = false; - bool error_quiet = false; - bool output_strip_trailing_whitespace = false; - bool error_strip_trailing_whitespace = false; - std::string timeout_string; - std::string input_file; - std::string output_file; - std::string error_file; - std::string output_variable; - std::string error_variable; - std::string result_variable; - std::string results_variable; - std::string working_directory; - cmProcessOutput::Encoding encoding = cmProcessOutput::None; - for (size_t i = 0; i < args.size(); ++i) { - if (args[i] == "COMMAND") { - doing_command = true; - command_index = cmds.size(); - cmds.emplace_back(); - } else if (args[i] == "OUTPUT_VARIABLE") { - doing_command = false; - if (++i < args.size()) { - output_variable = args[i]; - } else { - this->SetError(" called with no value for OUTPUT_VARIABLE."); - return false; - } - } else if (args[i] == "ERROR_VARIABLE") { - doing_command = false; - if (++i < args.size()) { - error_variable = args[i]; - } else { - this->SetError(" called with no value for ERROR_VARIABLE."); - return false; - } - } else if (args[i] == "RESULT_VARIABLE") { - doing_command = false; - if (++i < args.size()) { - result_variable = args[i]; - } else { - this->SetError(" called with no value for RESULT_VARIABLE."); - return false; - } - } else if (args[i] == "RESULTS_VARIABLE") { - doing_command = false; - if (++i < args.size()) { - results_variable = args[i]; - } else { - this->SetError(" called with no value for RESULTS_VARIABLE."); - return false; - } - } else if (args[i] == "WORKING_DIRECTORY") { - doing_command = false; - if (++i < args.size()) { - working_directory = args[i]; - } else { - this->SetError(" called with no value for WORKING_DIRECTORY."); - return false; - } - } else if (args[i] == "INPUT_FILE") { - doing_command = false; - if (++i < args.size()) { - input_file = args[i]; - } else { - this->SetError(" called with no value for INPUT_FILE."); - return false; - } - } else if (args[i] == "OUTPUT_FILE") { - doing_command = false; - if (++i < args.size()) { - output_file = args[i]; - } else { - this->SetError(" called with no value for OUTPUT_FILE."); - return false; - } - } else if (args[i] == "ERROR_FILE") { - doing_command = false; - if (++i < args.size()) { - error_file = args[i]; - } else { - this->SetError(" called with no value for ERROR_FILE."); - return false; - } - } else if (args[i] == "TIMEOUT") { - doing_command = false; - if (++i < args.size()) { - timeout_string = args[i]; - } else { - this->SetError(" called with no value for TIMEOUT."); - return false; - } - } else if (args[i] == "OUTPUT_QUIET") { - doing_command = false; - output_quiet = true; - } else if (args[i] == "ERROR_QUIET") { - doing_command = false; - error_quiet = true; - } else if (args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE") { - doing_command = false; - output_strip_trailing_whitespace = true; - } else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") { - doing_command = false; - error_strip_trailing_whitespace = true; - } else if (args[i] == "ENCODING") { - doing_command = false; - if (++i < args.size()) { - encoding = cmProcessOutput::FindEncoding(args[i]); - } else { - this->SetError(" called with no value for ENCODING."); - return false; - } - } else if (doing_command) { - cmds[command_index].push_back(args[i].c_str()); - } else { - std::ostringstream e; - e << " given unknown argument \"" << args[i] << "\"."; - this->SetError(e.str()); - return false; - } + + struct Arguments + { + std::vector<std::vector<std::string>> Commands; + std::string OutputVariable; + std::string ErrorVariable; + std::string ResultVariable; + std::string ResultsVariable; + std::string WorkingDirectory; + std::string InputFile; + std::string OutputFile; + std::string ErrorFile; + std::string Timeout; + bool OutputQuiet = false; + bool ErrorQuiet = false; + bool OutputStripTrailingWhitespace = false; + bool ErrorStripTrailingWhitespace = false; + std::string Encoding; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("COMMAND"_s, &Arguments::Commands) + .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable) + .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable) + .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable) + .Bind("RESULTS_VARIABLE"_s, &Arguments::ResultsVariable) + .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory) + .Bind("INPUT_FILE"_s, &Arguments::InputFile) + .Bind("OUTPUT_FILE"_s, &Arguments::OutputFile) + .Bind("ERROR_FILE"_s, &Arguments::ErrorFile) + .Bind("TIMEOUT"_s, &Arguments::Timeout) + .Bind("OUTPUT_QUIET"_s, &Arguments::OutputQuiet) + .Bind("ERROR_QUIET"_s, &Arguments::ErrorQuiet) + .Bind("OUTPUT_STRIP_TRAILING_WHITESPACE"_s, + &Arguments::OutputStripTrailingWhitespace) + .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s, + &Arguments::ErrorStripTrailingWhitespace) + .Bind("ENCODING"_s, &Arguments::Encoding); + + std::vector<std::string> unparsedArguments; + std::vector<std::string> keywordsMissingValue; + Arguments const arguments = + parser.Parse(args, &unparsedArguments, &keywordsMissingValue); + + if (!keywordsMissingValue.empty()) { + this->SetError(" called with no value for " + + keywordsMissingValue.front() + "."); + return false; + } + if (!unparsedArguments.empty()) { + this->SetError(" given unknown argument \"" + unparsedArguments.front() + + "\"."); + return false; } - if (!this->Makefile->CanIWriteThisFile(output_file)) { - std::string e = "attempted to output into a file: " + output_file + - " into a source directory."; - this->SetError(e); + if (!this->Makefile->CanIWriteThisFile(arguments.OutputFile)) { + this->SetError("attempted to output into a file: " + arguments.OutputFile + + " into a source directory."); cmSystemTools::SetFatalErrorOccured(); return false; } // Check for commands given. - if (cmds.empty()) { + if (arguments.Commands.empty()) { this->SetError(" called with no COMMAND argument."); return false; } - for (auto& cmd : cmds) { + for (std::vector<std::string> const& cmd : arguments.Commands) { if (cmd.empty()) { this->SetError(" given COMMAND argument with no value."); return false; } - // Add the null terminating pointer to the command argument list. - cmd.push_back(nullptr); } // Parse the timeout string. double timeout = -1; - if (!timeout_string.empty()) { - if (sscanf(timeout_string.c_str(), "%lg", &timeout) != 1) { + if (!arguments.Timeout.empty()) { + if (sscanf(arguments.Timeout.c_str(), "%lg", &timeout) != 1) { this->SetError(" called with TIMEOUT value that could not be parsed."); return false; } @@ -192,13 +122,17 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, cmsysProcess* cp = cmsysProcess_New(); // Set the command sequence. - for (auto const& cmd : cmds) { - cmsysProcess_AddCommand(cp, cmd.data()); + for (std::vector<std::string> const& cmd : arguments.Commands) { + std::vector<const char*> argv(cmd.size() + 1); + std::transform(cmd.begin(), cmd.end(), argv.begin(), + [](std::string const& s) { return s.c_str(); }); + argv.back() = nullptr; + cmsysProcess_AddCommand(cp, argv.data()); } // Set the process working directory. - if (!working_directory.empty()) { - cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str()); + if (!arguments.WorkingDirectory.empty()) { + cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str()); } // Always hide the process window. @@ -206,22 +140,24 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, // Check the output variables. bool merge_output = false; - if (!input_file.empty()) { - cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str()); + if (!arguments.InputFile.empty()) { + cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, + arguments.InputFile.c_str()); } - if (!output_file.empty()) { + if (!arguments.OutputFile.empty()) { cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT, - output_file.c_str()); + arguments.OutputFile.c_str()); } - if (!error_file.empty()) { - if (error_file == output_file) { + if (!arguments.ErrorFile.empty()) { + if (arguments.ErrorFile == arguments.OutputFile) { merge_output = true; } else { cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR, - error_file.c_str()); + arguments.ErrorFile.c_str()); } } - if (!output_variable.empty() && output_variable == error_variable) { + if (!arguments.OutputVariable.empty() && + arguments.OutputVariable == arguments.ErrorVariable) { merge_output = true; } if (merge_output) { @@ -242,19 +178,20 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, int length; char* data; int p; - cmProcessOutput processOutput(encoding); + cmProcessOutput processOutput( + cmProcessOutput::FindEncoding(arguments.Encoding)); std::string strdata; while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) { // Put the output in the right place. - if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) { - if (output_variable.empty()) { + if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) { + if (arguments.OutputVariable.empty()) { processOutput.DecodeText(data, length, strdata, 1); cmSystemTools::Stdout(strdata); } else { cmExecuteProcessCommandAppend(tempOutput, data, length); } - } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) { - if (error_variable.empty()) { + } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) { + if (arguments.ErrorVariable.empty()) { processOutput.DecodeText(data, length, strdata, 2); cmSystemTools::Stderr(strdata); } else { @@ -262,13 +199,13 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, } } } - if (!output_quiet && output_variable.empty()) { + if (!arguments.OutputQuiet && arguments.OutputVariable.empty()) { processOutput.DecodeText(std::string(), strdata, 1); if (!strdata.empty()) { cmSystemTools::Stdout(strdata); } } - if (!error_quiet && error_variable.empty()) { + if (!arguments.ErrorQuiet && arguments.ErrorVariable.empty()) { processOutput.DecodeText(std::string(), strdata, 2); if (!strdata.empty()) { cmSystemTools::Stderr(strdata); @@ -281,46 +218,49 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, processOutput.DecodeText(tempError, tempError); // Fix the text in the output strings. - cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace); - cmExecuteProcessCommandFixText(tempError, error_strip_trailing_whitespace); + cmExecuteProcessCommandFixText(tempOutput, + arguments.OutputStripTrailingWhitespace); + cmExecuteProcessCommandFixText(tempError, + arguments.ErrorStripTrailingWhitespace); // Store the output obtained. - if (!output_variable.empty() && !tempOutput.empty()) { - this->Makefile->AddDefinition(output_variable, tempOutput.data()); + if (!arguments.OutputVariable.empty() && !tempOutput.empty()) { + this->Makefile->AddDefinition(arguments.OutputVariable, tempOutput.data()); } - if (!merge_output && !error_variable.empty() && !tempError.empty()) { - this->Makefile->AddDefinition(error_variable, tempError.data()); + if (!merge_output && !arguments.ErrorVariable.empty() && + !tempError.empty()) { + this->Makefile->AddDefinition(arguments.ErrorVariable, tempError.data()); } // Store the result of running the process. - if (!result_variable.empty()) { + if (!arguments.ResultVariable.empty()) { switch (cmsysProcess_GetState(cp)) { case cmsysProcess_State_Exited: { int v = cmsysProcess_GetExitValue(cp); char buf[16]; sprintf(buf, "%d", v); - this->Makefile->AddDefinition(result_variable, buf); + this->Makefile->AddDefinition(arguments.ResultVariable, buf); } break; case cmsysProcess_State_Exception: - this->Makefile->AddDefinition(result_variable, + this->Makefile->AddDefinition(arguments.ResultVariable, cmsysProcess_GetExceptionString(cp)); break; case cmsysProcess_State_Error: - this->Makefile->AddDefinition(result_variable, + this->Makefile->AddDefinition(arguments.ResultVariable, cmsysProcess_GetErrorString(cp)); break; case cmsysProcess_State_Expired: - this->Makefile->AddDefinition(result_variable, + this->Makefile->AddDefinition(arguments.ResultVariable, "Process terminated due to timeout"); break; } } // Store the result of running the processes. - if (!results_variable.empty()) { + if (!arguments.ResultsVariable.empty()) { switch (cmsysProcess_GetState(cp)) { case cmsysProcess_State_Exited: { std::vector<std::string> res; - for (size_t i = 0; i < cmds.size(); ++i) { + for (size_t i = 0; i < arguments.Commands.size(); ++i) { switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) { case kwsysProcess_StateByIndex_Exited: { int exitCode = @@ -339,19 +279,19 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, break; } } - this->Makefile->AddDefinition(results_variable, + this->Makefile->AddDefinition(arguments.ResultsVariable, cmJoin(res, ";").c_str()); } break; case cmsysProcess_State_Exception: - this->Makefile->AddDefinition(results_variable, + this->Makefile->AddDefinition(arguments.ResultsVariable, cmsysProcess_GetExceptionString(cp)); break; case cmsysProcess_State_Error: - this->Makefile->AddDefinition(results_variable, + this->Makefile->AddDefinition(arguments.ResultsVariable, cmsysProcess_GetErrorString(cp)); break; case cmsysProcess_State_Expired: - this->Makefile->AddDefinition(results_variable, + this->Makefile->AddDefinition(arguments.ResultsVariable, "Process terminated due to timeout"); break; } diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index c25e1f4..5b611c0 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -2,10 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportCommand.h" +#include "cm_static_string_view.hxx" #include "cmsys/RegularExpression.hxx" #include <map> #include <sstream> +#include <utility> +#include "cmArgumentParser.h" #include "cmExportBuildAndroidMKGenerator.h" #include "cmExportBuildFileGenerator.h" #include "cmExportSetMap.h" @@ -18,6 +21,7 @@ #include "cmSystemTools.h" #include "cmTarget.h" +class cmExportSet; class cmExecutionStatus; #if defined(__HAIKU__) @@ -25,19 +29,6 @@ class cmExecutionStatus; # include <StorageDefs.h> #endif -cmExportCommand::cmExportCommand() - : Targets(&Helper, "TARGETS") - , Append(&Helper, "APPEND", &ArgumentGroup) - , ExportSetName(&Helper, "EXPORT", &ArgumentGroup) - , Namespace(&Helper, "NAMESPACE", &ArgumentGroup) - , Filename(&Helper, "FILE", &ArgumentGroup) - , ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup) - , AndroidMKFile(&Helper, "ANDROID_MK") -{ - this->ExportSet = nullptr; -} - -// cmExportCommand bool cmExportCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { @@ -49,45 +40,62 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, if (args[0] == "PACKAGE") { return this->HandlePackage(args); } + + struct Arguments + { + std::string ExportSetName; + std::vector<std::string> Targets; + std::string Namespace; + std::string Filename; + std::string AndroidMKFile; + bool Append = false; + bool ExportOld = false; + }; + + auto parser = cmArgumentParser<Arguments>{} + .Bind("NAMESPACE"_s, &Arguments::Namespace) + .Bind("FILE"_s, &Arguments::Filename); + if (args[0] == "EXPORT") { - this->ExportSetName.Follows(nullptr); - this->ArgumentGroup.Follows(&this->ExportSetName); + parser.Bind("EXPORT"_s, &Arguments::ExportSetName); } else { - this->Targets.Follows(nullptr); - this->ArgumentGroup.Follows(&this->Targets); + parser.Bind("TARGETS"_s, &Arguments::Targets); + parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile); + parser.Bind("APPEND"_s, &Arguments::Append); + parser.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, &Arguments::ExportOld); } std::vector<std::string> unknownArgs; - this->Helper.Parse(&args, &unknownArgs); + Arguments const arguments = parser.Parse(args, &unknownArgs); if (!unknownArgs.empty()) { - this->SetError("Unknown arguments."); + this->SetError("Unknown argument: \"" + unknownArgs.front() + "\"."); return false; } std::string fname; bool android = false; - if (this->AndroidMKFile.WasFound()) { - fname = this->AndroidMKFile.GetString(); + if (!arguments.AndroidMKFile.empty()) { + fname = arguments.AndroidMKFile; android = true; } - if (!this->Filename.WasFound() && fname.empty()) { + if (arguments.Filename.empty() && fname.empty()) { if (args[0] != "EXPORT") { this->SetError("FILE <filename> option missing."); return false; } - fname = this->ExportSetName.GetString() + ".cmake"; + fname = arguments.ExportSetName + ".cmake"; } else if (fname.empty()) { // Make sure the file has a .cmake extension. - if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) != + if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) != ".cmake") { std::ostringstream e; - e << "FILE option given filename \"" << this->Filename.GetString() + e << "FILE option given filename \"" << arguments.Filename << "\" which does not have an extension of \".cmake\".\n"; this->SetError(e.str()); return false; } - fname = this->Filename.GetString(); + fname = arguments.Filename; } // Get the file to write. @@ -109,33 +117,19 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator(); + cmExportSet* ExportSet = nullptr; if (args[0] == "EXPORT") { - if (this->Append.IsEnabled()) { - std::ostringstream e; - e << "EXPORT signature does not recognise the APPEND option."; - this->SetError(e.str()); - return false; - } - - if (this->ExportOld.IsEnabled()) { - std::ostringstream e; - e << "EXPORT signature does not recognise the " - "EXPORT_LINK_INTERFACE_LIBRARIES option."; - this->SetError(e.str()); - return false; - } - cmExportSetMap& setMap = gg->GetExportSets(); - std::string setName = this->ExportSetName.GetString(); - if (setMap.find(setName) == setMap.end()) { + auto const it = setMap.find(arguments.ExportSetName); + if (it == setMap.end()) { std::ostringstream e; - e << "Export set \"" << setName << "\" not found."; + e << "Export set \"" << arguments.ExportSetName << "\" not found."; this->SetError(e.str()); return false; } - this->ExportSet = setMap[setName]; - } else if (this->Targets.WasFound()) { - for (std::string const& currentTarget : this->Targets.GetVector()) { + ExportSet = it->second; + } else if (!arguments.Targets.empty()) { + for (std::string const& currentTarget : arguments.Targets) { if (this->Makefile->IsAlias(currentTarget)) { std::ostringstream e; e << "given ALIAS target \"" << currentTarget @@ -159,7 +153,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } targets.push_back(currentTarget); } - if (this->Append.IsEnabled()) { + if (arguments.Append) { if (cmExportBuildFileGenerator* ebfg = gg->GetExportedTargetsFile(fname)) { ebfg->AppendTargets(targets); @@ -179,15 +173,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, ebfg = new cmExportBuildFileGenerator; } ebfg->SetExportFile(fname.c_str()); - ebfg->SetNamespace(this->Namespace.GetCString()); - ebfg->SetAppendMode(this->Append.IsEnabled()); - if (this->ExportSet) { - ebfg->SetExportSet(this->ExportSet); + ebfg->SetNamespace(arguments.Namespace); + ebfg->SetAppendMode(arguments.Append); + if (ExportSet != nullptr) { + ebfg->SetExportSet(ExportSet); } else { ebfg->SetTargets(targets); } this->Makefile->AddExportBuildFileGenerator(ebfg); - ebfg->SetExportOld(this->ExportOld.IsEnabled()); + ebfg->SetExportOld(arguments.ExportOld); // Compute the set of configurations exported. std::vector<std::string> configurationTypes; @@ -198,7 +192,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, for (std::string const& ct : configurationTypes) { ebfg->AddConfiguration(ct); } - if (this->ExportSet) { + if (ExportSet != nullptr) { gg->AddBuildExportExportSet(ebfg); } else { gg->AddBuildExportSet(ebfg); diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h index a5c6751..99f9932 100644 --- a/Source/cmExportCommand.h +++ b/Source/cmExportCommand.h @@ -9,21 +9,12 @@ #include <vector> #include "cmCommand.h" -#include "cmCommandArgumentsHelper.h" class cmExecutionStatus; -class cmExportSet; -/** \class cmExportLibraryDependenciesCommand - * \brief Add a test to the lists of tests to run. - * - * cmExportLibraryDependenciesCommand adds a test to the list of tests to run - * - */ class cmExportCommand : public cmCommand { public: - cmExportCommand(); /** * This is a virtual constructor for the command. */ @@ -37,21 +28,6 @@ public: cmExecutionStatus& status) override; private: - cmCommandArgumentsHelper Helper; - cmCommandArgumentGroup ArgumentGroup; - cmCAStringVector Targets; - cmCAEnabler Append; - cmCAString ExportSetName; - cmCAString Namespace; - cmCAString Filename; - cmCAEnabler ExportOld; - cmCAString AndroidMKFile; - - cmExportSet* ExportSet; - - friend class cmExportBuildFileGenerator; - std::string ErrorMessage; - bool HandlePackage(std::vector<std::string> const& args); void StorePackageRegistryWin(std::string const& package, const char* content, const char* hash); diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d2bc851..f5ec9fe 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -3,6 +3,7 @@ #include "cmFileCommand.h" #include "cm_kwiml.h" +#include "cm_static_string_view.hxx" #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" @@ -19,7 +20,7 @@ #include <vector> #include "cmAlgorithms.h" -#include "cmCommandArgumentsHelper.h" +#include "cmArgumentParser.h" #include "cmCryptoHash.h" #include "cmFileCopier.h" #include "cmFileInstaller.h" @@ -268,36 +269,34 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args) return false; } - cmCommandArgumentsHelper argHelper; - cmCommandArgumentGroup group; + std::string const& fileNameArg = args[1]; + std::string const& variable = args[2]; - cmCAString readArg(&argHelper, "READ"); - cmCAString fileNameArg(&argHelper, nullptr); - cmCAString resultArg(&argHelper, nullptr); + struct Arguments + { + std::string Offset; + std::string Limit; + bool Hex = false; + }; + + static auto const parser = cmArgumentParser<Arguments>{} + .Bind("OFFSET"_s, &Arguments::Offset) + .Bind("LIMIT"_s, &Arguments::Limit) + .Bind("HEX"_s, &Arguments::Hex); - cmCAString offsetArg(&argHelper, "OFFSET", &group); - cmCAString limitArg(&argHelper, "LIMIT", &group); - cmCAEnabler hexOutputArg(&argHelper, "HEX", &group); - readArg.Follows(nullptr); - fileNameArg.Follows(&readArg); - resultArg.Follows(&fileNameArg); - group.Follows(&resultArg); - argHelper.Parse(&args, nullptr); + Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3)); - std::string fileName = fileNameArg.GetString(); + std::string fileName = fileNameArg; if (!cmsys::SystemTools::FileIsFullPath(fileName)) { fileName = this->Makefile->GetCurrentSourceDirectory(); - fileName += "/" + fileNameArg.GetString(); + fileName += "/" + fileNameArg; } - std::string variable = resultArg.GetString(); - // Open the specified file. #if defined(_WIN32) || defined(__CYGWIN__) - cmsys::ifstream file( - fileName.c_str(), - std::ios::in | - (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in)); + cmsys::ifstream file(fileName.c_str(), + arguments.Hex ? (std::ios::binary | std::ios::in) + : std::ios::in); #else cmsys::ifstream file(fileName.c_str()); #endif @@ -313,21 +312,21 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args) // is there a limit? long sizeLimit = -1; - if (!limitArg.GetString().empty()) { - sizeLimit = atoi(limitArg.GetCString()); + if (!arguments.Limit.empty()) { + sizeLimit = atoi(arguments.Limit.c_str()); } // is there an offset? long offset = 0; - if (!offsetArg.GetString().empty()) { - offset = atoi(offsetArg.GetCString()); + if (!arguments.Offset.empty()) { + offset = atoi(arguments.Offset.c_str()); } file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6 std::string output; - if (hexOutputArg.IsEnabled()) { + if (arguments.Hex) { // Convert part of the file into hex code char c; while ((sizeLimit != 0) && (file.get(c))) { @@ -1272,55 +1271,54 @@ bool cmFileCommand::HandleReadElfCommand(std::vector<std::string> const& args) return false; } - cmCommandArgumentsHelper argHelper; - cmCommandArgumentGroup group; - - cmCAString readArg(&argHelper, "READ_ELF"); - cmCAString fileNameArg(&argHelper, nullptr); + std::string const& fileNameArg = args[1]; - cmCAString rpathArg(&argHelper, "RPATH", &group); - cmCAString runpathArg(&argHelper, "RUNPATH", &group); - cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group); + struct Arguments + { + std::string RPath; + std::string RunPath; + std::string Error; + }; - readArg.Follows(nullptr); - fileNameArg.Follows(&readArg); - group.Follows(&fileNameArg); - argHelper.Parse(&args, nullptr); + static auto const parser = cmArgumentParser<Arguments>{} + .Bind("RPATH"_s, &Arguments::RPath) + .Bind("RUNPATH"_s, &Arguments::RunPath) + .Bind("CAPTURE_ERROR"_s, &Arguments::Error); + Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2)); - if (!cmSystemTools::FileExists(fileNameArg.GetString(), true)) { + if (!cmSystemTools::FileExists(fileNameArg, true)) { std::ostringstream e; - e << "READ_ELF given FILE \"" << fileNameArg.GetString() - << "\" that does not exist."; + e << "READ_ELF given FILE \"" << fileNameArg << "\" that does not exist."; this->SetError(e.str()); return false; } #if defined(CMAKE_USE_ELF_PARSER) - cmELF elf(fileNameArg.GetCString()); + cmELF elf(fileNameArg.c_str()); - if (!rpathArg.GetString().empty()) { + if (!arguments.RPath.empty()) { if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) { std::string rpath(se_rpath->Value); std::replace(rpath.begin(), rpath.end(), ':', ';'); - this->Makefile->AddDefinition(rpathArg.GetString(), rpath.c_str()); + this->Makefile->AddDefinition(arguments.RPath, rpath.c_str()); } } - if (!runpathArg.GetString().empty()) { + if (!arguments.RunPath.empty()) { if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) { std::string runpath(se_runpath->Value); std::replace(runpath.begin(), runpath.end(), ':', ';'); - this->Makefile->AddDefinition(runpathArg.GetString(), runpath.c_str()); + this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str()); } } return true; #else std::string error = "ELF parser not available on this platform."; - if (errorArg.GetString().empty()) { + if (arguments.Error.empty()) { this->SetError(error); return false; } - this->Makefile->AddDefinition(errorArg.GetString(), error.c_str()); + this->Makefile->AddDefinition(arguments.Error, error.c_str()); return true; #endif } @@ -2597,44 +2595,39 @@ bool cmFileCommand::HandleCreateLinkCommand( return false; } - cmCommandArgumentsHelper argHelper; - cmCommandArgumentGroup group; - - cmCAString linkArg(&argHelper, "CREATE_LINK"); - cmCAString fileArg(&argHelper, nullptr); - cmCAString newFileArg(&argHelper, nullptr); + std::string const& fileName = args[1]; + std::string const& newFileName = args[2]; - cmCAString resultArg(&argHelper, "RESULT", &group); - cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group); - cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group); + struct Arguments + { + std::string Result; + bool CopyOnError = false; + bool Symbolic = false; + }; - linkArg.Follows(nullptr); - fileArg.Follows(&linkArg); - newFileArg.Follows(&fileArg); - group.Follows(&newFileArg); + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("RESULT"_s, &Arguments::Result) + .Bind("COPY_ON_ERROR"_s, &Arguments::CopyOnError) + .Bind("SYMBOLIC"_s, &Arguments::Symbolic); std::vector<std::string> unconsumedArgs; - argHelper.Parse(&args, &unconsumedArgs); + Arguments const arguments = + parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs); if (!unconsumedArgs.empty()) { this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"'); return false; } - std::string fileName = fileArg.GetString(); - std::string newFileName = newFileArg.GetString(); - - // Output variable for storing the result. - const std::string& resultVar = resultArg.GetString(); - // The system error message generated in the operation. std::string result; // Check if the paths are distinct. if (fileName == newFileName) { result = "CREATE_LINK cannot use same file and newfile"; - if (!resultVar.empty()) { - this->Makefile->AddDefinition(resultVar, result.c_str()); + if (!arguments.Result.empty()) { + this->Makefile->AddDefinition(arguments.Result, result.c_str()); return true; } this->SetError(result); @@ -2642,10 +2635,10 @@ bool cmFileCommand::HandleCreateLinkCommand( } // Hard link requires original file to exist. - if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) { + if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) { result = "Cannot hard link \'" + fileName + "\' as it does not exist."; - if (!resultVar.empty()) { - this->Makefile->AddDefinition(resultVar, result.c_str()); + if (!arguments.Result.empty()) { + this->Makefile->AddDefinition(arguments.Result, result.c_str()); return true; } this->SetError(result); @@ -2661,8 +2654,8 @@ bool cmFileCommand::HandleCreateLinkCommand( << "' because existing path cannot be removed: " << cmSystemTools::GetLastSystemError() << "\n"; - if (!resultVar.empty()) { - this->Makefile->AddDefinition(resultVar, e.str().c_str()); + if (!arguments.Result.empty()) { + this->Makefile->AddDefinition(arguments.Result, e.str().c_str()); return true; } this->SetError(e.str()); @@ -2673,14 +2666,14 @@ bool cmFileCommand::HandleCreateLinkCommand( bool completed = false; // Check if the command requires a symbolic link. - if (symbolicArg.IsEnabled()) { + if (arguments.Symbolic) { completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result); } else { completed = cmSystemTools::CreateLink(fileName, newFileName, &result); } // Check if copy-on-error is enabled in the arguments. - if (!completed && copyOnErrorArg.IsEnabled()) { + if (!completed && arguments.CopyOnError) { completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName); if (!completed) { result = "Copy failed: " + cmSystemTools::GetLastSystemError(); @@ -2690,14 +2683,14 @@ bool cmFileCommand::HandleCreateLinkCommand( // Check if the operation was successful. if (completed) { result = "0"; - } else if (resultVar.empty()) { + } else if (arguments.Result.empty()) { // The operation failed and the result is not reported in a variable. this->SetError(result); return false; } - if (!resultVar.empty()) { - this->Makefile->AddDefinition(resultVar, result.c_str()); + if (!arguments.Result.empty()) { + this->Makefile->AddDefinition(arguments.Result, result.c_str()); } return true; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index cef36fc..af409e4 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -28,6 +28,7 @@ #include <algorithm> #include <assert.h> #include <errno.h> +#include <iterator> #include <map> #include <memory> // IWYU pragma: keep #include <set> @@ -327,6 +328,51 @@ static const struct InListNode : public cmGeneratorExpressionNode } } inListNode; +static const struct FilterNode : public cmGeneratorExpressionNode +{ + FilterNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 3; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 3) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> expression requires three parameters"); + return {}; + } + + if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") { + reportError( + context, content->GetOriginalExpression(), + "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE"); + return {}; + } + + const bool exclude = parameters[1] == "EXCLUDE"; + + cmsys::RegularExpression re; + if (!re.compile(parameters[2])) { + reportError(context, content->GetOriginalExpression(), + "$<FILTER:...> failed to compile regex"); + return {}; + } + + std::vector<std::string> values, result; + cmSystemTools::ExpandListArgument(parameters.front(), values, true); + + std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result), + [&re, exclude](std::string const& input) { + return exclude ^ re.find(input); + }); + return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";"); + } +} filterNode; + static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode { RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default) @@ -2251,6 +2297,119 @@ static const TargetOutputNameArtifact<ArtifactLinkerTag> static const TargetOutputNameArtifact<ArtifactPdbTag> targetPdbOutputNameNode; +class ArtifactFilePrefixTag; +class ArtifactLinkerFilePrefixTag; +class ArtifactFileSuffixTag; +class ArtifactLinkerFileSuffixTag; + +template <typename ArtifactT> +struct TargetFileArtifactResultGetter +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content); +}; + +template <> +struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + return target->GetFilePrefix(context->Config); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_PREFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + cmStateEnums::ArtifactType artifact = + target->HasImportLibrary(context->Config) + ? cmStateEnums::ImportLibraryArtifact + : cmStateEnums::RuntimeBinaryArtifact; + + return target->GetFilePrefix(context->Config, artifact); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent*) + { + return target->GetFileSuffix(context->Config); + } +}; +template <> +struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag> +{ + static std::string Get(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (!target->IsLinkable()) { + ::reportError(context, content->GetOriginalExpression(), + "TARGET_LINKER_SUFFIX is allowed only for libraries and " + "executables with ENABLE_EXPORTS."); + return std::string(); + } + + cmStateEnums::ArtifactType artifact = + target->HasImportLibrary(context->Config) + ? cmStateEnums::ImportLibraryArtifact + : cmStateEnums::RuntimeBinaryArtifact; + + return target->GetFileSuffix(context->Config, artifact); + } +}; + +template <typename ArtifactT> +struct TargetFileArtifact : public TargetArtifactBase +{ + TargetFileArtifact() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + cmGeneratorTarget* target = + this->GetTarget(parameters, context, content, dagChecker); + if (!target) { + return std::string(); + } + + std::string result = + TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content); + if (context->HadError) { + return std::string(); + } + return result; + } +}; + +static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode; +static const TargetFileArtifact<ArtifactLinkerFilePrefixTag> + targetLinkerFilePrefixNode; +static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode; +static const TargetFileArtifact<ArtifactLinkerFileSuffixTag> + targetLinkerFileSuffixNode; + static const struct ShellPathNode : public cmGeneratorExpressionNode { ShellPathNode() {} // NOLINT(modernize-use-equals-default) @@ -2315,6 +2474,10 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File }, { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File }, { "TARGET_PDB_FILE", &targetPdbNodeGroup.File }, + { "TARGET_FILE_PREFIX", &targetFilePrefixNode }, + { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode }, + { "TARGET_FILE_SUFFIX", &targetFileSuffixNode }, + { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode }, { "TARGET_FILE_NAME", &targetNodeGroup.FileName }, { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName }, { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName }, @@ -2331,6 +2494,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "STREQUAL", &strEqualNode }, { "EQUAL", &equalNode }, { "IN_LIST", &inListNode }, + { "FILTER", &filterNode }, { "REMOVE_DUPLICATES", &removeDuplicatesNode }, { "LOWER_CASE", &lowerCaseNode }, { "UPPER_CASE", &upperCaseNode }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f8c16cc..3fb95bf 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -464,6 +464,134 @@ std::string cmGeneratorTarget::GetOutputName( return i->second; } +std::string cmGeneratorTarget::GetFilePrefix( + const std::string& config, cmStateEnums::ArtifactType artifact) const +{ + if (this->IsImported()) { + const char* prefix = this->GetFilePrefixInternal(artifact); + + return prefix ? prefix : std::string(); + } + + std::string prefix, suffix, base; + this->GetFullNameInternal(config, artifact, prefix, base, suffix); + return prefix; +} +std::string cmGeneratorTarget::GetFileSuffix( + const std::string& config, cmStateEnums::ArtifactType artifact) const +{ + if (this->IsImported()) { + const char* suffix = this->GetFileSuffixInternal(artifact); + + return suffix ? suffix : std::string(); + } + + std::string prefix, suffix, base; + this->GetFullNameInternal(config, artifact, prefix, base, suffix); + return suffix; +} + +const char* cmGeneratorTarget::GetFilePrefixInternal( + cmStateEnums::ArtifactType artifact, const std::string& language) const +{ + // no prefix for non-main target types. + if (this->GetType() != cmStateEnums::STATIC_LIBRARY && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GetType() != cmStateEnums::EXECUTABLE) { + return nullptr; + } + + const bool isImportedLibraryArtifact = + (artifact == cmStateEnums::ImportLibraryArtifact); + + // Return an empty prefix for the import library if this platform + // does not support import libraries. + if (isImportedLibraryArtifact && + !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { + return nullptr; + } + + // The implib option is only allowed for shared libraries, module + // libraries, and executables. + if (this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GetType() != cmStateEnums::EXECUTABLE) { + artifact = cmStateEnums::RuntimeBinaryArtifact; + } + + // Compute prefix value. + const char* targetPrefix = + (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX") + : this->GetProperty("PREFIX")); + + if (!targetPrefix) { + const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact); + if (!language.empty() && prefixVar && *prefixVar) { + std::string langPrefix = prefixVar + std::string("_") + language; + targetPrefix = this->Makefile->GetDefinition(langPrefix); + } + + // if there is no prefix on the target nor specific language + // use the cmake definition. + if (!targetPrefix && prefixVar) { + targetPrefix = this->Makefile->GetDefinition(prefixVar); + } + } + + return targetPrefix; +} +const char* cmGeneratorTarget::GetFileSuffixInternal( + cmStateEnums::ArtifactType artifact, const std::string& language) const +{ + // no suffix for non-main target types. + if (this->GetType() != cmStateEnums::STATIC_LIBRARY && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GetType() != cmStateEnums::EXECUTABLE) { + return nullptr; + } + + const bool isImportedLibraryArtifact = + (artifact == cmStateEnums::ImportLibraryArtifact); + + // Return an empty suffix for the import library if this platform + // does not support import libraries. + if (isImportedLibraryArtifact && + !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) { + return nullptr; + } + + // The implib option is only allowed for shared libraries, module + // libraries, and executables. + if (this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GetType() != cmStateEnums::EXECUTABLE) { + artifact = cmStateEnums::RuntimeBinaryArtifact; + } + + // Compute suffix value. + const char* targetSuffix = + (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX") + : this->GetProperty("SUFFIX")); + + if (!targetSuffix) { + const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact); + if (!language.empty() && suffixVar && *suffixVar) { + std::string langSuffix = suffixVar + std::string("_") + language; + targetSuffix = this->Makefile->GetDefinition(langSuffix); + } + + // if there is no suffix on the target nor specific language + // use the cmake definition. + if (!targetSuffix && suffixVar) { + targetSuffix = this->Makefile->GetDefinition(suffixVar); + } + } + + return targetSuffix; +} + void cmGeneratorTarget::ClearSourcesCache() { this->KindedSourcesMap.clear(); @@ -3788,6 +3916,11 @@ void cmGeneratorTarget::GetFullNameInternal( return; } + // retrieve prefix and suffix + std::string ll = this->GetLinkerLanguage(config); + const char* targetPrefix = this->GetFilePrefixInternal(artifact, ll); + const char* targetSuffix = this->GetFileSuffixInternal(artifact, ll); + // The implib option is only allowed for shared libraries, module // libraries, and executables. if (this->GetType() != cmStateEnums::SHARED_LIBRARY && @@ -3797,12 +3930,6 @@ void cmGeneratorTarget::GetFullNameInternal( } // Compute the full name for main target types. - const char* targetPrefix = - (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX") - : this->GetProperty("PREFIX")); - const char* targetSuffix = - (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX") - : this->GetProperty("SUFFIX")); const char* configPostfix = nullptr; if (!config.empty()) { std::string configProp = cmSystemTools::UpperCase(config); @@ -3814,30 +3941,6 @@ void cmGeneratorTarget::GetFullNameInternal( configPostfix = nullptr; } } - const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact); - const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact); - - // Check for language-specific default prefix and suffix. - std::string ll = this->GetLinkerLanguage(config); - if (!ll.empty()) { - if (!targetSuffix && suffixVar && *suffixVar) { - std::string langSuff = suffixVar + std::string("_") + ll; - targetSuffix = this->Makefile->GetDefinition(langSuff); - } - if (!targetPrefix && prefixVar && *prefixVar) { - std::string langPrefix = prefixVar + std::string("_") + ll; - targetPrefix = this->Makefile->GetDefinition(langPrefix); - } - } - - // if there is no prefix on the target use the cmake definition - if (!targetPrefix && prefixVar) { - targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str(); - } - // if there is no suffix on the target use the cmake definition - if (!targetSuffix && suffixVar) { - targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str(); - } // frameworks have directory prefix but no suffix std::string fw_prefix; diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 065b457..81f5255 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -534,6 +534,15 @@ public: std::string GetOutputName(const std::string& config, cmStateEnums::ArtifactType artifact) const; + /** Get target file prefix */ + std::string GetFilePrefix(const std::string& config, + cmStateEnums::ArtifactType artifact = + cmStateEnums::RuntimeBinaryArtifact) const; + /** Get target file prefix */ + std::string GetFileSuffix(const std::string& config, + cmStateEnums::ArtifactType artifact = + cmStateEnums::RuntimeBinaryArtifact) const; + /** Clears cached meta data for local and external source files. * The meta data will be recomputed on demand. */ @@ -728,6 +737,11 @@ private: mutable std::map<std::string, bool> DebugCompatiblePropertiesDone; + const char* GetFilePrefixInternal(cmStateEnums::ArtifactType artifact, + const std::string& language = "") const; + const char* GetFileSuffixInternal(cmStateEnums::ArtifactType artifact, + const std::string& language = "") const; + std::string GetFullNameInternal(const std::string& config, cmStateEnums::ArtifactType artifact) const; void GetFullNameInternal(const std::string& config, diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 2fc6121..db673bb 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1146,6 +1146,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( // Add CMakeLists.txt file for user convenience. this->AddXCodeProjBuildRule(gtgt, classes); + // Add the Info.plist we are about to generate for an App Bundle. + if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { + std::string plist = this->ComputeInfoPListLocation(gtgt); + cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(plist, true); + classes.push_back(sf); + } + std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare()); gtgt->ComputeObjectMapping(); @@ -2862,13 +2869,13 @@ bool cmGlobalXCodeGenerator::CreateGroups( continue; } - // add the soon to be generated Info.plist file as a source for a - // MACOSX_BUNDLE file - if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { - std::string plist = this->ComputeInfoPListLocation(gtgt); - mf->GetOrCreateSource(plist, true); - gtgt->AddSource(plist); - } + auto addSourceToGroup = [this, mf, gtgt, + &sourceGroups](std::string const& source) { + cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); + cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup); + std::string key = GetGroupMapKeyFromPath(gtgt, source); + this->GroupMap[key] = pbxgroup; + }; // Put cmSourceFile instances in proper groups: for (auto const& si : gtgt->GetAllConfigSources()) { @@ -2877,12 +2884,7 @@ bool cmGlobalXCodeGenerator::CreateGroups( // Object library files go on the link line instead. continue; } - // Add the file to the list of sources. - std::string const& source = sf->GetFullPath(); - cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); - cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup); - std::string key = GetGroupMapKeyFromPath(gtgt, source); - this->GroupMap[key] = pbxgroup; + addSourceToGroup(sf->GetFullPath()); } // Add CMakeLists.txt file for user convenience. @@ -2891,11 +2893,14 @@ bool cmGlobalXCodeGenerator::CreateGroups( gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(); listfile += "/CMakeLists.txt"; cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(listfile); - std::string const& source = sf->GetFullPath(); - cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); - cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup); - std::string key = GetGroupMapKeyFromPath(gtgt, source); - this->GroupMap[key] = pbxgroup; + addSourceToGroup(sf->GetFullPath()); + } + + // Add the Info.plist we are about to generate for an App Bundle. + if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { + std::string plist = this->ComputeInfoPListLocation(gtgt); + cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(plist, true); + addSourceToGroup(sf->GetFullPath()); } } } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 20d1a31..dba4bbb 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallCommand.h" +#include "cm_static_string_view.hxx" #include "cmsys/Glob.hxx" #include <set> #include <sstream> @@ -9,7 +10,7 @@ #include <utility> #include "cmAlgorithms.h" -#include "cmCommandArgumentsHelper.h" +#include "cmArgumentParser.h" #include "cmExportSet.h" #include "cmExportSetMap.h" #include "cmGeneratorExpression.h" @@ -219,49 +220,51 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args) return true; } -/*struct InstallPart -{ - InstallPart(cmCommandArgumentsHelper* helper, const char* key, - cmCommandArgumentGroup* group); - cmCAStringVector argVector; - cmInstallCommandArguments args; -};*/ - bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) { // This is the TARGETS mode. std::vector<cmTarget*> targets; - cmCommandArgumentsHelper argHelper; - cmCommandArgumentGroup group; - cmCAStringVector genericArgVector(&argHelper, nullptr); - cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group); - cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group); - cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group); - cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group); - cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group); - cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group); - cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group); - cmCAStringVector privateHeaderArgVector(&argHelper, "PRIVATE_HEADER", - &group); - cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group); - cmCAStringVector resourceArgVector(&argHelper, "RESOURCE", &group); - genericArgVector.Follows(nullptr); - group.Follows(&genericArgVector); - - argHelper.Parse(&args, nullptr); + struct ArgVectors + { + std::vector<std::string> Archive; + std::vector<std::string> Library; + std::vector<std::string> Runtime; + std::vector<std::string> Object; + std::vector<std::string> Framework; + std::vector<std::string> Bundle; + std::vector<std::string> Includes; + std::vector<std::string> PrivateHeader; + std::vector<std::string> PublicHeader; + std::vector<std::string> Resource; + }; + + static auto const argHelper = + cmArgumentParser<ArgVectors>{} + .Bind("ARCHIVE"_s, &ArgVectors::Archive) + .Bind("LIBRARY"_s, &ArgVectors::Library) + .Bind("RUNTIME"_s, &ArgVectors::Runtime) + .Bind("OBJECTS"_s, &ArgVectors::Object) + .Bind("FRAMEWORK"_s, &ArgVectors::Framework) + .Bind("BUNDLE"_s, &ArgVectors::Bundle) + .Bind("INCLUDES"_s, &ArgVectors::Includes) + .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader) + .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader) + .Bind("RESOURCE"_s, &ArgVectors::Resource); + + std::vector<std::string> genericArgVector; + ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector); // now parse the generic args (i.e. the ones not specialized on LIBRARY/ // ARCHIVE, RUNTIME etc. (see above) // These generic args also contain the targets and the export stuff + std::vector<std::string> targetList; + std::string exports; std::vector<std::string> unknownArgs; cmInstallCommandArguments genericArgs(this->DefaultComponentName); - cmCAStringVector targetList(&genericArgs.Parser, "TARGETS"); - cmCAString exports(&genericArgs.Parser, "EXPORT", - &genericArgs.ArgumentGroup); - targetList.Follows(nullptr); - genericArgs.ArgumentGroup.Follows(&targetList); - genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs); + genericArgs.Bind("TARGETS"_s, targetList); + genericArgs.Bind("EXPORT"_s, exports); + genericArgs.Parse(genericArgVector, &unknownArgs); bool success = genericArgs.Finalize(); cmInstallCommandArguments archiveArgs(this->DefaultComponentName); @@ -277,16 +280,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // now parse the args for specific parts of the target (e.g. LIBRARY, // RUNTIME, ARCHIVE etc. - archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs); - libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs); - runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs); - objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs); - frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs); - bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs); - privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs); - publicHeaderArgs.Parse(&publicHeaderArgVector.GetVector(), &unknownArgs); - resourceArgs.Parse(&resourceArgVector.GetVector(), &unknownArgs); - includesArgs.Parse(&includesArgVector.GetVector(), &unknownArgs); + archiveArgs.Parse(argVectors.Archive, &unknownArgs); + libraryArgs.Parse(argVectors.Library, &unknownArgs); + runtimeArgs.Parse(argVectors.Runtime, &unknownArgs); + objectArgs.Parse(argVectors.Object, &unknownArgs); + frameworkArgs.Parse(argVectors.Framework, &unknownArgs); + bundleArgs.Parse(argVectors.Bundle, &unknownArgs); + privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs); + publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs); + resourceArgs.Parse(argVectors.Resource, &unknownArgs); + includesArgs.Parse(&argVectors.Includes, &unknownArgs); if (!unknownArgs.empty()) { // Unknown argument. @@ -382,7 +385,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } // Check if there is something to do. - if (targetList.GetVector().empty()) { + if (targetList.empty()) { return true; } @@ -390,7 +393,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) bool dll_platform = !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); - for (std::string const& tgt : targetList.GetVector()) { + for (std::string const& tgt : targetList) { if (this->Makefile->IsAlias(tgt)) { std::ostringstream e; @@ -663,8 +666,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // generators for them. bool createInstallGeneratorsForTargetFileSets = true; - if (target.IsFrameworkOnApple() || - target.GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (target.IsFrameworkOnApple()) { createInstallGeneratorsForTargetFileSets = false; } @@ -748,7 +750,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Add this install rule to an export if one was specified and // this is not a namelink-only rule. - if (!exports.GetString().empty() && !namelinkOnly) { + if (!exports.empty() && !namelinkOnly) { cmTargetExport* te = new cmTargetExport; te->TargetName = target.GetName(); te->ArchiveGenerator = archiveGenerator; @@ -759,7 +761,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) te->RuntimeGenerator = runtimeGenerator; te->ObjectsGenerator = objectGenerator; this->Makefile->GetGlobalGenerator() - ->GetExportSets()[exports.GetString()] + ->GetExportSets()[exports] ->AddTargetExport(te); te->InterfaceIncludeDirectories = @@ -818,11 +820,10 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) // This is the FILES mode. bool programs = (args[0] == "PROGRAMS"); cmInstallCommandArguments ica(this->DefaultComponentName); - cmCAStringVector files(&ica.Parser, programs ? "PROGRAMS" : "FILES"); - files.Follows(nullptr); - ica.ArgumentGroup.Follows(&files); + std::vector<std::string> files; + ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files); std::vector<std::string> unknownArgs; - ica.Parse(&args, &unknownArgs); + ica.Parse(args, &unknownArgs); if (!unknownArgs.empty()) { // Unknown argument. @@ -840,7 +841,7 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) return false; } - const std::vector<std::string>& filesVector = files.GetVector(); + const std::vector<std::string>& filesVector = files; // Check if there is something to do. if (filesVector.empty()) { @@ -1271,16 +1272,19 @@ bool cmInstallCommand::HandleExportAndroidMKMode( #ifdef CMAKE_BUILD_WITH_CMAKE // This is the EXPORT mode. cmInstallCommandArguments ica(this->DefaultComponentName); - cmCAString exp(&ica.Parser, "EXPORT_ANDROID_MK"); - cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup); - cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES", - &ica.ArgumentGroup); - cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup); - exp.Follows(nullptr); - - ica.ArgumentGroup.Follows(&exp); + + std::string exp; + std::string name_space; + bool exportOld = false; + std::string filename; + + ica.Bind("EXPORT_ANDROID_MK"_s, exp); + ica.Bind("NAMESPACE"_s, name_space); + ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld); + ica.Bind("FILE"_s, filename); + std::vector<std::string> unknownArgs; - ica.Parse(&args, &unknownArgs); + ica.Parse(args, &unknownArgs); if (!unknownArgs.empty()) { // Unknown argument. @@ -1304,7 +1308,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode( } // Check the file name. - std::string fname = filename.GetString(); + std::string fname = filename; if (fname.find_first_of(":/\\") != std::string::npos) { std::ostringstream e; e << args[0] << " given invalid export file name \"" << fname << "\". " @@ -1325,7 +1329,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode( } if (fname.find_first_of(":/\\") != std::string::npos) { std::ostringstream e; - e << args[0] << " given export name \"" << exp.GetString() << "\". " + e << args[0] << " given export name \"" << exp << "\". " << "This name cannot be safely converted to a file name. " << "Specify a different export name or use the FILE option to set " << "a file name explicitly."; @@ -1338,7 +1342,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode( } cmExportSet* exportSet = - this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()]; + this->Makefile->GetGlobalGenerator()->GetExportSets()[exp]; cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(this->Makefile); @@ -1347,8 +1351,8 @@ bool cmInstallCommand::HandleExportAndroidMKMode( cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), message, - ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(), - exportOld.IsEnabled(), true); + ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld, + true); this->Makefile->AddInstallGenerator(exportGenerator); return true; @@ -1363,16 +1367,19 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) { // This is the EXPORT mode. cmInstallCommandArguments ica(this->DefaultComponentName); - cmCAString exp(&ica.Parser, "EXPORT"); - cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup); - cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES", - &ica.ArgumentGroup); - cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup); - exp.Follows(nullptr); - - ica.ArgumentGroup.Follows(&exp); + + std::string exp; + std::string name_space; + bool exportOld = false; + std::string filename; + + ica.Bind("EXPORT"_s, exp); + ica.Bind("NAMESPACE"_s, name_space); + ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld); + ica.Bind("FILE"_s, filename); + std::vector<std::string> unknownArgs; - ica.Parse(&args, &unknownArgs); + ica.Parse(args, &unknownArgs); if (!unknownArgs.empty()) { // Unknown argument. @@ -1396,7 +1403,7 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) } // Check the file name. - std::string fname = filename.GetString(); + std::string fname = filename; if (fname.find_first_of(":/\\") != std::string::npos) { std::ostringstream e; e << args[0] << " given invalid export file name \"" << fname << "\". " @@ -1418,12 +1425,12 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) // Construct the file name. if (fname.empty()) { - fname = exp.GetString(); + fname = exp; fname += ".cmake"; if (fname.find_first_of(":/\\") != std::string::npos) { std::ostringstream e; - e << args[0] << " given export name \"" << exp.GetString() << "\". " + e << args[0] << " given export name \"" << exp << "\". " << "This name cannot be safely converted to a file name. " << "Specify a different export name or use the FILE option to set " << "a file name explicitly."; @@ -1433,8 +1440,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) } cmExportSet* exportSet = - this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()]; - if (exportOld.IsEnabled()) { + this->Makefile->GetGlobalGenerator()->GetExportSets()[exp]; + if (exportOld) { for (cmTargetExport* te : *exportSet->GetTargetExports()) { cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(te->TargetName); @@ -1461,8 +1468,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), message, - ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(), - exportOld.IsEnabled(), false); + ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld, + false); this->Makefile->AddInstallGenerator(exportGenerator); return true; diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index c64bd8a..8b33782 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -4,6 +4,7 @@ #include "cmRange.h" #include "cmSystemTools.h" +#include "cm_static_string_view.hxx" #include <utility> @@ -18,20 +19,19 @@ const std::string cmInstallCommandArguments::EmptyString; cmInstallCommandArguments::cmInstallCommandArguments( std::string defaultComponent) - : Destination(&Parser, "DESTINATION", &ArgumentGroup) - , Component(&Parser, "COMPONENT", &ArgumentGroup) - , NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup) - , ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup) - , Rename(&Parser, "RENAME", &ArgumentGroup) - , Permissions(&Parser, "PERMISSIONS", &ArgumentGroup) - , Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup) - , Optional(&Parser, "OPTIONAL", &ArgumentGroup) - , NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup) - , NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup) - , Type(&Parser, "TYPE", &ArgumentGroup) - , GenericArguments(nullptr) - , DefaultComponentName(std::move(defaultComponent)) + : DefaultComponentName(std::move(defaultComponent)) { + this->Bind("DESTINATION"_s, this->Destination); + this->Bind("COMPONENT"_s, this->Component); + this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent); + this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll); + this->Bind("RENAME"_s, this->Rename); + this->Bind("PERMISSIONS"_s, this->Permissions); + this->Bind("CONFIGURATIONS"_s, this->Configurations); + this->Bind("OPTIONAL"_s, this->Optional); + this->Bind("NAMELINK_ONLY"_s, this->NamelinkOnly); + this->Bind("NAMELINK_SKIP"_s, this->NamelinkSkip); + this->Bind("TYPE"_s, this->Type); } const std::string& cmInstallCommandArguments::GetDestination() const @@ -47,8 +47,8 @@ const std::string& cmInstallCommandArguments::GetDestination() const const std::string& cmInstallCommandArguments::GetComponent() const { - if (!this->Component.GetString().empty()) { - return this->Component.GetString(); + if (!this->Component.empty()) { + return this->Component; } if (this->GenericArguments != nullptr) { return this->GenericArguments->GetComponent(); @@ -62,16 +62,16 @@ const std::string& cmInstallCommandArguments::GetComponent() const const std::string& cmInstallCommandArguments::GetNamelinkComponent() const { - if (!this->NamelinkComponent.GetString().empty()) { - return this->NamelinkComponent.GetString(); + if (!this->NamelinkComponent.empty()) { + return this->NamelinkComponent; } return this->GetComponent(); } const std::string& cmInstallCommandArguments::GetRename() const { - if (!this->Rename.GetString().empty()) { - return this->Rename.GetString(); + if (!this->Rename.empty()) { + return this->Rename; } if (this->GenericArguments != nullptr) { return this->GenericArguments->GetRename(); @@ -92,7 +92,7 @@ const std::string& cmInstallCommandArguments::GetPermissions() const bool cmInstallCommandArguments::GetOptional() const { - if (this->Optional.IsEnabled()) { + if (this->Optional) { return true; } if (this->GenericArguments != nullptr) { @@ -103,7 +103,7 @@ bool cmInstallCommandArguments::GetOptional() const bool cmInstallCommandArguments::GetExcludeFromAll() const { - if (this->ExcludeFromAll.IsEnabled()) { + if (this->ExcludeFromAll) { return true; } if (this->GenericArguments != nullptr) { @@ -114,7 +114,7 @@ bool cmInstallCommandArguments::GetExcludeFromAll() const bool cmInstallCommandArguments::GetNamelinkOnly() const { - if (this->NamelinkOnly.IsEnabled()) { + if (this->NamelinkOnly) { return true; } if (this->GenericArguments != nullptr) { @@ -125,7 +125,7 @@ bool cmInstallCommandArguments::GetNamelinkOnly() const bool cmInstallCommandArguments::GetNamelinkSkip() const { - if (this->NamelinkSkip.IsEnabled()) { + if (this->NamelinkSkip) { return true; } if (this->GenericArguments != nullptr) { @@ -136,7 +136,7 @@ bool cmInstallCommandArguments::GetNamelinkSkip() const bool cmInstallCommandArguments::HasNamelinkComponent() const { - if (!this->NamelinkComponent.GetString().empty()) { + if (!this->NamelinkComponent.empty()) { return true; } if (this->GenericArguments != nullptr) { @@ -147,19 +147,19 @@ bool cmInstallCommandArguments::HasNamelinkComponent() const const std::string& cmInstallCommandArguments::GetType() const { - return this->Type.GetString(); + return this->Type; } const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations() const { - if (!this->Configurations.GetVector().empty()) { - return this->Configurations.GetVector(); + if (!this->Configurations.empty()) { + return this->Configurations; } if (this->GenericArguments != nullptr) { return this->GenericArguments->GetConfigurations(); } - return this->Configurations.GetVector(); + return this->Configurations; } bool cmInstallCommandArguments::Finalize() @@ -167,21 +167,15 @@ bool cmInstallCommandArguments::Finalize() if (!this->CheckPermissions()) { return false; } - this->DestinationString = this->Destination.GetString(); + this->DestinationString = this->Destination; cmSystemTools::ConvertToUnixSlashes(this->DestinationString); return true; } -void cmInstallCommandArguments::Parse(const std::vector<std::string>* args, - std::vector<std::string>* unconsumedArgs) -{ - this->Parser.Parse(args, unconsumedArgs); -} - bool cmInstallCommandArguments::CheckPermissions() { this->PermissionsString.clear(); - for (std::string const& perm : this->Permissions.GetVector()) { + for (std::string const& perm : this->Permissions) { if (!cmInstallCommandArguments::CheckPermissions( perm, this->PermissionsString)) { return false; diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 9c0d417..5d2ee0a 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -8,9 +8,9 @@ #include <string> #include <vector> -#include "cmCommandArgumentsHelper.h" +#include "cmArgumentParser.h" -class cmInstallCommandArguments +class cmInstallCommandArguments : public cmArgumentParser<void> { public: cmInstallCommandArguments(std::string defaultComponent); @@ -18,8 +18,6 @@ public: { this->GenericArguments = args; } - void Parse(const std::vector<std::string>* args, - std::vector<std::string>* unconsumedArgs); // Compute destination path.and check permissions bool Finalize(); @@ -37,30 +35,25 @@ public: bool HasNamelinkComponent() const; const std::string& GetType() const; - // once HandleDirectoryMode() is also switched to using - // cmInstallCommandArguments then these two functions can become non-static - // private member functions without arguments static bool CheckPermissions(const std::string& onePerm, std::string& perm); - cmCommandArgumentsHelper Parser; - cmCommandArgumentGroup ArgumentGroup; private: - cmCAString Destination; - cmCAString Component; - cmCAString NamelinkComponent; - cmCAEnabler ExcludeFromAll; - cmCAString Rename; - cmCAStringVector Permissions; - cmCAStringVector Configurations; - cmCAEnabler Optional; - cmCAEnabler NamelinkOnly; - cmCAEnabler NamelinkSkip; - cmCAString Type; + std::string Destination; + std::string Component; + std::string NamelinkComponent; + bool ExcludeFromAll = false; + std::string Rename; + std::vector<std::string> Permissions; + std::vector<std::string> Configurations; + bool Optional = false; + bool NamelinkOnly = false; + bool NamelinkSkip = false; + std::string Type; std::string DestinationString; std::string PermissionsString; - cmInstallCommandArguments* GenericArguments; + cmInstallCommandArguments* GenericArguments = nullptr; static const char* PermissionsTable[]; static const std::string EmptyString; std::string DefaultComponentName; diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index ab8d103..5213432 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -8,10 +8,12 @@ #include <utility> #include "cmAlgorithms.h" +#include "cmArgumentParser.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" #include "cmSystemTools.h" +#include "cm_string_view.hxx" class cmExecutionStatus; @@ -28,42 +30,43 @@ static std::string EscapeArg(const std::string& arg) return escapedArg; } -namespace { -enum insideValues +static std::string JoinList(std::vector<std::string> const& arg, bool escape) { - NONE, - SINGLE, - MULTI -}; + return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";") + : cmJoin(cmMakeRange(arg), ";"); +} + +namespace { typedef std::map<std::string, bool> options_map; typedef std::map<std::string, std::string> single_map; typedef std::map<std::string, std::vector<std::string>> multi_map; typedef std::set<std::string> options_set; -} -// function to be called every time, a new key word was parsed or all -// parameters where parsed. -static void DetectKeywordsMissingValues(insideValues currentState, - const std::string& currentArgName, - int& argumentsFound, - options_set& keywordsMissingValues) +struct UserArgumentParser : public cmArgumentParser<void> { - if (currentState == SINGLE || - (currentState == MULTI && argumentsFound == 0)) { - keywordsMissingValues.insert(currentArgName); + template <typename T, typename H> + void Bind(std::vector<std::string> const& names, + std::map<std::string, T>& ref, H duplicateKey) + { + for (std::string const& key : names) { + auto const it = ref.emplace(key, T{}).first; + bool const inserted = this->cmArgumentParser<void>::Bind( + cm::string_view(it->first), it->second); + if (!inserted) { + duplicateKey(key); + } + } } +}; - argumentsFound = 0; -} +} // namespace -static void PassParsedArguments(const std::string& prefix, - cmMakefile& makefile, - const options_map& options, - const single_map& singleValArgs, - const multi_map& multiValArgs, - const std::vector<std::string>& unparsed, - const options_set& keywordsMissingValues) +static void PassParsedArguments( + const std::string& prefix, cmMakefile& makefile, const options_map& options, + const single_map& singleValArgs, const multi_map& multiValArgs, + const std::vector<std::string>& unparsed, + const options_set& keywordsMissingValues, bool parseFromArgV) { for (auto const& iter : options) { makefile.AddDefinition(prefix + iter.first, @@ -81,7 +84,7 @@ static void PassParsedArguments(const std::string& prefix, for (auto const& iter : multiValArgs) { if (!iter.second.empty()) { makefile.AddDefinition(prefix + iter.first, - cmJoin(cmMakeRange(iter.second), ";").c_str()); + JoinList(iter.second, parseFromArgV).c_str()); } else { makefile.RemoveDefinition(prefix + iter.first); } @@ -89,7 +92,7 @@ static void PassParsedArguments(const std::string& prefix, if (!unparsed.empty()) { makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS", - cmJoin(cmMakeRange(unparsed), ";").c_str()); + JoinList(unparsed, parseFromArgV).c_str()); } else { makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS"); } @@ -141,6 +144,8 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, // the first argument is the prefix const std::string prefix = (*argIter++) + "_"; + UserArgumentParser parser; + // define the result maps holding key/value pairs for // options, single values and multi values options_map options; @@ -150,45 +155,25 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, // anything else is put into a vector of unparsed strings std::vector<std::string> unparsed; - // remember already defined keywords - std::set<std::string> used_keywords; - const std::string dup_warning = "keyword defined more than once: "; + auto const duplicateKey = [this](std::string const& key) { + this->GetMakefile()->IssueMessage( + MessageType::WARNING, "keyword defined more than once: " + key); + }; // the second argument is a (cmake) list of options without argument std::vector<std::string> list; cmSystemTools::ExpandListArgument(*argIter++, list); - for (std::string const& iter : list) { - if (!used_keywords.insert(iter).second) { - this->GetMakefile()->IssueMessage(MessageType::WARNING, - dup_warning + iter); - } - options[iter]; // default initialize - } + parser.Bind(list, options, duplicateKey); // the third argument is a (cmake) list of single argument options list.clear(); cmSystemTools::ExpandListArgument(*argIter++, list); - for (std::string const& iter : list) { - if (!used_keywords.insert(iter).second) { - this->GetMakefile()->IssueMessage(MessageType::WARNING, - dup_warning + iter); - } - singleValArgs[iter]; // default initialize - } + parser.Bind(list, singleValArgs, duplicateKey); // the fourth argument is a (cmake) list of multi argument options list.clear(); cmSystemTools::ExpandListArgument(*argIter++, list); - for (std::string const& iter : list) { - if (!used_keywords.insert(iter).second) { - this->GetMakefile()->IssueMessage(MessageType::WARNING, - dup_warning + iter); - } - multiValArgs[iter]; // default initialize - } - - insideValues insideValues = NONE; - std::string currentArgName; + parser.Bind(list, multiValArgs, duplicateKey); list.clear(); if (!parseFromArgV) { @@ -223,68 +208,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, } } - options_set keywordsMissingValues; - int multiArgumentsFound = 0; - - // iterate over the arguments list and fill in the values where applicable - for (std::string const& arg : list) { - const options_map::iterator optIter = options.find(arg); - if (optIter != options.end()) { - DetectKeywordsMissingValues(insideValues, currentArgName, - multiArgumentsFound, keywordsMissingValues); - insideValues = NONE; - optIter->second = true; - continue; - } - - const single_map::iterator singleIter = singleValArgs.find(arg); - if (singleIter != singleValArgs.end()) { - DetectKeywordsMissingValues(insideValues, currentArgName, - multiArgumentsFound, keywordsMissingValues); - insideValues = SINGLE; - currentArgName = arg; - continue; - } - - const multi_map::iterator multiIter = multiValArgs.find(arg); - if (multiIter != multiValArgs.end()) { - DetectKeywordsMissingValues(insideValues, currentArgName, - multiArgumentsFound, keywordsMissingValues); - insideValues = MULTI; - currentArgName = arg; - continue; - } - - switch (insideValues) { - case SINGLE: - singleValArgs[currentArgName] = arg; - insideValues = NONE; - break; - case MULTI: - ++multiArgumentsFound; - if (parseFromArgV) { - multiValArgs[currentArgName].push_back(EscapeArg(arg)); - } else { - multiValArgs[currentArgName].push_back(arg); - } - break; - default: - multiArgumentsFound = 0; - - if (parseFromArgV) { - unparsed.push_back(EscapeArg(arg)); - } else { - unparsed.push_back(arg); - } - break; - } - } + std::vector<std::string> keywordsMissingValues; - DetectKeywordsMissingValues(insideValues, currentArgName, - multiArgumentsFound, keywordsMissingValues); + parser.Parse(list, &unparsed, &keywordsMissingValues); - PassParsedArguments(prefix, *this->Makefile, options, singleValArgs, - multiValArgs, unparsed, keywordsMissingValues); + PassParsedArguments( + prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed, + options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()), + parseFromArgV); return true; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index d201061..212608d 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -3023,6 +3023,12 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value) { errno = 0; char* endp; + while (isspace(*str)) { + ++str; + } + if (*str == '-') { + return false; + } *value = strtoul(str, &endp, 10); return (*endp == '\0') && (endp != str) && (errno == 0); } diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index d2c3496..994fcf7 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -67,6 +67,8 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( builtIns.insert("IMPORTED_GLOBAL"); builtIns.insert("MANUALLY_ADDED_DEPENDENCIES"); builtIns.insert("NAME"); + builtIns.insert("PRIVATE_HEADER"); + builtIns.insert("PUBLIC_HEADER"); builtIns.insert("TYPE"); } |