mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-10 17:14:10 +00:00
Add and use a couple helper functions for issuing policy warnings. This improves consistency and allows some simplification of many call sites. (One or two instances in particular are greatly simplified.)
159 lines
4.7 KiB
C++
159 lines
4.7 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmWhileCommand.h"
|
|
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include <cm/memory>
|
|
#include <cm/string_view>
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmConditionEvaluator.h"
|
|
#include "cmExecutionStatus.h"
|
|
#include "cmExpandedCommandArgument.h"
|
|
#include "cmFunctionBlocker.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmOutputConverter.h"
|
|
#include "cmPolicies.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
class cmWhileFunctionBlocker : public cmFunctionBlocker
|
|
{
|
|
public:
|
|
cmWhileFunctionBlocker(cmMakefile* mf, std::vector<cmListFileArgument> args);
|
|
~cmWhileFunctionBlocker() override;
|
|
|
|
cm::string_view StartCommandName() const override { return "while"_s; }
|
|
cm::string_view EndCommandName() const override { return "endwhile"_s; }
|
|
|
|
bool ArgumentsMatch(cmListFileFunction const& lff,
|
|
cmMakefile& mf) const override;
|
|
|
|
bool Replay(std::vector<cmListFileFunction> functions,
|
|
cmExecutionStatus& inStatus) override;
|
|
|
|
private:
|
|
cmMakefile* Makefile;
|
|
std::vector<cmListFileArgument> Args;
|
|
};
|
|
|
|
cmWhileFunctionBlocker::cmWhileFunctionBlocker(
|
|
cmMakefile* const mf, std::vector<cmListFileArgument> args)
|
|
: Makefile{ mf }
|
|
, Args{ std::move(args) }
|
|
{
|
|
this->Makefile->PushLoopBlock();
|
|
}
|
|
|
|
cmWhileFunctionBlocker::~cmWhileFunctionBlocker()
|
|
{
|
|
this->Makefile->PopLoopBlock();
|
|
}
|
|
|
|
bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
|
|
cmMakefile&) const
|
|
{
|
|
return lff.Arguments().empty() || lff.Arguments() == this->Args;
|
|
}
|
|
|
|
bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
|
|
cmExecutionStatus& inStatus)
|
|
{
|
|
auto& mf = inStatus.GetMakefile();
|
|
|
|
cmListFileBacktrace whileBT =
|
|
mf.GetBacktrace().Push(this->GetStartingContext());
|
|
|
|
std::vector<cmExpandedCommandArgument> expandedArguments;
|
|
// At least same size expected for `expandedArguments` as `Args`
|
|
expandedArguments.reserve(this->Args.size());
|
|
|
|
auto expandArgs = [&mf](std::vector<cmListFileArgument> const& args,
|
|
std::vector<cmExpandedCommandArgument>& out)
|
|
-> std::vector<cmExpandedCommandArgument>& {
|
|
out.clear();
|
|
mf.ExpandArguments(args, out);
|
|
return out;
|
|
};
|
|
|
|
// For compatibility with projects that do not set CMP0130 to NEW,
|
|
// we tolerate condition errors that evaluate to false.
|
|
bool enforceError = true;
|
|
std::string errorString;
|
|
MessageType messageType;
|
|
|
|
for (cmConditionEvaluator conditionEvaluator(mf, whileBT);
|
|
(enforceError = /* enforce condition errors that evaluate to true */
|
|
conditionEvaluator.IsTrue(expandArgs(this->Args, expandedArguments),
|
|
errorString, messageType));) {
|
|
// 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()) {
|
|
inStatus.SetReturnInvoked(status.GetReturnVariables());
|
|
return true;
|
|
}
|
|
if (status.GetBreakInvoked()) {
|
|
return true;
|
|
}
|
|
if (status.GetContinueInvoked()) {
|
|
break;
|
|
}
|
|
if (status.HasExitCode()) {
|
|
inStatus.SetExitCode(status.GetExitCode());
|
|
return true;
|
|
}
|
|
if (cmSystemTools::GetFatalErrorOccurred()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!errorString.empty() && !enforceError) {
|
|
// This error should only be enforced if CMP0130 is NEW.
|
|
if (mf.GetPolicyStatus(cmPolicies::CMP0130) != cmPolicies::OLD) {
|
|
enforceError = true;
|
|
}
|
|
}
|
|
|
|
if (!errorString.empty() && enforceError) {
|
|
std::string err = "while() given incorrect arguments:\n ";
|
|
for (auto const& i : expandedArguments) {
|
|
err += " ";
|
|
err += cmOutputConverter::EscapeForCMake(i.GetValue());
|
|
}
|
|
err += "\n";
|
|
err += errorString;
|
|
if (mf.GetPolicyStatus(cmPolicies::CMP0130) == cmPolicies::WARN) {
|
|
mf.IssuePolicyWarning(cmPolicies::CMP0130, {}, err, whileBT);
|
|
} else {
|
|
mf.IssueMessage(messageType, err, whileBT);
|
|
if (messageType == MessageType::FATAL_ERROR) {
|
|
cmSystemTools::SetFatalErrorOccurred();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmWhileCommand(std::vector<cmListFileArgument> const& args,
|
|
cmExecutionStatus& status)
|
|
{
|
|
if (args.empty()) {
|
|
status.SetError("called with incorrect number of arguments");
|
|
return false;
|
|
}
|
|
|
|
// create a function blocker
|
|
auto& makefile = status.GetMakefile();
|
|
makefile.AddFunctionBlocker(
|
|
cm::make_unique<cmWhileFunctionBlocker>(&makefile, args));
|
|
|
|
return true;
|
|
}
|