|
|
@@ -3,10 +3,14 @@
|
|
|
#include "cmIfCommand.h"
|
|
|
|
|
|
#include "cm_memory.hxx"
|
|
|
+#include "cm_static_string_view.hxx"
|
|
|
+#include "cm_string_view.hxx"
|
|
|
|
|
|
#include "cmConditionEvaluator.h"
|
|
|
#include "cmExecutionStatus.h"
|
|
|
#include "cmExpandedCommandArgument.h"
|
|
|
+#include "cmFunctionBlocker.h"
|
|
|
+#include "cmListFileCache.h"
|
|
|
#include "cmMakefile.h"
|
|
|
#include "cmMessageType.h"
|
|
|
#include "cmOutputConverter.h"
|
|
|
@@ -28,152 +32,138 @@ static std::string cmIfCommandError(
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-//=========================================================================
|
|
|
-bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
|
|
|
- cmMakefile& mf,
|
|
|
- cmExecutionStatus& inStatus)
|
|
|
+class cmIfFunctionBlocker : public cmFunctionBlocker
|
|
|
{
|
|
|
- // we start by recording all the functions
|
|
|
- if (lff.Name.Lower == "if") {
|
|
|
- this->ScopeDepth++;
|
|
|
- } else if (lff.Name.Lower == "endif") {
|
|
|
- this->ScopeDepth--;
|
|
|
- // if this is the endif for this if statement, then start executing
|
|
|
- if (!this->ScopeDepth) {
|
|
|
- // Remove the function blocker for this scope or bail.
|
|
|
- std::unique_ptr<cmFunctionBlocker> fb(
|
|
|
- mf.RemoveFunctionBlocker(this, lff));
|
|
|
- if (!fb) {
|
|
|
- return false;
|
|
|
+public:
|
|
|
+ cm::string_view StartCommandName() const override { return "if"_s; }
|
|
|
+ cm::string_view EndCommandName() const override { return "endif"_s; }
|
|
|
+
|
|
|
+ bool ArgumentsMatch(cmListFileFunction const& lff,
|
|
|
+ cmMakefile&) const override;
|
|
|
+
|
|
|
+ bool Replay(std::vector<cmListFileFunction> functions,
|
|
|
+ cmExecutionStatus& inStatus) override;
|
|
|
+
|
|
|
+ std::vector<cmListFileArgument> Args;
|
|
|
+ bool IsBlocking;
|
|
|
+ bool HasRun = false;
|
|
|
+ bool ElseSeen = false;
|
|
|
+};
|
|
|
+
|
|
|
+bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
|
|
|
+ cmMakefile&) const
|
|
|
+{
|
|
|
+ return lff.Arguments.empty() || lff.Arguments == this->Args;
|
|
|
+}
|
|
|
+
|
|
|
+bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
|
|
|
+ cmExecutionStatus& inStatus)
|
|
|
+{
|
|
|
+ cmMakefile& mf = inStatus.GetMakefile();
|
|
|
+ // execute the functions for the true parts of the if statement
|
|
|
+ cmExecutionStatus status(mf);
|
|
|
+ int scopeDepth = 0;
|
|
|
+ for (cmListFileFunction const& func : functions) {
|
|
|
+ // keep track of scope depth
|
|
|
+ if (func.Name.Lower == "if") {
|
|
|
+ scopeDepth++;
|
|
|
+ }
|
|
|
+ if (func.Name.Lower == "endif") {
|
|
|
+ scopeDepth--;
|
|
|
+ }
|
|
|
+ // watch for our state change
|
|
|
+ if (scopeDepth == 0 && func.Name.Lower == "else") {
|
|
|
+
|
|
|
+ if (this->ElseSeen) {
|
|
|
+ cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
+ mf.GetCMakeInstance()->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "A duplicate ELSE command was found inside an IF block.", bt);
|
|
|
+ cmSystemTools::SetFatalErrorOccured();
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- // execute the functions for the true parts of the if statement
|
|
|
- cmExecutionStatus status(mf);
|
|
|
- int scopeDepth = 0;
|
|
|
- for (cmListFileFunction const& func : this->Functions) {
|
|
|
- // keep track of scope depth
|
|
|
- if (func.Name.Lower == "if") {
|
|
|
- scopeDepth++;
|
|
|
- }
|
|
|
- if (func.Name.Lower == "endif") {
|
|
|
- scopeDepth--;
|
|
|
+ this->IsBlocking = this->HasRun;
|
|
|
+ this->HasRun = true;
|
|
|
+ this->ElseSeen = true;
|
|
|
+
|
|
|
+ // if trace is enabled, print a (trivially) evaluated "else"
|
|
|
+ // statement
|
|
|
+ if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
|
|
|
+ mf.PrintCommandTrace(func);
|
|
|
+ }
|
|
|
+ } else if (scopeDepth == 0 && func.Name.Lower == "elseif") {
|
|
|
+ if (this->ElseSeen) {
|
|
|
+ cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
+ mf.GetCMakeInstance()->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ "An ELSEIF command was found after an ELSE command.", bt);
|
|
|
+ cmSystemTools::SetFatalErrorOccured();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this->HasRun) {
|
|
|
+ this->IsBlocking = true;
|
|
|
+ } else {
|
|
|
+ // if trace is enabled, print the evaluated "elseif" statement
|
|
|
+ if (mf.GetCMakeInstance()->GetTrace()) {
|
|
|
+ mf.PrintCommandTrace(func);
|
|
|
}
|
|
|
- // watch for our state change
|
|
|
- if (scopeDepth == 0 && func.Name.Lower == "else") {
|
|
|
-
|
|
|
- if (this->ElseSeen) {
|
|
|
- cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
- mf.GetCMakeInstance()->IssueMessage(
|
|
|
- MessageType::FATAL_ERROR,
|
|
|
- "A duplicate ELSE command was found inside an IF block.", bt);
|
|
|
- cmSystemTools::SetFatalErrorOccured();
|
|
|
- return true;
|
|
|
- }
|
|
|
|
|
|
- this->IsBlocking = this->HasRun;
|
|
|
- this->HasRun = true;
|
|
|
- this->ElseSeen = true;
|
|
|
+ std::string errorString;
|
|
|
|
|
|
- // if trace is enabled, print a (trivially) evaluated "else"
|
|
|
- // statement
|
|
|
- if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
|
|
|
- mf.PrintCommandTrace(func);
|
|
|
- }
|
|
|
- } else if (scopeDepth == 0 && func.Name.Lower == "elseif") {
|
|
|
- if (this->ElseSeen) {
|
|
|
- cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
- mf.GetCMakeInstance()->IssueMessage(
|
|
|
- MessageType::FATAL_ERROR,
|
|
|
- "An ELSEIF command was found after an ELSE command.", bt);
|
|
|
+ std::vector<cmExpandedCommandArgument> expandedArguments;
|
|
|
+ mf.ExpandArguments(func.Arguments, expandedArguments);
|
|
|
+
|
|
|
+ MessageType messType;
|
|
|
+
|
|
|
+ cmListFileContext conditionContext =
|
|
|
+ cmListFileContext::FromCommandContext(
|
|
|
+ func, this->GetStartingContext().FilePath);
|
|
|
+
|
|
|
+ cmConditionEvaluator conditionEvaluator(mf, conditionContext,
|
|
|
+ mf.GetBacktrace(func));
|
|
|
+
|
|
|
+ bool isTrue =
|
|
|
+ conditionEvaluator.IsTrue(expandedArguments, errorString, messType);
|
|
|
+
|
|
|
+ if (!errorString.empty()) {
|
|
|
+ std::string err = cmIfCommandError(expandedArguments);
|
|
|
+ err += errorString;
|
|
|
+ cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
+ mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
|
|
|
+ if (messType == MessageType::FATAL_ERROR) {
|
|
|
cmSystemTools::SetFatalErrorOccured();
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
- if (this->HasRun) {
|
|
|
- this->IsBlocking = true;
|
|
|
- } else {
|
|
|
- // if trace is enabled, print the evaluated "elseif" statement
|
|
|
- if (mf.GetCMakeInstance()->GetTrace()) {
|
|
|
- mf.PrintCommandTrace(func);
|
|
|
- }
|
|
|
-
|
|
|
- std::string errorString;
|
|
|
-
|
|
|
- std::vector<cmExpandedCommandArgument> expandedArguments;
|
|
|
- mf.ExpandArguments(func.Arguments, expandedArguments);
|
|
|
-
|
|
|
- MessageType messType;
|
|
|
-
|
|
|
- cmListFileContext conditionContext =
|
|
|
- cmListFileContext::FromCommandContext(
|
|
|
- func, this->GetStartingContext().FilePath);
|
|
|
-
|
|
|
- cmConditionEvaluator conditionEvaluator(mf, conditionContext,
|
|
|
- mf.GetBacktrace(func));
|
|
|
-
|
|
|
- bool isTrue = conditionEvaluator.IsTrue(expandedArguments,
|
|
|
- errorString, messType);
|
|
|
-
|
|
|
- if (!errorString.empty()) {
|
|
|
- std::string err = cmIfCommandError(expandedArguments);
|
|
|
- err += errorString;
|
|
|
- cmListFileBacktrace bt = mf.GetBacktrace(func);
|
|
|
- mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
|
|
|
- if (messType == MessageType::FATAL_ERROR) {
|
|
|
- cmSystemTools::SetFatalErrorOccured();
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (isTrue) {
|
|
|
- this->IsBlocking = false;
|
|
|
- this->HasRun = true;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- // should we execute?
|
|
|
- else if (!this->IsBlocking) {
|
|
|
- status.Clear();
|
|
|
- mf.ExecuteCommand(func, status);
|
|
|
- if (status.GetReturnInvoked()) {
|
|
|
- inStatus.SetReturnInvoked();
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (status.GetBreakInvoked()) {
|
|
|
- inStatus.SetBreakInvoked();
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (status.GetContinueInvoked()) {
|
|
|
- inStatus.SetContinueInvoked();
|
|
|
- return true;
|
|
|
- }
|
|
|
+ if (isTrue) {
|
|
|
+ this->IsBlocking = false;
|
|
|
+ this->HasRun = true;
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // record the command
|
|
|
- this->Functions.push_back(lff);
|
|
|
-
|
|
|
- // always return true
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//=========================================================================
|
|
|
-bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
|
|
|
- cmMakefile&)
|
|
|
-{
|
|
|
- if (lff.Name.Lower == "endif") {
|
|
|
- // if the endif has arguments, then make sure
|
|
|
- // they match the arguments of the matching if
|
|
|
- if (lff.Arguments.empty() || lff.Arguments == this->Args) {
|
|
|
- return true;
|
|
|
+ // should we execute?
|
|
|
+ else if (!this->IsBlocking) {
|
|
|
+ status.Clear();
|
|
|
+ mf.ExecuteCommand(func, status);
|
|
|
+ if (status.GetReturnInvoked()) {
|
|
|
+ inStatus.SetReturnInvoked();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (status.GetBreakInvoked()) {
|
|
|
+ inStatus.SetBreakInvoked();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (status.GetContinueInvoked()) {
|
|
|
+ inStatus.SetContinueInvoked();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return false;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
//=========================================================================
|
|
|
@@ -208,7 +198,6 @@ bool cmIfCommand(std::vector<cmListFileArgument> const& args,
|
|
|
{
|
|
|
auto fb = cm::make_unique<cmIfFunctionBlocker>();
|
|
|
// if is isn't true block the commands
|
|
|
- fb->ScopeDepth = 1;
|
|
|
fb->IsBlocking = !isTrue;
|
|
|
if (isTrue) {
|
|
|
fb->HasRun = true;
|