continue: Add a new CMake language command for loop continuation (#14013)
Inspired-by: Doug Barbieri Signed-off-by: Gregor Jasny <gjasny@googlemail.com>
This commit is contained in:
parent
8e75f1d2fa
commit
0de867dde2
|
@ -8,3 +8,5 @@ Break from an enclosing foreach or while loop.
|
||||||
break()
|
break()
|
||||||
|
|
||||||
Breaks from an enclosing foreach loop or while loop
|
Breaks from an enclosing foreach loop or while loop
|
||||||
|
|
||||||
|
See also the :command:`continue` command.
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
continue
|
||||||
|
--------
|
||||||
|
|
||||||
|
Continue to the top of enclosing foreach or while loop.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
continue()
|
||||||
|
|
||||||
|
The ``continue`` command allows a cmake script to abort the rest of a block
|
||||||
|
in a :command:`foreach` or :command:`while` loop, and start at the top of
|
||||||
|
the next iteration. See also the :command:`break` command.
|
|
@ -31,6 +31,7 @@ These commands may be used freely in CMake projects.
|
||||||
/command/cmake_minimum_required
|
/command/cmake_minimum_required
|
||||||
/command/cmake_policy
|
/command/cmake_policy
|
||||||
/command/configure_file
|
/command/configure_file
|
||||||
|
/command/continue
|
||||||
/command/create_test_sourcelist
|
/command/create_test_sourcelist
|
||||||
/command/define_property
|
/command/define_property
|
||||||
/command/elseif
|
/command/elseif
|
||||||
|
|
|
@ -469,8 +469,10 @@ Loops
|
||||||
|
|
||||||
The :command:`foreach`/:command:`endforeach` and
|
The :command:`foreach`/:command:`endforeach` and
|
||||||
:command:`while`/:command:`endwhile` commands delimit code
|
:command:`while`/:command:`endwhile` commands delimit code
|
||||||
blocks to be executed in a loop. The :command:`break` command
|
blocks to be executed in a loop. Inside such blocks the
|
||||||
may be used inside such blocks to terminate the loop early.
|
:command:`break` command may be used to terminate the loop
|
||||||
|
early whereas the :command:`continue` command may be used
|
||||||
|
to start with the next iteration immediately.
|
||||||
|
|
||||||
Command Definitions
|
Command Definitions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
add-continue-command
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* A new :command:`continue` command was added that can be called inside loop
|
||||||
|
contexts to end the current iteration and start the next one at the top of
|
||||||
|
the loop block.
|
|
@ -28,6 +28,7 @@
|
||||||
#include "cmCMakePolicyCommand.cxx"
|
#include "cmCMakePolicyCommand.cxx"
|
||||||
#include "cmCommandArgumentsHelper.cxx"
|
#include "cmCommandArgumentsHelper.cxx"
|
||||||
#include "cmConfigureFileCommand.cxx"
|
#include "cmConfigureFileCommand.cxx"
|
||||||
|
#include "cmContinueCommand.cxx"
|
||||||
#include "cmCoreTryCompile.cxx"
|
#include "cmCoreTryCompile.cxx"
|
||||||
#include "cmCreateTestSourceList.cxx"
|
#include "cmCreateTestSourceList.cxx"
|
||||||
#include "cmDefinePropertyCommand.cxx"
|
#include "cmDefinePropertyCommand.cxx"
|
||||||
|
@ -70,6 +71,7 @@ void GetBootstrapCommands1(std::list<cmCommand*>& commands)
|
||||||
commands.push_back(new cmCMakeMinimumRequired);
|
commands.push_back(new cmCMakeMinimumRequired);
|
||||||
commands.push_back(new cmCMakePolicyCommand);
|
commands.push_back(new cmCMakePolicyCommand);
|
||||||
commands.push_back(new cmConfigureFileCommand);
|
commands.push_back(new cmConfigureFileCommand);
|
||||||
|
commands.push_back(new cmContinueCommand);
|
||||||
commands.push_back(new cmCreateTestSourceList);
|
commands.push_back(new cmCreateTestSourceList);
|
||||||
commands.push_back(new cmDefinePropertyCommand);
|
commands.push_back(new cmDefinePropertyCommand);
|
||||||
commands.push_back(new cmElseCommand);
|
commands.push_back(new cmElseCommand);
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#include "cmContinueCommand.h"
|
||||||
|
|
||||||
|
// cmContinueCommand
|
||||||
|
bool cmContinueCommand::InitialPass(std::vector<std::string> const &args,
|
||||||
|
cmExecutionStatus &status)
|
||||||
|
{
|
||||||
|
if(!this->Makefile->IsLoopBlock())
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
|
||||||
|
"A CONTINUE command was found outside of a "
|
||||||
|
"proper FOREACH or WHILE loop scope.");
|
||||||
|
cmSystemTools::SetFatalErrorOccured();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.SetContinueInvoked(true);
|
||||||
|
|
||||||
|
if(!args.empty())
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
|
||||||
|
"The CONTINUE command does not accept any "
|
||||||
|
"arguments.");
|
||||||
|
cmSystemTools::SetFatalErrorOccured();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2000-2014 Kitware, Inc., Insight Software Consortium
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#ifndef cmContinueCommand_h
|
||||||
|
#define cmContinueCommand_h
|
||||||
|
|
||||||
|
#include "cmCommand.h"
|
||||||
|
|
||||||
|
/** \class cmContinueCommand
|
||||||
|
* \brief Continue from an enclosing foreach or while loop
|
||||||
|
*
|
||||||
|
* cmContinueCommand returns from an enclosing foreach or while loop
|
||||||
|
*/
|
||||||
|
class cmContinueCommand : public cmCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* This is a virtual constructor for the command.
|
||||||
|
*/
|
||||||
|
virtual cmCommand* Clone()
|
||||||
|
{
|
||||||
|
return new cmContinueCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called when the command is first encountered in
|
||||||
|
* the CMakeLists.txt file.
|
||||||
|
*/
|
||||||
|
virtual bool InitialPass(std::vector<std::string> const& args,
|
||||||
|
cmExecutionStatus &status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This determines if the command is invoked when in script mode.
|
||||||
|
*/
|
||||||
|
virtual bool IsScriptable() const { return true; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the command as specified in CMakeList.txt.
|
||||||
|
*/
|
||||||
|
virtual std::string GetName() const { return "continue"; }
|
||||||
|
|
||||||
|
cmTypeMacro(cmContinueCommand, cmCommand);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -36,10 +36,16 @@ public:
|
||||||
virtual bool GetBreakInvoked()
|
virtual bool GetBreakInvoked()
|
||||||
{ return this->BreakInvoked; }
|
{ return this->BreakInvoked; }
|
||||||
|
|
||||||
|
virtual void SetContinueInvoked(bool val)
|
||||||
|
{ this->ContinueInvoked = val; }
|
||||||
|
virtual bool GetContinueInvoked()
|
||||||
|
{ return this->ContinueInvoked; }
|
||||||
|
|
||||||
virtual void Clear()
|
virtual void Clear()
|
||||||
{
|
{
|
||||||
this->ReturnInvoked = false;
|
this->ReturnInvoked = false;
|
||||||
this->BreakInvoked = false;
|
this->BreakInvoked = false;
|
||||||
|
this->ContinueInvoked = false;
|
||||||
this->NestedError = false;
|
this->NestedError = false;
|
||||||
}
|
}
|
||||||
virtual void SetNestedError(bool val) { this->NestedError = val; }
|
virtual void SetNestedError(bool val) { this->NestedError = val; }
|
||||||
|
@ -49,6 +55,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
bool ReturnInvoked;
|
bool ReturnInvoked;
|
||||||
bool BreakInvoked;
|
bool BreakInvoked;
|
||||||
|
bool ContinueInvoked;
|
||||||
bool NestedError;
|
bool NestedError;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,10 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
||||||
mf.AddDefinition(this->Args[0],oldDef.c_str());
|
mf.AddDefinition(this->Args[0],oldDef.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (status.GetContinueInvoked())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(cmSystemTools::GetFatalErrorOccured() )
|
if(cmSystemTools::GetFatalErrorOccured() )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -151,6 +151,11 @@ IsFunctionBlocked(const cmListFileFunction& lff,
|
||||||
inStatus.SetBreakInvoked(true);
|
inStatus.SetBreakInvoked(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (status.GetContinueInvoked())
|
||||||
|
{
|
||||||
|
inStatus.SetContinueInvoked(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -83,6 +83,10 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (status.GetContinueInvoked())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(cmSystemTools::GetFatalErrorOccured() )
|
if(cmSystemTools::GetFatalErrorOccured() )
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -102,6 +102,7 @@ add_RunCMake_test(add_dependencies)
|
||||||
add_RunCMake_test(build_command)
|
add_RunCMake_test(build_command)
|
||||||
add_RunCMake_test(export)
|
add_RunCMake_test(export)
|
||||||
add_RunCMake_test(cmake_minimum_required)
|
add_RunCMake_test(cmake_minimum_required)
|
||||||
|
add_RunCMake_test(continue)
|
||||||
add_RunCMake_test(file)
|
add_RunCMake_test(file)
|
||||||
add_RunCMake_test(find_package)
|
add_RunCMake_test(find_package)
|
||||||
add_RunCMake_test(get_filename_component)
|
add_RunCMake_test(get_filename_component)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
cmake_minimum_required(VERSION 3.1)
|
||||||
|
project(${RunCMake_TEST} NONE)
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1,10 @@
|
||||||
|
list(APPEND foo 1 2 3 4 5)
|
||||||
|
|
||||||
|
message(STATUS "start")
|
||||||
|
foreach(iter IN LISTS foo)
|
||||||
|
if("${iter}" EQUAL 1 OR "${iter}" EQUAL 3 OR "${iter}" EQUAL 5)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
message(STATUS "${iter}")
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "end")
|
|
@ -0,0 +1,4 @@
|
||||||
|
-- start
|
||||||
|
-- 2
|
||||||
|
-- 4
|
||||||
|
-- end
|
|
@ -0,0 +1,8 @@
|
||||||
|
message(STATUS "start")
|
||||||
|
foreach(iter RANGE 1 5)
|
||||||
|
if("${iter}" EQUAL 1 OR "${iter}" EQUAL 3 OR "${iter}" EQUAL 5)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
message(STATUS "${iter}")
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "end")
|
|
@ -0,0 +1,6 @@
|
||||||
|
-- start
|
||||||
|
-- 7 2
|
||||||
|
-- 7 4
|
||||||
|
-- 9 2
|
||||||
|
-- 9 4
|
||||||
|
-- end
|
|
@ -0,0 +1,13 @@
|
||||||
|
message(STATUS "start")
|
||||||
|
foreach(outer RANGE 7 9)
|
||||||
|
if("${outer}" EQUAL 8)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
foreach(inner RANGE 1 5)
|
||||||
|
if("${inner}" EQUAL 1 OR "${inner}" EQUAL 3 OR "${inner}" EQUAL 5)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
message(STATUS "${outer} ${inner}")
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "end")
|
|
@ -0,0 +1,6 @@
|
||||||
|
-- start
|
||||||
|
-- a
|
||||||
|
-- aa
|
||||||
|
-- aaaa
|
||||||
|
-- aaaaa
|
||||||
|
-- end
|
|
@ -0,0 +1,10 @@
|
||||||
|
message(STATUS "start")
|
||||||
|
unset(iter)
|
||||||
|
while(NOT "${iter}" STREQUAL "aaaaa")
|
||||||
|
set(iter "${iter}a")
|
||||||
|
if("${iter}" STREQUAL "aaa")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
message(STATUS "${iter}")
|
||||||
|
endwhile()
|
||||||
|
message(STATUS "end")
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,4 @@
|
||||||
|
CMake Error at NoArgumentsToContinue.cmake:2 \(continue\):
|
||||||
|
The CONTINUE command does not accept any arguments.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1,3 @@
|
||||||
|
foreach(i RANGE 1 2)
|
||||||
|
continue(1)
|
||||||
|
endforeach()
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,5 @@
|
||||||
|
CMake Error at NoEnclosingBlock.cmake:1 \(continue\):
|
||||||
|
A CONTINUE command was found outside of a proper FOREACH or WHILE loop
|
||||||
|
scope.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1 @@
|
||||||
|
continue()
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,6 @@
|
||||||
|
CMake Error at NoEnclosingBlockInFunction.cmake:2 \(continue\):
|
||||||
|
A CONTINUE command was found outside of a proper FOREACH or WHILE loop
|
||||||
|
scope.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
NoEnclosingBlockInFunction.cmake:6 \(foo\)
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1,8 @@
|
||||||
|
function(foo)
|
||||||
|
continue()
|
||||||
|
endfunction(foo)
|
||||||
|
|
||||||
|
foreach(i RANGE 1 2)
|
||||||
|
foo()
|
||||||
|
message(STATUS "Hello World")
|
||||||
|
endforeach()
|
|
@ -0,0 +1,9 @@
|
||||||
|
include(RunCMake)
|
||||||
|
|
||||||
|
run_cmake(ContinueForeach)
|
||||||
|
run_cmake(ContinueForEachInLists)
|
||||||
|
run_cmake(ContinueNestedForeach)
|
||||||
|
run_cmake(ContinueWhile)
|
||||||
|
run_cmake(NoArgumentsToContinue)
|
||||||
|
run_cmake(NoEnclosingBlock)
|
||||||
|
run_cmake(NoEnclosingBlockInFunction)
|
Loading…
Reference in New Issue