diff options
158 files changed, 2179 insertions, 1718 deletions
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst index 4e85d8c..3706153 100644 --- a/Help/command/add_library.rst +++ b/Help/command/add_library.rst @@ -111,9 +111,9 @@ may contain only sources that compile, header files, and other files that would not affect linking of a normal library (e.g. ``.txt``). They may contain custom commands generating such sources, but not ``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries -cannot be linked. Some native build systems may not like targets that -have only object files, so consider adding at least one real source file -to any target that references ``$<TARGET_OBJECTS:objlib>``. +cannot be linked. Some native build systems (such as Xcode) may not like +targets that have only object files, so consider adding at least one real +source file to any target that references ``$<TARGET_OBJECTS:objlib>``. Alias Libraries ^^^^^^^^^^^^^^^ diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst index 871ac4e..61dfc03 100644 --- a/Help/command/enable_language.rst +++ b/Help/command/enable_language.rst @@ -10,7 +10,10 @@ Enable a language (CXX/C/Fortran/etc) This command enables support for the named language in CMake. This is the same as the project command but does not create any of the extra variables that are created by the project command. Example languages -are CXX, C, Fortran. +are ``CXX``, ``C``, ``CUDA``, ``Fortran``, and ``ASM``. + +If enabling ``ASM``, enable it last so that CMake can check whether +compilers for other languages like ``C`` work for assembly too. This command must be called in file scope, not in a function call. Furthermore, it must be called in the highest directory common to all diff --git a/Help/command/project.rst b/Help/command/project.rst index 139f69c..eb185e4 100644 --- a/Help/command/project.rst +++ b/Help/command/project.rst @@ -46,11 +46,15 @@ variable will be set to its argument. The argument must be a string with short description of the project (only a few words). Optionally you can specify which languages your project supports. -Example languages are ``C``, ``CXX`` (i.e. C++), ``Fortran``, etc. +Example languages include ``C``, ``CXX`` (i.e. C++), ``CUDA``, +``Fortran``, and ``ASM``. By default ``C`` and ``CXX`` are enabled if no language options are given. Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages, to skip enabling any languages. +If enabling ``ASM``, list it last so that CMake can check whether +compilers for other languages like ``C`` work for assembly too. + If a variable exists called :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`, the file pointed to by that variable will be included as the last step of the project command. diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index 9fd92ec..694bae5 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -130,6 +130,7 @@ All Modules /module/FindIcotool /module/FindICU /module/FindImageMagick + /module/FindIconv /module/FindIntl /module/FindITK /module/FindJasper diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index c2aef99..28171c6 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -517,9 +517,6 @@ Each target object can have the following keys: with the sysroot path. "fileGroups" contains the source files making up the target. -"crossReferences" - contains the location of the target in the corresponding CMakeLists.txt - file and the locations of the related statements like "target_link_libraries" FileGroups are used to group sources using similar settings together. @@ -545,16 +542,6 @@ Each fileGroup object may contain the following keys: All file paths in the fileGroup are either absolute or relative to the sourceDirectory of the target. -CrossReferences object is used to report the location of the target (including -the entire call stack if the target is defined in a function) and the related -"target_link_libraries", "target_include_directories", "target_compile_definitions" -and "target_compile_options" statements. - -See the example below for details on the internal format of the "crossReferences" object. -Line numbers stated in the "backtrace" entries are 1-based. The last entry of a backtrace -is a special entry with missing "line" and "name" fields that specifies the initial -CMakeLists.txt file. - Example:: [== "CMake Server" ==[ @@ -591,34 +578,7 @@ CMake will reply:: "linkerLanguage": "C", "name": "cmForm", "sourceDirectory": "/home/code/src/cmake/Source/CursesDialog/form", - "type": "STATIC_LIBRARY", - "crossReferences": { - "backtrace": [ - { - "line": 7, - "name": "add_executable", - "path": "C:/full/path/CMakeLists.txt" - }, - { - "path": "c:/full/path/CMakeLists.txt" - } - ], - "relatedStatements": [ - { - "backtrace": [ - { - "line": 8, - "name": "target_link_libraries", - "path": "c:/full/path/CMakeLists.txt" - }, - { - "path": "c:/full/path/CMakeLists.txt" - } - ], - "type": "target_link_libraries" - } - ] - } + "type": "STATIC_LIBRARY" } ] }, @@ -669,17 +629,6 @@ Each test object can have the following keys: contains the test command. "properties" contains a list of test property objects. -"backtrace" - contains a list of backtrace objects that specify where the test was defined. - -Each backtrace object can have the following keys: - -"path" - contains the full path to the file containing the statement. -"line" - contains the line number in the file where the statement was defined. -"name" - contains the name of the statement that added the test. Each test property object can have the following keys: diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 1dce3e0..735b93b 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -50,6 +50,7 @@ Variables that Provide Information /variable/CMAKE_IMPORT_LIBRARY_SUFFIX /variable/CMAKE_JOB_POOL_COMPILE /variable/CMAKE_JOB_POOL_LINK + /variable/CMAKE_JOB_POOLS /variable/CMAKE_LANG_COMPILER_AR /variable/CMAKE_LANG_COMPILER_RANLIB /variable/CMAKE_LINK_LIBRARY_SUFFIX diff --git a/Help/module/FindIconv.rst b/Help/module/FindIconv.rst new file mode 100644 index 0000000..c1f3ed0 --- /dev/null +++ b/Help/module/FindIconv.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/FindIconv.cmake diff --git a/Help/prop_gbl/JOB_POOLS.rst b/Help/prop_gbl/JOB_POOLS.rst index 2ce74b8..b904f7a 100644 --- a/Help/prop_gbl/JOB_POOLS.rst +++ b/Help/prop_gbl/JOB_POOLS.rst @@ -19,5 +19,8 @@ Defined pools could be used globally by setting or per target by setting the target properties :prop_tgt:`JOB_POOL_COMPILE` and :prop_tgt:`JOB_POOL_LINK`. +If not set, this property uses the value of the :variable:`CMAKE_JOB_POOLS` +variable. + Build targets provided by CMake that are meant for individual interactive use, such as ``install``, are placed in the ``console`` pool automatically. diff --git a/Help/prop_sf/COMPILE_DEFINITIONS.rst b/Help/prop_sf/COMPILE_DEFINITIONS.rst index 1626825..8d2108c 100644 --- a/Help/prop_sf/COMPILE_DEFINITIONS.rst +++ b/Help/prop_sf/COMPILE_DEFINITIONS.rst @@ -17,3 +17,13 @@ by the native build tool. Xcode does not support per-configuration definitions on source files. .. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt + +Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions" +with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` +manual for available expressions. However, :generator:`Xcode` +does not support per-config per-source settings, so expressions +that depend on the build configuration are not allowed with that +generator. + +Generator expressions should be preferred instead of setting the alternative per-configuration +property. diff --git a/Help/release/3.10.rst b/Help/release/3.10.rst index 35fe602..6a19dbf 100644 --- a/Help/release/3.10.rst +++ b/Help/release/3.10.rst @@ -255,3 +255,15 @@ Other Changes incompatible with the old behavior, it is expected that behavior under typical use cases with properly-quoted command-lines has not changed. + +Updates +======= + +Changes made since CMake 3.10.0 include the following. + +3.10.1 +------ + +* The :manual:`cmake-server(7)` ``codemodel`` response ``crossReferences`` + field added by 3.10.0 has been dropped due to excessive memory usage. + Another approach will be needed to provide backtrace information. diff --git a/Help/release/dev/FindIconv.rst b/Help/release/dev/FindIconv.rst new file mode 100644 index 0000000..98f2591 --- /dev/null +++ b/Help/release/dev/FindIconv.rst @@ -0,0 +1,4 @@ +FindIconv +--------- + +* A :module:`FindIconv` module was added to locate iconv support. diff --git a/Help/release/dev/cmake-job-pool.rst b/Help/release/dev/cmake-job-pool.rst new file mode 100644 index 0000000..836d9c1 --- /dev/null +++ b/Help/release/dev/cmake-job-pool.rst @@ -0,0 +1,7 @@ +cmake-job-pool +-------------- + +* A :variable:`CMAKE_JOB_POOLS` variable was added specify a value to use for + the :prop_gbl:`JOB_POOLS` property. This enables control over build + parallelism with command line configuration parameters when using the Ninja + generator. diff --git a/Help/release/dev/src-COMPILE_DEFINITIONS-genex.rst b/Help/release/dev/src-COMPILE_DEFINITIONS-genex.rst new file mode 100644 index 0000000..892344f --- /dev/null +++ b/Help/release/dev/src-COMPILE_DEFINITIONS-genex.rst @@ -0,0 +1,5 @@ +src-COMPILE_DEFINITIONS-genex +----------------------------- + +* The :prop_sf:`COMPILE_DEFINITIONS` source file property learned to support + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/release/dev/whitelist-more-interface-properties.rst b/Help/release/dev/whitelist-more-interface-properties.rst new file mode 100644 index 0000000..793361c --- /dev/null +++ b/Help/release/dev/whitelist-more-interface-properties.rst @@ -0,0 +1,7 @@ +whitelist-more-interface-properties +----------------------------------- + +* ``INTERFACE`` libraries may now have custom properties set on them if they + start with either an underscore (``_``) or a lowercase ASCII character. The + original intention was to only allow properties which made sense for + ``INTERFACE`` libraries, but it also blocked usage of custom properties. diff --git a/Help/variable/CMAKE_JOB_POOLS.rst b/Help/variable/CMAKE_JOB_POOLS.rst new file mode 100644 index 0000000..72b50b4 --- /dev/null +++ b/Help/variable/CMAKE_JOB_POOLS.rst @@ -0,0 +1,6 @@ +CMAKE_JOB_POOLS +--------------- + +If the :prop_gbl:`JOB_POOLS` global property is not set, the value +of this variable is used in its place. See :prop_gbl:`JOB_POOLS` +for additional information. diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake index f7cf54a..ed8f598 100644 --- a/Modules/CMakeDetermineASMCompiler.cmake +++ b/Modules/CMakeDetermineASMCompiler.cmake @@ -163,8 +163,8 @@ if (NOT _CMAKE_TOOLCHAIN_PREFIX) endif () -include(CMakeFindBinUtils) set(_CMAKE_PROCESSING_LANGUAGE "ASM") +include(CMakeFindBinUtils) include(Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-FindBinUtils OPTIONAL) unset(_CMAKE_PROCESSING_LANGUAGE) diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake index 4e56ce1..7e6ca1e 100644 --- a/Modules/CMakeDetermineCCompiler.cmake +++ b/Modules/CMakeDetermineCCompiler.cmake @@ -166,8 +166,8 @@ if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) endif () -include(CMakeFindBinUtils) set(_CMAKE_PROCESSING_LANGUAGE "C") +include(CMakeFindBinUtils) include(Compiler/${CMAKE_C_COMPILER_ID}-FindBinUtils OPTIONAL) unset(_CMAKE_PROCESSING_LANGUAGE) diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index c9cd7e2..f5a3ebd 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -73,7 +73,10 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN) CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu) endif() +set(_CMAKE_PROCESSING_LANGUAGE "CUDA") include(CMakeFindBinUtils) +unset(_CMAKE_PROCESSING_LANGUAGE) + if(MSVC_CUDA_ARCHITECTURE_ID) set(SET_MSVC_CUDA_ARCHITECTURE_ID "set(MSVC_CUDA_ARCHITECTURE_ID ${MSVC_CUDA_ARCHITECTURE_ID})") diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake index 4541844..c0fb3b6 100644 --- a/Modules/CMakeDetermineCXXCompiler.cmake +++ b/Modules/CMakeDetermineCXXCompiler.cmake @@ -164,8 +164,8 @@ if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) endif () -include(CMakeFindBinUtils) set(_CMAKE_PROCESSING_LANGUAGE "CXX") +include(CMakeFindBinUtils) include(Compiler/${CMAKE_CXX_COMPILER_ID}-FindBinUtils OPTIONAL) unset(_CMAKE_PROCESSING_LANGUAGE) diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake index 2549c22..cf502f6 100644 --- a/Modules/CMakeDetermineFortranCompiler.cmake +++ b/Modules/CMakeDetermineFortranCompiler.cmake @@ -258,8 +258,8 @@ if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) endif () -include(CMakeFindBinUtils) set(_CMAKE_PROCESSING_LANGUAGE "Fortran") +include(CMakeFindBinUtils) include(Compiler/${CMAKE_Fortran_COMPILER_ID}-FindBinUtils OPTIONAL) unset(_CMAKE_PROCESSING_LANGUAGE) diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake index 2604906..dd02d54 100644 --- a/Modules/CMakeDetermineSwiftCompiler.cmake +++ b/Modules/CMakeDetermineSwiftCompiler.cmake @@ -34,7 +34,9 @@ if (NOT _CMAKE_TOOLCHAIN_LOCATION) get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Swift_COMPILER}" PATH) endif () +set(_CMAKE_PROCESSING_LANGUAGE "Swift") include(CMakeFindBinUtils) +unset(_CMAKE_PROCESSING_LANGUAGE) # configure variables set in this file for fast reload later on configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index e4103d0..ece0547 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -20,16 +20,9 @@ # on UNIX, cygwin and mingw # if it's the MS C/CXX compiler, search for link -if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_Fortran_SIMULATE_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" - OR "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC" - OR (CMAKE_HOST_WIN32 AND ( - "x${CMAKE_C_COMPILER_ID}" STREQUAL "xPGI" - OR "x${CMAKE_Fortran_COMPILER_ID}" STREQUAL "xPGI" - )) +if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" + OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC" + OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI") OR (CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")) diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake index 5a7298b..9d2c74d 100644 --- a/Modules/CheckCCompilerFlag.cmake +++ b/Modules/CheckCCompilerFlag.cmake @@ -32,6 +32,7 @@ effect or even a specific one is beyond the scope of this module. in such variables may cause a false negative for this check. #]=======================================================================] +include_guard(GLOBAL) include(CheckCSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake index 56e68d5..114213a 100644 --- a/Modules/CheckCSourceCompiles.cmake +++ b/Modules/CheckCSourceCompiles.cmake @@ -60,6 +60,7 @@ Check if given C source compiles and links into an executable. #]=======================================================================] +include_guard(GLOBAL) macro(CHECK_C_SOURCE_COMPILES SOURCE VAR) if(NOT DEFINED "${VAR}") diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake index 8da9f1e..fa51346 100644 --- a/Modules/CheckCSourceRuns.cmake +++ b/Modules/CheckCSourceRuns.cmake @@ -60,6 +60,8 @@ subsequently be run. #]=======================================================================] +include_guard(GLOBAL) + macro(CHECK_C_SOURCE_RUNS SOURCE VAR) if(NOT DEFINED "${VAR}") set(MACRO_CHECK_FUNCTION_DEFINITIONS diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake index f731b70..dd60835 100644 --- a/Modules/CheckCXXCompilerFlag.cmake +++ b/Modules/CheckCXXCompilerFlag.cmake @@ -32,6 +32,7 @@ effect or even a specific one is beyond the scope of this module. in such variables may cause a false negative for this check. #]=======================================================================] +include_guard(GLOBAL) include(CheckCXXSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake index 4634a7b..ed8661b 100644 --- a/Modules/CheckCXXSourceCompiles.cmake +++ b/Modules/CheckCXXSourceCompiles.cmake @@ -60,6 +60,8 @@ Check if given C++ source compiles and links into an executable. #]=======================================================================] +include_guard(GLOBAL) + macro(CHECK_CXX_SOURCE_COMPILES SOURCE VAR) if(NOT DEFINED "${VAR}") set(_FAIL_REGEX) diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake index 558708c..83bf2f2 100644 --- a/Modules/CheckCXXSourceRuns.cmake +++ b/Modules/CheckCXXSourceRuns.cmake @@ -60,6 +60,8 @@ subsequently be run. #]=======================================================================] +include_guard(GLOBAL) + macro(CHECK_CXX_SOURCE_RUNS SOURCE VAR) if(NOT DEFINED "${VAR}") set(MACRO_CHECK_FUNCTION_DEFINITIONS diff --git a/Modules/CheckCXXSymbolExists.cmake b/Modules/CheckCXXSymbolExists.cmake index 8552154..117a458 100644 --- a/Modules/CheckCXXSymbolExists.cmake +++ b/Modules/CheckCXXSymbolExists.cmake @@ -32,6 +32,7 @@ # CMAKE_REQUIRED_LIBRARIES = list of libraries to link # CMAKE_REQUIRED_QUIET = execute quietly without messages +include_guard(GLOBAL) include(CheckSymbolExists) macro(CHECK_CXX_SYMBOL_EXISTS SYMBOL FILES VARIABLE) diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake index 8a1a8b9..2cb2532 100644 --- a/Modules/CheckFortranCompilerFlag.cmake +++ b/Modules/CheckFortranCompilerFlag.cmake @@ -32,6 +32,7 @@ effect or even a specific one is beyond the scope of this module. in such variables may cause a false negative for this check. #]=======================================================================] +include_guard(GLOBAL) include(CheckFortranSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) diff --git a/Modules/CheckFortranFunctionExists.cmake b/Modules/CheckFortranFunctionExists.cmake index 5fc740a..f3ced93 100644 --- a/Modules/CheckFortranFunctionExists.cmake +++ b/Modules/CheckFortranFunctionExists.cmake @@ -24,6 +24,8 @@ # # CMAKE_REQUIRED_LIBRARIES = list of libraries to link +include_guard(GLOBAL) + macro(CHECK_FORTRAN_FUNCTION_EXISTS FUNCTION VARIABLE) if(NOT DEFINED ${VARIABLE}) message(STATUS "Looking for Fortran ${FUNCTION}") diff --git a/Modules/CheckFortranSourceCompiles.cmake b/Modules/CheckFortranSourceCompiles.cmake index 4df17e3..d2b0cca 100644 --- a/Modules/CheckFortranSourceCompiles.cmake +++ b/Modules/CheckFortranSourceCompiles.cmake @@ -66,6 +66,7 @@ Check if given Fortran source compiles and links into an executable. #]=======================================================================] +include_guard(GLOBAL) macro(CHECK_Fortran_SOURCE_COMPILES SOURCE VAR) if(NOT DEFINED "${VAR}") diff --git a/Modules/CheckFunctionExists.cmake b/Modules/CheckFunctionExists.cmake index ef08062..d00aa8a 100644 --- a/Modules/CheckFunctionExists.cmake +++ b/Modules/CheckFunctionExists.cmake @@ -38,6 +38,8 @@ # * ``check_function_exists()`` only verifies linking, it does not verify # that the function is declared in system headers. +include_guard(GLOBAL) + macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE) if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") set(MACRO_CHECK_FUNCTION_DEFINITIONS diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake index c566e14..e5554c4 100644 --- a/Modules/CheckIncludeFile.cmake +++ b/Modules/CheckIncludeFile.cmake @@ -34,6 +34,8 @@ # at once. See the :module:`CheckIncludeFileCXX` module to check for headers # using the ``CXX`` language. +include_guard(GLOBAL) + macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE) if(NOT DEFINED "${VARIABLE}") if(CMAKE_REQUIRED_INCLUDES) diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake index 19b1ef6..7948bab 100644 --- a/Modules/CheckIncludeFileCXX.cmake +++ b/Modules/CheckIncludeFileCXX.cmake @@ -33,6 +33,8 @@ # See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFiles` # to check for one or more ``C`` headers. +include_guard(GLOBAL) + macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE) if(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") if(CMAKE_REQUIRED_INCLUDES) diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake index 347231c..59afdab 100644 --- a/Modules/CheckIncludeFiles.cmake +++ b/Modules/CheckIncludeFiles.cmake @@ -39,6 +39,8 @@ # See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFileCXX` # to check for a single header file in ``C`` or ``CXX`` languages. +include_guard(GLOBAL) + macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE) if(NOT DEFINED "${VARIABLE}") set(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n") @@ -60,9 +62,9 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE) endif() if(_lang STREQUAL "C") - set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${var}.c) + set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${VARIABLE}.c) elseif(_lang STREQUAL "CXX") - set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${var}.cpp) + set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckIncludeFiles/${VARIABLE}.cpp) else() message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n") endif() diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake index 70c14d7..ce92bfe 100644 --- a/Modules/CheckLanguage.cmake +++ b/Modules/CheckLanguage.cmake @@ -31,6 +31,8 @@ # message(STATUS "No Fortran support") # endif() +include_guard(GLOBAL) + macro(check_language lang) if(NOT DEFINED CMAKE_${lang}_COMPILER) set(_desc "Looking for a ${lang} compiler") diff --git a/Modules/CheckLibraryExists.cmake b/Modules/CheckLibraryExists.cmake index 528a450..487cc59 100644 --- a/Modules/CheckLibraryExists.cmake +++ b/Modules/CheckLibraryExists.cmake @@ -29,6 +29,8 @@ # CMAKE_REQUIRED_LIBRARIES = list of libraries to link # CMAKE_REQUIRED_QUIET = execute quietly without messages +include_guard(GLOBAL) + macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE) if(NOT DEFINED "${VARIABLE}") set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION diff --git a/Modules/CheckPrototypeDefinition.cmake b/Modules/CheckPrototypeDefinition.cmake index 7859594..ceb4d88 100644 --- a/Modules/CheckPrototypeDefinition.cmake +++ b/Modules/CheckPrototypeDefinition.cmake @@ -41,9 +41,9 @@ # - get_filename_component(__check_proto_def_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +include_guard(GLOBAL) function(CHECK_PROTOTYPE_DEFINITION _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE) diff --git a/Modules/CheckStructHasMember.cmake b/Modules/CheckStructHasMember.cmake index 085b464..8689a5c 100644 --- a/Modules/CheckStructHasMember.cmake +++ b/Modules/CheckStructHasMember.cmake @@ -38,6 +38,7 @@ # Example: CHECK_STRUCT_HAS_MEMBER("struct timeval" tv_sec sys/select.h # HAVE_TIMEVAL_TV_SEC LANGUAGE C) +include_guard(GLOBAL) include(CheckCSourceCompiles) include(CheckCXXSourceCompiles) diff --git a/Modules/CheckSymbolExists.cmake b/Modules/CheckSymbolExists.cmake index 6d52d56..d9c9ae4 100644 --- a/Modules/CheckSymbolExists.cmake +++ b/Modules/CheckSymbolExists.cmake @@ -43,6 +43,8 @@ the way the check is run: execute quietly without messages #]=======================================================================] +include_guard(GLOBAL) + macro(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE) if(CMAKE_C_COMPILER_LOADED) __CHECK_SYMBOL_EXISTS_IMPL("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" "${SYMBOL}" "${FILES}" "${VARIABLE}" ) diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake index fcf1df7..2b5deec 100644 --- a/Modules/CheckTypeSize.cmake +++ b/Modules/CheckTypeSize.cmake @@ -71,11 +71,13 @@ include(CheckIncludeFile) include(CheckIncludeFileCXX) +get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) + +include_guard(GLOBAL) + cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) -get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) - #----------------------------------------------------------------------------- # Helper function. DO NOT CALL DIRECTLY. function(__check_type_size_impl type var map builtin language) diff --git a/Modules/CheckVariableExists.cmake b/Modules/CheckVariableExists.cmake index fd5c36c..ab456d1 100644 --- a/Modules/CheckVariableExists.cmake +++ b/Modules/CheckVariableExists.cmake @@ -32,6 +32,8 @@ # CMAKE_REQUIRED_LIBRARIES = list of libraries to link # CMAKE_REQUIRED_QUIET = execute quietly without messages +include_guard(GLOBAL) + macro(CHECK_VARIABLE_EXISTS VAR VARIABLE) if(NOT DEFINED "${VARIABLE}") set(MACRO_CHECK_VARIABLE_DEFINITIONS diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 9ea8136..04b5cf9 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -1755,7 +1755,7 @@ function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file cuda_target options add_custom_command( OUTPUT ${output_file} DEPENDS ${object_files} - COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} -dlink ${object_files} -o ${output_file} + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} -dlink ${object_files} ${CUDA_cublas_device_LIBRARY} -o ${output_file} ${flags} COMMENT "Building NVCC intermediate link file ${output_file_relative_path}" COMMAND_EXPAND_LISTS @@ -1768,7 +1768,7 @@ function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file cuda_target options PRE_LINK COMMAND ${CMAKE_COMMAND} -E echo "Building NVCC intermediate link file ${output_file_relative_path}" COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}" - COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} ${flags} -dlink ${object_files} -o "${output_file}" + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} ${flags} -dlink ${object_files} ${CUDA_cublas_device_LIBRARY} -o "${output_file}" COMMAND_EXPAND_LISTS ${_verbatim} ) diff --git a/Modules/FindIconv.cmake b/Modules/FindIconv.cmake new file mode 100644 index 0000000..bf20f6f --- /dev/null +++ b/Modules/FindIconv.cmake @@ -0,0 +1,133 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindIconv +--------- + +This module finds the ``iconv()`` POSIX.1 functions on the system. +These functions might be provided in the regular C library or externally +in the form of an additional library. + +The following variables are provided to indicate iconv support: + +.. variable:: Iconv_FOUND + + Variable indicating if the iconv support was found. + +.. variable:: Iconv_INCLUDE_DIRS + + The directories containing the iconv headers. + +.. variable:: Iconv_LIBRARIES + + The iconv libraries to be linked. + +.. variable:: Iconv_IS_BUILT_IN + + A variable indicating whether iconv support is stemming from the + C library or not. Even if the C library provides `iconv()`, the presence of + an external `libiconv` implementation might lead to this being false. + +Additionally, the following :prop_tgt:`IMPORTED` target is being provided: + +.. variable:: Iconv::Iconv + + Imported target for using iconv. + +The following cache variables may also be set: + +.. variable:: Iconv_INCLUDE_DIR + + The directory containing the iconv headers. + +.. variable:: Iconv_LIBRARY + + The iconv library (if not implicitly given in the C library). + +.. note:: + On POSIX platforms, iconv might be part of the C library and the cache + variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty. + +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake) +if(CMAKE_C_COMPILER_LOADED) + include(${CMAKE_CURRENT_LIST_DIR}/CheckCSourceCompiles.cmake) +elseif(CMAKE_CXX_COMPILER_LOADED) + include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSourceCompiles.cmake) +else() + # If neither C nor CXX are loaded, implicit iconv makes no sense. + set(Iconv_IS_BUILT_IN FALSE) +endif() + +# iconv can only be provided in libc on a POSIX system. +# If any cache variable is already set, we'll skip this test. +if(NOT DEFINED Iconv_IS_BUILT_IN) + if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY) + cmake_push_check_state(RESET) + # We always suppress the message here: Otherwise on supported systems + # not having iconv in their C library (e.g. those using libiconv) + # would always display a confusing "Looking for iconv - not found" message + set(CMAKE_FIND_QUIETLY TRUE) + # The following code will not work, but it's sufficient to see if it compiles. + # Note: libiconv will define the iconv functions as macros, so CheckSymbolExists + # will not yield correct results. + set(Iconv_IMPLICIT_TEST_CODE + " + #include <stddef.h> + #include <iconv.h> + int main() { + char *a, *b; + size_t i, j; + iconv_t ic; + ic = iconv_open(\"to\", \"from\"); + iconv(ic, &a, &i, &b, &j); + iconv_close(ic); + } + " + ) + if(CMAKE_C_COMPILER_LOADED) + check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + else() + check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + endif() + cmake_pop_check_state() + else() + set(Iconv_IS_BUILT_IN FALSE) + endif() +endif() + +if(NOT Iconv_IS_BUILT_IN) + find_path(Iconv_INCLUDE_DIR + NAMES "iconv.h" + DOC "iconv include directory") + set(Iconv_LIBRARY_NAMES "iconv" "libiconv") +else() + set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory") + set(Iconv_LIBRARY_NAMES "c") +endif() + +find_library(Iconv_LIBRARY + NAMES ${Iconv_LIBRARY_NAMES} + DOC "iconv library (potentially the C library)") + +mark_as_advanced(Iconv_INCLUDE_DIR) +mark_as_advanced(Iconv_LIBRARY) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +if(NOT Iconv_IS_BUILT_IN) + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR) +else() + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY) +endif() + +if(Iconv_FOUND) + set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}") + set(Iconv_LIBRARIES "${Iconv_LIBRARY}") + if(NOT TARGET Iconv::Iconv) + add_library(Iconv::Iconv INTERFACE IMPORTED) + endif() + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}") + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}") +endif() diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake index 3320a07..4d9444a 100644 --- a/Modules/FindMPI.cmake +++ b/Modules/FindMPI.cmake @@ -602,6 +602,9 @@ function (_MPI_interrogate_compiler lang) if(MPI_DIRECT_LIB_NAMES_WORK) set(MPI_PLAIN_LIB_NAMES_WORK "${MPI_DIRECT_LIB_NAMES_WORK};${MPI_PLAIN_LIB_NAMES_WORK}") endif() + if(MPI_${LANG}_EXTRA_LIB_NAMES) + list(APPEND MPI_PLAIN_LIB_NAMES_WORK "${MPI_${LANG}_EXTRA_LIB_NAMES}") + endif() # MPI might require pthread to work. The above mechanism wouldn't detect it, but we need to # link it in that case. -lpthread is covered by the normal library treatment on the other hand. @@ -1076,18 +1079,21 @@ foreach (LANG IN ITEMS C CXX) endif() # If a list of libraries was given, we'll split it into new-style cache variables + unset(MPI_${LANG}_EXTRA_LIB_NAMES) if(NOT MPI_${LANG}_LIB_NAMES) foreach(_MPI_LIB IN LISTS MPI_${LANG}_LIBRARIES MPI_LIBRARY MPI_EXTRA_LIBRARY) - get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB}" NAME_WE) - get_filename_component(_MPI_LIB_NAME "${_MPI_LIB}" NAME) - get_filename_component(_MPI_LIB_DIR "${_MPI_LIB}" DIRECTORY) - list(APPEND MPI_PLAIN_LIB_NAMES_WORK "${_MPI_PLAIN_LIB_NAME}") - find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY - NAMES "${_MPI_LIB_NAME}" "lib${_MPI_LIB_NAME}" - HINTS ${_MPI_LIB_DIR} $ENV{MPI_LIB} - DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI" - ) - mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY) + if(_MPI_LIB) + get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB}" NAME_WE) + get_filename_component(_MPI_LIB_NAME "${_MPI_LIB}" NAME) + get_filename_component(_MPI_LIB_DIR "${_MPI_LIB}" DIRECTORY) + list(APPEND MPI_${LANG}_EXTRA_LIB_NAMES "${_MPI_PLAIN_LIB_NAME}") + find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY + NAMES "${_MPI_LIB_NAME}" "lib${_MPI_LIB_NAME}" + HINTS ${_MPI_LIB_DIR} $ENV{MPI_LIB} + DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI" + ) + mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY) + endif() endforeach() endif() endforeach() @@ -1336,7 +1342,7 @@ foreach(LANG IN ITEMS C CXX Fortran) set(MPI_${LANG}_FIND_VERSION_EXACT ${MPI_FIND_VERSION_EXACT}) unset(MPI_${LANG}_REQUIRED_VARS) - if (MPI_${LANG}_WRAPPER_FOUND OR MPI_${LANG}_GUESS_FOUND) + if (NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}") foreach(mpilibname IN LISTS MPI_${LANG}_LIB_NAMES) list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${mpilibname}_LIBRARY") endforeach() diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake index 5d79110..297a5fb 100644 --- a/Modules/FindOpenCL.cmake +++ b/Modules/FindOpenCL.cmake @@ -76,6 +76,7 @@ find_path(OpenCL_INCLUDE_DIR ENV NVSDKCOMPUTE_ROOT ENV CUDA_PATH ENV ATISTREAMSDKROOT + ENV OCL_ROOT PATH_SUFFIXES include OpenCL/common/inc @@ -94,6 +95,7 @@ if(WIN32) ENV CUDA_PATH ENV NVSDKCOMPUTE_ROOT ENV ATISTREAMSDKROOT + ENV OCL_ROOT PATH_SUFFIXES "AMD APP/lib/x86" lib/x86 @@ -109,6 +111,7 @@ if(WIN32) ENV CUDA_PATH ENV NVSDKCOMPUTE_ROOT ENV ATISTREAMSDKROOT + ENV OCL_ROOT PATH_SUFFIXES "AMD APP/lib/x86_64" lib/x86_64 diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake index 3d47367..c525101 100644 --- a/Modules/GoogleTest.cmake +++ b/Modules/GoogleTest.cmake @@ -217,6 +217,14 @@ same as the Google Test name (i.e. ``suite.testcase``); see also executable is being used in multiple calls to ``gtest_discover_tests()``. Note that this variable is only available in CTest. + ``TIMEOUT num`` + Specifies how long (in seconds) CMake will wait for the test to enumerate + available tests. If the test takes longer than this, discovery (and your + build) will fail. Most test executables will enumerate their tests very + quickly, but under some exceptional circumstances, a test may require a + longer timeout. The default is 5. See also the ``TIMEOUT`` option of + :command:`execute_process`. + #]=======================================================================] #------------------------------------------------------------------------------ @@ -349,7 +357,7 @@ function(gtest_discover_tests TARGET) cmake_parse_arguments( "" "NO_PRETTY_TYPES;NO_PRETTY_VALUES" - "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST" + "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;TIMEOUT" "EXTRA_ARGS;PROPERTIES" ${ARGN} ) @@ -360,6 +368,9 @@ function(gtest_discover_tests TARGET) if(NOT _TEST_LIST) set(_TEST_LIST ${TARGET}_TESTS) endif() + if(NOT _TIMEOUT) + set(_TIMEOUT 5) + endif() get_property( has_counter @@ -407,6 +418,7 @@ function(gtest_discover_tests TARGET) -D "NO_PRETTY_VALUES=${_NO_PRETTY_VALUES}" -D "TEST_LIST=${_TEST_LIST}" -D "CTEST_FILE=${ctest_tests_file}" + -D "TEST_DISCOVERY_TIMEOUT=${_TIMEOUT}" -P "${_GOOGLETEST_DISCOVER_TESTS_SCRIPT}" VERBATIM ) diff --git a/Modules/GoogleTestAddTests.cmake b/Modules/GoogleTestAddTests.cmake index 7d0d909..5a4bdca 100644 --- a/Modules/GoogleTestAddTests.cmake +++ b/Modules/GoogleTestAddTests.cmake @@ -24,19 +24,24 @@ endfunction() # Run test executable to get list of available tests if(NOT EXISTS "${TEST_EXECUTABLE}") message(FATAL_ERROR - "Specified test executable '${TEST_EXECUTABLE}' does not exist" + "Specified test executable does not exist.\n" + " Path: '${TEST_EXECUTABLE}'" ) endif() execute_process( COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" --gtest_list_tests + TIMEOUT ${TEST_DISCOVERY_TIMEOUT} OUTPUT_VARIABLE output RESULT_VARIABLE result ) if(NOT ${result} EQUAL 0) + string(REPLACE "\n" "\n " output "${output}") message(FATAL_ERROR - "Error running test executable '${TEST_EXECUTABLE}':\n" + "Error running test executable.\n" + " Path: '${TEST_EXECUTABLE}'\n" " Result: ${result}\n" - " Output: ${output}\n" + " Output:\n" + " ${output}\n" ) endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 33ab093..5611e55 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -348,6 +348,8 @@ set(SRCS cmTestGenerator.cxx cmTestGenerator.h cmUuid.cxx + cmUVHandlePtr.cxx + cmUVHandlePtr.h cmVariableWatch.cxx cmVariableWatch.h cmVersion.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index eca7be2..ae3bb06 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 10) -set(CMake_VERSION_PATCH 20171129) +set(CMake_VERSION_PATCH 20171207) #set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in index f4ca3d5..22b4a36 100644 --- a/Source/CMakeVersion.rc.in +++ b/Source/CMakeVersion.rc.in @@ -1,11 +1,14 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#define VER_FILEVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ -#define VER_FILEVERSION_STR "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@.@CMake_VERSION_PATCH@\0" +#define VER_FILEVERSION @CMake_RCVERSION@ +#define VER_FILEVERSION_STR "@CMake_RCVERSION_STR@\0" -#define VER_PRODUCTVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ -#define VER_PRODUCTVERSION_STR "@CMake_VERSION@\0" +#define VER_PRODUCTVERSION @CMake_RCVERSION@ +#define VER_PRODUCTVERSION_STR "@CMake_RCVERSION_STR@\0" + +/* Version-information resource identifier. */ +#define VS_VERSION_INFO 1 VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index d9218d7..79264ed 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -27,3 +27,13 @@ endif() if(CMake_VERSION_IS_DIRTY) set(CMake_VERSION ${CMake_VERSION}-dirty) endif() + +# Compute the binary version that appears in the RC file. Version +# components in the RC file are 16-bit integers so we may have to +# split the patch component. +if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$") + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMAKE_MATCH_1},${CMAKE_MATCH_2}) +else() + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH}) +endif() +set(CMake_RCVERSION_STR ${CMake_VERSION}) diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx index 4f5b2a0..9ea8540 100644 --- a/Source/CPack/cmCPackPKGGenerator.cxx +++ b/Source/CPack/cmCPackPKGGenerator.cxx @@ -189,7 +189,7 @@ void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component, // This way, selecting C will automatically select everything it depends // on (B and A), while selecting something that depends on C--either D // or E--will automatically cause C to get selected. - std::ostringstream selected("my.choice.selected"); + std::ostringstream selected("my.choice.selected", std::ios_base::ate); std::set<const cmCPackComponent*> visited; AddDependencyAttributes(component, visited, selected); visited.clear(); diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index b603758..672087d 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -337,7 +337,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) } int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr, - remainingTime.count(), nullptr); + remainingTime, nullptr); if (runTestRes != cmsysProcess_State_Exited || retval != 0) { out << "Test command failed: " << testCommand[0] << "\n"; diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index f25c9c3..ef4d3c6 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -17,7 +17,6 @@ #include <set> #include <stdlib.h> #include <string.h> -#include <type_traits> static const char* cmCTestErrorMatches[] = { "^[Bb]us [Ee]rror", @@ -283,7 +282,7 @@ int cmCTestBuildHandler::ProcessHandler() this->Quiet); // do we have time for this - if (this->CTest->GetRemainingTimeAllowed() < 120) { + if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) { return 0; } diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx index ab77986..eb067e5 100644 --- a/Source/CTest/cmCTestConfigureHandler.cxx +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -9,7 +9,6 @@ #include <chrono> #include <ostream> #include <string> -#include <type_traits> cmCTestConfigureHandler::cmCTestConfigureHandler() { @@ -63,8 +62,9 @@ int cmCTestConfigureHandler::ProcessHandler() cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Configure with command: " << cCommand << std::endl, this->Quiet); - res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal, - buildDirectory.c_str(), 0, ofs); + res = this->CTest->RunMakeCommand( + cCommand.c_str(), output, &retVal, buildDirectory.c_str(), + std::chrono::duration<double>::zero(), ofs); if (ofs) { ofs.close(); diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index bbfe9bd..39b90d8 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -11,6 +11,7 @@ #include "cmParseGTMCoverage.h" #include "cmParseJacocoCoverage.h" #include "cmParsePHPCoverage.h" +#include "cmProcess.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" #include "cmXMLWriter.h" @@ -27,7 +28,6 @@ #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <type_traits> #include <utility> class cmMakefile; @@ -41,7 +41,7 @@ public: { this->Process = cmsysProcess_New(); this->PipeState = -1; - this->TimeOut = -1; + this->TimeOut = std::chrono::duration<double>(-1); } ~cmCTestRunProcess() { @@ -65,7 +65,7 @@ public: } } void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; } - void SetTimeout(double t) { this->TimeOut = t; } + void SetTimeout(std::chrono::duration<double> t) { this->TimeOut = t; } bool StartProcess() { std::vector<const char*> args; @@ -80,7 +80,7 @@ public: } cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1); - if (this->TimeOut != -1) { + if (this->TimeOut >= std::chrono::duration<double>::zero()) { cmsysProcess_SetTimeout(this->Process, this->TimeOut); } cmsysProcess_Execute(this->Process); @@ -109,7 +109,7 @@ private: cmsysProcess* Process; std::vector<std::string> CommandLineStrings; std::string WorkingDirectory; - double TimeOut; + std::chrono::duration<double> TimeOut; }; cmCTestCoverageHandler::cmCTestCoverageHandler() @@ -277,7 +277,7 @@ int cmCTestCoverageHandler::ProcessHandler() this->CTest->ClearSubmitFiles(cmCTest::PartCoverage); int error = 0; // do we have time for this - if (this->CTest->GetRemainingTimeAllowed() < 120) { + if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) { return error; } @@ -1023,8 +1023,9 @@ int cmCTestCoverageHandler::HandleGCovCoverage( int retVal = 0; *cont->OFS << "* Run coverage for: " << fileDir << std::endl; *cont->OFS << " Command: " << command << std::endl; - int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal, - tempDir.c_str(), 0 /*this->TimeOut*/); + int res = this->CTest->RunCommand( + covargs, &output, &errors, &retVal, tempDir.c_str(), + std::chrono::duration<double>::zero() /*this->TimeOut*/); *cont->OFS << " Output: " << output << std::endl; *cont->OFS << " Errors: " << errors << std::endl; @@ -1387,8 +1388,9 @@ int cmCTestCoverageHandler::HandleLCovCoverage( int retVal = 0; *cont->OFS << "* Run coverage for: " << fileDir << std::endl; *cont->OFS << " Command: " << command << std::endl; - int res = this->CTest->RunCommand(covargs, &output, &errors, &retVal, - fileDir.c_str(), 0 /*this->TimeOut*/); + int res = this->CTest->RunCommand( + covargs, &output, &errors, &retVal, fileDir.c_str(), + std::chrono::duration<double>::zero() /*this->TimeOut*/); *cont->OFS << " Output: " << output << std::endl; *cont->OFS << " Errors: " << errors << std::endl; diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 2e7874d..57d2489 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -14,7 +14,6 @@ #include <iostream> #include <sstream> #include <string.h> -#include <type_traits> struct CatToErrorType { diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5443494..a056f4b 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -1,5 +1,9 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#ifdef _WIN32 +/* windows.h defines min() and max() macros that interfere. */ +#define NOMINMAX +#endif #include "cmCTestRunTest.h" #include "cmCTest.h" @@ -14,6 +18,7 @@ #include "cmsys/Base64.h" #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" +#include <algorithm> #include <chrono> #include <iomanip> #include <sstream> @@ -26,7 +31,7 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->CTest = handler->CTest; this->TestHandler = handler; this->TestProcess = nullptr; - this->TestResult.ExecutionTime = 0; + this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.ReturnValue = 0; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; this->TestResult.TestCount = 0; @@ -52,7 +57,7 @@ bool cmCTestRunTest::CheckOutput() std::string line; while ((timeout = timeEnd - std::chrono::steady_clock::now(), timeout > std::chrono::seconds(0))) { - int p = this->TestProcess->GetNextOutputLine(line, timeout.count()); + int p = this->TestProcess->GetNextOutputLine(line, timeout); if (p == cmsysProcess_Pipe_None) { // Process has terminated and all output read. return false; @@ -71,7 +76,9 @@ bool cmCTestRunTest::CheckOutput() cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() << ": " << "Test timeout changed to " - << this->TestProperties->AlternateTimeout + << std::chrono::duration_cast<std::chrono::seconds>( + this->TestProperties->AlternateTimeout) + .count() << std::endl); this->TestProcess->ResetStartTime(); this->TestProcess->ChangeTimeout( @@ -259,7 +266,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; char buf[1024]; - sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime()); + sprintf(buf, "%6.2f sec", + double(std::chrono::duration_cast<std::chrono::milliseconds>( + this->TestProcess->GetTotalTime()) + .count()) / + 1000.0); cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n"); if (outputTestErrorsToConsole) { @@ -295,12 +306,16 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) reasonType = "Test Fail Reason"; pass = false; } - double ttime = this->TestProcess->GetTotalTime(); - int hours = static_cast<int>(ttime / (60 * 60)); - int minutes = static_cast<int>(ttime / 60) % 60; - int seconds = static_cast<int>(ttime) % 60; + auto ttime = this->TestProcess->GetTotalTime(); + auto hours = std::chrono::duration_cast<std::chrono::hours>(ttime); + ttime -= hours; + auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ttime); + ttime -= minutes; + auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ttime); char buffer[100]; - sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); + sprintf(buffer, "%02d:%02d:%02d", static_cast<unsigned>(hours.count()), + static_cast<unsigned>(minutes.count()), + static_cast<unsigned>(seconds.count())); *this->TestHandler->LogFile << "----------------------------------------------------------" << std::endl; @@ -380,7 +395,11 @@ void cmCTestRunTest::ComputeWeightedCost() { double prev = static_cast<double>(this->TestProperties->PreviousRuns); double avgcost = static_cast<double>(this->TestProperties->Cost); - double current = this->TestResult.ExecutionTime; + double current = + double(std::chrono::duration_cast<std::chrono::milliseconds>( + this->TestResult.ExecutionTime) + .count()) / + 1000.0; if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) { this->TestProperties->Cost = @@ -418,7 +437,7 @@ bool cmCTestRunTest::StartTest(size_t total) // Return immediately if test is disabled if (this->TestProperties->Disabled) { this->TestResult.Properties = this->TestProperties; - this->TestResult.ExecutionTime = 0; + this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; this->TestResult.CompletionStatus = "Disabled"; @@ -433,7 +452,7 @@ bool cmCTestRunTest::StartTest(size_t total) } this->TestResult.Properties = this->TestProperties; - this->TestResult.ExecutionTime = 0; + this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; this->TestResult.CompletionStatus = "Failed to start"; @@ -516,7 +535,7 @@ bool cmCTestRunTest::StartTest(size_t total) } this->StartTime = this->CTest->CurrentTime(); - double timeout = this->ResolveTimeout(); + auto timeout = this->ResolveTimeout(); if (this->StopTimePassed) { return false; @@ -597,9 +616,9 @@ void cmCTestRunTest::DartProcessing() } } -double cmCTestRunTest::ResolveTimeout() +std::chrono::duration<double> cmCTestRunTest::ResolveTimeout() { - double timeout = this->TestProperties->Timeout; + auto timeout = this->TestProperties->Timeout; if (this->CTest->GetStopTime().empty()) { return timeout; @@ -629,31 +648,37 @@ double cmCTestRunTest::ResolveTimeout() lctime->tm_mon + 1, lctime->tm_mday, this->CTest->GetStopTime().c_str(), tzone_offset); - time_t stop_time = curl_getdate(buf, ¤t_time); - if (stop_time == -1) { + time_t stop_time_t = curl_getdate(buf, ¤t_time); + if (stop_time_t == -1) { return timeout; } + auto stop_time = std::chrono::system_clock::from_time_t(stop_time_t); + // the stop time refers to the next day if (this->CTest->NextDayStopTime) { - stop_time += 24 * 60 * 60; + stop_time += std::chrono::hours(24); } - int stop_timeout = - static_cast<int>(stop_time - current_time) % (24 * 60 * 60); + auto stop_timeout = + (stop_time - std::chrono::system_clock::from_time_t(current_time)) % + std::chrono::hours(24); this->CTest->LastStopTimeout = stop_timeout; - if (stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout) { + if (stop_timeout <= std::chrono::duration<double>::zero() || + stop_timeout > this->CTest->LastStopTimeout) { cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " "Stopping all tests." << std::endl); this->StopTimePassed = true; - return 0; + return std::chrono::duration<double>::zero(); } - return timeout == 0 ? stop_timeout - : (timeout < stop_timeout ? timeout : stop_timeout); + return timeout == std::chrono::duration<double>::zero() + ? stop_timeout + : (timeout < stop_timeout ? timeout : stop_timeout); } -bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, +bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut, + bool explicitTimeout, std::vector<std::string>* environment) { this->TestProcess = new cmProcess; @@ -664,26 +689,37 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout, this->TestProcess->SetCommandArguments(this->Arguments); // determine how much time we have - double timeout = this->CTest->GetRemainingTimeAllowed() - 120; - if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout) { + std::chrono::duration<double> timeout = + std::min<std::chrono::duration<double>>( + this->CTest->GetRemainingTimeAllowed(), std::chrono::minutes(2)); + if (this->CTest->GetTimeOut() > std::chrono::duration<double>::zero() && + this->CTest->GetTimeOut() < timeout) { timeout = this->CTest->GetTimeOut(); } - if (testTimeOut > 0 && + if (testTimeOut > std::chrono::duration<double>::zero() && testTimeOut < this->CTest->GetRemainingTimeAllowed()) { timeout = testTimeOut; } // always have at least 1 second if we got to here - if (timeout <= 0) { - timeout = 1; + if (timeout <= std::chrono::duration<double>::zero()) { + timeout = std::chrono::seconds(1); } // handle timeout explicitly set to 0 - if (testTimeOut == 0 && explicitTimeout) { - timeout = 0; - } - cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index - << ": " - << "Test timeout computed to be: " << timeout << "\n", - this->TestHandler->GetQuiet()); + if (testTimeOut == std::chrono::duration<double>::zero() && + explicitTimeout) { + timeout = std::chrono::duration<double>::zero(); + } + cmCTestOptionalLog( + this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index + << ": " + << "Test timeout computed to be: " + << (timeout == std::chrono::duration<double>::max() + ? std::string("infinite") + : std::to_string( + std::chrono::duration_cast<std::chrono::seconds>(timeout) + .count())) + << "\n", + this->TestHandler->GetQuiet()); this->TestProcess->SetTimeout(timeout); diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index d3bb229..cd380ca 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <chrono> #include <set> #include <stddef.h> #include <string> @@ -78,8 +79,9 @@ private: void DartProcessing(); void ExeNotFound(std::string exe); // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT) - double ResolveTimeout(); - bool ForkProcess(double testTimeOut, bool explicitTimeout, + std::chrono::duration<double> ResolveTimeout(); + bool ForkProcess(std::chrono::duration<double> testTimeOut, + bool explicitTimeout, std::vector<std::string>* environment); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 3bf27a0..922f5c7 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -1,5 +1,12 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ + +#ifdef _WIN32 +/* windows.h defines min() and max() macros, unless told to otherwise. This + * interferes with std::min() and std::max() at the very least. */ +#define NOMINMAX +#endif + #include "cmCTestScriptHandler.h" #include "cmsys/Directory.hxx" @@ -10,7 +17,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <type_traits> #include <utility> #include "cmCTest.h" @@ -961,21 +967,21 @@ bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce( return cmSystemTools::RemoveADirectory(directoryPath); } -double cmCTestScriptHandler::GetRemainingTimeAllowed() +std::chrono::duration<double> cmCTestScriptHandler::GetRemainingTimeAllowed() { if (!this->Makefile) { - return 1.0e7; + return std::chrono::duration<double>::max(); } const char* timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT"); if (!timelimitS) { - return 1.0e7; + return std::chrono::duration<double>::max(); } auto timelimit = std::chrono::duration<double>(atof(timelimitS)); auto duration = std::chrono::duration_cast<std::chrono::duration<double>>( std::chrono::steady_clock::now() - this->ScriptStartTime); - return (timelimit - duration).count(); + return (timelimit - duration); } diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index 2090d04..9b7fa75 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -94,9 +94,9 @@ public: /** * Return the time remaianing that the script is allowed to run in * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has - * not been set it returns 1e7 seconds + * not been set it returns a very large value. */ - double GetRemainingTimeAllowed(); + std::chrono::duration<double> GetRemainingTimeAllowed(); cmCTestScriptHandler(); ~cmCTestScriptHandler() override; diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index febd39e..232bd58 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -7,6 +7,7 @@ #include "cmMakefile.h" #include "cmSystemTools.h" +#include <chrono> #include <sstream> #include <stdlib.h> #include <vector> @@ -36,14 +37,14 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() const char* ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT"); - double timeout; + std::chrono::duration<double> timeout; if (ctestTimeout) { - timeout = atof(ctestTimeout); + timeout = std::chrono::duration<double>(atof(ctestTimeout)); } else { timeout = this->CTest->GetTimeOut(); - if (timeout <= 0) { + if (timeout <= std::chrono::duration<double>::zero()) { // By default use timeout of 10 minutes - timeout = 600; + timeout = std::chrono::minutes(10); } } this->CTest->SetTimeOut(timeout); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index e7c719c..1e15cc5 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -16,7 +16,6 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#include <type_traits> #include "cmAlgorithms.h" #include "cmCTest.h" @@ -654,7 +653,11 @@ void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject) for (std::string const& l : p.Labels) { // only use labels found in labels if (labels.find(l) != labels.end()) { - labelTimes[l] += result.ExecutionTime * result.Properties->Processors; + labelTimes[l] += + double(std::chrono::duration_cast<std::chrono::milliseconds>( + result.ExecutionTime) + .count()) / + 1000.0 * result.Properties->Processors; ++labelCounts[l]; } } @@ -1240,7 +1243,9 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, p.Cost = static_cast<float>(rand()); } - if (p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0) { + if (p.Timeout == std::chrono::duration<double>::zero() && + this->CTest->GetGlobalTimeout() != + std::chrono::duration<double>::zero()) { p.Timeout = this->CTest->GetGlobalTimeout(); } @@ -1322,7 +1327,11 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.StartElement("NamedMeasurement"); xml.Attribute("type", "numeric/double"); xml.Attribute("name", "Execution Time"); - xml.Element("Value", result.ExecutionTime); + xml.Element("Value", + double(std::chrono::duration_cast<std::chrono::milliseconds>( + result.ExecutionTime) + .count()) / + 1000.0); xml.EndElement(); // NamedMeasurement if (!result.Reason.empty()) { const char* reasonType = "Pass Reason"; @@ -2143,7 +2152,7 @@ bool cmCTestTestHandler::SetTestsProperties( rt.FixturesRequired.insert(lval.begin(), lval.end()); } if (key == "TIMEOUT") { - rt.Timeout = atof(val.c_str()); + rt.Timeout = std::chrono::duration<double>(atof(val.c_str())); rt.ExplicitTimeout = true; } if (key == "COST") { @@ -2223,7 +2232,8 @@ bool cmCTestTestHandler::SetTestsProperties( "TIMEOUT_AFTER_MATCH expects two arguments, found " << propArgs.size() << std::endl); } else { - rt.AlternateTimeout = atof(propArgs[0].c_str()); + rt.AlternateTimeout = + std::chrono::duration<double>(atof(propArgs[0].c_str())); std::vector<std::string> lval; cmSystemTools::ExpandListArgument(propArgs[1], lval); for (std::string const& cr : lval) { @@ -2341,7 +2351,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.WillFail = false; test.Disabled = false; test.RunSerial = false; - test.Timeout = 0; + test.Timeout = std::chrono::duration<double>::zero(); test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 8572e7b..19b345e 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -124,9 +124,9 @@ public: float Cost; int PreviousRuns; bool RunSerial; - double Timeout; + std::chrono::duration<double> Timeout; bool ExplicitTimeout; - double AlternateTimeout; + std::chrono::duration<double> AlternateTimeout; int Index; // Requested number of process slots int Processors; @@ -147,7 +147,7 @@ public: std::string Path; std::string Reason; std::string FullCommandLine; - double ExecutionTime; + std::chrono::duration<double> ExecutionTime; int ReturnValue; int Status; std::string ExceptionStatus; diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index f86d4a3..809abd1 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -20,7 +20,6 @@ #include <chrono> #include <memory> // IWYU pragma: keep #include <sstream> -#include <type_traits> static const char* cmCTestUpdateHandlerUpdateStrings[] = { "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4" diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 78dd598..69ffb33 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -4,13 +4,22 @@ #include "cmProcessOutput.h" #include <iostream> -#include <type_traits> + +void cmsysProcess_SetTimeout(cmsysProcess* process, + std::chrono::duration<double> timeout) +{ + cmsysProcess_SetTimeout( + process, + double( + std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) / + 1000.0); +}; cmProcess::cmProcess() { this->Process = nullptr; - this->Timeout = 0; - this->TotalTime = 0; + this->Timeout = std::chrono::duration<double>::zero(); + this->TotalTime = std::chrono::duration<double>::zero(); this->ExitValue = 0; this->Id = 0; this->StartTime = std::chrono::steady_clock::time_point(); @@ -101,10 +110,15 @@ bool cmProcess::Buffer::GetLast(std::string& line) return false; } -int cmProcess::GetNextOutputLine(std::string& line, double timeout) +int cmProcess::GetNextOutputLine(std::string& line, + std::chrono::duration<double> timeout) { cmProcessOutput processOutput(cmProcessOutput::UTF8); std::string strdata; + double waitTimeout = + double( + std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) / + 1000.0; for (;;) { // Look for lines already buffered. if (this->Output.GetLine(line)) { @@ -114,7 +128,8 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout) // Check for more data from the process. char* data; int length; - int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout); + int p = + cmsysProcess_WaitForData(this->Process, &data, &length, &waitTimeout); if (p == cmsysProcess_Pipe_Timeout) { return cmsysProcess_Pipe_Timeout; } @@ -137,23 +152,19 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout) } // No more data. Wait for process exit. - if (!cmsysProcess_WaitForExit(this->Process, &timeout)) { + if (!cmsysProcess_WaitForExit(this->Process, &waitTimeout)) { return cmsysProcess_Pipe_Timeout; } // Record exit information. this->ExitValue = cmsysProcess_GetExitValue(this->Process); - this->TotalTime = - static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::steady_clock::now() - this->StartTime) - .count()) / - 1000.0; + this->TotalTime = std::chrono::steady_clock::now() - this->StartTime; // Because of a processor clock scew the runtime may become slightly // negative. If someone changed the system clock while the process was // running this may be even more. Make sure not to report a negative // duration here. - if (this->TotalTime <= 0.0) { - this->TotalTime = 0.0; + if (this->TotalTime <= std::chrono::duration<double>::zero()) { + this->TotalTime = std::chrono::duration<double>::zero(); } // std::cerr << "Time to run: " << this->TotalTime << "\n"; return cmsysProcess_Pipe_None; @@ -226,7 +237,7 @@ int cmProcess::ReportStatus() return result; } -void cmProcess::ChangeTimeout(double t) +void cmProcess::ChangeTimeout(std::chrono::duration<double> t) { this->Timeout = t; cmsysProcess_SetTimeout(this->Process, this->Timeout); diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index ddd69b6..cbb611d 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -10,6 +10,13 @@ #include <string> #include <vector> +/* + * A wrapper function for cmsysProcess_SetTimeout that takes an + * std::chrono::duration. For convenience only. + */ +void cmsysProcess_SetTimeout(cmsysProcess* process, + std::chrono::duration<double> timeout); + /** \class cmProcess * \brief run a process with c++ * @@ -24,8 +31,8 @@ public: void SetCommand(const char* command); void SetCommandArguments(std::vector<std::string> const& arg); void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; } - void SetTimeout(double t) { this->Timeout = t; } - void ChangeTimeout(double t); + void SetTimeout(std::chrono::duration<double> t) { this->Timeout = t; } + void ChangeTimeout(std::chrono::duration<double> t); void ResetStartTime(); // Return true if the process starts bool StartProcess(); @@ -37,7 +44,7 @@ public: int GetId() { return this->Id; } void SetId(int id) { this->Id = id; } int GetExitValue() { return this->ExitValue; } - double GetTotalTime() { return this->TotalTime; } + std::chrono::duration<double> GetTotalTime() { return this->TotalTime; } int GetExitException(); std::string GetExitExceptionString(); /** @@ -47,12 +54,13 @@ public: * cmsysProcess_Pipe_STDOUT = Line came from stdout or stderr * cmsysProcess_Pipe_Timeout = Timeout expired while waiting */ - int GetNextOutputLine(std::string& line, double timeout); + int GetNextOutputLine(std::string& line, + std::chrono::duration<double> timeout); private: - double Timeout; + std::chrono::duration<double> Timeout; std::chrono::steady_clock::time_point StartTime; - double TotalTime; + std::chrono::duration<double> TotalTime; cmsysProcess* Process; class Buffer : public std::vector<char> { diff --git a/Source/Checks/cm_cxx_attribute_fallthrough.cxx b/Source/Checks/cm_cxx_attribute_fallthrough.cxx deleted file mode 100644 index 50605b7..0000000 --- a/Source/Checks/cm_cxx_attribute_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - __attribute__((fallthrough)); - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_fallthrough.cxx b/Source/Checks/cm_cxx_fallthrough.cxx deleted file mode 100644 index 2825bed..0000000 --- a/Source/Checks/cm_cxx_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[fallthrough]]; - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index a30a5e6..2704c40 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -41,13 +41,6 @@ function(cm_check_cxx_feature name) endif() endfunction() -cm_check_cxx_feature(fallthrough) -if(NOT CMake_HAVE_CXX_FALLTHROUGH) - cm_check_cxx_feature(gnu_fallthrough) - if(NOT CMake_HAVE_CXX_GNU_FALLTHROUGH) - cm_check_cxx_feature(attribute_fallthrough) - endif() -endif() cm_check_cxx_feature(make_unique) if(CMake_HAVE_CXX_MAKE_UNIQUE) set(CMake_HAVE_CXX_UNIQUE_PTR 1) diff --git a/Source/Checks/cm_cxx_gnu_fallthrough.cxx b/Source/Checks/cm_cxx_gnu_fallthrough.cxx deleted file mode 100644 index ebc15f4..0000000 --- a/Source/Checks/cm_cxx_gnu_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[gnu::fallthrough]]; - default: - return i; - } -} diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx index abed70e..cb67f85 100644 --- a/Source/QtDialog/RegexExplorer.cxx +++ b/Source/QtDialog/RegexExplorer.cxx @@ -8,7 +8,7 @@ RegexExplorer::RegexExplorer(QWidget* p) { this->setupUi(this); - for (int i = 1; i < cmsys::RegularExpression::NSUBEXP; ++i) { + for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) { matchNumber->addItem(QString("Match %1").arg(QString::number(i)), QVariant(i)); } @@ -105,7 +105,7 @@ void RegexExplorer::on_matchNumber_currentIndexChanged(int index) QVariant itemData = matchNumber->itemData(index); int idx = itemData.toInt(); - if (idx < 1 || idx >= cmsys::RegularExpression::NSUBEXP) { + if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) { return; } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index d358e3d..a4ca301 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1,5 +1,11 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#ifdef _WIN32 +/* windows.h defines min() and max() macros by default. This interferes with + * C++ functions names. + */ +#define NOMINMAX +#endif #include "cmCTest.h" #include "cm_curl.h" @@ -44,6 +50,7 @@ #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmProcess.h" #include "cmProcessOutput.h" #include "cmState.h" #include "cmStateSnapshot.h" @@ -278,9 +285,9 @@ cmCTest::cmCTest() this->TestModel = cmCTest::EXPERIMENTAL; this->MaxTestNameWidth = 30; this->InteractiveDebugMode = true; - this->TimeOut = 0; - this->GlobalTimeout = 0; - this->LastStopTimeout = 24 * 60 * 60; + this->TimeOut = std::chrono::duration<double>::zero(); + this->GlobalTimeout = std::chrono::duration<double>::zero(); + this->LastStopTimeout = std::chrono::hours(24); this->CompressXMLFiles = false; this->ScheduleType.clear(); this->StopTime.clear(); @@ -678,7 +685,8 @@ bool cmCTest::UpdateCTestConfiguration() this->BinaryDir = this->GetCTestConfiguration("BuildDirectory"); cmSystemTools::ChangeDirectory(this->BinaryDir); } - this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str()); + this->TimeOut = + std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str())); std::string const& testLoad = this->GetCTestConfiguration("TestLoad"); if (!testLoad.empty()) { unsigned long load; @@ -836,7 +844,8 @@ int cmCTest::ProcessSteps() for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) { notest = !this->Parts[p]; } - if (this->Parts[PartUpdate] && (this->GetRemainingTimeAllowed() - 120 > 0)) { + if (this->Parts[PartUpdate] && + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { cmCTestGenericHandler* uphandler = this->GetHandler("update"); uphandler->SetPersistentOption( "SourceDirectory", @@ -850,33 +859,34 @@ int cmCTest::ProcessSteps() return 0; } if (this->Parts[PartConfigure] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { if (this->GetHandler("configure")->ProcessHandler() < 0) { res |= cmCTest::CONFIGURE_ERRORS; } } - if (this->Parts[PartBuild] && (this->GetRemainingTimeAllowed() - 120 > 0)) { + if (this->Parts[PartBuild] && + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("build")->ProcessHandler() < 0) { res |= cmCTest::BUILD_ERRORS; } } if ((this->Parts[PartTest] || notest) && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("test")->ProcessHandler() < 0) { res |= cmCTest::TEST_ERRORS; } } if (this->Parts[PartCoverage] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("coverage")->ProcessHandler() < 0) { res |= cmCTest::COVERAGE_ERRORS; } } if (this->Parts[PartMemCheck] && - (this->GetRemainingTimeAllowed() - 120 > 0)) { + (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { this->UpdateCTestConfiguration(); if (this->GetHandler("memcheck")->ProcessHandler() < 0) { res |= cmCTest::MEMORY_ERRORS; @@ -955,7 +965,8 @@ int cmCTest::GetTestModelFromString(const char* str) //###################################################################### int cmCTest::RunMakeCommand(const char* command, std::string& output, - int* retVal, const char* dir, int timeout, + int* retVal, const char* dir, + std::chrono::duration<double> timeout, std::ostream& ofs, Encoding encoding) { // First generate the command and arguments @@ -1071,26 +1082,37 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output, //###################################################################### int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, - int* retVal, std::ostream* log, double testTimeOut, + int* retVal, std::ostream* log, + std::chrono::duration<double> testTimeOut, std::vector<std::string>* environment, Encoding encoding) { bool modifyEnv = (environment && !environment->empty()); // determine how much time we have - double timeout = this->GetRemainingTimeAllowed() - 120; - if (this->TimeOut > 0 && this->TimeOut < timeout) { + std::chrono::duration<double> timeout = + std::min<std::chrono::duration<double>>(this->GetRemainingTimeAllowed(), + std::chrono::minutes(2)); + if (this->TimeOut > std::chrono::duration<double>::zero() && + this->TimeOut < timeout) { timeout = this->TimeOut; } - if (testTimeOut > 0 && testTimeOut < this->GetRemainingTimeAllowed()) { + if (testTimeOut > std::chrono::duration<double>::zero() && + testTimeOut < this->GetRemainingTimeAllowed()) { timeout = testTimeOut; } // always have at least 1 second if we got to here - if (timeout <= 0) { - timeout = 1; + if (timeout <= std::chrono::duration<double>::zero()) { + timeout = std::chrono::seconds(1); } - cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, - "Test timeout computed to be: " << timeout << "\n"); + cmCTestLog( + this, HANDLER_VERBOSE_OUTPUT, "Test timeout computed to be: " + << (timeout == std::chrono::duration<double>::max() + ? std::string("infinite") + : std::to_string( + std::chrono::duration_cast<std::chrono::seconds>(timeout) + .count())) + << "\n"); if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) && !this->ForceNewCTestProcess) { cmCTest inst; @@ -1107,10 +1129,12 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, // make sure we pass the timeout in for any build and test // invocations. Since --build-generator is required this is a // good place to check for it, and to add the arguments in - if (strcmp(i, "--build-generator") == 0 && timeout > 0) { + if (strcmp(i, "--build-generator") == 0 && + timeout > std::chrono::duration<double>::zero()) { args.push_back("--test-timeout"); std::ostringstream msg; - msg << timeout; + msg << std::chrono::duration_cast<std::chrono::seconds>(timeout) + .count(); args.push_back(msg.str()); } args.push_back(i); @@ -1757,7 +1781,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) { i++; - double timeout = atof(args[i].c_str()); + auto timeout = std::chrono::duration<double>(atof(args[i].c_str())); this->GlobalTimeout = timeout; } @@ -2564,7 +2588,9 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable( bool cmCTest::RunCommand(std::vector<std::string> const& args, std::string* stdOut, std::string* stdErr, int* retVal, - const char* dir, double timeout, Encoding encoding) + const char* dir, + std::chrono::duration<double> timeout, + Encoding encoding) { std::vector<const char*> argv; argv.reserve(args.size() + 1); @@ -2775,10 +2801,10 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg, } } -double cmCTest::GetRemainingTimeAllowed() +std::chrono::duration<double> cmCTest::GetRemainingTimeAllowed() { if (!this->GetHandler("script")) { - return 1.0e7; + return std::chrono::duration<double>::max(); } cmCTestScriptHandler* ch = diff --git a/Source/cmCTest.h b/Source/cmCTest.h index a2d6fc3..ba94866 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -7,6 +7,7 @@ #include "cmProcessOutput.h" #include "cmsys/String.hxx" +#include <chrono> #include <map> #include <set> #include <sstream> @@ -139,10 +140,13 @@ public: /** what is the configuraiton type, e.g. Debug, Release etc. */ std::string const& GetConfigType(); - double GetTimeOut() { return this->TimeOut; } - void SetTimeOut(double t) { this->TimeOut = t; } + std::chrono::duration<double> GetTimeOut() { return this->TimeOut; } + void SetTimeOut(std::chrono::duration<double> t) { this->TimeOut = t; } - double GetGlobalTimeout() { return this->GlobalTimeout; } + std::chrono::duration<double> GetGlobalTimeout() + { + return this->GlobalTimeout; + } /** how many test to run at the same time */ int GetParallelLevel() { return this->ParallelLevel; } @@ -200,9 +204,9 @@ public: /** * Return the time remaining that the script is allowed to run in * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has - * not been set it returns 1e7 seconds + * not been set it returns a very large duration. */ - double GetRemainingTimeAllowed(); + std::chrono::duration<double> GetRemainingTimeAllowed(); /** * Open file in the output directory and set the stream @@ -248,7 +252,9 @@ public: */ bool RunCommand(std::vector<std::string> const& args, std::string* stdOut, std::string* stdErr, int* retVal = nullptr, - const char* dir = nullptr, double timeout = 0.0, + const char* dir = nullptr, + std::chrono::duration<double> timeout = + std::chrono::duration<double>::zero(), Encoding encoding = cmProcessOutput::Auto); /** @@ -268,7 +274,8 @@ public: * and retVal is return value or exception. */ int RunMakeCommand(const char* command, std::string& output, int* retVal, - const char* dir, int timeout, std::ostream& ofs, + const char* dir, std::chrono::duration<double> timeout, + std::ostream& ofs, Encoding encoding = cmProcessOutput::Auto); /** Return the current tag */ @@ -315,7 +322,7 @@ public: * environment variables are restored to their previous values. */ int RunTest(std::vector<const char*> args, std::string* output, int* retVal, - std::ostream* logfile, double testTimeOut, + std::ostream* logfile, std::chrono::duration<double> testTimeOut, std::vector<std::string>* environment, Encoding encoding = cmProcessOutput::Auto); @@ -503,11 +510,11 @@ private: int TestModel; std::string SpecificTrack; - double TimeOut; + std::chrono::duration<double> TimeOut; - double GlobalTimeout; + std::chrono::duration<double> GlobalTimeout; - int LastStopTimeout; + std::chrono::duration<double> LastStopTimeout; int MaxTestNameWidth; diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 9a78aca..c80439b 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -19,22 +19,11 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER -#cmakedefine CMake_HAVE_CXX_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_GNU_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH #cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" -#if defined(CMake_HAVE_CXX_FALLTHROUGH) -#define CM_FALLTHROUGH [[fallthrough]] -#elif defined(CMake_HAVE_CXX_GNU_FALLTHROUGH) -#define CM_FALLTHROUGH [[gnu::fallthrough]] -#elif defined(CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH) -#define CM_FALLTHROUGH __attribute__((fallthrough)) -#else -#define CM_FALLTHROUGH -#endif +#define CM_FALLTHROUGH cmsys_FALLTHROUGH #define CM_DISABLE_COPY(Class) \ Class(Class const&) = delete; \ diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx index 28ba12c..50e1936 100644 --- a/Source/cmConnection.cxx +++ b/Source/cmConnection.cxx @@ -26,7 +26,7 @@ void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { if (nread >= 0) { conn->ReadData(std::string(buf->base, buf->base + nread)); @@ -55,7 +55,7 @@ void cmEventBasedConnection::on_write(uv_write_t* req, int status) void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) { (void)(status); - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { conn->Connect(stream); @@ -76,7 +76,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) #endif auto data = _data; - assert(this->WriteStream); + assert(this->WriteStream.get()); if (BufferStrategy) { data = BufferStrategy->BufferOutMessage(data); } @@ -87,8 +87,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) req->req.data = this; req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); memcpy(req->buf.base, data.c_str(), ds); - uv_write(reinterpret_cast<uv_write_t*>(req), - static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1, + uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1, on_write); } @@ -156,13 +155,11 @@ bool cmConnection::OnServeStart(std::string* errString) bool cmEventBasedConnection::OnConnectionShuttingDown() { - if (this->WriteStream) { + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - if (this->ReadStream) { - this->ReadStream->data = nullptr; - } - this->ReadStream = nullptr; - this->WriteStream = nullptr; + + WriteStream.reset(); + return true; } diff --git a/Source/cmConnection.h b/Source/cmConnection.h index ddb7744..ce2d2dc 100644 --- a/Source/cmConnection.h +++ b/Source/cmConnection.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include "cm_uv.h" #include <cstddef> @@ -107,8 +108,6 @@ public: bool OnConnectionShuttingDown() override; virtual void OnDisconnect(int errorCode); - uv_stream_t* ReadStream = nullptr; - uv_stream_t* WriteStream = nullptr; static void on_close(uv_handle_t* handle); @@ -119,6 +118,8 @@ public: } protected: + cm::uv_stream_ptr WriteStream; + std::string RawReadBuffer; std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 3d72ae3..bd1b6bb 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -362,9 +362,8 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( // Add source file specific flags. if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - const char* processed = ge.Parse(cflags)->Evaluate(lg, config); - lg->AppendFlags(flags, processed); + cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config); + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags)); } return flags; @@ -380,6 +379,7 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( cmMakefile* makefile = lg->GetMakefile(); const std::string& language = source->GetLanguage(); const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + cmGeneratorExpressionInterpreter genexInterpreter(lg, target, config); // Add the export symbol definition for shared library objects. if (const char* exportMacro = target->GetExportMacro()) { @@ -388,11 +388,14 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( // Add preprocessor definitions for this target and configuration. lg->AddCompileDefinitions(defines, target, config, language); - lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, source->GetProperty(defPropName)); + if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(compile_defs)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(config_compile_defs)); } std::string definesString; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index cface0d..611fbf8 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -153,4 +153,54 @@ private: bool EvaluateForBuildsystem; }; +class cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(cmGeneratorExpressionInterpreter) + +public: + cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget, + const std::string& config) + : LocalGenerator(localGenerator) + , GeneratorTarget(generatorTarget) + , Config(config) + { + } + + const char* Evaluate(const char* expression) + { + this->CompiledGeneratorExpression = + this->GeneratorExpression.Parse(expression); + + return this->CompiledGeneratorExpression->Evaluate( + this->LocalGenerator, this->Config, false, this->GeneratorTarget); + } + const char* Evaluate(const std::string& expression) + { + return this->Evaluate(expression.c_str()); + } + +protected: + cmGeneratorExpression& GetGeneratorExpression() + { + return this->GeneratorExpression; + } + + cmCompiledGeneratorExpression& GetCompiledGeneratorExpression() + { + return *(this->CompiledGeneratorExpression); + } + + cmLocalGenerator* GetLocalGenerator() { return this->LocalGenerator; } + + cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } + +private: + cmGeneratorExpression GeneratorExpression; + std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression; + cmLocalGenerator* LocalGenerator = nullptr; + cmGeneratorTarget* GeneratorTarget = nullptr; + std::string Config; +}; + #endif diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 99f33e5..92e6a29 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -358,6 +358,10 @@ public: virtual bool IsIPOSupported() const { return false; } + /** Return whether the generator can import external visual studio project + using INCLUDE_EXTERNAL_MSPROJECT */ + virtual bool IsIncludeExternalMSProjectSupported() const { return false; } + /** Return whether the generator should use EFFECTIVE_PLATFORM_NAME. This is relevant for mixed macOS and iOS builds. */ virtual bool UseEffectivePlatformName(cmMakefile*) const { return false; } diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 55a6813..f4fc3cf 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -101,6 +101,8 @@ public: /** Return true if building for Windows CE */ virtual bool TargetsWindowsCE() const { return false; } + bool IsIncludeExternalMSProjectSupported() const override { return true; } + class TargetSet : public std::set<cmGeneratorTarget const*> { }; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index c376c8d..bbf4175 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -676,9 +676,51 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath( return buildFile; } +class XCodeGeneratorExpressionInterpreter + : public cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(XCodeGeneratorExpressionInterpreter) + +public: + XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile, + cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget) + : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, + "NO-PER-CONFIG-SUPPORT-IN-XCODE") + , SourceFile(sourceFile) + { + } + + using cmGeneratorExpressionInterpreter::Evaluate; + + const char* Evaluate(const char* expression, const char* property) + { + const char* processed = this->Evaluate(expression); + if (this->GetCompiledGeneratorExpression() + .GetHadContextSensitiveCondition()) { + std::ostringstream e; + /* clang-format off */ + e << + "Xcode does not support per-config per-source " << property << ":\n" + " " << expression << "\n" + "specified for source:\n" + " " << this->SourceFile->GetFullPath() << "\n"; + /* clang-format on */ + this->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str()); + } + + return processed; + } + +private: + cmSourceFile* SourceFile = nullptr; +}; + cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt) { + XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt); + // Add flags from target and source file properties. std::string flags; const char* srcfmt = sf->GetProperty("Fortran_FORMAT"); @@ -693,30 +735,16 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( break; } if (const char* cflags = sf->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::string configName = "NO-PER-CONFIG-SUPPORT-IN-XCODE"; - std::unique_ptr<cmCompiledGeneratorExpression> compiledExpr = - ge.Parse(cflags); - const char* processed = - compiledExpr->Evaluate(lg, configName, false, gtgt); - if (compiledExpr->GetHadContextSensitiveCondition()) { - std::ostringstream e; - /* clang-format off */ - e << - "Xcode does not support per-config per-source COMPILE_FLAGS:\n" - " " << cflags << "\n" - "specified for source:\n" - " " << sf->GetFullPath() << "\n"; - /* clang-format on */ - lg->IssueMessage(cmake::FATAL_ERROR, e.str()); - } - lg->AppendFlags(flags, processed); + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, "COMPILE_FLAGS")); } // Add per-source definitions. BuildObjectListOrString flagsBuild(this, false); - this->AppendDefines(flagsBuild, sf->GetProperty("COMPILE_DEFINITIONS"), - true); + if (const char* compile_defs = sf->GetProperty("COMPILE_DEFINITIONS")) { + this->AppendDefines( + flagsBuild, + genexInterpreter.Evaluate(compile_defs, "COMPILE_DEFINITIONS"), true); + } if (!flagsBuild.IsEmpty()) { if (!flags.empty()) { flags += ' '; diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx index bd16b1d..85e8cd3 100644 --- a/Source/cmIncludeExternalMSProjectCommand.cxx +++ b/Source/cmIncludeExternalMSProjectCommand.cxx @@ -3,6 +3,7 @@ #include "cmIncludeExternalMSProjectCommand.h" #ifdef _WIN32 +#include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" #include "cmSystemTools.h" @@ -22,7 +23,9 @@ bool cmIncludeExternalMSProjectCommand::InitialPass( } // only compile this for win32 to avoid coverage errors #ifdef _WIN32 - if (this->Makefile->GetDefinition("WIN32")) { + if (this->Makefile->GetDefinition("WIN32") || + this->Makefile->GetGlobalGenerator() + ->IsIncludeExternalMSProjectSupported()) { enum Doing { DoingNone, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 477ce51..2d969d2 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -207,6 +207,9 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) const char* jobpools = this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS"); + if (!jobpools) { + jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS"); + } if (jobpools) { cmGlobalNinjaGenerator::WriteComment( os, "Pools defined by global property JOB_POOLS"); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index f01ed7a..53966cd 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -615,6 +615,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( switch (target->GetType()) { case cmStateEnums::OBJECT_LIBRARY: targetBuilds = false; // no manifest tool for object library + CM_FALLTHROUGH; case cmStateEnums::STATIC_LIBRARY: projectType = "typeStaticLibrary"; configType = "4"; @@ -630,6 +631,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: configType = "10"; + CM_FALLTHROUGH; default: targetBuilds = false; break; @@ -1456,15 +1458,14 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( i != configs.end(); ++i, ++ci) { std::string configUpper = cmSystemTools::UpperCase(*i); cmLVS7GFileConfig fc; + cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i); bool needfc = false; if (!objectName.empty()) { fc.ObjectName = objectName; needfc = true; } if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - fc.CompileFlags = cge->Evaluate(lg, *i, false, gt); + fc.CompileFlags = genexInterpreter.Evaluate(cflags); needfc = true; } if (lg->FortranProject) { @@ -1483,13 +1484,13 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } } if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { - fc.CompileDefs = cdefs; + fc.CompileDefs = genexInterpreter.Evaluate(cdefs); needfc = true; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; - if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) { - fc.CompileDefsConfig = ccdefs; + if (const char* ccdefs = sf.GetProperty(defPropName)) { + fc.CompileDefsConfig = genexInterpreter.Evaluate(ccdefs); needfc = true; } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index dd8a373..5e0c582 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -425,6 +425,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::string config = this->LocalGenerator->GetConfigName(); std::string configUpper = cmSystemTools::UpperCase(config); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config); // Add Fortran format flags. if (lang == "Fortran") { @@ -433,10 +435,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Add flags from source file properties. if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); + const char* evaluatedFlags = genexInterpreter.Evaluate(cflags); this->LocalGenerator->AppendFlags(flags, evaluatedFlags); *this->FlagFileStream << "# Custom flags: " << relativeObj << "_FLAGS = " << evaluatedFlags << "\n" @@ -448,18 +447,19 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Add source-sepcific preprocessor definitions. if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) { - this->LocalGenerator->AppendDefines(defines, compile_defs); + const char* evaluatedDefs = genexInterpreter.Evaluate(compile_defs); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj - << "_DEFINES = " << compile_defs << "\n" + << "_DEFINES = " << evaluatedDefs << "\n" << "\n"; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; if (const char* config_compile_defs = source.GetProperty(defPropName)) { - this->LocalGenerator->AppendDefines(defines, config_compile_defs); + const char* evaluatedDefs = genexInterpreter.Evaluate(config_compile_defs); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_" - << configUpper << " = " << config_compile_defs - << "\n" + << configUpper << " = " << evaluatedDefs << "\n" << "\n"; } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 0262b3c..1036977 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -136,12 +136,11 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( // Add source file specific flags. if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - std::string config = this->LocalGenerator->GetConfigName(); - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); - this->LocalGenerator->AppendFlags(flags, evaluatedFlags); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, + this->LocalGenerator->GetConfigName()); + this->LocalGenerator->AppendFlags(flags, + genexInterpreter.Evaluate(cflags)); } return flags; @@ -178,13 +177,20 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, const std::string& language) { std::set<std::string> defines; - this->LocalGenerator->AppendDefines( - defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(this->GetConfigName()); - this->LocalGenerator->AppendDefines(defines, - source->GetProperty(defPropName)); + const std::string config = this->LocalGenerator->GetConfigName(); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config); + + if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) { + this->LocalGenerator->AppendDefines( + defines, genexInterpreter.Evaluate(compile_defs)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + this->LocalGenerator->AppendDefines( + defines, genexInterpreter.Evaluate(config_compile_defs)); } std::string definesString = this->GetDefines(language); diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx index 9e565f6..3dab2f0 100644 --- a/Source/cmPipeConnection.cxx +++ b/Source/cmPipeConnection.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmPipeConnection.h" +#include <algorithm> + #include "cmServer.h" cmPipeConnection::cmPipeConnection(const std::string& name, @@ -13,39 +15,33 @@ cmPipeConnection::cmPipeConnection(const std::string& name, void cmPipeConnection::Connect(uv_stream_t* server) { - if (this->ClientPipe) { + if (this->WriteStream.get()) { // Accept and close all pipes but the first: - uv_pipe_t* rejectPipe = new uv_pipe_t(); + cm::uv_pipe_ptr rejectPipe; + + rejectPipe.init(*this->Server->GetLoop(), 0); + uv_accept(server, rejectPipe); - uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0); - uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe)); - uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), - &on_close_delete<uv_pipe_t>); return; } - this->ClientPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0); - this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this); - auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe); - if (uv_accept(server, client) != 0) { - uv_close(reinterpret_cast<uv_handle_t*>(client), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; + cm::uv_pipe_ptr ClientPipe; + ClientPipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); + + if (uv_accept(server, ClientPipe) != 0) { return; } - this->ReadStream = client; - this->WriteStream = client; - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); + uv_read_start(ClientPipe, on_alloc_buffer, on_read); + WriteStream = std::move(ClientPipe); Server->OnConnected(this); } bool cmPipeConnection::OnServeStart(std::string* errorMessage) { - this->ServerPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0); - this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this); + this->ServerPipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); int r; if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { @@ -53,8 +49,8 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) ": " + uv_err_name(r); return false; } - auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe); - if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) { + + if ((r = uv_listen(this->ServerPipe, 1, on_new_connection)) != 0) { *errorMessage = std::string("Internal Error listening on ") + this->PipeName + ": " + uv_err_name(r); return false; @@ -65,18 +61,11 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) bool cmPipeConnection::OnConnectionShuttingDown() { - if (this->ClientPipe) { - uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), - &on_close_delete<uv_pipe_t>); + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; - this->ServerPipe = nullptr; - this->WriteStream = nullptr; - this->ReadStream = nullptr; + this->ServerPipe.reset(); return cmEventBasedConnection::OnConnectionShuttingDown(); } diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h index 7b89842..49f9fdf 100644 --- a/Source/cmPipeConnection.h +++ b/Source/cmPipeConnection.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include <string> #include "cmConnection.h" @@ -23,6 +24,5 @@ public: private: const std::string PipeName; - uv_pipe_t* ServerPipe = nullptr; - uv_pipe_t* ClientPipe = nullptr; + cm::uv_pipe_ptr ServerPipe; }; diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 9af4c0a..1b04ca2 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -18,17 +18,19 @@ #include <cstdint> #include <iostream> #include <memory> +#include <mutex> #include <utility> void on_signal(uv_signal_t* signal, int signum) { - auto conn = reinterpret_cast<cmServerBase*>(signal->data); + auto conn = static_cast<cmServerBase*>(signal->data); conn->OnSignal(signum); } static void on_walk_to_shutdown(uv_handle_t* handle, void* arg) { (void)arg; + assert(uv_is_closing(handle)); if (!uv_is_closing(handle)) { uv_close(handle, &cmEventBasedConnection::on_close); } @@ -58,6 +60,8 @@ cmServer::cmServer(cmConnection* conn, bool supportExperimental) cmServer::~cmServer() { + Close(); + for (cmServerProtocol* p : this->SupportedProtocols) { delete p; } @@ -409,7 +413,7 @@ void cmServer::StartShutDown() static void __start_thread(void* arg) { - auto server = reinterpret_cast<cmServerBase*>(arg); + auto server = static_cast<cmServerBase*>(arg); std::string error; bool success = server->Serve(&error); if (!success || error.empty() == false) { @@ -417,22 +421,19 @@ static void __start_thread(void* arg) } } -static void __shutdownThread(uv_async_t* arg) -{ - auto server = reinterpret_cast<cmServerBase*>(arg->data); - on_walk_to_shutdown(reinterpret_cast<uv_handle_t*>(arg), nullptr); - server->StartShutDown(); -} - bool cmServerBase::StartServeThread() { ServeThreadRunning = true; - uv_async_init(&Loop, &this->ShutdownSignal, __shutdownThread); - this->ShutdownSignal.data = this; uv_thread_create(&ServeThread, __start_thread, this); return true; } +static void __shutdownThread(uv_async_t* arg) +{ + auto server = static_cast<cmServerBase*>(arg->data); + server->StartShutDown(); +} + bool cmServerBase::Serve(std::string* errorMessage) { #ifndef NDEBUG @@ -443,14 +444,13 @@ bool cmServerBase::Serve(std::string* errorMessage) errorMessage->clear(); - uv_signal_init(&Loop, &this->SIGINTHandler); - uv_signal_init(&Loop, &this->SIGHUPHandler); + ShutdownSignal.init(Loop, __shutdownThread, this); - this->SIGINTHandler.data = this; - this->SIGHUPHandler.data = this; + SIGINTHandler.init(Loop, this); + SIGHUPHandler.init(Loop, this); - uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT); - uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP); + SIGINTHandler.start(&on_signal, SIGINT); + SIGHUPHandler.start(&on_signal, SIGHUP); OnServeStart(); @@ -473,7 +473,6 @@ bool cmServerBase::Serve(std::string* errorMessage) return false; } - ServeThreadRunning = false; return true; } @@ -487,18 +486,12 @@ void cmServerBase::OnServeStart() void cmServerBase::StartShutDown() { - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGINTHandler))) { - uv_signal_stop(&this->SIGINTHandler); - } - - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGHUPHandler))) { - uv_signal_stop(&this->SIGHUPHandler); - } + ShutdownSignal.reset(); + SIGINTHandler.reset(); + SIGHUPHandler.reset(); { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); for (auto& connection : Connections) { connection->OnConnectionShuttingDown(); } @@ -519,26 +512,33 @@ cmServerBase::cmServerBase(cmConnection* connection) { auto err = uv_loop_init(&Loop); (void)err; + Loop.data = this; assert(err == 0); AddNewConnection(connection); } -cmServerBase::~cmServerBase() +void cmServerBase::Close() { + if (Loop.data) { + if (ServeThreadRunning) { + this->ShutdownSignal.send(); + uv_thread_join(&ServeThread); + } - if (ServeThreadRunning) { - uv_async_send(&this->ShutdownSignal); - uv_thread_join(&ServeThread); + uv_loop_close(&Loop); + Loop.data = nullptr; } - - uv_loop_close(&Loop); +} +cmServerBase::~cmServerBase() +{ + Close(); } void cmServerBase::AddNewConnection(cmConnection* ownedConnection) { { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); Connections.emplace_back(ownedConnection); } ownedConnection->SetServer(this); @@ -555,13 +555,13 @@ void cmServerBase::OnDisconnect(cmConnection* pConnection) return m.get() == pConnection; }; { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); Connections.erase( std::remove_if(Connections.begin(), Connections.end(), pred), Connections.end()); } if (Connections.empty()) { - StartShutDown(); + this->ShutdownSignal.send(); } } diff --git a/Source/cmServer.h b/Source/cmServer.h index 6e46f8c..ca37ce2 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -8,6 +8,8 @@ #include "cm_thread.hxx" #include "cm_uv.h" +#include "cmUVHandlePtr.h" + #include <memory> // IWYU pragma: keep #include <string> #include <vector> @@ -58,7 +60,7 @@ public: virtual bool OnSignal(int signum); uv_loop_t* GetLoop(); - + void Close(); void OnDisconnect(cmConnection* pConnection); protected: @@ -67,7 +69,7 @@ protected: bool ServeThreadRunning = false; uv_thread_t ServeThread; - uv_async_t ShutdownSignal; + cm::uv_async_ptr ShutdownSignal; #ifndef NDEBUG public: // When the server starts it will mark down it's current thread ID, @@ -80,8 +82,8 @@ protected: uv_loop_t Loop; - uv_signal_t SIGINTHandler; - uv_signal_t SIGHUPHandler; + cm::uv_signal_ptr SIGINTHandler; + cm::uv_signal_ptr SIGHUPHandler; }; class cmServer : public cmServerBase diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 44af75f..78c8f06 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -5,6 +5,9 @@ #include "cmConfigure.h" #include "cmServer.h" #include "cmServerDictionary.h" +#include "cm_uv.h" + +#include <algorithm> #ifdef _WIN32 #include "io.h" #else @@ -18,36 +21,34 @@ cmStdIoConnection::cmStdIoConnection( { } -void cmStdIoConnection::SetupStream(uv_stream_t*& stream, int file_id) +cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) { - assert(stream == nullptr); switch (uv_guess_handle(file_id)) { case UV_TTY: { - auto tty = new uv_tty_t(); - uv_tty_init(this->Server->GetLoop(), tty, file_id, file_id == 0); + cm::uv_tty_ptr tty; + tty.init(*this->Server->GetLoop(), file_id, file_id == 0, + static_cast<cmEventBasedConnection*>(this)); uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL); - stream = reinterpret_cast<uv_stream_t*>(tty); - break; + return std::move(tty); } case UV_FILE: if (file_id == 0) { - return; + return nullptr; } // Intentional fallthrough; stdin can _not_ be treated as a named // pipe, however stdout can be. CM_FALLTHROUGH; case UV_NAMED_PIPE: { - auto pipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), pipe, 0); + cm::uv_pipe_ptr pipe; + pipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); uv_pipe_open(pipe, file_id); - stream = reinterpret_cast<uv_stream_t*>(pipe); - break; + return std::move(pipe); } default: assert(false && "Unable to determine stream type"); - return; + return nullptr; } - stream->data = static_cast<cmEventBasedConnection*>(this); } void cmStdIoConnection::SetServer(cmServerBase* s) @@ -57,14 +58,14 @@ void cmStdIoConnection::SetServer(cmServerBase* s) return; } - SetupStream(this->ReadStream, 0); - SetupStream(this->WriteStream, 1); + this->ReadStream = SetupStream(0); + this->WriteStream = SetupStream(1); } void shutdown_connection(uv_prepare_t* prepare) { cmStdIoConnection* connection = - reinterpret_cast<cmStdIoConnection*>(prepare->data); + static_cast<cmStdIoConnection*>(prepare->data); if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) { uv_close(reinterpret_cast<uv_handle_t*>(prepare), @@ -76,7 +77,7 @@ void shutdown_connection(uv_prepare_t* prepare) bool cmStdIoConnection::OnServeStart(std::string* pString) { Server->OnConnected(this); - if (this->ReadStream) { + if (this->ReadStream.get()) { uv_read_start(this->ReadStream, on_alloc_buffer, on_read); } else if (uv_guess_handle(0) == UV_FILE) { char buffer[1024]; @@ -94,44 +95,14 @@ bool cmStdIoConnection::OnServeStart(std::string* pString) return cmConnection::OnServeStart(pString); } -void cmStdIoConnection::ShutdownStream(uv_stream_t*& stream) -{ - if (!stream) { - return; - } - switch (stream->type) { - case UV_TTY: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_tty_t>); - } - break; - } - case UV_FILE: - case UV_NAMED_PIPE: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_pipe_t>); - } - break; - } - default: - assert(false && "Unable to determine stream type"); - } - - stream = nullptr; -} - bool cmStdIoConnection::OnConnectionShuttingDown() { - if (ReadStream) { + if (ReadStream.get()) { uv_read_stop(ReadStream); + ReadStream->data = nullptr; } - ShutdownStream(ReadStream); - ShutdownStream(WriteStream); + this->ReadStream.reset(); cmEventBasedConnection::OnConnectionShuttingDown(); diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h index 4ca908d..a70edb4 100644 --- a/Source/cmServerConnection.h +++ b/Source/cmServerConnection.h @@ -8,7 +8,7 @@ #include "cmConnection.h" #include "cmPipeConnection.h" -#include "cm_uv.h" +#include "cmUVHandlePtr.h" class cmServerBase; @@ -46,8 +46,8 @@ public: bool OnServeStart(std::string* pString) override; private: - void SetupStream(uv_stream_t*& stream, int file_id); - void ShutdownStream(uv_stream_t*& stream); + cm::uv_stream_ptr SetupStream(int file_id); + cm::uv_stream_ptr ReadStream; }; /*** diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index 62dee11..685542c 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -97,11 +97,6 @@ static const std::string kCTEST_INFO = "ctestInfo"; static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; -static const std::string kTARGET_CROSS_REFERENCES_KEY = "crossReferences"; -static const std::string kLINE_NUMBER_KEY = "line"; -static const std::string kBACKTRACE_KEY = "backtrace"; -static const std::string kRELATED_STATEMENTS_KEY = "relatedStatements"; - static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==["; static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index cfac513..ad66467 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -11,7 +11,6 @@ #include "cmInstallGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" -#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmProperty.h" @@ -692,6 +691,8 @@ static Json::Value DumpSourceFilesList( std::vector<cmSourceFile*> files; target->GetSourceFiles(files, config); + cmGeneratorExpressionInterpreter genexInterpreter( + target->GetLocalGenerator(), target, config); std::unordered_map<LanguageData, std::vector<std::string>> fileGroups; for (cmSourceFile* file : files) { @@ -703,21 +704,23 @@ static Json::Value DumpSourceFilesList( std::string compileFlags = ld.Flags; if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - auto cge = ge.Parse(cflags); - const char* processed = - cge->Evaluate(target->GetLocalGenerator(), config); - lg->AppendFlags(compileFlags, processed); + lg->AppendFlags(compileFlags, genexInterpreter.Evaluate(cflags)); } fileData.Flags = compileFlags; fileData.IncludePathList = ld.IncludePathList; std::set<std::string> defines; - lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS")); + if (const char* defs = file->GetProperty("COMPILE_DEFINITIONS")) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(defs)); + } + const std::string defPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, file->GetProperty(defPropName)); + if (const char* config_defs = file->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(config_defs)); + } + defines.insert(ld.Defines.begin(), ld.Defines.end()); fileData.SetDefines(defines); @@ -740,37 +743,6 @@ static Json::Value DumpSourceFilesList( return result; } -static Json::Value DumpBacktrace(const cmListFileBacktrace& backtrace) -{ - Json::Value result = Json::arrayValue; - - cmListFileBacktrace backtraceCopy = backtrace; - while (!backtraceCopy.Top().FilePath.empty()) { - Json::Value entry = Json::objectValue; - entry[kPATH_KEY] = backtraceCopy.Top().FilePath; - if (backtraceCopy.Top().Line) { - entry[kLINE_NUMBER_KEY] = static_cast<int>(backtraceCopy.Top().Line); - } - if (!backtraceCopy.Top().Name.empty()) { - entry[kNAME_KEY] = backtraceCopy.Top().Name; - } - result.append(entry); - backtraceCopy = backtraceCopy.Pop(); - } - return result; -} - -static void DumpBacktraceRange(Json::Value& result, const std::string& type, - cmBacktraceRange range) -{ - for (auto const& bt : range) { - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = type; - obj[kBACKTRACE_KEY] = DumpBacktrace(bt); - result.append(obj); - } -} - static Json::Value DumpCTestInfo(cmTest* testInfo) { Json::Value result = Json::objectValue; @@ -795,9 +767,6 @@ static Json::Value DumpCTestInfo(cmTest* testInfo) } result[kPROPERTIES_KEY] = properties; - // Need backtrace to figure out where this test was originally added - result[kBACKTRACE_KEY] = DumpBacktrace(testInfo->GetBacktrace()); - return result; } @@ -929,22 +898,6 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, result[kINSTALL_PATHS] = installPaths; } - Json::Value crossRefs = Json::objectValue; - crossRefs[kBACKTRACE_KEY] = DumpBacktrace(target->Target->GetBacktrace()); - - Json::Value statements = Json::arrayValue; - DumpBacktraceRange(statements, "target_compile_definitions", - target->Target->GetCompileDefinitionsBacktraces()); - DumpBacktraceRange(statements, "target_include_directories", - target->Target->GetIncludeDirectoriesBacktraces()); - DumpBacktraceRange(statements, "target_compile_options", - target->Target->GetCompileOptionsBacktraces()); - DumpBacktraceRange(statements, "target_link_libraries", - target->Target->GetLinkImplementationBacktraces()); - - crossRefs[kRELATED_STATEMENTS_KEY] = std::move(statements); - result[kTARGET_CROSS_REFERENCES_KEY] = std::move(crossRefs); - if (target->HaveWellDefinedOutputFiles()) { Json::Value artifacts = Json::arrayValue; artifacts.append( diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h index c9f42e4..b212c7e 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -3,7 +3,7 @@ #ifndef cmStandardLexer_h #define cmStandardLexer_h -#include "cmConfigure.h" // IWYU pragma: keep +#include "cmsys/Configure.h" // IWYU pragma: keep /* Disable some warnings. */ #if defined(_MSC_VER) diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 37bcb70..97bb0a2 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -25,16 +25,17 @@ const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] = { bool cmTargetLinkLibrariesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - // must have one argument + // Must have at least one argument. if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } - + // Alias targets cannot be on the LHS of this command. if (this->Makefile->IsAlias(args[0])) { this->SetError("can not be used on an ALIAS target."); return false; } + // Lookup the target for which libraries are specified. this->Target = this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget( @@ -78,8 +79,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( break; } } - - // now actually print the message + // Now actually print the message. switch (t) { case cmake::AUTHOR_WARNING: this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str()); @@ -94,6 +94,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // OBJECT libraries are not allowed on the LHS of the command. if (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Object library target \"" << args[0] << "\" " @@ -103,6 +104,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // Having a UTILITY library on the LHS is a bug. if (this->Target->GetType() == cmStateEnums::UTILITY) { std::ostringstream e; const char* modal = nullptr; @@ -129,7 +131,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( } } - // but we might not have any libs after variable expansion + // But we might not have any libs after variable expansion. if (args.size() < 2) { return true; } @@ -142,8 +144,8 @@ bool cmTargetLinkLibrariesCommand::InitialPass( // specification if the keyword is encountered as the first argument. this->CurrentProcessingState = ProcessingLinkLibraries; - // add libraries, note that there is an optional prefix - // of debug and optimized that can be used + // Add libraries, note that there is an optional prefix + // of debug and optimized that can be used. for (unsigned int i = 1; i < args.size(); ++i) { if (args[i] == "LINK_INTERFACE_LIBRARIES") { this->CurrentProcessingState = ProcessingPlainLinkInterface; @@ -160,8 +162,9 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordPublicInterface && this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "The INTERFACE option must appear as the second " - "argument, just after the target name."); + cmake::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " + "argument, just after the target name."); return true; } this->CurrentProcessingState = ProcessingKeywordLinkInterface; @@ -183,7 +186,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -206,7 +209,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -349,12 +352,11 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, // form must be the plain form. const char* existingSig = (sig == cmTarget::KeywordTLLSignature ? "plain" : "keyword"); - e << "The " << existingSig << " signature for target_link_libraries " - "has already been used with the target \"" - << this->Target->GetName() << "\". All uses of " - "target_link_libraries with a target " - << modal << " be either " - "all-keyword or all-plain.\n"; + e << "The " << existingSig << " signature for target_link_libraries has " + "already been used with the target \"" + << this->Target->GetName() + << "\". All uses of target_link_libraries with a target " << modal + << " be either all-keyword or all-plain.\n"; this->Target->GetTllSignatureTraces(e, sig == cmTarget::KeywordTLLSignature ? cmTarget::PlainTLLSignature @@ -366,10 +368,13 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, } } - // Handle normal case first. + // Handle normal case where the command was called with another keyword than + // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) if (this->CurrentProcessingState != ProcessingKeywordLinkInterface && this->CurrentProcessingState != ProcessingPlainLinkInterface) { + // Assure that the target on the LHS was created in the current directory. cmTarget* t = this->Makefile->FindLocalNonAliasTarget(this->Target->GetName()); if (!t) { @@ -388,92 +393,100 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, << this->Target->GetName() << "\" which is not built in this directory."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } else { - - cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); + return false; + } - if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && - (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && - (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && - (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && - !tgt->IsExecutableWithExports()) { - std::ostringstream e; - e << "Target \"" << lib << "\" of type " - << cmState::GetTargetTypeName(tgt->GetType()) - << " may not be linked into another target. " - << "One may link only to STATIC or SHARED libraries, or " - << "to executables with the ENABLE_EXPORTS property set."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } + cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); - this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && + (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && + (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && + (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && + !tgt->IsExecutableWithExports()) { + std::ostringstream e; + e << "Target \"" << lib << "\" of type " + << cmState::GetTargetTypeName(tgt->GetType()) + << " may not be linked into another target. One may link only to " + "INTERFACE, STATIC or SHARED libraries, or to executables with the " + "ENABLE_EXPORTS property set."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } - if (this->CurrentProcessingState == ProcessingLinkLibraries) { - this->Target->AppendProperty( - "INTERFACE_LINK_LIBRARIES", - this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); - return true; - } - if (this->CurrentProcessingState != ProcessingKeywordPublicInterface && - this->CurrentProcessingState != ProcessingPlainPublicInterface) { - if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { - std::string configLib = - this->Target->GetDebugGeneratorExpressions(lib, llt); - if (cmGeneratorExpression::IsValidTargetName(lib) || - cmGeneratorExpression::Find(lib) != std::string::npos) { - configLib = "$<LINK_ONLY:" + configLib + ">"; - } - this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", - configLib.c_str()); + this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + } + + // Handle (additional) case where the command was called with PRIVATE / + // LINK_PRIVATE and stop its processing. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall only be populated if it is a + // STATIC library.) + if (this->CurrentProcessingState == ProcessingKeywordPrivateInterface || + this->CurrentProcessingState == ProcessingPlainPrivateInterface) { + if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { + std::string configLib = + this->Target->GetDebugGeneratorExpressions(lib, llt); + if (cmGeneratorExpression::IsValidTargetName(lib) || + cmGeneratorExpression::Find(lib) != std::string::npos) { + configLib = "$<LINK_ONLY:" + configLib + ">"; } - // Not a 'public' or 'interface' library. Do not add to interface - // property. - return true; + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + configLib.c_str()); } + return true; } + // Handle general case where the command was called with another keyword than + // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) this->Target->AppendProperty( "INTERFACE_LINK_LIBRARIES", this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); + // Stop processing if called without any keyword. + if (this->CurrentProcessingState == ProcessingLinkLibraries) { + return true; + } + // Stop processing if policy CMP0022 is set to NEW. const cmPolicies::PolicyStatus policy22Status = this->Target->GetPolicyStatusCMP0022(); - if (policy22Status != cmPolicies::OLD && policy22Status != cmPolicies::WARN) { return true; } - + // Stop processing if called with an INTERFACE library on the LHS. if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { return true; } - // Get the list of configurations considered to be DEBUG. - std::vector<std::string> debugConfigs = - this->Makefile->GetCMakeInstance()->GetDebugConfigs(); - std::string prop; - - // Include this library in the link interface for the target. - if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { - // Put in the DEBUG configuration interfaces. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - this->Target->AppendProperty(prop, lib.c_str()); + // Handle (additional) backward-compatibility case where the command was + // called with PUBLIC / INTERFACE / LINK_PUBLIC / LINK_INTERFACE_LIBRARIES. + // (The policy CMP0022 is not set to NEW.) + { + // Get the list of configurations considered to be DEBUG. + std::vector<std::string> debugConfigs = + this->Makefile->GetCMakeInstance()->GetDebugConfigs(); + std::string prop; + + // Include this library in the link interface for the target. + if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { + // Put in the DEBUG configuration interfaces. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + this->Target->AppendProperty(prop, lib.c_str()); + } } - } - if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { - // Put in the non-DEBUG configuration interfaces. - this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); - - // Make sure the DEBUG configuration interfaces exist so that the - // general one will not be used as a fall-back. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - if (!this->Target->GetProperty(prop)) { - this->Target->SetProperty(prop, ""); + if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { + // Put in the non-DEBUG configuration interfaces. + this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); + + // Make sure the DEBUG configuration interfaces exist so that the + // general one will not be used as a fall-back. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + if (!this->Target->GetProperty(prop)) { + this->Target->SetProperty(prop, ""); + } } } } diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index f41af49..a2f3ecd 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -20,6 +20,9 @@ class cmTarget; * cmTargetLinkLibrariesCommand is used to specify a list of libraries to link * into executable(s) or shared objects. The names of the libraries * should be those defined by the LIBRARY(library) command(s). + * + * Additionally, it allows to propagate usage-requirements (including link + * libraries) from one target into another. */ class cmTargetLinkLibrariesCommand : public cmCommand { diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index ed9026e..06ce0b1 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -3,6 +3,7 @@ #include "cmTargetPropertyComputer.h" +#include <cctype> #include <sstream> #include <unordered_set> @@ -49,6 +50,12 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( if (cmHasLiteralPrefix(prop, "INTERFACE_")) { return true; } + if (cmHasLiteralPrefix(prop, "_")) { + return true; + } + if (std::islower(prop[0])) { + return true; + } static std::unordered_set<std::string> builtIns; if (builtIns.empty()) { builtIns.insert("COMPATIBLE_INTERFACE_BOOL"); diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx new file mode 100644 index 0000000..eb70416 --- /dev/null +++ b/Source/cmUVHandlePtr.cxx @@ -0,0 +1,227 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define cmUVHandlePtr_cxx +#include "cmUVHandlePtr.h" + +#include <assert.h> +#include <mutex> +#include <stdlib.h> + +#include "cm_uv.h" + +namespace cm { + +static void close_delete(uv_handle_t* h) +{ + free(h); +} + +template <typename T> +static void default_delete(T* type_handle) +{ + auto handle = reinterpret_cast<uv_handle_t*>(type_handle); + if (handle) { + assert(!uv_is_closing(handle)); + if (!uv_is_closing(handle)) { + uv_close(handle, &close_delete); + } + } +} + +/** + * Encapsulates delete logic for a given handle type T + */ +template <typename T> +struct uv_handle_deleter +{ + void operator()(T* type_handle) const { default_delete(type_handle); } +}; + +template <typename T> +void uv_handle_ptr_base_<T>::allocate(void* data) +{ + reset(); + + /* + We use calloc since we know all these types are c structs + and we just want to 0 init them. New would do the same thing; + but casting from uv_handle_t to certain other types -- namely + uv_timer_t -- triggers a cast_align warning on certain systems. + */ + handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>()); + handle->data = data; +} + +template <typename T> +void uv_handle_ptr_base_<T>::reset() +{ + handle.reset(); +} + +template <typename T> +uv_handle_ptr_base_<T>::operator uv_handle_t*() +{ + return reinterpret_cast<uv_handle_t*>(handle.get()); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::operator->() const noexcept +{ + return handle.get(); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::get() const +{ + return handle.get(); +} + +template <typename T> +uv_handle_ptr_<T>::operator T*() const +{ + return this->handle.get(); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +template <> +struct uv_handle_deleter<uv_async_t> +{ + /*** + * Wile uv_async_send is itself thread-safe, there are + * no strong guarantees that close hasn't already been + * called on the handle; and that it might be deleted + * as the send call goes through. This mutex guards + * against that. + * + * The shared_ptr here is to allow for copy construction + * which is mandated by the standard for Deleter on + * shared_ptrs. + */ + std::shared_ptr<std::mutex> handleMutex; + + uv_handle_deleter() + : handleMutex(std::make_shared<std::mutex>()) + { + } + + void operator()(uv_async_t* handle) + { + std::lock_guard<std::mutex> lock(*handleMutex); + default_delete(handle); + } +}; + +void uv_async_ptr::send() +{ + auto deleter = std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle); + assert(deleter); + + std::lock_guard<std::mutex> lock(*deleter->handleMutex); + if (this->handle) { + uv_async_send(*this); + } +} + +int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data) +{ + allocate(data); + return uv_async_init(&loop, handle.get(), async_cb); +} +#endif + +template <> +struct uv_handle_deleter<uv_signal_t> +{ + void operator()(uv_signal_t* handle) const + { + if (handle) { + uv_signal_stop(handle); + default_delete(handle); + } + } +}; + +int uv_signal_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_signal_init(&loop, handle.get()); +} + +int uv_signal_ptr::start(uv_signal_cb cb, int signum) +{ + assert(handle); + return uv_signal_start(*this, cb, signum); +} + +void uv_signal_ptr::stop() +{ + if (handle) { + uv_signal_stop(*this); + } +} + +int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data) +{ + allocate(data); + return uv_pipe_init(&loop, *this, ipc); +} + +uv_pipe_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data) +{ + allocate(data); + return uv_spawn(&loop, *this, &options); +} + +int uv_timer_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_timer_init(&loop, *this); +} + +int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) +{ + assert(handle); + return uv_timer_start(*this, cb, timeout, repeat); +} + +uv_tty_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data) +{ + allocate(data); + return uv_tty_init(&loop, *this, fd, readable); +} +#endif + +template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \ + template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream) + +#ifdef CMAKE_BUILD_WITH_CMAKE +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty) +#endif +} diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h new file mode 100644 index 0000000..a6ce565 --- /dev/null +++ b/Source/cmUVHandlePtr.h @@ -0,0 +1,222 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once +#include "cmConfigure.h" // IWYU pragma: keep + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <type_traits> + +#include "cm_uv.h" + +#define CM_PERFECT_FWD_CTOR(Class, FwdTo) \ + template <typename... Args> \ + Class(Args&&... args) \ + : FwdTo(std::forward<Args>(args)...) \ + { \ + } + +namespace cm { + +/*** +* RAII class to simplify and insure the safe usage of uv_*_t types. This +* includes making sure resources are properly freed and contains casting +* operators which allow for passing into relevant uv_* functions. +* +*@tparam T actual uv_*_t type represented. +*/ +template <typename T> +class uv_handle_ptr_base_ +{ +protected: + template <typename _T> + friend class uv_handle_ptr_base_; + + /** + * This must be a pointer type since the handle can outlive this class. + * When uv_close is eventually called on the handle, the memory the + * handle inhabits must be valid until the close callback is called + * which can be later on in the loop. + */ + std::shared_ptr<T> handle; + + /** + * Allocate memory for the type and optionally set it's 'data' pointer. + * Protected since this should only be called for an appropriate 'init' + * call. + * + * @param data data pointer to set + */ + void allocate(void* data = nullptr); + +public: + CM_DISABLE_COPY(uv_handle_ptr_base_) + uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept; + uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept; + + /** + * This move constructor allows us to move out of a more specialized + * uv type into a less specialized one. The only constraint is that + * the right hand side is castable to T. + * + * This allows you to return uv_handle_ptr or uv_stream_ptr from a function + * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact + * and clean up after it without caring about the exact type. + */ + template <typename S, typename = typename std::enable_if< + std::is_rvalue_reference<S&&>::value>::type> + uv_handle_ptr_base_(S&& rhs) + { + // This will force a compiler error if rhs doesn't have a casting + // operator to get T* + this->handle = std::shared_ptr<T>(rhs.handle, rhs); + rhs.handle.reset(); + } + + // Dtor and ctor need to be inline defined like this for default ctors and + // dtors to work. + uv_handle_ptr_base_() {} + uv_handle_ptr_base_(std::nullptr_t) {} + ~uv_handle_ptr_base_() { reset(); } + + /** + * Properly close the handle if needed and sets the inner handle to nullptr + */ + void reset(); + + /** + * Allow less verbose calling of uv_handle_* functions + * @return reinterpreted handle + */ + operator uv_handle_t*(); + + T* get() const; + T* operator->() const noexcept; +}; + +template <typename T> +inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_( + uv_handle_ptr_base_<T>&&) noexcept = default; +template <typename T> +inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=( + uv_handle_ptr_base_<T>&&) noexcept = default; + +/** + * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t* + * too. It is broken out like this so we can reuse most of the code for the + * uv_handle_ptr class. + */ +template <typename T> +class uv_handle_ptr_ : public uv_handle_ptr_base_<T> +{ + template <typename _T> + friend class uv_handle_ptr_; + +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<T>); + + /*** + * Allow less verbose calling of uv_<T> functions + * @return reinterpreted handle + */ + operator T*() const; +}; + +/*** + * This specialization is required to avoid duplicate 'operator uv_handle_t*()' + * declarations + */ +template <> +class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<uv_handle_t>); +}; + +class uv_async_ptr : public uv_handle_ptr_<uv_async_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_async_ptr, uv_handle_ptr_<uv_async_t>); + + int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr); + + void send(); +}; + +struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t> +{ + CM_PERFECT_FWD_CTOR(uv_signal_ptr, uv_handle_ptr_<uv_signal_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_signal_cb cb, int signum); + + void stop(); +}; + +struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t> +{ + CM_PERFECT_FWD_CTOR(uv_pipe_ptr, uv_handle_ptr_<uv_pipe_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int ipc, void* data = nullptr); +}; + +struct uv_process_ptr : public uv_handle_ptr_<uv_process_t> +{ + CM_PERFECT_FWD_CTOR(uv_process_ptr, uv_handle_ptr_<uv_process_t>); + + int spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data = nullptr); +}; + +struct uv_timer_ptr : public uv_handle_ptr_<uv_timer_t> +{ + CM_PERFECT_FWD_CTOR(uv_timer_ptr, uv_handle_ptr_<uv_timer_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat); +}; + +struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t> +{ + CM_PERFECT_FWD_CTOR(uv_tty_ptr, uv_handle_ptr_<uv_tty_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr); +}; + +typedef uv_handle_ptr_<uv_stream_t> uv_stream_ptr; +typedef uv_handle_ptr_<uv_handle_t> uv_handle_ptr; + +#ifndef cmUVHandlePtr_cxx + +extern template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \ + extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + extern template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(async) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(process) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty) + +#undef UV_HANDLE_PTR_INSTANTIATE_EXTERN + +#endif +} diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index caeeeb9..8589a96 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -52,6 +52,7 @@ static std::string cmVS10EscapeComment(std::string comment) case '>': /* no break */ case '^': echoable += '^'; /* no break */ + CM_FALLTHROUGH; default: echoable += *c; break; @@ -66,11 +67,14 @@ static bool cmVS10IsTargetsFile(std::string const& path) return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; } -static std::string computeProjectFileExtension(cmGeneratorTarget const* t) +static std::string computeProjectFileExtension(cmGeneratorTarget const* t, + const std::string& config) { std::string res; res = ".vcxproj"; - if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t)) { + std::string lang = t->GetLinkerLanguage(config); + if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) || + lang == "CSharp") { res = ".csproj"; } return res; @@ -199,8 +203,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) { return; } - this->ProjectFileExtension = - computeProjectFileExtension(this->GeneratorTarget); + this->ProjectFileExtension = computeProjectFileExtension( + this->GeneratorTarget, *this->Configurations.begin()); if (this->ProjectFileExtension == ".vcxproj") { this->ProjectType = vcxproj; this->Managed = false; @@ -1393,7 +1397,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() std::string path = this->LocalGenerator->GetCurrentBinaryDirectory(); path += "/"; path += this->Name; - path += computeProjectFileExtension(this->GeneratorTarget); + path += computeProjectFileExtension(this->GeneratorTarget, + *this->Configurations.begin()); path += ".filters"; cmGeneratedFileStream fout(path.c_str()); fout.SetCopyIfDifferent(true); @@ -2061,14 +2066,15 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string flags; bool configDependentFlags = false; std::string defines; + bool configDependentDefines = false; if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - - if (cmGeneratorExpression::Find(cflags) != std::string::npos) { - configDependentFlags = true; - } + configDependentFlags = + cmGeneratorExpression::Find(cflags) != std::string::npos; flags += cflags; } if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { + configDependentDefines = + cmGeneratorExpression::Find(cdefs) != std::string::npos; defines += cdefs; } std::string lang = @@ -2118,12 +2124,13 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (!configDefines.empty()) { configDefines += ";"; } + configDependentDefines |= + cmGeneratorExpression::Find(ccdefs) != std::string::npos; configDefines += ccdefs; } // if we have flags or defines for this config then // use them - if (!flags.empty() || configDependentFlags || !configDefines.empty() || - compileAs || noWinRT) { + if (!flags.empty() || !configDefines.empty() || compileAs || noWinRT) { (*this->BuildFileStream) << firstString; firstString = ""; // only do firstString once hasFlags = true; @@ -2144,6 +2151,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } else if (srclang == "CSharp") { flagtable = gg->GetCSharpFlagTable(); } + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, *config); cmVisualStudioGeneratorOptions clOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler, flagtable, 0, this); @@ -2154,11 +2163,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddFlag("CompileAsWinRT", "false"); } if (configDependentFlags) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(flags); - std::string evaluatedFlags = cge->Evaluate( - this->LocalGenerator, *config, false, this->GeneratorTarget); - clOptions.Parse(evaluatedFlags.c_str()); + clOptions.Parse(genexInterpreter.Evaluate(flags)); } else { clOptions.Parse(flags.c_str()); } @@ -2170,7 +2175,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AppendFlag("DisableSpecificWarnings", "%(DisableSpecificWarnings)"); } - clOptions.AddDefines(configDefines.c_str()); + if (configDependentDefines) { + clOptions.AddDefines(genexInterpreter.Evaluate(configDefines)); + } else { + clOptions.AddDefines(configDefines.c_str()); + } clOptions.SetConfiguration((*config).c_str()); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -3670,7 +3679,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() path = lg->GetCurrentBinaryDirectory(); path += "/"; path += dt->GetName(); - path += computeProjectFileExtension(dt); + path += computeProjectFileExtension(dt, *this->Configurations.begin()); } this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; diff --git a/Source/cm_thread.hxx b/Source/cm_thread.hxx index b8c25c7..84e6a5c 100644 --- a/Source/cm_thread.hxx +++ b/Source/cm_thread.hxx @@ -7,36 +7,11 @@ #include "cm_uv.h" namespace cm { -class mutex -{ - uv_mutex_t _M_; - -public: - mutex() { uv_mutex_init(&_M_); } - ~mutex() { uv_mutex_destroy(&_M_); } - - void lock() { uv_mutex_lock(&_M_); } - - void unlock() { uv_mutex_unlock(&_M_); } -}; - -template <typename T> -class lock_guard -{ - T& _mutex; - -public: - lock_guard(T& m) - : _mutex(m) - { - _mutex.lock(); - } - ~lock_guard() { _mutex.unlock(); } -}; class shared_mutex { uv_rwlock_t _M_; + CM_DISABLE_COPY(shared_mutex) public: shared_mutex() { uv_rwlock_init(&_M_); } @@ -55,6 +30,7 @@ template <typename T> class shared_lock { T& _mutex; + CM_DISABLE_COPY(shared_lock) public: shared_lock(T& m) @@ -64,15 +40,5 @@ public: } ~shared_lock() { _mutex.unlock_shared(); } }; - -template <typename T> -class unique_lock : public lock_guard<T> -{ -public: - unique_lock(T& m) - : lock_guard<T>(m) - { - } -}; } #endif diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 3d9f65a..b78fbe6 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -270,10 +270,12 @@ static int HandleCppLint(const std::string& runCmd, << "\n"; return 1; } - + std::cerr << "Warning: cpplint diagnostics:\n"; // Output the output from cpplint to stderr std::cerr << stdOut; - return ret; + // always return 0 so the build can continue as cpplint returns non-zero + // for any warning + return 0; } static int HandleCppCheck(const std::string& runCmd, diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 51f4088..64b6484 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -1033,6 +1033,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ) ENDIF() SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConfigure testSystemTools testCommandLineArguments testCommandLineArguments1 diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in index 1c07a4e..1e67874 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -12,6 +12,31 @@ #define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ +#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) +#elif defined(__has_cpp_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) +#else +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 +#endif + +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#if __cplusplus >= 201703L && @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] +#endif +#endif +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast<void>(0) +#endif + +#undef @KWSYS_NAMESPACE@__has_cpp_attribute + /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ #if defined(KWSYS_NAMESPACE) @@ -22,6 +47,7 @@ #define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING #define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +#define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH #endif #endif diff --git a/Source/kwsys/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in index 46d65a8..cf68146 100644 --- a/Source/kwsys/ConsoleBuf.hxx.in +++ b/Source/kwsys/ConsoleBuf.hxx.in @@ -264,6 +264,7 @@ private: if (m_isConsoleInput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeInputCodepage = input_pipe_codepage; break; @@ -290,6 +291,7 @@ private: if (m_isConsoleOutput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeOutputCodepage = output_pipe_codepage; break; diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx index 26e84e0..fa3551c 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -45,9 +45,9 @@ RegularExpression::RegularExpression(const RegularExpression& rxp) this->program = new char[this->progsize]; // Allocate storage for (ind = this->progsize; ind-- != 0;) // Copy regular expresion this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field if (rxp.regmust != 0) { char* dum = rxp.program; ind = 0; @@ -78,9 +78,9 @@ RegularExpression& RegularExpression::operator=(const RegularExpression& rxp) this->program = new char[this->progsize]; // Allocate storage for (ind = this->progsize; ind-- != 0;) // Copy regular expresion this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field if (rxp.regmust != 0) { char* dum = rxp.program; ind = 0; @@ -123,8 +123,9 @@ bool RegularExpression::deep_equal(const RegularExpression& rxp) const while (ind-- != 0) // Else while still characters if (this->program[ind] != rxp.program[ind]) // If regexp are different return false; // Return failure - return (this->startp[0] == rxp.startp[0] && // Else if same start/end ptrs, - this->endp[0] == rxp.endp[0]); // Return true + // Else if same start/end ptrs, return true + return (this->regmatch.start() == rxp.regmatch.start() && + this->regmatch.end() == rxp.regmatch.end()); } // The remaining code in this file is derived from the regular expression code @@ -276,31 +277,35 @@ const unsigned char MAGIC = 0234; ///////////////////////////////////////////////////////////////////////// /* - * Global work variables for compile(). + * Read only utility variables. */ -static const char* regparse; // Input-scan pointer. -static int regnpar; // () count. static char regdummy; -static char* regcode; // Code-emit pointer; ®dummy = don't. -static long regsize; // Code size. +static char* const regdummyptr = ®dummy; /* - * Forward declarations for compile()'s friends. + * Utility class for RegularExpression::compile(). */ -// #ifndef static -// #define static static -// #endif -static char* reg(int, int*); -static char* regbranch(int*); -static char* regpiece(int*); -static char* regatom(int*); -static char* regnode(char); +class RegExpCompile +{ +public: + const char* regparse; // Input-scan pointer. + int regnpar; // () count. + char* regcode; // Code-emit pointer; regdummyptr = don't. + long regsize; // Code size. + + char* reg(int, int*); + char* regbranch(int*); + char* regpiece(int*); + char* regatom(int*); + char* regnode(char); + void regc(char); + void reginsert(char, char*); + static void regtail(char*, const char*); + static void regoptail(char*, const char*); +}; + static const char* regnext(const char*); static char* regnext(char*); -static void regc(char); -static void reginsert(char, char*); -static void regtail(char*, const char*); -static void regoptail(char*, const char*); #ifdef STRCSPN static int strcspn(); @@ -337,19 +342,20 @@ bool RegularExpression::compile(const char* exp) } // First pass: determine size, legality. - regparse = exp; - regnpar = 1; - regsize = 0L; - regcode = ®dummy; - regc(static_cast<char>(MAGIC)); - if (!reg(0, &flags)) { + RegExpCompile comp; + comp.regparse = exp; + comp.regnpar = 1; + comp.regsize = 0L; + comp.regcode = regdummyptr; + comp.regc(static_cast<char>(MAGIC)); + if (!comp.reg(0, &flags)) { printf("RegularExpression::compile(): Error in compile.\n"); return false; } - this->startp[0] = this->endp[0] = this->searchstring = 0; + this->regmatch.clear(); // Small enough for pointer-storage convention? - if (regsize >= 32767L) { // Probably could be 65535L. + if (comp.regsize >= 32767L) { // Probably could be 65535L. // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), printf("RegularExpression::compile(): Expression too big.\n"); return false; @@ -360,8 +366,8 @@ bool RegularExpression::compile(const char* exp) if (this->program != 0) delete[] this->program; //#endif - this->program = new char[regsize]; - this->progsize = static_cast<int>(regsize); + this->program = new char[comp.regsize]; + this->progsize = static_cast<int>(comp.regsize); if (this->program == 0) { // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory), @@ -370,11 +376,11 @@ bool RegularExpression::compile(const char* exp) } // Second pass: emit code. - regparse = exp; - regnpar = 1; - regcode = this->program; - regc(static_cast<char>(MAGIC)); - reg(0, &flags); + comp.regparse = exp; + comp.regnpar = 1; + comp.regcode = this->program; + comp.regc(static_cast<char>(MAGIC)); + comp.reg(0, &flags); // Dig out information for optimizations. this->regstart = '\0'; // Worst-case defaults. @@ -423,7 +429,7 @@ bool RegularExpression::compile(const char* exp) * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ -static char* reg(int paren, int* flagp) +char* RegExpCompile::reg(int paren, int* flagp) { char* ret; char* br; @@ -435,7 +441,7 @@ static char* reg(int paren, int* flagp) // Make an OPEN node, if parenthesized. if (paren) { - if (regnpar >= RegularExpression::NSUBEXP) { + if (regnpar >= RegularExpressionMatch::NSUBEXP) { // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens), printf("RegularExpression::compile(): Too many parentheses.\n"); return 0; @@ -501,7 +507,7 @@ static char* reg(int paren, int* flagp) * * Implements the concatenation operator. */ -static char* regbranch(int* flagp) +char* RegExpCompile::regbranch(int* flagp) { char* ret; char* chain; @@ -538,7 +544,7 @@ static char* regbranch(int* flagp) * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ -static char* regpiece(int* flagp) +char* RegExpCompile::regpiece(int* flagp) { char* ret; char op; @@ -605,7 +611,7 @@ static char* regpiece(int* flagp) * faster to run. Backslashed characters are exceptions, each becoming a * separate node; the code is simpler that way and it's not worth fixing. */ -static char* regatom(int* flagp) +char* RegExpCompile::regatom(int* flagp) { char* ret; int flags; @@ -724,13 +730,13 @@ static char* regatom(int* flagp) - regnode - emit a node Location. */ -static char* regnode(char op) +char* RegExpCompile::regnode(char op) { char* ret; char* ptr; ret = regcode; - if (ret == ®dummy) { + if (ret == regdummyptr) { regsize += 3; return (ret); } @@ -747,9 +753,9 @@ static char* regnode(char op) /* - regc - emit (if appropriate) a byte of code */ -static void regc(char b) +void RegExpCompile::regc(char b) { - if (regcode != ®dummy) + if (regcode != regdummyptr) *regcode++ = b; else regsize++; @@ -760,13 +766,13 @@ static void regc(char b) * * Means relocating the operand. */ -static void reginsert(char op, char* opnd) +void RegExpCompile::reginsert(char op, char* opnd) { char* src; char* dst; char* place; - if (regcode == ®dummy) { + if (regcode == regdummyptr) { regsize += 3; return; } @@ -786,13 +792,13 @@ static void reginsert(char op, char* opnd) /* - regtail - set the next-pointer at the end of a node chain */ -static void regtail(char* p, const char* val) +void RegExpCompile::regtail(char* p, const char* val) { char* scan; char* temp; int offset; - if (p == ®dummy) + if (p == regdummyptr) return; // Find last node. @@ -815,10 +821,10 @@ static void regtail(char* p, const char* val) /* - regoptail - regtail on operand of first argument; nop if operandless */ -static void regoptail(char* p, const char* val) +void RegExpCompile::regoptail(char* p, const char* val) { // "Operandless" and "op != BRANCH" are synonymous in practice. - if (p == 0 || p == ®dummy || OP(p) != BRANCH) + if (p == 0 || p == regdummyptr || OP(p) != BRANCH) return; regtail(OPERAND(p), val); } @@ -830,34 +836,30 @@ static void regoptail(char* p, const char* val) //////////////////////////////////////////////////////////////////////// /* - * Global work variables for find(). + * Utility class for RegularExpression::find(). */ -static const char* reginput; // String-input pointer. -static const char* regbol; // Beginning of input, for ^ check. -static const char** regstartp; // Pointer to startp array. -static const char** regendp; // Ditto for endp. +class RegExpFind +{ +public: + const char* reginput; // String-input pointer. + const char* regbol; // Beginning of input, for ^ check. + const char** regstartp; // Pointer to startp array. + const char** regendp; // Ditto for endp. -/* - * Forwards. - */ -static int regtry(const char*, const char**, const char**, const char*); -static int regmatch(const char*); -static int regrepeat(const char*); - -#ifdef DEBUG -int regnarrate = 0; -void regdump(); -static char* regprop(); -#endif + int regtry(const char*, const char**, const char**, const char*); + int regmatch(const char*); + int regrepeat(const char*); +}; // find -- Matches the regular expression to the given string. // Returns true if found, and sets start and end indexes accordingly. - -bool RegularExpression::find(const char* string) +bool RegularExpression::find(char const* string, + RegularExpressionMatch& rmatch) const { const char* s; - this->searchstring = string; + rmatch.clear(); + rmatch.searchstring = string; if (!this->program) { return false; @@ -868,7 +870,7 @@ bool RegularExpression::find(const char* string) // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf( "RegularExpression::find(): Compiled regular expression corrupted.\n"); - return 0; + return false; } // If there is a "must appear" string, look for it. @@ -880,42 +882,45 @@ bool RegularExpression::find(const char* string) s++; } if (s == 0) // Not present. - return (0); + return false; } + RegExpFind regFind; + // Mark beginning of line for ^ . - regbol = string; + regFind.regbol = string; // Simplest case: anchored match need be tried only once. if (this->reganch) - return (regtry(string, this->startp, this->endp, this->program) != 0); + return ( + regFind.regtry(string, rmatch.startp, rmatch.endp, this->program) != 0); // Messy cases: unanchored match. s = string; if (this->regstart != '\0') // We know what char it must start with. while ((s = strchr(s, this->regstart)) != 0) { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; s++; } else // We don't -- general case. do { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; } while (*s++ != '\0'); // Failure. - return (0); + return false; } /* - regtry - try match at specific point 0 failure, 1 success */ -static int regtry(const char* string, const char** start, const char** end, - const char* prog) +int RegExpFind::regtry(const char* string, const char** start, + const char** end, const char* prog) { int i; const char** sp1; @@ -927,7 +932,7 @@ static int regtry(const char* string, const char** start, const char** end, sp1 = start; ep = end; - for (i = RegularExpression::NSUBEXP; i > 0; i--) { + for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) { *sp1++ = 0; *ep++ = 0; } @@ -950,7 +955,7 @@ static int regtry(const char* string, const char** start, const char** end, * by recursion. * 0 failure, 1 success */ -static int regmatch(const char* prog) +int RegExpFind::regmatch(const char* prog) { const char* scan; // Current node. const char* next; // Next node. @@ -1129,7 +1134,7 @@ static int regmatch(const char* prog) /* - regrepeat - repeatedly match something simple, report how many */ -static int regrepeat(const char* p) +int RegExpFind::regrepeat(const char* p) { int count = 0; const char* scan; @@ -1176,7 +1181,7 @@ static const char* regnext(const char* p) { int offset; - if (p == ®dummy) + if (p == regdummyptr) return (0); offset = NEXT(p); @@ -1193,7 +1198,7 @@ static char* regnext(char* p) { int offset; - if (p == ®dummy) + if (p == regdummyptr) return (0); offset = NEXT(p); diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index 763fdab..a3fe72d 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -34,6 +34,115 @@ namespace @KWSYS_NAMESPACE@ { +// Forward declaration +class RegularExpression; + +/** \class RegularExpressionMatch + * \brief Stores the pattern matches of a RegularExpression + */ +class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch +{ +public: + RegularExpressionMatch(); + + bool isValid() const; + void clear(); + + std::string::size_type start() const; + std::string::size_type end() const; + std::string::size_type start(int n) const; + std::string::size_type end(int n) const; + std::string match(int n) const; + + enum + { + NSUBEXP = 10 + }; + +private: + friend class RegularExpression; + const char* startp[NSUBEXP]; + const char* endp[NSUBEXP]; + const char* searchstring; +}; + +/** + * \brief Creates an invalid match object + */ +inline RegularExpressionMatch::RegularExpressionMatch() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns true if the match pointers are valid + */ +inline bool RegularExpressionMatch::isValid() const +{ + return (this->startp[0] != 0); +} + +/** + * \brief Resets to the (invalid) construction state. + */ +inline void RegularExpressionMatch::clear() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns the start index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start() const +{ + return static_cast<std::string::size_type>(this->startp[0] - searchstring); +} + +/** + * \brief Returns the end index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end() const +{ + return static_cast<std::string::size_type>(this->endp[0] - searchstring); +} + +/** + * \brief Returns the start index of nth submatch. + * start(0) is the start of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start(int n) const +{ + return static_cast<std::string::size_type>(this->startp[n] - + this->searchstring); +} + +/** + * \brief Returns the end index of nth submatch. + * end(0) is the end of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end(int n) const +{ + return static_cast<std::string::size_type>(this->endp[n] - + this->searchstring); +} + +/** + * \brief Returns the nth submatch as a string. + */ +inline std::string RegularExpressionMatch::match(int n) const +{ + if (this->startp[n] == 0) { + return std::string(); + } else { + return std::string(this->startp[n], static_cast<std::string::size_type>( + this->endp[n] - this->startp[n])); + } +} + /** \class RegularExpression * \brief Implements pattern matching with regular expressions. * @@ -170,6 +279,9 @@ namespace @KWSYS_NAMESPACE@ { * the same as the two characters before the first p encounterd in * the line. It would match "drepa qrepb" in "rep drepa qrepb". * + * All methods of RegularExpression can be called simultaneously from + * different threads but only if each invocation uses an own instance of + * RegularExpression. */ class @KWSYS_NAMESPACE@_EXPORT RegularExpression { @@ -213,9 +325,19 @@ public: /** * Matches the regular expression to the given string. + * Returns true if found, and sets start and end indexes + * in the RegularExpressionMatch instance accordingly. + * + * This method is thread safe when called with different + * RegularExpressionMatch instances. + */ + bool find(char const*, RegularExpressionMatch&) const; + + /** + * Matches the regular expression to the given string. * Returns true if found, and sets start and end indexes accordingly. */ - bool find(char const*); + inline bool find(char const*); /** * Matches the regular expression to the given std string. @@ -224,14 +346,18 @@ public: inline bool find(std::string const&); /** - * Index to start of first find. + * Match indices */ + inline RegularExpressionMatch const& regMatch() const; inline std::string::size_type start() const; + inline std::string::size_type end() const; + inline std::string::size_type start(int n) const; + inline std::string::size_type end(int n) const; /** - * Index to end of first find. + * Match strings */ - inline std::string::size_type end() const; + inline std::string match(int n) const; /** * Copy the given regular expression. @@ -266,29 +392,14 @@ public: */ inline void set_invalid(); - /** - * Destructor. - */ - // awf added - std::string::size_type start(int n) const; - std::string::size_type end(int n) const; - std::string match(int n) const; - - enum - { - NSUBEXP = 10 - }; - private: - const char* startp[NSUBEXP]; - const char* endp[NSUBEXP]; + RegularExpressionMatch regmatch; char regstart; // Internal use only char reganch; // Internal use only const char* regmust; // Internal use only std::string::size_type regmlen; // Internal use only char* program; int progsize; - const char* searchstring; }; /** @@ -344,51 +455,42 @@ inline bool RegularExpression::compile(std::string const& s) * Matches the regular expression to the given std string. * Returns true if found, and sets start and end indexes accordingly. */ -inline bool RegularExpression::find(std::string const& s) +inline bool RegularExpression::find(const char* s) { - return this->find(s.c_str()); + return this->find(s, this->regmatch); } /** - * Set the start position for the regular expression. + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. */ -inline std::string::size_type RegularExpression::start() const +inline bool RegularExpression::find(std::string const& s) { - return static_cast<std::string::size_type>(this->startp[0] - searchstring); + return this->find(s.c_str()); } /** - * Returns the start/end index of the last item found. + * Returns the internal match object */ -inline std::string::size_type RegularExpression::end() const +inline RegularExpressionMatch const& RegularExpression::regMatch() const { - return static_cast<std::string::size_type>(this->endp[0] - searchstring); + return this->regmatch; } /** - * Returns true if two regular expressions have different - * compiled program for pattern matching. + * Returns the start index of the full match. */ -inline bool RegularExpression::operator!=(const RegularExpression& r) const +inline std::string::size_type RegularExpression::start() const { - return (!(*this == r)); + return regmatch.start(); } /** - * Returns true if a valid regular expression is compiled - * and ready for pattern matching. + * Returns the end index of the full match. */ -inline bool RegularExpression::is_valid() const -{ - return (this->program != 0); -} - -inline void RegularExpression::set_invalid() +inline std::string::size_type RegularExpression::end() const { - //#ifndef _WIN32 - delete[] this->program; - //#endif - this->program = 0; + return regmatch.end(); } /** @@ -396,7 +498,7 @@ inline void RegularExpression::set_invalid() */ inline std::string::size_type RegularExpression::start(int n) const { - return static_cast<std::string::size_type>(this->startp[n] - searchstring); + return regmatch.start(n); } /** @@ -404,7 +506,7 @@ inline std::string::size_type RegularExpression::start(int n) const */ inline std::string::size_type RegularExpression::end(int n) const { - return static_cast<std::string::size_type>(this->endp[n] - searchstring); + return regmatch.end(n); } /** @@ -412,12 +514,33 @@ inline std::string::size_type RegularExpression::end(int n) const */ inline std::string RegularExpression::match(int n) const { - if (this->startp[n] == 0) { - return std::string(""); - } else { - return std::string(this->startp[n], static_cast<std::string::size_type>( - this->endp[n] - this->startp[n])); - } + return regmatch.match(n); +} + +/** + * Returns true if two regular expressions have different + * compiled program for pattern matching. + */ +inline bool RegularExpression::operator!=(const RegularExpression& r) const +{ + return (!(*this == r)); +} + +/** + * Returns true if a valid regular expression is compiled + * and ready for pattern matching. + */ +inline bool RegularExpression::is_valid() const +{ + return (this->program != 0); +} + +inline void RegularExpression::set_invalid() +{ + //#ifndef _WIN32 + delete[] this->program; + //#endif + this->program = 0; } } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/testConfigure.cxx b/Source/kwsys/testConfigure.cxx new file mode 100644 index 0000000..916dcc1 --- /dev/null +++ b/Source/kwsys/testConfigure.cxx @@ -0,0 +1,30 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +#include "Configure.hxx.in" +#endif + +static bool testFallthrough(int n) +{ + int r = 0; + switch (n) { + case 1: + ++r; + KWSYS_FALLTHROUGH; + default: + ++r; + } + return r == 2; +} + +int testConfigure(int, char* []) +{ + bool res = true; + res = testFallthrough(1) && res; + return res ? 0 : 1; +} diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index d1a1df5..9f09185 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -12,6 +12,7 @@ set(CMakeLib_TESTS testXMLParser testXMLSafe testFindPackageCommand + testUVRAII ) set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) @@ -31,6 +32,9 @@ create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS}) add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS}) target_link_libraries(CMakeLibTests CMakeLib) +set_property(TARGET CMakeLibTests PROPERTY C_CLANG_TIDY "") +set_property(TARGET CMakeLibTests PROPERTY CXX_CLANG_TIDY "") + add_executable(testEncoding testEncoding.cxx) target_link_libraries(testEncoding cmsys) diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx new file mode 100644 index 0000000..44def25 --- /dev/null +++ b/Tests/CMakeLib/testUVRAII.cxx @@ -0,0 +1,181 @@ +#include "cmUVHandlePtr.h" + +#include <algorithm> +#include <chrono> +#include <iostream> +#include <thread> + +#include "cm_uv.h" + +static void signal_reset_fn(uv_async_t* handle) +{ + auto ptr = static_cast<cm::uv_async_ptr*>(handle->data); + ptr->reset(); +} + +// A common pattern is to use an async signal to shutdown the server. +static bool testAsyncShutdown() +{ + uv_loop_t Loop; + auto err = uv_loop_init(&Loop); + if (err != 0) { + std::cerr << "Could not init loop" << std::endl; + return false; + } + + { + cm::uv_async_ptr signal; + signal.init(Loop, &signal_reset_fn, &signal); + + std::thread([&] { + std::this_thread::sleep_for(std::chrono::seconds(2)); + signal.send(); + }).detach(); + + if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { + std::cerr << "Unclean exit state in testAsyncDtor" << std::endl; + return false; + } + + if (signal.get()) { + std::cerr << "Loop exited with signal not being cleaned up" << std::endl; + return false; + } + } + + uv_loop_close(&Loop); + + return true; +} + +static void signal_fn(uv_async_t*) +{ +} + +// Async dtor is sort of a pain; since it locks a mutex we must be sure its +// dtor always calls reset otherwise the mutex is deleted then locked. +static bool testAsyncDtor() +{ + uv_loop_t Loop; + auto err = uv_loop_init(&Loop); + if (err != 0) { + std::cerr << "Could not init loop" << std::endl; + return false; + } + + { + cm::uv_async_ptr signal; + signal.init(Loop, signal_fn); + } + + if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { + std::cerr << "Unclean exit state in testAsyncDtor" << std::endl; + return false; + } + + uv_loop_close(&Loop); + + return true; +} + +// Async needs a relatively stateful deleter; make sure that is properly +// accounted for and doesn't try to hold on to invalid state when it is +// moved +static bool testAsyncMove() +{ + uv_loop_t Loop; + auto err = uv_loop_init(&Loop); + if (err != 0) { + std::cerr << "Could not init loop" << std::endl; + return false; + } + + { + cm::uv_async_ptr signal; + { + cm::uv_async_ptr signalTmp; + signalTmp.init(Loop, signal_fn); + signal = std::move(signalTmp); + } + } + + if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { + std::cerr << "Unclean exit state in testAsyncDtor" << std::endl; + return false; + } + + uv_loop_close(&Loop); + return true; +} + +// When a type is castable to another uv type (pipe -> stream) here, +// and the deleter is convertible as well, we should allow moves from +// one type to the other. +static bool testCrossAssignment() +{ + uv_loop_t Loop; + auto err = uv_loop_init(&Loop); + if (err != 0) { + std::cerr << "Could not init loop" << std::endl; + return false; + } + + { + cm::uv_pipe_ptr pipe; + pipe.init(Loop, 0); + + cm::uv_stream_ptr stream = std::move(pipe); + if (pipe.get()) { + std::cerr << "Move should be sure to invalidate the previous ptr" + << std::endl; + return false; + } + cm::uv_handle_ptr handle = std::move(stream); + if (stream.get()) { + std::cerr << "Move should be sure to invalidate the previous ptr" + << std::endl; + return false; + } + } + + if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { + std::cerr << "Unclean exit state in testCrossAssignment" << std::endl; + return false; + } + + uv_loop_close(&Loop); + return true; +} + +// This test can't fail at run time; but this makes sure we have all our move +// ctors created correctly. +static bool testAllMoves() +{ + using namespace cm; + struct allTypes + { + uv_stream_ptr _7; + uv_timer_ptr _8; + uv_tty_ptr _9; + uv_process_ptr _11; + uv_pipe_ptr _12; + uv_async_ptr _13; + uv_signal_ptr _14; + uv_handle_ptr _15; + }; + + allTypes a; + allTypes b(std::move(a)); + allTypes c = std::move(b); + return true; +}; + +int testUVRAII(int, char** const) +{ + if ((testAsyncShutdown() && + testAsyncDtor() & testAsyncMove() & testCrossAssignment() & + testAllMoves()) == 0) { + return -1; + } + return 0; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 4a7b8c9..9507880 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -149,9 +149,7 @@ if(BUILD_TESTING) if(NOT CMake_TEST_EXTERNAL_CMAKE) add_subdirectory(CMakeLib) - if(CMake_TEST_SERVER_MODE) - add_subdirectory(CMakeServerLib) - endif() + add_subdirectory(CMakeServerLib) endif() add_subdirectory(CMakeOnly) add_subdirectory(RunCMake) @@ -1433,6 +1431,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(GoogleTest) endif() + if(CMake_TEST_FindIconv) + add_subdirectory(FindIconv) + endif() + if(CMake_TEST_FindICU) add_subdirectory(FindICU) endif() diff --git a/Tests/CMakeServerLib/CMakeLists.txt b/Tests/CMakeServerLib/CMakeLists.txt index f5351fd..5e1ad0c 100644 --- a/Tests/CMakeServerLib/CMakeLists.txt +++ b/Tests/CMakeServerLib/CMakeLists.txt @@ -12,6 +12,9 @@ create_test_sourcelist(CMakeLib_TEST_SRCS CMakeServerLibTests.cxx ${CMakeServerL add_executable(CMakeServerLibTests ${CMakeLib_TEST_SRCS}) target_link_libraries(CMakeServerLibTests CMakeLib CMakeServerLib) +SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY C_CLANG_TIDY "") +SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY CXX_CLANG_TIDY "") + foreach(test ${CMakeServerLib_TESTS}) add_test(CMakeServerLib.${test} CMakeServerLibTests ${test} ${${test}_ARGS}) endforeach() diff --git a/Tests/CMakeServerLib/testServerBuffering.cpp b/Tests/CMakeServerLib/testServerBuffering.cpp index 97be891..7330ead 100644 --- a/Tests/CMakeServerLib/testServerBuffering.cpp +++ b/Tests/CMakeServerLib/testServerBuffering.cpp @@ -1,7 +1,6 @@ #include "cmConnection.h" #include "cmServerConnection.h" #include <iostream> -#include <stddef.h> #include <string> #include <vector> @@ -51,8 +50,8 @@ int testServerBuffering(int, char** const) std::unique_ptr<cmConnectionBufferStrategy>(new cmServerBufferStrategy); std::vector<std::string> response; std::string rawBuffer; - for (size_t i = 0; i < fullMessage.size(); i++) { - rawBuffer += fullMessage[i]; + for (auto& messageChar : fullMessage) { + rawBuffer += messageChar; std::string packet = bufferingStrategy->BufferMessage(rawBuffer); do { if (!packet.empty() && packet != "\r\n") { diff --git a/Tests/FindIconv/CMakeLists.txt b/Tests/FindIconv/CMakeLists.txt new file mode 100644 index 0000000..b205b80 --- /dev/null +++ b/Tests/FindIconv/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindIconv.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindIconv/Test" + "${CMake_BINARY_DIR}/Tests/FindIconv/Test" + ${build_generator_args} + --build-project TestFindIconv + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindIconv/Test/CMakeLists.txt b/Tests/FindIconv/Test/CMakeLists.txt new file mode 100644 index 0000000..c59adb3 --- /dev/null +++ b/Tests/FindIconv/Test/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) +project(TestFindIconv CXX) +include(CTest) + +find_package(Iconv REQUIRED) + +add_executable(test_iconv_tgt main.cxx) +target_link_libraries(test_iconv_tgt Iconv::Iconv) +add_test(NAME test_iconv_tgt COMMAND test_iconv_tgt) + +add_executable(test_iconv_var main.cxx) +target_include_directories(test_iconv_var PRIVATE ${Iconv_INCLUDE_DIRS}) +target_link_libraries(test_iconv_var PRIVATE ${Iconv_LIBRARIES}) +add_test(NAME test_iconv_var COMMAND test_iconv_var) diff --git a/Tests/FindIconv/Test/main.cxx b/Tests/FindIconv/Test/main.cxx new file mode 100644 index 0000000..415ee37 --- /dev/null +++ b/Tests/FindIconv/Test/main.cxx @@ -0,0 +1,52 @@ +extern "C" { +#include <iconv.h> +} +#include <array> +#include <cstddef> +#include <cstdlib> +#include <iostream> +#include <string> +#include <system_error> + +class iconv_desc +{ +private: + iconv_t iconvd_; + +public: + iconv_desc(const std::string& tocode, const std::string& fromcode) + { + iconvd_ = iconv_open(tocode.c_str(), fromcode.c_str()); + if (iconvd_ == reinterpret_cast<iconv_t>(-1)) + throw std::system_error(errno, std::system_category()); + } + + ~iconv_desc() { iconv_close(iconvd_); } + + operator iconv_t() { return this->iconvd_; } +}; + +int main() +{ + try { + auto conv_d = iconv_desc{ "ISO-8859-1", "UTF-8" }; + auto from_str = std::array<char, 10>{ u8"a\xC3\xA4o\xC3\xB6u\xC3\xBC" }; + auto to_str = std::array<char, 7>{}; + + auto from_str_ptr = from_str.data(); + auto from_len = from_str.size(); + auto to_str_ptr = to_str.data(); + auto to_len = to_str.size(); + const auto iconv_ret = + iconv(conv_d, &from_str_ptr, &from_len, &to_str_ptr, &to_len); + if (iconv_ret == static_cast<std::size_t>(-1)) + throw std::system_error(errno, std::system_category()); + std::cout << '\'' << from_str.data() << "\' converted to \'" + << to_str.data() << '\'' << std::endl; + return EXIT_SUCCESS; + } catch (const std::system_error& ex) { + std::cerr << "ERROR: " << ex.code() << '\n' + << ex.code().message() << std::endl; + } + return EXIT_FAILURE; +} diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 83fd11d..5165970 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -258,8 +258,13 @@ add_custom_target(check-part4 ALL VERBATIM ) -add_executable(srcgenex srcgenex.c) -set_property(SOURCE srcgenex.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>") +#----------------------------------------------------------------------------- +# Cover source file properties with generator expressions. +add_executable(srcgenex_flags srcgenex_flags.c) +set_property(SOURCE srcgenex_flags.c PROPERTY COMPILE_FLAGS "-DNAME=$<TARGET_PROPERTY:NAME>") + +add_executable(srcgenex_defs srcgenex_defs.c) +set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>) #----------------------------------------------------------------------------- # Cover test properties with generator expressions. diff --git a/Tests/GeneratorExpression/srcgenex.c b/Tests/GeneratorExpression/srcgenex_defs.c index 56d3c3f..883e631 100644 --- a/Tests/GeneratorExpression/srcgenex.c +++ b/Tests/GeneratorExpression/srcgenex_defs.c @@ -1,4 +1,4 @@ -int srcgenex(void) +int srcgenex_defs(void) { return 0; } diff --git a/Tests/GeneratorExpression/srcgenex_flags.c b/Tests/GeneratorExpression/srcgenex_flags.c new file mode 100644 index 0000000..3de2b12 --- /dev/null +++ b/Tests/GeneratorExpression/srcgenex_flags.c @@ -0,0 +1,12 @@ +int srcgenex_flags(void) +{ + return 0; +} + +int main(int argc, char* argv[]) +{ +#ifndef NAME +#error NAME not defined +#endif + return NAME(); +} diff --git a/Tests/RunCMake/Cpplint/C-error-Build-result.txt b/Tests/RunCMake/Cpplint/C-error-Build-result.txt index d197c91..573541a 100644 --- a/Tests/RunCMake/Cpplint/C-error-Build-result.txt +++ b/Tests/RunCMake/Cpplint/C-error-Build-result.txt @@ -1 +1 @@ -[^0] +0 diff --git a/Tests/RunCMake/Cpplint/C-error-launch-Build-result.txt b/Tests/RunCMake/Cpplint/C-error-launch-Build-result.txt index d197c91..573541a 100644 --- a/Tests/RunCMake/Cpplint/C-error-launch-Build-result.txt +++ b/Tests/RunCMake/Cpplint/C-error-launch-Build-result.txt @@ -1 +1 @@ -[^0] +0 diff --git a/Tests/RunCMake/Cpplint/CXX-error-Build-result.txt b/Tests/RunCMake/Cpplint/CXX-error-Build-result.txt index d197c91..573541a 100644 --- a/Tests/RunCMake/Cpplint/CXX-error-Build-result.txt +++ b/Tests/RunCMake/Cpplint/CXX-error-Build-result.txt @@ -1 +1 @@ -[^0] +0 diff --git a/Tests/RunCMake/Cpplint/CXX-error-launch-Build-result.txt b/Tests/RunCMake/Cpplint/CXX-error-launch-Build-result.txt index d197c91..573541a 100644 --- a/Tests/RunCMake/Cpplint/CXX-error-launch-Build-result.txt +++ b/Tests/RunCMake/Cpplint/CXX-error-launch-Build-result.txt @@ -1 +1 @@ -[^0] +0 diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-result.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-stderr.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-stderr.txt new file mode 100644 index 0000000..55a4a7a --- /dev/null +++ b/Tests/RunCMake/GoogleTest/GoogleTest-test-missing-stderr.txt @@ -0,0 +1,2 @@ +Unable to find executable: timeout_test_NOT_BUILT +Errors while running CTest diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-timeout-result.txt b/Tests/RunCMake/GoogleTest/GoogleTest-timeout-result.txt new file mode 100644 index 0000000..d197c91 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/GoogleTest-timeout-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-timeout-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-timeout-stdout.txt new file mode 100644 index 0000000..8464c80 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/GoogleTest-timeout-stdout.txt @@ -0,0 +1,7 @@ +( *|[0-9]+>)CMake Error at .*GoogleTestAddTests.cmake:[0-9]+ \(message\): +( *|[0-9]+>) Error running test executable. +?( *|[0-9]+>) +( *|[0-9]+>) Path: '.*timeout_test(\.exe)?' +( *|[0-9]+>) Result: Process terminated due to timeout +( *|[0-9]+>) Output: +( *|[0-9]+>) + diff --git a/Tests/RunCMake/GoogleTest/GoogleTest.cmake b/Tests/RunCMake/GoogleTest/GoogleTest.cmake index 58f4196..5e4b8ef 100644 --- a/Tests/RunCMake/GoogleTest/GoogleTest.cmake +++ b/Tests/RunCMake/GoogleTest/GoogleTest.cmake @@ -21,3 +21,9 @@ gtest_discover_tests( EXTRA_ARGS how now "\"brown\" cow" PROPERTIES LABELS TEST2 ) + +add_executable(timeout_test timeout_test.cpp) + +gtest_discover_tests( + timeout_test +) diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake index b79af26..73014d1 100644 --- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake @@ -9,24 +9,45 @@ function(run_GoogleTest) endif() file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(GoogleTest) + run_cmake_command(GoogleTest-build ${CMAKE_COMMAND} --build . --config Debug + --target fake_gtest + ) + + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(GoogleTest-timeout + ${CMAKE_COMMAND} + --build . + --config Debug + --target timeout_test ) + set(RunCMake_TEST_OUTPUT_MERGE 0) + run_cmake_command(GoogleTest-test1 ${CMAKE_CTEST_COMMAND} -C Debug -L TEST1 --no-label-summary ) + run_cmake_command(GoogleTest-test2 ${CMAKE_CTEST_COMMAND} -C Debug -L TEST2 --no-label-summary ) + + run_cmake_command(GoogleTest-test-missing + ${CMAKE_CTEST_COMMAND} + -C Debug + -R timeout + --no-label-summary + ) endfunction() run_GoogleTest() diff --git a/Tests/RunCMake/GoogleTest/timeout_test.cpp b/Tests/RunCMake/GoogleTest/timeout_test.cpp new file mode 100644 index 0000000..a8e5c1c --- /dev/null +++ b/Tests/RunCMake/GoogleTest/timeout_test.cpp @@ -0,0 +1,15 @@ +#if defined(_WIN32) +#include <windows.h> +#else +#include <unistd.h> +#endif + +int main() +{ +#if defined(_WIN32) + Sleep(10000); +#else + sleep(10); +#endif + return 0; +} diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt index 8809f89..d5ee4f9 100644 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt @@ -1,6 +1,6 @@ CMake Error at LinkObjRHS1.cmake:3 \(target_link_libraries\): Target "AnObjLib" of type OBJECT_LIBRARY may not be linked into another - target. One may link only to STATIC or SHARED libraries, or to executables - with the ENABLE_EXPORTS property set. + target. One may link only to INTERFACE, STATIC or SHARED libraries, or to + executables with the ENABLE_EXPORTS property set. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 6e7c2f3..7100b31 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -5,3 +5,4 @@ run_cmake(VsCustomProps) run_cmake(VsDebuggerWorkingDir) run_cmake(VsCSharpCustomTags) run_cmake(VsCSharpReferenceProps) +run_cmake(VsCSharpWithoutSources) diff --git a/Tests/RunCMake/VS10Project/VsCSharpWithoutSources-check.cmake b/Tests/RunCMake/VS10Project/VsCSharpWithoutSources-check.cmake new file mode 100644 index 0000000..90ae7c3 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCSharpWithoutSources-check.cmake @@ -0,0 +1,5 @@ +set(csProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.csproj") +if(NOT EXISTS "${csProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCSharpWithoutSources.cmake b/Tests/RunCMake/VS10Project/VsCSharpWithoutSources.cmake new file mode 100644 index 0000000..5fdeaa0 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCSharpWithoutSources.cmake @@ -0,0 +1,7 @@ +enable_language(CSharp) + +add_library(foo SHARED + "${CMAKE_CURRENT_LIST_FILE}") + +set_target_properties(foo PROPERTIES + LINKER_LANGUAGE CSharp) diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-result.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt new file mode 100644 index 0000000..46a294d --- /dev/null +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt @@ -0,0 +1,8 @@ +^CMake Error in CMakeLists.txt: + Xcode does not support per-config per-source COMPILE_DEFINITIONS: + + \$<\$<CONFIG:Debug>:MYDEBUG> + + specified for source: + + .*/Tests/RunCMake/XcodeProject/main.c$ diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions.cmake b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions.cmake new file mode 100644 index 0000000..f9df55f --- /dev/null +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_executable(main main.c) +set_property(SOURCE main.c PROPERTY COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:MYDEBUG>") diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index f730b83..7eb624c 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -19,6 +19,7 @@ if (NOT XCODE_VERSION VERSION_LESS 6) endif() run_cmake(PerConfigPerSourceFlags) +run_cmake(PerConfigPerSourceDefinitions) # Use a single build tree for a few tests without cleaning. diff --git a/Tests/RunCMake/interface_library/whitelist.cmake b/Tests/RunCMake/interface_library/whitelist.cmake index 98ef05c..bf64f01 100644 --- a/Tests/RunCMake/interface_library/whitelist.cmake +++ b/Tests/RunCMake/interface_library/whitelist.cmake @@ -4,3 +4,13 @@ add_library(iface INTERFACE) set_property(TARGET iface PROPERTY OUTPUT_NAME output) set_property(TARGET iface APPEND PROPERTY OUTPUT_NAME append) get_target_property(outname iface OUTPUT_NAME) + +# Properties starting with `_` are allowed. +set_property(TARGET iface PROPERTY "_custom_property" output) +set_property(TARGET iface APPEND PROPERTY "_custom_property" append) +get_target_property(outname iface "_custom_property") + +# Properties starting with a lowercase letter are allowed. +set_property(TARGET iface PROPERTY "custom_property" output) +set_property(TARGET iface APPEND PROPERTY "custom_property" append) +get_target_property(outname iface "custom_property") diff --git a/Tests/RunCMake/target_link_libraries/MixedSignature-stderr.txt b/Tests/RunCMake/target_link_libraries/MixedSignature-stderr.txt index a0c66db..c6237f4 100644 --- a/Tests/RunCMake/target_link_libraries/MixedSignature-stderr.txt +++ b/Tests/RunCMake/target_link_libraries/MixedSignature-stderr.txt @@ -1,5 +1,5 @@ CMake Error at MixedSignature.cmake:6 \(target_link_libraries\): - The PUBLIC or PRIVATE option must appear as the second argument, just after - the target name. + The INTERFACE, PUBLIC or PRIVATE option must appear as the second argument, + just after the target name. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py index 39e3618..6e8761a 100644 --- a/Tests/Server/cmakelib.py +++ b/Tests/Server/cmakelib.py @@ -100,6 +100,14 @@ def waitForRawMessage(cmakeCommand): return jsonPayload stdoutdata = stdoutdata[(end+len(']== "CMake Server" ==]')):] +# Python2 has no problem writing the output of encodes directly, +# but Python3 returns only 'int's for encode and so must be turned +# into bytes. We use the existence of 'to_bytes' on an int to +# determine which behavior is appropriate. It might be more clear +# to do this in the code which uses the flag, but introducing +# this lookup cost at every byte sent isn't ideal. +has_to_bytes = "to_bytes" in dir(10) + def writeRawData(cmakeCommand, content): writeRawData.counter += 1 payload = """ @@ -116,7 +124,25 @@ def writeRawData(cmakeCommand, content): if print_communication: printClient(content, "(Use \\r\\n:", rn, ")") - cmakeCommand.write(payload.encode('utf-8')) + # To stress test how cmake deals with fragmentation in the + # communication channel, we send only one byte at a time. + # Certain communication methods / platforms might still buffer + # it all into one message since its so close together, but in + # general this will catch places where we assume full buffers + # come in all at once. + encoded_payload = payload.encode('utf-8') + + # Python version 3+ can't write ints directly; but 'to_bytes' + # for int was only added in python 3.2. If this is a 3+ version + # of python without that conversion function; just write the whole + # thing out at once. + if sys.version_info[0] > 2 and not has_to_bytes: + cmakeCommand.write(encoded_payload) + else: + for c in encoded_payload: + if has_to_bytes: + c = c.to_bytes(1, byteorder='big') + cmakeCommand.write(c) writeRawData.counter = 0 diff --git a/Utilities/GitSetup/config.sample b/Utilities/GitSetup/config.sample deleted file mode 100644 index eeb468b..0000000 --- a/Utilities/GitSetup/config.sample +++ /dev/null @@ -1,32 +0,0 @@ -# Kitware Local Git Setup Scripts - Sample Project Configuration -# -# Copy to "config" and edit as necessary. - -[hooks] - url = http://public.kitware.com/GitSetup.git - #branch = hooks - -[ssh] - host = public.kitware.com - key = id_git_public - request-url = https://www.kitware.com/Admin/SendPassword.cgi - -[stage] - #url = git://public.kitware.com/stage/Project.git - #pushurl = git@public.kitware.com:stage/Project.git - -[gerrit] - #project = Project - site = http://review.source.kitware.com - # pushurl placeholder "$username" is literal - pushurl = $username@review.source.kitware.com:Project - -[upstream] - url = git://public.kitware.com/Project.git - -[gitlab] - host = gitlab.kitware.com - group-path = group - group-name = Group - project-path = project - project-name = Project diff --git a/Utilities/GitSetup/git-gerrit-push b/Utilities/GitSetup/git-gerrit-push deleted file mode 100755 index b46f753..0000000 --- a/Utilities/GitSetup/git-gerrit-push +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -USAGE="[<remote>] [--no-topic] [--dry-run] [--]" -OPTIONS_SPEC= -SUBDIRECTORY_OK=Yes -. "$(git --exec-path)/git-sh-setup" - -#----------------------------------------------------------------------------- - -remote='' -refspecs='' -no_topic='' -dry_run='' - -# Parse the command line options. -while test $# != 0; do - case "$1" in - --no-topic) no_topic=1 ;; - --dry-run) dry_run=--dry-run ;; - --) shift; break ;; - -*) usage ;; - *) test -z "$remote" || usage ; remote="$1" ;; - esac - shift -done -test $# = 0 || usage - -# Default remote. -test -n "$remote" || remote="gerrit" - -if test -z "$no_topic"; then - # Identify and validate the topic branch name. - head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' - if test -z "$topic" -o "$topic" = "master"; then - die 'Please name your topic: - git checkout -b descriptive-name' - fi - # The topic branch will be pushed by name. - refspecs="HEAD:refs/for/master/$topic $refspecs" -fi - -# Fetch the current upstream master branch head. -# This helps computation of a minimal pack to push. -echo "Fetching $remote master" -fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" - -# Exit early if we have nothing to push. -if test -z "$refspecs"; then - echo 'Nothing to push!' - exit 0 -fi - -# Push. Save output and exit code. -echo "Pushing to $remote" -push_stdout=$(git push --porcelain $dry_run "$remote" $refspecs); push_exit=$? -echo "$push_stdout" - -# Reproduce the push exit code. -exit $push_exit diff --git a/Utilities/GitSetup/git-gitlab-push b/Utilities/GitSetup/git-gitlab-push deleted file mode 100755 index 768f853..0000000 --- a/Utilities/GitSetup/git-gitlab-push +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -USAGE='[<remote>] [<options>...] [--] - -OPTIONS - ---dry-run - Show what would be pushed without actually updating the destination - --f,--force - Force-push the topic HEAD to rewrite the destination branch - ---no-default - Do not push the default branch (e.g. master) - ---no-topic - Do not push the topic HEAD. -' -OPTIONS_SPEC= -SUBDIRECTORY_OK=Yes -. "$(git --exec-path)/git-sh-setup" - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -# Load the project configuration. -gitlab_upstream='' && -gitlab_configured='' && -config="${BASH_SOURCE%/*}/config" && -protocol=$(git config -f "$config" --get gitlab.protocol || - echo "https") && -host=$(git config -f "$config" --get gitlab.host) && -site=$(git config -f "$config" --get gitlab.site || - echo "$protocol://$host") && -group_path=$(git config -f "$config" --get gitlab.group-path) && -project_path=$(git config -f "$config" --get gitlab.project-path) && -gitlab_upstream="$site/$group_path/$project_path.git" && -gitlab_pushurl=$(git config --get remote.gitlab.pushurl || - git config --get remote.gitlab.url) && -gitlab_configured=1 - -#----------------------------------------------------------------------------- - -remote='' -refspecs='' -force='' -lease=false -lease_flag='' -no_topic='' -no_default='' -dry_run='' - -# Parse the command line options. -while test $# != 0; do - case "$1" in - -f|--force) force='+'; lease=true ;; - --no-topic) no_topic=1 ;; - --dry-run) dry_run=--dry-run ;; - --no-default) no_default=1 ;; - --) shift; break ;; - -*) usage ;; - *) test -z "$remote" || usage ; remote="$1" ;; - esac - shift -done -test $# = 0 || usage - -# Default remote. -test -n "$remote" || remote="gitlab" - -if test -z "$no_topic"; then - # Identify and validate the topic branch name. - head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' - if test -z "$topic" -o "$topic" = "master"; then - die 'Please name your topic: - git checkout -b descriptive-name' - fi - - if $lease; then - have_ref=false - remoteref="refs/remotes/$remote/$topic" - if git rev-parse --verify -q "$remoteref"; then - have_ref=true - else - die "It seems that a local ref for the branch is -missing; forcing a push is dangerous and may overwrite -previous work. Fetch from the $remote remote first or -push without '-f' or '--force'." - fi - - have_lease_flag=false - if git push -h | egrep-q -e '--force-with-lease'; then - have_lease_flag=true - fi - - if $have_lease_flag && $have_ref; then - # Set the lease flag. - lease_flag="--force-with-lease=$topic:$remoteref" - # Clear the force string. - force='' - fi - fi - - # The topic branch will be pushed by name. - refspecs="${force}HEAD:refs/heads/$topic $refspecs" -fi - -# Fetch the current remote master branch head. -# This helps computation of a minimal pack to push. -echo "Fetching $remote master" -fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" -gitlab_head=$(git rev-parse FETCH_HEAD) || exit - -# Fetch the current upstream master branch head. -if origin_fetchurl=$(git config --get remote.origin.url) && - test "$origin_fetchurl" = "$gitlab_upstream"; then - upstream_remote='origin' -else - upstream_remote="$gitlab_upstream" -fi -echo "Fetching $upstream_remote master" -fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out" -upstream_head=$(git rev-parse FETCH_HEAD) || exit - -# Add a refspec to keep the remote master up to date if possible. -if test -z "$no_default" && - base=$(git merge-base "$gitlab_head" "$upstream_head") && - test "$base" = "$gitlab_head"; then - refspecs="$upstream_head:refs/heads/master $refspecs" -fi - -# Exit early if we have nothing to push. -if test -z "$refspecs"; then - echo 'Nothing to push!' - exit 0 -fi - -# Push. Save output and exit code. -echo "Pushing to $remote" -push_config='-c advice.pushUpdateRejected=false' -push_stdout=$(git $push_config push $lease_flag --porcelain $dry_run "$remote" $refspecs); push_exit=$? -echo "$push_stdout" - -if test "$push_exit" -ne 0 && test -z "$force"; then - # Advise the user to fetch if needed. - if echo "$push_stdout" | egrep-q 'stale info'; then - echo " -You have pushed to your branch from another machine; you may be overwriting -commits unintentionally. Fetch from the $remote remote and check that you are -not pushing an outdated branch." - fi - - # Advise the user to force-push if needed. - if echo "$push_stdout" | egrep-q 'non-fast-forward'; then - echo ' -Add "-f" or "--force" to push a rewritten topic.' - fi -fi - -# Reproduce the push exit code. -exit $push_exit diff --git a/Utilities/GitSetup/setup-gerrit b/Utilities/GitSetup/setup-gerrit deleted file mode 100755 index 6d46e3c..0000000 --- a/Utilities/GitSetup/setup-gerrit +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to push to -# a Gerrit Code Review instance for this project. - -# Project configuration instructions: -# -# - Run a Gerrit Code Review server -# -# - Populate adjacent "config" file with: -# gerrit.site = Top Gerrit URL (not project-specific) -# gerrit.project = Name of project in Gerrit -# gerrit.pushurl = Review site push URL with "$username" placeholder -# gerrit.remote = Gerrit remote name, if not "gerrit" -# gerrit.url = Gerrit project URL, if not "$site/p/$project" -# optionally with "$username" placeholder - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -site=$(git config -f config --get gerrit.site) && -project=$(git config -f config --get gerrit.project) && -remote=$(git config -f config --get gerrit.remote || - echo "gerrit") && -fetchurl_=$(git config -f config --get gerrit.url || - echo "$site/p/$project") && -pushurl_=$(git config -f config --get gerrit.pushurl || - git config -f config --get gerrit.url) || -die 'This project is not configured to use Gerrit.' - -# Get current gerrit push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure Gerrit? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured. - -'"$project"' changes must be pushed to our Gerrit Code Review site: - - '"$site/p/$project"' - -Register a Gerrit account and select a username (used below). -You will need an OpenID: - - http://openid.net/get-an-openid/ -' && - read -ep 'Configure Gerrit? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Sign-in to Gerrit to get/set your username at - - '"$site"'/#/settings - -Add your SSH public keys at - - '"$site"'/#/settings/ssh-keys -' && - read -ep "Gerrit username? [$USER]: " gu && - if test -z "$gu"; then - gu="$USER" - fi && - fetchurl="${fetchurl_/\$username/$gu}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_/\$username/$gu}" && - if test "$pushurl" != "$fetchurl"; then - git config remote."$remote".pushurl "$pushurl" - fi && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi && - -# Optionally test Gerrit access. -if test -n "$pushurl"; then - read -ep 'Test access to Gerrit (SSH)? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - echo -n 'Testing Gerrit access by SSH...' - if git ls-remote --heads "$pushurl" >/dev/null; then - echo 'passed.' - else - echo 'failed.' && - die 'Could not access Gerrit. Add your SSH public keys at - - '"$site"'/#/settings/ssh-keys -' - fi - fi -fi && - -# Set up GerritId hook. -hook=$(git config --get hooks.GerritId || echo '') && -if test -z "$hook"; then - echo ' -Enabling GerritId hook to add a "Change-Id" footer to commit -messages for interaction with Gerrit. Run - - git config hooks.GerritId false - -to disable this feature (but you will be on your own).' && - git config hooks.GerritId true -else - echo 'GerritId hook already configured to "'"$hook"'".' -fi diff --git a/Utilities/GitSetup/setup-gitlab b/Utilities/GitSetup/setup-gitlab deleted file mode 100755 index 9c7574d..0000000 --- a/Utilities/GitSetup/setup-gitlab +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to push to -# a personal fork for this project in GitLab. - -# Project configuration instructions: -# -# - Run a GitLab server -# -# - Populate adjacent "config" file with: -# gitlab.protocol = Top GitLab protocol, if not 'https' -# gitlab.host = Top GitLab fully qualified host name -# gitlab.site = Top GitLab URL, if not "<protocol>://<host>" -# gitlab.group-name = Name of group containing project in GitLab -# gitlab.group-path = Path of group containing project in GitLab -# gitlab.project-name = Name of project within GitLab group -# gitlab.project-path = Path of project within GitLab group -# gitlab.url = GitLab push URL with "$username" placeholder, -# if not "<site>/$username/<project-path>.git" -# gitlab.pushurl = GitLab push URL with "$username" placeholder, -# if not "git@<host>:$username/<project-path>.git" -# gitlab.remote = GitLab remote name, if not "gitlab" - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -protocol=$(git config -f config --get gitlab.protocol || - echo "https") && -host=$(git config -f config --get gitlab.host) && -site=$(git config -f config --get gitlab.site || - echo "$protocol://$host") && -group_path=$(git config -f config --get gitlab.group-path) && -group_name=$(git config -f config --get gitlab.group-name) && -project_name=$(git config -f config --get gitlab.project-name) && -project_path=$(git config -f config --get gitlab.project-path) && -pushurl_=$(git config -f config --get gitlab.pushurl || - echo "git@$host:\$username/$project_path.git") && -remote=$(git config -f config --get gitlab.remote || - echo "gitlab") && -fetchurl_=$(git config -f config --get gitlab.url || - echo "$site/\$username/$project_path.git") || -die 'This project is not configured to use GitLab.' - -# Get current gitlab push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure GitLab? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured. -' && - read -ep 'Configure GitLab to contribute to '"$project_name"'? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -setup_instructions='Add your SSH public keys at - - '"$site"'/profile/keys - -Then visit the main repository at: - - '"$site/$group_path/$project_path"' - -and use the Fork button in the upper right. -' - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Sign-in to GitLab to get/set your username at - - '"$site/profile/account"' - -'"$setup_instructions" && - read -ep "GitLab username? [$USER]: " gu && - if test -z "$gu"; then - gu="$USER" - fi && - fetchurl="${fetchurl_/\$username/$gu}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_/\$username/$gu}" && - git config remote."$remote".pushurl "$pushurl" && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi && - -# Optionally test GitLab access. -if test -n "$pushurl"; then - read -ep 'Test access to GitLab (SSH)? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - echo -n 'Testing GitLab access by SSH...' - if git ls-remote --heads "$pushurl" >/dev/null; then - echo 'passed.' - else - echo 'failed.' && - die 'Could not access your GitLab fork of this project. -'"$setup_instructions" - fi - fi -fi diff --git a/Utilities/GitSetup/setup-hooks b/Utilities/GitSetup/setup-hooks index ca07712..6a17b10 100755 --- a/Utilities/GitSetup/setup-hooks +++ b/Utilities/GitSetup/setup-hooks @@ -26,7 +26,7 @@ # hooks.url = Repository URL publishing "hooks" branch # hooks.branch = Repository branch instead of "hooks" -egrep-q() { +egrep_q() { egrep "$@" >/dev/null 2>/dev/null } @@ -42,7 +42,7 @@ if url=$(git config --get hooks.url); then # Fetch hooks from locally configured repository. branch=$(git config hooks.branch || echo hooks) elif git for-each-ref refs/remotes/origin/hooks 2>/dev/null | - egrep-q 'refs/remotes/origin/hooks$'; then + egrep_q 'refs/remotes/origin/hooks$'; then # Use hooks cloned from origin. url=.. && branch=remotes/origin/hooks elif url=$(git config -f config --get hooks.url); then diff --git a/Utilities/GitSetup/setup-ssh b/Utilities/GitSetup/setup-ssh deleted file mode 100755 index 8920a5b..0000000 --- a/Utilities/GitSetup/setup-ssh +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up ssh push access to the repository host. - -# Project configuration instructions: -# -# - Populate adjacent "config" file with: -# ssh.host = Repository host name -# ssh.user = Username on host, if not "git" -# ssh.key = Local ssh key name -# ssh.request-url = Web page URL to request ssh access - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -host=$(git config -f config --get ssh.host) && -user=$(git config -f config --get ssh.user || echo git) && -key=$(git config -f config --get ssh.key) && -request_url=$(git config -f config --get ssh.request-url) || -die 'This project is not configured for ssh push access.' - -# Check for existing configuration. -if test -r ~/.ssh/config && - egrep-q 'Host[= ]'"${host//\./\\.}" ~/.ssh/config; then - echo 'Host "'"$host"'" is already in ~/.ssh/config' && - setup= && - question='Test' -else - echo 'Host "'"$host"'" not found in ~/.ssh/config' && - setup=1 && - question='Setup and test' -fi && - -# Ask the user whether to make changes. -echo '' && -read -ep "${question} push access by ssh to $user@$host? [y/N]: " access && -if test "$access" != "y" -a "$access" != "Y"; then - exit 0 -fi && - -# Setup host configuration if necessary. -if test -n "$setup"; then - if ! test -d ~/.ssh; then - mkdir -p ~/.ssh && - chmod 700 ~/.ssh - fi && - if ! test -f ~/.ssh/config; then - touch ~/.ssh/config && - chmod 600 ~/.ssh/config - fi && - ssh_config='Host='"$host"' - IdentityFile ~/.ssh/'"$key" && - echo "Adding to ~/.ssh/config: - -$ssh_config -" && - echo "$ssh_config" >> ~/.ssh/config && - if ! test -e ~/.ssh/"$key"; then - if test -f ~/.ssh/id_rsa; then - # Take care of the common case. - ln -s id_rsa ~/.ssh/"$key" - echo ' -Assuming ~/.ssh/id_rsa is the private key corresponding to the public key for - - '"$user@$host"' - -If this is incorrect place private key at "~/.ssh/'"$key"'".' - else - echo ' -Place the private key corresponding to the public key registered for - - '"$user@$host"' - -at "~/.ssh/'"$key"'".' - fi - read -e -n 1 -p 'Press any key to continue...' - fi -fi || exit 1 - -# Test access configuration. -echo 'Testing ssh push access to "'"$user@$host"'"...' && -if ! ssh "$user@$host" info; then - die 'No ssh push access to "'"$user@$host"'". You may need to request access at - - '"$request_url"' -' -fi diff --git a/Utilities/GitSetup/setup-stage b/Utilities/GitSetup/setup-stage deleted file mode 100755 index ce6ec45..0000000 --- a/Utilities/GitSetup/setup-stage +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the topic stage for pushing changes. - -# Project configuration instructions: -# -# - Run a Topic Stage repository next to the main project repository. -# -# - Populate adjacent "config" file with: -# stage.url = Topic Stage repository URL -# stage.pushurl = Topic Stage push URL if not "$url" - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -fetchurl_=$(git config -f config --get stage.url) && -pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") && -remote=$(git config -f config --get stage.remote || echo 'stage') || -die 'This project is not configured to use a topic stage.' - -# Get current stage push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure Topic Stage? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - setup=1 -fi - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Setting up the topic stage...' && - fetchurl="${fetchurl_}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_}" && - if test "$pushurl" != "$fetchurl"; then - git config remote."$remote".pushurl "$pushurl" - fi && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi || die 'Could not configure the topic stage remote.' diff --git a/Utilities/GitSetup/setup-upstream b/Utilities/GitSetup/setup-upstream deleted file mode 100755 index 92ce1da..0000000 --- a/Utilities/GitSetup/setup-upstream +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to use the -# preferred upstream repository URLs. - -# Project configuration instructions: -# -# - Populate adjacent "config" file with: -# upstream.url = Preferred fetch url for upstream remote -# upstream.remote = Preferred name for upstream remote, if not "origin" - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -url=$(git config -f config --get upstream.url) && -remote=$(git config -f config --get upstream.remote || - echo 'origin') || -die 'This project is not configured to use a preferred upstream repository.' - -# Get current upstream URLs. -fetchurl=$(git config --get remote."$remote".url || echo '') && -pushurl=$(git config --get remote."$remote".pushurl || echo '') && - -if test "$fetchurl" = "$url"; then - echo 'Remote "'"$remote"'" already uses recommended upstream repository.' - exit 0 -fi - -upstream_recommend=' -We recommended configuring the "'"$remote"'" remote to fetch from upstream at - - '"$url"' -' - -# Tell user about current configuration. -if test -n "$fetchurl"; then - echo 'Remote "'"$remote"'" is currently configured to fetch from - - '"$fetchurl"' -' && - if test -n "$pushurl"; then - echo 'and push to - - '"$pushurl" - fi && - echo "$upstream_recommend" && - if test -n "$pushurl"; then - echo 'and to never push to it directly. -' - fi && - - read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured.' && - echo "$upstream_recommend" && - read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -# Perform setup if necessary. -if test -n "$setup"; then - if test -z "$fetchurl"; then - git remote add "$remote" "$url" - else - git config remote."$remote".url "$url" && - if old=$(git config --get remote."$remote".pushurl); then - git config --unset remote."$remote".pushurl || - echo 'Warning: failed to unset remote.'"$remote"'.pushurl' - fi - fi && - echo 'Remote "'"$remote"'" is now configured to fetch from - - '"$url"' -' -fi diff --git a/Utilities/GitSetup/tips b/Utilities/GitSetup/tips index 784e1ed..f47d84c 100755 --- a/Utilities/GitSetup/tips +++ b/Utilities/GitSetup/tips @@ -19,7 +19,7 @@ # Project configuration instructions: NONE -egrep-q() { +egrep_q() { egrep "$@" >/dev/null 2>/dev/null } @@ -33,7 +33,7 @@ One may enable color output from Git commands with fi # Suggest bash completion. -if ! bash -i -c 'echo $PS1' | egrep-q '__git_ps1'; then +if ! bash -i -c 'echo $PS1' | egrep_q '__git_ps1'; then echo ' A dynamic, informative Git shell prompt can be obtained by sourcing the git bash-completion script in your "~/.bashrc". Set the PS1 diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index 6477d59..5408402 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -63,6 +63,11 @@ { symbol: [ "std::__decay_and_strip<const std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] }, { symbol: [ "std::__decay_and_strip<__gnu_cxx::__normal_iterator<const cmCTestTestHandler::cmCTestTestProperties *, std::vector<cmCTestTestHandler::cmCTestTestProperties, std::allocator<cmCTestTestHandler::cmCTestTestProperties> > > &>::__type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::__success_type<std::chrono::duration<double, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::__success_type<std::chrono::duration<long, std::ratio<1, 1000000000> > >::type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<60, 1> > >::type", private, "\"cmConfigure.h\"", public ] }, + { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1000> > >::type", private, "\"cmConfigure.h\"", public ] }, # KWIML { include: [ "<stdint.h>", public, "\"cm_kwiml.h\"", public ] }, diff --git a/Utilities/Scripts/update-gitsetup.bash b/Utilities/Scripts/update-gitsetup.bash index 8f0da76..70fb165 100755 --- a/Utilities/Scripts/update-gitsetup.bash +++ b/Utilities/Scripts/update-gitsetup.bash @@ -11,6 +11,13 @@ readonly repo="https://gitlab.kitware.com/utils/gitsetup.git" readonly tag="setup" readonly shortlog=false readonly paths=" + .gitattributes + LICENSE + NOTICE + README + setup-hooks + setup-user + tips " extract_source () { @@ -418,6 +418,7 @@ CMAKE_CXX_SOURCES="\ cmTryRunCommand \ cmUnexpectedCommand \ cmUnsetCommand \ + cmUVHandlePtr \ cmVersion \ cmWhileCommand \ cmWorkingDirectory \ @@ -1068,6 +1069,7 @@ TMPFILE=`cmake_tmp_file` echo ' #include <iostream> #include <memory> +#include <unordered_map> #if __cplusplus < 201103L #error "Compiler is not in a mode aware of C++11." |