From c46728d3e01d86963bb25643aa75622a2313905d Mon Sep 17 00:00:00 2001 From: bergmann Date: Wed, 6 Nov 2019 23:33:24 +0100 Subject: [PATCH] * Updated project structure --- .gitmodules | 5 +- CMakeLists.txt | 98 ++++++++++++++++++------------------- README.md | 3 ++ TODO | 1 + cmake/cppargs-const.cmake | 34 ++++++------- cmake/cppargs-options.cmake | 18 +++---- cmake/cppargs-var.cmake | 48 ++++++++++-------- cmake/modules | 2 +- src/CMakeLists.txt | 48 +++++++++--------- test/CMakeLists.txt | 87 +++++++++++++++++--------------- 10 files changed, 179 insertions(+), 165 deletions(-) create mode 100644 README.md create mode 100644 TODO diff --git a/.gitmodules b/.gitmodules index 148f1e8..37e8830 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "cmake/modules"] path = cmake/modules - url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git -[submodule "/home/bergmann/projects/TotoStarOnline/projects/worker/cppargs/cmake/modules"] - path = /home/bergmann/projects/TotoStarOnline/projects/worker/cppargs/cmake/modules - url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git + url = b3rgmann@git.bergmann89.de:cpp/CMakeModules.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 786ab24..c2130e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,63 +1,63 @@ # Initialize CMake ################################################################################ -CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) +CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) # Set CMAKE_BUILD_TYPE -If ( NOT CMAKE_BUILD_TYPE ) - Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) -EndIf ( NOT CMAKE_BUILD_TYPE ) -Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) +If ( NOT CMAKE_BUILD_TYPE ) + Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) +EndIf ( NOT CMAKE_BUILD_TYPE ) +Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) # Set CMAKE_MODULE_PATH -If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) - Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) -EndIf ( ) -If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) - Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) -EndIf ( ) +If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) + Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) +EndIf ( ) +If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/cmake" ) + Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/cmake" ) +EndIf ( ) # Project ######################################################################################### -Include ( CTest ) -Include ( GNUInstallDirs ) -Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-options.cmake ) -Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-const.cmake ) -Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-var.cmake ) -Project ( ${CPPARGS_PROJECT_NAME} - DESCRIPTION "${CPPARGS_PROJECT_DESCRIPTION}" - VERSION "${CPPARGS_VERSION}" ) +Include ( GNUInstallDirs ) +Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-options.cmake ) +Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-const.cmake ) +Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-var.cmake ) +Project ( ${CPPARGS_PROJECT_NAME} + DESCRIPTION "${CPPARGS_PROJECT_DESCRIPTION}" + VERSION "${CPPARGS_VERSION}" ) +Include ( CTest ) # Subdirectories -Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) -Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) +Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) # Install -If ( NOT CPPARGS_HAS_EXPORT - OR NOT CPPARGS_INSTALL_PACKAGE ) - Return ( ) -EndIf ( ) - -Include ( CMakePackageConfigHelpers ) -Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config-version.cmake" - VERSION ${CPPARGS_VERSION} - COMPATIBILITY AnyNewerVersion ) -Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config.cmake" - @ONLY ) - -Set ( ConfigPackageLocation "${CPPARGS_INSTALL_DIR_SHARE}/cmake" ) -Install ( EXPORT - cppargs - NAMESPACE - cppargs:: - DESTINATION - ${ConfigPackageLocation} ) -Install ( FILES +If ( NOT CPPARGS_HAS_EXPORT + OR NOT CPPARGS_INSTALL_PACKAGE ) + Return ( ) +EndIf ( ) + +Include ( CMakePackageConfigHelpers ) +Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config-version.cmake" + VERSION ${CPPARGS_VERSION} + COMPATIBILITY AnyNewerVersion ) +Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppargs-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config-version.cmake" - DESTINATION - ${ConfigPackageLocation} - COMPONENT - Devel ) + @ONLY ) + +Set ( ConfigPackageLocation "${CPPARGS_INSTALL_DIR_SHARE}/cmake" ) +Install ( EXPORT + cppargs + NAMESPACE + cppargs:: + DESTINATION + ${ConfigPackageLocation} ) +Install ( FILES + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppargs-config-version.cmake" + DESTINATION + ${ConfigPackageLocation} + COMPONENT + Devel ) diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4e25d2 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# cppargs + +Library to parse command line arguments. diff --git a/TODO b/TODO new file mode 100644 index 0000000..1eacccc --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +- Refactor this project and use cpprtti instand of custom implementation diff --git a/cmake/cppargs-const.cmake b/cmake/cppargs-const.cmake index b733576..464b711 100644 --- a/cmake/cppargs-const.cmake +++ b/cmake/cppargs-const.cmake @@ -1,28 +1,28 @@ # This file contains constant variables that are fixed to this project # Version -Set ( CPPARGS_VERSION_MAJOR 1 ) -Set ( CPPARGS_VERSION_MINOR 0 ) -Set ( CPPARGS_VERSION_PATCH 0 ) -Set ( CPPARGS_VERSION_BUILD 0 ) -Set ( CPPARGS_VERSION_HASH "" ) -Set ( CPPARGS_VERSION_BEHIND 0 ) -Set ( CPPARGS_VERSION_DIRTY 0 ) +Set ( CPPARGS_VERSION_MAJOR 1 ) +Set ( CPPARGS_VERSION_MINOR 0 ) +Set ( CPPARGS_VERSION_PATCH 0 ) +Set ( CPPARGS_VERSION_BUILD 0 ) +Set ( CPPARGS_VERSION_HASH "" ) +Set ( CPPARGS_VERSION_BEHIND 0 ) +Set ( CPPARGS_VERSION_DIRTY 0 ) # Names -Set ( CPPARGS_PROJECT_NAME "cppargs" ) -Set ( CPPARGS_PROJECT_DESCRIPTION "Library to parse command line arguments." ) +Set ( CPPARGS_PROJECT_NAME "cppargs" ) +Set ( CPPARGS_PROJECT_DESCRIPTION "Library to parse command line arguments." ) # Include generated variables for further usage -Include ( ${CMAKE_CURRENT_LIST_DIR}/cppargs-var.cmake ) +Include ( ${CMAKE_CURRENT_LIST_DIR}/cppargs-var.cmake ) # Install directories -Set ( CPPARGS_INSTALL_DIR_INCLUDE "${CMAKE_INSTALL_INCLUDEDIR}/${CPPARGS_NAME}" ) -Set ( CPPARGS_INSTALL_DIR_LIB "${CMAKE_INSTALL_LIBDIR}" ) -Set ( CPPARGS_INSTALL_DIR_SHARE "${CMAKE_INSTALL_DATAROOTDIR}/${CPPARGS_NAME}" ) +Set ( CPPARGS_INSTALL_DIR_INCLUDE "${CMAKE_INSTALL_INCLUDEDIR}/${CPPARGS_NAME}" ) +Set ( CPPARGS_INSTALL_DIR_LIB "${CMAKE_INSTALL_LIBDIR}" ) +Set ( CPPARGS_INSTALL_DIR_SHARE "${CMAKE_INSTALL_DATAROOTDIR}/${CPPARGS_NAME}" ) # C Standard -Set ( CMAKE_C_STANDARD 11 ) -Set ( CMAKE_CXX_STANDARD 17 ) -Set ( CMAKE_C_STANDARD_REQUIRED ON ) -Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) +Set ( CMAKE_C_STANDARD 11 ) +Set ( CMAKE_CXX_STANDARD 17 ) +Set ( CMAKE_C_STANDARD_REQUIRED ON ) +Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) diff --git a/cmake/cppargs-options.cmake b/cmake/cppargs-options.cmake index 6e73193..5f4748b 100644 --- a/cmake/cppargs-options.cmake +++ b/cmake/cppargs-options.cmake @@ -1,11 +1,11 @@ # This file contains options that can be passed to the cmake command -Option ( CPPARGS_INSTALL_HEADER - "Install headers of cppargs." - ON ) -Option ( CPPARGS_INSTALL_PACKAGE - "Install the cmake package of cppargs." - ON ) -Option ( CPPARGS_USE_GIT_VERSION - "Read the git tags to get the version of cppargs" - ON ) +Option ( CPPARGS_INSTALL_HEADER + "Install headers of cppargs." + ON ) +Option ( CPPARGS_INSTALL_PACKAGE + "Install the cmake package of cppargs." + ON ) +Option ( CPPARGS_USE_GIT_VERSION + "Read the git tags to get the version of cppargs" + ON ) diff --git a/cmake/cppargs-var.cmake b/cmake/cppargs-var.cmake index d2b5fe9..db2cfa9 100644 --- a/cmake/cppargs-var.cmake +++ b/cmake/cppargs-var.cmake @@ -1,26 +1,32 @@ # This file contains generated variables that are needed for the project # Git Version -If ( CPPARGS_USE_GIT_VERSION ) - Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) - If ( HAS_GIT_HELPER ) - GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. - CPPARGS_VERSION_MAJOR - CPPARGS_VERSION_MINOR - CPPARGS_VERSION_PATCH - CPPARGS_VERSION_BUILD - CPPARGS_VERSION_HASH - CPPARGS_VERSION_BEHIND - CPPARGS_VERSION_DIRTY ) - EndIf ( ) -EndIf ( ) +If ( CPPARGS_USE_GIT_VERSION ) + Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) + If ( HAS_GIT_HELPER ) + GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. + CPPARGS_VERSION_MAJOR + CPPARGS_VERSION_MINOR + CPPARGS_VERSION_PATCH + CPPARGS_VERSION_BUILD + CPPARGS_VERSION_HASH + CPPARGS_VERSION_BEHIND + CPPARGS_VERSION_DIRTY ) + EndIf ( ) +EndIf ( ) # Strings -Set ( CPPARGS_VERSION_SHORT "${CPPARGS_VERSION_MAJOR}.${CPPARGS_VERSION_MINOR}" ) -Set ( CPPARGS_VERSION "${CPPARGS_VERSION_SHORT}.${CPPARGS_VERSION_PATCH}.${CPPARGS_VERSION_BUILD}" ) -Set ( CPPARGS_VERSION_COMPLETE "${CPPARGS_VERSION}" ) -Set ( CPPARGS_NAME "${CPPARGS_PROJECT_NAME}-${CPPARGS_VERSION_SHORT}" ) -Set ( CPPARGS_OUTPUTNAME "${CPPARGS_PROJECT_NAME}" ) -If ( CPPARGS_VERSION_BEHIND ) - Set ( CPPARGS_VERSION_COMPLETE "${CPPARGS_VERSION_COMPLETE}+${CPPARGS_VERSION_BEHIND}" ) -EndIf ( ) +Set ( CPPARGS_VERSION_SHORT + "${CPPARGS_VERSION_MAJOR}.${CPPARGS_VERSION_MINOR}" ) +Set ( CPPARGS_VERSION + "${CPPARGS_VERSION_SHORT}.${CPPARGS_VERSION_PATCH}.${CPPARGS_VERSION_BUILD}" ) +Set ( CPPARGS_VERSION_COMPLETE + "${CPPARGS_VERSION}" ) +Set ( CPPARGS_NAME + "${CPPARGS_PROJECT_NAME}-${CPPARGS_VERSION_SHORT}" ) +Set ( CPPARGS_OUTPUTNAME + "${CPPARGS_PROJECT_NAME}" ) +If ( CPPARGS_VERSION_BEHIND ) + Set ( CPPARGS_VERSION_COMPLETE + "${CPPARGS_VERSION_COMPLETE}+${CPPARGS_VERSION_BEHIND}" ) +EndIf ( ) diff --git a/cmake/modules b/cmake/modules index ebbae4f..94b9877 160000 --- a/cmake/modules +++ b/cmake/modules @@ -1 +1 @@ -Subproject commit ebbae4fbb42d671331b4c6e9d1d142f41dcacc1b +Subproject commit 94b9877d65e46c9d8169ebc46f163d02e4d9dcf3 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2625430..f4f2dd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,35 +1,35 @@ # Initialize ###################################################################################### -Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) -Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) -Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) +Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) +Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) +Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) -Find_Package ( cppcore REQUIRED ) +Find_Package ( cppcore REQUIRED ) # Interface Library ############################################################################### -Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) -Add_Library ( cppargs INTERFACE ) -Target_Include_Directories ( cppargs - INTERFACE - $ - $ ) -Target_Link_Libraries ( cppargs - INTERFACE - cppcore::cppcore ) +Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) +Add_Library ( cppargs INTERFACE ) +Target_Include_Directories ( cppargs + INTERFACE + $ + $ ) +Target_Link_Libraries ( cppargs + INTERFACE + cppcore::cppcore ) # Install ######################################################################################### -Set ( CPPARGS_HAS_EXPORT False PARENT_SCOPE ) +Set ( CPPARGS_HAS_EXPORT False PARENT_SCOPE ) # Header -If ( CPPARGS_INSTALL_HEADER ) - Set ( CPPARGS_HAS_EXPORT True PARENT_SCOPE ) - Install ( FILES ${CPPARGS_INCLUDE_DIR}/cppargs.h - DESTINATION ${CPPARGS_INSTALL_DIR_INCLUDE} ) - Install ( DIRECTORY ${CPPARGS_INCLUDE_DIR}/cppargs - DESTINATION ${CPPARGS_INSTALL_DIR_INCLUDE} ) - Install ( TARGETS cppargs - EXPORT cppargs - DESTINATION ${CPPCORE_INSTALL_DIR_INCLUDE} ) -EndIf ( ) +If ( CPPARGS_INSTALL_HEADER ) + Set ( CPPARGS_HAS_EXPORT True PARENT_SCOPE ) + Install ( FILES ${CPPARGS_INCLUDE_DIR}/cppargs.h + DESTINATION ${CPPARGS_INSTALL_DIR_INCLUDE} ) + Install ( DIRECTORY ${CPPARGS_INCLUDE_DIR}/cppargs + DESTINATION ${CPPARGS_INSTALL_DIR_INCLUDE} ) + Install ( TARGETS cppargs + EXPORT cppargs + DESTINATION ${CPPARGS_INSTALL_DIR_INCLUDE} ) +EndIf ( ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4d8cc88..03eb680 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,52 +1,59 @@ # Initialize ###################################################################################### -Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) -Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) -Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) +Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) +Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) +Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) + +Find_Package ( Sanitizers QUIET ) # Test ############################################################################################ -Find_Package ( GTest ) -If ( NOT "${GTest_FOUND}" ) - Return ( ) -EndIf ( ) +Find_Package ( GTest ) +If ( NOT "${GTest_FOUND}" ) + Return ( ) +EndIf ( ) -File ( GLOB_RECURSE CPPARGS_TEST_HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) -File ( GLOB_RECURSE CPPARGS_TEST_INLINE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) -File ( GLOB_RECURSE CPPARGS_TEST_SOURCE_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) +File ( GLOB_RECURSE CPPARGS_TEST_HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) +File ( GLOB_RECURSE CPPARGS_TEST_INLINE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) +File ( GLOB_RECURSE CPPARGS_TEST_SOURCE_FILES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) -ForEach ( FILE IN LISTS CPPARGS_TEST_SOURCE_FILES ) +ForEach ( FILE IN LISTS CPPARGS_TEST_SOURCE_FILES ) # add test - Get_Filename_Component ( TEST_DIR ${FILE} DIRECTORY ) - Get_Filename_Component ( TEST_NAME ${FILE} NAME_WE ) - Set ( TEST_NAME "${TEST_DIR}/${TEST_NAME}" ) - String ( REPLACE "\\" "-" TEST_NAME "${TEST_NAME}" ) - String ( REPLACE "/" "-" TEST_NAME "${TEST_NAME}" ) - String ( REPLACE "_" "-" TEST_NAME "${TEST_NAME}" ) - Set ( TEST_NAME "test-${TEST_NAME}" ) - Add_Executable ( ${TEST_NAME} - EXCLUDE_FROM_ALL - ${CPPARGS_TEST_HEADER_FILES} - ${CPPARGS_TEST_INLINE_FILES} - ${FILE} ) - Target_Link_Libraries ( ${TEST_NAME} - PUBLIC - cppargs - GTest::Main ) + Get_Filename_Component ( TEST_DIR ${FILE} DIRECTORY ) + Get_Filename_Component ( TEST_NAME ${FILE} NAME_WE ) + Set ( TEST_NAME "${TEST_DIR}/${TEST_NAME}" ) + String ( REPLACE "\\" "-" TEST_NAME "${TEST_NAME}" ) + String ( REPLACE "/" "-" TEST_NAME "${TEST_NAME}" ) + String ( REPLACE "_" "-" TEST_NAME "${TEST_NAME}" ) + Set ( TEST_NAME "test-${TEST_NAME}" ) + Add_Executable ( ${TEST_NAME} + EXCLUDE_FROM_ALL + ${CPPARGS_TEST_HEADER_FILES} + ${CPPARGS_TEST_INLINE_FILES} + ${FILE} ) + Target_Link_Libraries ( ${TEST_NAME} + PUBLIC + cppargs + GTest::Main ) + + # Sanitizers + If ( Sanitizers_FOUND ) + Add_Sanitizers ( ${TEST_NAME} ) + EndIf ( ) # pedantic - If ( HAS_PEDANTIC ) - Pedantic_Apply_Flags_Target ( ${TEST_NAME} ALL ) - EndIf ( ) + If ( HAS_PEDANTIC ) + Pedantic_Apply_Flags_Target ( ${TEST_NAME} ALL ) + EndIf ( ) # test - If ( HAS_CMAKE_TESTS ) - Add_CMake_Test ( NAME ${TEST_NAME} TARGET ${TEST_NAME} GROUP cppargs ) - Else ( ) - Add_Test ( NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - EndIf ( ) -EndForEach ( ) + If ( HAS_CMAKE_TESTS ) + Add_CMake_Test ( NAME ${TEST_NAME} TARGET ${TEST_NAME} GROUP cppargs ) + Else ( ) + Add_Test ( NAME ${TEST_NAME} COMMAND ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + EndIf ( ) +EndForEach ( )