123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmBlockCommand.h"
- #include <cstdint>
- #include <initializer_list>
- #include <utility>
- #include <cm/memory>
- #include <cm/optional>
- #include <cm/string_view>
- #include <cmext/enum_set>
- #include <cmext/string_view>
- #include "cmArgumentParser.h"
- #include "cmArgumentParserTypes.h"
- #include "cmExecutionStatus.h"
- #include "cmFunctionBlocker.h"
- #include "cmListFileCache.h"
- #include "cmMakefile.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- namespace {
- enum class ScopeType : std::uint8_t
- {
- VARIABLES,
- POLICIES
- };
- using ScopeSet = cm::enum_set<ScopeType>;
- class BlockScopePushPop
- {
- public:
- BlockScopePushPop(cmMakefile* m, const ScopeSet& scopes);
- ~BlockScopePushPop() = default;
- BlockScopePushPop(const BlockScopePushPop&) = delete;
- BlockScopePushPop& operator=(const BlockScopePushPop&) = delete;
- private:
- std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
- std::unique_ptr<cmMakefile::VariablePushPop> VariableScope;
- };
- BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, const ScopeSet& scopes)
- {
- if (scopes.contains(ScopeType::POLICIES)) {
- this->PolicyScope = cm::make_unique<cmMakefile::PolicyPushPop>(mf);
- }
- if (scopes.contains(ScopeType::VARIABLES)) {
- this->VariableScope = cm::make_unique<cmMakefile::VariablePushPop>(mf);
- }
- }
- class cmBlockFunctionBlocker : public cmFunctionBlocker
- {
- public:
- cmBlockFunctionBlocker(cmMakefile* mf, const ScopeSet& scopes,
- std::vector<std::string> variableNames);
- ~cmBlockFunctionBlocker() override;
- cm::string_view StartCommandName() const override { return "block"_s; }
- cm::string_view EndCommandName() const override { return "endblock"_s; }
- bool EndCommandSupportsArguments() const override { return false; }
- bool ArgumentsMatch(cmListFileFunction const& lff,
- cmMakefile& mf) const override;
- bool Replay(std::vector<cmListFileFunction> functions,
- cmExecutionStatus& inStatus) override;
- private:
- cmMakefile* Makefile;
- ScopeSet Scopes;
- BlockScopePushPop BlockScope;
- std::vector<std::string> VariableNames;
- };
- cmBlockFunctionBlocker::cmBlockFunctionBlocker(
- cmMakefile* const mf, const ScopeSet& scopes,
- std::vector<std::string> variableNames)
- : Makefile{ mf }
- , Scopes{ scopes }
- , BlockScope{ mf, scopes }
- , VariableNames{ std::move(variableNames) }
- {
- }
- cmBlockFunctionBlocker::~cmBlockFunctionBlocker()
- {
- if (this->Scopes.contains(ScopeType::VARIABLES)) {
- this->Makefile->RaiseScope(this->VariableNames);
- }
- }
- bool cmBlockFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
- cmMakefile&) const
- {
- // no arguments expected for endblock()
- // but this method should not be called because EndCommandHasArguments()
- // returns false.
- return lff.Arguments().empty();
- }
- bool cmBlockFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
- cmExecutionStatus& inStatus)
- {
- auto& mf = inStatus.GetMakefile();
- // Invoke all the functions that were collected in the block.
- for (cmListFileFunction const& fn : functions) {
- cmExecutionStatus status(mf);
- mf.ExecuteCommand(fn, status);
- if (status.GetReturnInvoked()) {
- mf.RaiseScope(status.GetReturnVariables());
- inStatus.SetReturnInvoked(status.GetReturnVariables());
- return true;
- }
- if (status.GetBreakInvoked()) {
- inStatus.SetBreakInvoked();
- return true;
- }
- if (status.GetContinueInvoked()) {
- inStatus.SetContinueInvoked();
- return true;
- }
- if (cmSystemTools::GetFatalErrorOccurred()) {
- return true;
- }
- }
- return true;
- }
- } // anonymous namespace
- bool cmBlockCommand(std::vector<std::string> const& args,
- cmExecutionStatus& status)
- {
- struct Arguments : public ArgumentParser::ParseResult
- {
- cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> ScopeFor;
- ArgumentParser::MaybeEmpty<std::vector<std::string>> Propagate;
- };
- static auto const parser = cmArgumentParser<Arguments>{}
- .Bind("SCOPE_FOR"_s, &Arguments::ScopeFor)
- .Bind("PROPAGATE"_s, &Arguments::Propagate);
- std::vector<std::string> unrecognizedArguments;
- auto parsedArgs = parser.Parse(args, &unrecognizedArguments);
- if (!unrecognizedArguments.empty()) {
- status.SetError(cmStrCat("called with unsupported argument \"",
- unrecognizedArguments[0], '"'));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
- if (parsedArgs.MaybeReportError(status.GetMakefile())) {
- cmSystemTools::SetFatalErrorOccurred();
- return true;
- }
- ScopeSet scopes;
- if (parsedArgs.ScopeFor) {
- for (auto const& scope : *parsedArgs.ScopeFor) {
- if (scope == "VARIABLES"_s) {
- scopes.insert(ScopeType::VARIABLES);
- continue;
- }
- if (scope == "POLICIES"_s) {
- scopes.insert(ScopeType::POLICIES);
- continue;
- }
- status.SetError(cmStrCat("SCOPE_FOR unsupported scope \"", scope, '"'));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
- } else {
- scopes = { ScopeType::VARIABLES, ScopeType::POLICIES };
- }
- if (!scopes.contains(ScopeType::VARIABLES) &&
- !parsedArgs.Propagate.empty()) {
- status.SetError(
- "PROPAGATE cannot be specified without a new scope for VARIABLES");
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
- // create a function blocker
- auto fb = cm::make_unique<cmBlockFunctionBlocker>(
- &status.GetMakefile(), scopes, parsedArgs.Propagate);
- status.GetMakefile().AddFunctionBlocker(std::move(fb));
- return true;
- }
|