mirror of
https://github.com/reactos/CMake.git
synced 2025-02-17 18:17:57 +00:00
Merge topic 'argument-parser'
b783e62533 cmExecuteProcessCommand: Port to cmArgumentParser 9bddb03f31 cmParseArgumentsCommand: Port to cmArgumentParser 45edf1ad66 Retire cmCommandArgumentsHelper f5acecaa6f cmExportCommand: Port to cmArgumentParser e6b6bb0618 cmInstallCommand: Port to cmArgumentParser 4336a29edd cmFileCommand: Port to cmArgumentParser 4359fe133b Introduce cmArgumentParser Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Leonid Pospelov <pospelovlm@yandex.ru> Merge-request: !3137
This commit is contained in:
commit
aa0692de67
@ -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
|
||||
|
93
Source/cmArgumentParser.cxx
Normal file
93
Source/cmArgumentParser.cxx
Normal file
@ -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 = (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
|
143
Source/cmArgumentParser.h
Normal file
143
Source/cmArgumentParser.h
Normal file
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
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);
|
||||
static auto const parser = cmArgumentParser<Arguments>{}
|
||||
.Bind("OFFSET"_s, &Arguments::Offset)
|
||||
.Bind("LIMIT"_s, &Arguments::Limit)
|
||||
.Bind("HEX"_s, &Arguments::Hex);
|
||||
|
||||
std::string fileName = fileNameArg.GetString();
|
||||
Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
|
||||
|
||||
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;
|
||||
std::string const& fileNameArg = args[1];
|
||||
|
||||
cmCAString readArg(&argHelper, "READ_ELF");
|
||||
cmCAString fileNameArg(&argHelper, nullptr);
|
||||
struct Arguments
|
||||
{
|
||||
std::string RPath;
|
||||
std::string RunPath;
|
||||
std::string Error;
|
||||
};
|
||||
|
||||
cmCAString rpathArg(&argHelper, "RPATH", &group);
|
||||
cmCAString runpathArg(&argHelper, "RUNPATH", &group);
|
||||
cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group);
|
||||
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));
|
||||
|
||||
readArg.Follows(nullptr);
|
||||
fileNameArg.Follows(&readArg);
|
||||
group.Follows(&fileNameArg);
|
||||
argHelper.Parse(&args, nullptr);
|
||||
|
||||
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;
|
||||
std::string const& fileName = args[1];
|
||||
std::string const& newFileName = args[2];
|
||||
|
||||
cmCAString linkArg(&argHelper, "CREATE_LINK");
|
||||
cmCAString fileArg(&argHelper, nullptr);
|
||||
cmCAString newFileArg(&argHelper, nullptr);
|
||||
struct Arguments
|
||||
{
|
||||
std::string Result;
|
||||
bool CopyOnError = false;
|
||||
bool Symbolic = false;
|
||||
};
|
||||
|
||||
cmCAString resultArg(&argHelper, "RESULT", &group);
|
||||
cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group);
|
||||
cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group);
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
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;
|
||||
};
|
||||
|
||||
argHelper.Parse(&args, nullptr);
|
||||
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;
|
||||
@ -748,7 +751,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 +762,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 +821,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 +842,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 +1273,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 +1309,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 +1330,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 +1343,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 +1352,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 +1368,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 +1404,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 +1426,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 +1441,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 +1469,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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
std::vector<std::string> keywordsMissingValues;
|
||||
|
||||
// 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;
|
||||
}
|
||||
parser.Parse(list, &unparsed, &keywordsMissingValues);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DetectKeywordsMissingValues(insideValues, currentArgName,
|
||||
multiArgumentsFound, 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;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ include_directories(
|
||||
)
|
||||
|
||||
set(CMakeLib_TESTS
|
||||
testArgumentParser.cxx
|
||||
testGeneratedFileStream.cxx
|
||||
testRST.cxx
|
||||
testRange.cxx
|
||||
|
148
Tests/CMakeLib/testArgumentParser.cxx
Normal file
148
Tests/CMakeLib/testArgumentParser.cxx
Normal file
@ -0,0 +1,148 @@
|
||||
/* 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 "cm_static_string_view.hxx"
|
||||
#include "cm_string_view.hxx"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
struct Result
|
||||
{
|
||||
bool Option1 = false;
|
||||
bool Option2 = false;
|
||||
|
||||
std::string String1;
|
||||
std::string String2;
|
||||
|
||||
std::vector<std::string> List1;
|
||||
std::vector<std::string> List2;
|
||||
std::vector<std::string> List3;
|
||||
|
||||
std::vector<std::vector<std::string>> Multi1;
|
||||
std::vector<std::vector<std::string>> Multi2;
|
||||
std::vector<std::vector<std::string>> Multi3;
|
||||
};
|
||||
|
||||
std::initializer_list<cm::string_view> const args = {
|
||||
/* clang-format off */
|
||||
"OPTION_1", // option
|
||||
"STRING_1", // string arg missing value
|
||||
"STRING_2", "foo", "bar", // string arg + unparsed value
|
||||
"LIST_1", // list arg missing values
|
||||
"LIST_2", "foo", "bar", // list arg with 2 elems
|
||||
"LIST_3", "bar", // list arg ...
|
||||
"LIST_3", "foo", // ... with continuation
|
||||
"MULTI_2", // multi list with 0 lists
|
||||
"MULTI_3", "foo", "bar", // multi list with first list with two elems
|
||||
"MULTI_3", "bar", "foo", // multi list with second list with two elems
|
||||
/* clang-format on */
|
||||
};
|
||||
|
||||
bool verifyResult(Result const& result,
|
||||
std::vector<std::string> const& unparsedArguments,
|
||||
std::vector<std::string> const& keywordsMissingValue)
|
||||
{
|
||||
static std::vector<std::string> const foobar = { "foo", "bar" };
|
||||
static std::vector<std::string> const barfoo = { "bar", "foo" };
|
||||
static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
|
||||
|
||||
#define ASSERT_TRUE(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
|
||||
return false; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
ASSERT_TRUE(result.Option1);
|
||||
ASSERT_TRUE(!result.Option2);
|
||||
|
||||
ASSERT_TRUE(result.String1.empty());
|
||||
ASSERT_TRUE(result.String2 == "foo");
|
||||
|
||||
ASSERT_TRUE(result.List1.empty());
|
||||
ASSERT_TRUE(result.List2 == foobar);
|
||||
ASSERT_TRUE(result.List3 == barfoo);
|
||||
|
||||
ASSERT_TRUE(result.Multi1.empty());
|
||||
ASSERT_TRUE(result.Multi2.size() == 1);
|
||||
ASSERT_TRUE(result.Multi2[0].empty());
|
||||
ASSERT_TRUE(result.Multi3.size() == 2);
|
||||
ASSERT_TRUE(result.Multi3[0] == foobar);
|
||||
ASSERT_TRUE(result.Multi3[1] == barfoo);
|
||||
|
||||
ASSERT_TRUE(unparsedArguments.size() == 1);
|
||||
ASSERT_TRUE(unparsedArguments[0] == "bar");
|
||||
ASSERT_TRUE(keywordsMissingValue == missing);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testArgumentParserDynamic()
|
||||
{
|
||||
Result result;
|
||||
std::vector<std::string> unparsedArguments;
|
||||
std::vector<std::string> keywordsMissingValue;
|
||||
|
||||
cmArgumentParser<void>{}
|
||||
.Bind("OPTION_1"_s, result.Option1)
|
||||
.Bind("OPTION_2"_s, result.Option2)
|
||||
.Bind("STRING_1"_s, result.String1)
|
||||
.Bind("STRING_2"_s, result.String2)
|
||||
.Bind("LIST_1"_s, result.List1)
|
||||
.Bind("LIST_2"_s, result.List2)
|
||||
.Bind("LIST_3"_s, result.List3)
|
||||
.Bind("MULTI_1"_s, result.Multi1)
|
||||
.Bind("MULTI_2"_s, result.Multi2)
|
||||
.Bind("MULTI_3"_s, result.Multi3)
|
||||
.Parse(args, &unparsedArguments, &keywordsMissingValue);
|
||||
|
||||
return verifyResult(result, unparsedArguments, keywordsMissingValue);
|
||||
}
|
||||
|
||||
bool testArgumentParserStatic()
|
||||
{
|
||||
static auto const parser = //
|
||||
cmArgumentParser<Result>{}
|
||||
.Bind("OPTION_1"_s, &Result::Option1)
|
||||
.Bind("OPTION_2"_s, &Result::Option2)
|
||||
.Bind("STRING_1"_s, &Result::String1)
|
||||
.Bind("STRING_2"_s, &Result::String2)
|
||||
.Bind("LIST_1"_s, &Result::List1)
|
||||
.Bind("LIST_2"_s, &Result::List2)
|
||||
.Bind("LIST_3"_s, &Result::List3)
|
||||
.Bind("MULTI_1"_s, &Result::Multi1)
|
||||
.Bind("MULTI_2"_s, &Result::Multi2)
|
||||
.Bind("MULTI_3"_s, &Result::Multi3);
|
||||
|
||||
std::vector<std::string> unparsedArguments;
|
||||
std::vector<std::string> keywordsMissingValue;
|
||||
Result const result =
|
||||
parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
|
||||
|
||||
return verifyResult(result, unparsedArguments, keywordsMissingValue);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int testArgumentParser(int /*unused*/, char* /*unused*/ [])
|
||||
{
|
||||
if (!testArgumentParserDynamic()) {
|
||||
std::cout << "While executing testArgumentParserDynamic().\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!testArgumentParserStatic()) {
|
||||
std::cout << "While executing testArgumentParserStatic().\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
CMake Error at AppendExport.cmake:[0-9]+ \(export\):
|
||||
export EXPORT signature does not recognise the APPEND option.
|
||||
export Unknown argument: "APPEND".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,5 +1,4 @@
|
||||
CMake Error at OldIface.cmake:[0-9]+ \(export\):
|
||||
export EXPORT signature does not recognise the
|
||||
EXPORT_LINK_INTERFACE_LIBRARIES option.
|
||||
export Unknown argument: "EXPORT_LINK_INTERFACE_LIBRARIES".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -68,6 +68,7 @@
|
||||
{ symbol: [ "std::__decay_and_strip<cmGeneratorTarget *&>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<cmFindCommon::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<cmSearchPath>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<cm::string_view>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<const std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
{ symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
|
||||
|
@ -260,6 +260,7 @@ CMAKE_CXX_SOURCES="\
|
||||
cmAddLibraryCommand \
|
||||
cmAddSubDirectoryCommand \
|
||||
cmAddTestCommand \
|
||||
cmArgumentParser \
|
||||
cmBreakCommand \
|
||||
cmBuildCommand \
|
||||
cmCMakeMinimumRequired \
|
||||
@ -268,7 +269,6 @@ CMAKE_CXX_SOURCES="\
|
||||
cmCacheManager \
|
||||
cmCommand \
|
||||
cmCommandArgumentParserHelper \
|
||||
cmCommandArgumentsHelper \
|
||||
cmCommands \
|
||||
cmCommonTargetGenerator \
|
||||
cmComputeComponentGraph \
|
||||
|
Loading…
x
Reference in New Issue
Block a user