summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt4
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/bills-comments.txt68
-rw-r--r--Source/QtDialog/CMakeSetup.cxx3
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx1
-rw-r--r--Source/cmArgumentParser.cxx93
-rw-r--r--Source/cmArgumentParser.h143
-rw-r--r--Source/cmCommandArgumentsHelper.cxx233
-rw-r--r--Source/cmCommandArgumentsHelper.h194
-rw-r--r--Source/cmExecuteProcessCommand.cxx280
-rw-r--r--Source/cmExportCommand.cxx102
-rw-r--r--Source/cmExportCommand.h24
-rw-r--r--Source/cmFileCommand.cxx155
-rw-r--r--Source/cmGeneratorExpressionNode.cxx164
-rw-r--r--Source/cmGeneratorTarget.cxx163
-rw-r--r--Source/cmGeneratorTarget.h14
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx41
-rw-r--r--Source/cmInstallCommand.cxx175
-rw-r--r--Source/cmInstallCommandArguments.cxx66
-rw-r--r--Source/cmInstallCommandArguments.h35
-rw-r--r--Source/cmParseArgumentsCommand.cxx159
-rw-r--r--Source/cmSystemTools.cxx6
-rw-r--r--Source/cmTargetPropertyComputer.cxx2
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");
}