diff options
91 files changed, 1526 insertions, 402 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fc033ba..51a1d8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -cmake_minimum_required(VERSION 3.1...3.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1...3.14 FATAL_ERROR) set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake) project(CMake) @@ -822,4 +822,10 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE) # Install auxiliary files integrating with other tools. add_subdirectory(Auxiliary) + + # Optionally sign installed binaries. + if(CMake_INSTALL_SIGNTOOL) + configure_file(Source/CMakeInstallSignTool.cmake.in Source/CMakeInstallSignTool.cmake @ONLY) + install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/Source/CMakeInstallSignTool.cmake) + endif() endif() diff --git a/Help/release/dev/apple-clang-supports-cxx20.rst b/Help/release/dev/apple-clang-supports-cxx20.rst new file mode 100644 index 0000000..f19ee68 --- /dev/null +++ b/Help/release/dev/apple-clang-supports-cxx20.rst @@ -0,0 +1,4 @@ +apple-clang-supports-cxx20 +-------------------------- + +* AppleClang compiler have learned how to compile C++20. diff --git a/Help/release/dev/iar-new_architectures.rst b/Help/release/dev/iar-new_architectures.rst new file mode 100644 index 0000000..d661c80 --- /dev/null +++ b/Help/release/dev/iar-new_architectures.rst @@ -0,0 +1,6 @@ +iar-new_architectures +--------------------- + +* Support was added for the IAR compiler architectures Renesas RX, + RL78, RH850 and Texas Instruments MSP430. +* The IAR compilers built for Linux (IAR BuildLx) now work as well. diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in index c88094a..8f5747a 100644 --- a/Modules/CMakePlatformId.h.in +++ b/Modules/CMakePlatformId.h.in @@ -159,9 +159,18 @@ # elif defined(__ICCRX__) # define ARCHITECTURE_ID "RX" +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + # elif defined(__ICCAVR__) # define ARCHITECTURE_ID "AVR" +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + # else /* unknown architecture */ # define ARCHITECTURE_ID "" # endif diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake index 2042360..3fa6990 100644 --- a/Modules/Compiler/AppleClang-CXX.cmake +++ b/Modules/Compiler/AppleClang-CXX.cmake @@ -17,10 +17,12 @@ endif() if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro greater than 201103L set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) endif() if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) @@ -28,9 +30,13 @@ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") endif() - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0) + set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a") + set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a") +endif() + __compiler_check_default_language_standard(CXX 4.0 98) diff --git a/Modules/Compiler/IAR-ASM.cmake b/Modules/Compiler/IAR-ASM.cmake index f9c0ced..71f2ac6 100644 --- a/Modules/Compiler/IAR-ASM.cmake +++ b/Modules/Compiler/IAR-ASM.cmake @@ -12,11 +12,26 @@ elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") __compiler_iar_ilink(ASM) set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa) +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850") + set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") + __compiler_iar_ilink(ASM) + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa) + +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78") + set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") + __compiler_iar_ilink(ASM) + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa) + elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") __compiler_iar_xlink(ASM) set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa) +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430") + set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -S <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") + __compiler_iar_xlink(ASM) + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s43;asm;msa) + else() message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.") endif() diff --git a/Modules/Compiler/IAR-C.cmake b/Modules/Compiler/IAR-C.cmake index af5874c..4b02a9a 100644 --- a/Modules/Compiler/IAR-C.cmake +++ b/Modules/Compiler/IAR-C.cmake @@ -38,20 +38,23 @@ elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") __compiler_iar_ilink(C) __compiler_check_default_language_standard(C 1.10 90 2.10 99 4.10 11) +elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850") + __compiler_iar_ilink(C) + __compiler_check_default_language_standard(C 1.10 90 1.10 99 2.10 11) + +elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78") + __compiler_iar_ilink(C) + __compiler_check_default_language_standard(C 1.10 90 1.10 99 4.10 11) + elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") __compiler_iar_xlink(C) __compiler_check_default_language_standard(C 7.10 99) set(CMAKE_C_OUTPUT_EXTENSION ".r90") - if(NOT CMAKE_C_LINK_FLAGS) - set(CMAKE_C_LINK_FLAGS "-Fmotorola") - endif() - - # add the target specific include directory: - get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH) - get_filename_component(_compilerDir "${_compilerDir}" PATH) - include_directories("${_compilerDir}/inc" ) - include_directories("${_compilerDir}/inc/Atmel" ) +elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430") + __compiler_iar_xlink(C) + __compiler_check_default_language_standard(C 1.10 90 5.10 99) + set(CMAKE_C_OUTPUT_EXTENSION ".r43") else() message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.") diff --git a/Modules/Compiler/IAR-CXX.cmake b/Modules/Compiler/IAR-CXX.cmake index 04ccbe5..22ec118 100644 --- a/Modules/Compiler/IAR-CXX.cmake +++ b/Modules/Compiler/IAR-CXX.cmake @@ -4,12 +4,14 @@ include(Compiler/IAR) include(Compiler/CMakeCommonCompilerMacros) # Common -if(NOT CMAKE_IAR_CXX_FLAG) - if(NOT CMAKE_CXX_COMPILER_VERSION) - message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.") - endif() +if(NOT CMAKE_CXX_COMPILER_VERSION) + message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.") +endif() - if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7) +if(NOT CMAKE_IAR_CXX_FLAG) + # The --c++ flag was introduced in platform version 9 for all architectures except ARM where it was introduced already in version 7 + if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8 OR + (CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 6 AND "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") ) set(CMAKE_IAR_CXX_FLAG --c++) else() set(CMAKE_IAR_CXX_FLAG --eec++) @@ -45,20 +47,22 @@ elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") __compiler_iar_ilink(CXX) __compiler_check_default_language_standard(CXX 2.10 98 4.10 14) +elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850") + __compiler_iar_ilink(CXX) + __compiler_check_default_language_standard(CXX 1.10 98 2.10 14) + +elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78") + __compiler_iar_ilink(CXX) + __compiler_check_default_language_standard(CXX 1.10 98 4.10 14) + elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") __compiler_iar_xlink(CXX) __compiler_check_default_language_standard(CXX 7.10 98) - set(CMAKE_CXX_OUTPUT_EXTENSION ".r90") - if(NOT CMAKE_CXX_LINK_FLAGS) - set(CMAKE_CXX_LINK_FLAGS "-Fmotorola") - endif() - - # add the target specific include directory: - get_filename_component(_compilerDir "${CMAKE_C_COMPILER}" PATH) - get_filename_component(_compilerDir "${_compilerDir}" PATH) - include_directories("${_compilerDir}/inc" ) - include_directories("${_compilerDir}/inc/Atmel" ) +elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430") + __compiler_iar_xlink(CXX) + __compiler_check_default_language_standard(CXX 5.10 98) + set(CMAKE_CXX_OUTPUT_EXTENSION ".r43") else() message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." ) diff --git a/Modules/Compiler/IAR-DetermineCompiler.cmake b/Modules/Compiler/IAR-DetermineCompiler.cmake index cdfb095..6b09c40 100644 --- a/Modules/Compiler/IAR-DetermineCompiler.cmake +++ b/Modules/Compiler/IAR-DetermineCompiler.cmake @@ -31,7 +31,7 @@ set(_compiler_id_version_compute " # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(((__VER__) / 1000) % 1000) # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@((__VER__) % 1000) # define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__IAR_SYSTEMS_ICC__) -# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__)) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__)) # define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__VER__) / 100) # define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__VER__) - (((__VER__) / 100)*100)) # define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__SUBVERSION__) diff --git a/Modules/Compiler/IAR-FindBinUtils.cmake b/Modules/Compiler/IAR-FindBinUtils.cmake index 7fc6b59..3f13dce 100644 --- a/Modules/Compiler/IAR-FindBinUtils.cmake +++ b/Modules/Compiler/IAR-FindBinUtils.cmake @@ -11,7 +11,9 @@ get_filename_component(__iar_hint_2 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPI set(__iar_hints "${__iar_hint_1}" "${__iar_hint_2}") if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" OR - "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") + "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX" OR + "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850" OR + "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78") string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _archid_lower) @@ -41,9 +43,10 @@ set(CMAKE_IAR_OBJMANIP \"${CMAKE_IAR_OBJMANIP}\") set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\") ") -elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") +elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR" OR + "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430") - # For AVR and AVR32, IAR uses the "xlink" linker and the "xar" archiver: + # Find the "xlink" linker and "xar" archiver: find_program(CMAKE_IAR_LINKER xlink HINTS ${__iar_hints} DOC "The IAR XLINK linker") find_program(CMAKE_IAR_AR xar HINTS ${__iar_hints} diff --git a/Modules/Compiler/Intel-CXX-FeatureTests.cmake b/Modules/Compiler/Intel-CXX-FeatureTests.cmake index aa35b97..bbefe15 100644 --- a/Modules/Compiler/Intel-CXX-FeatureTests.cmake +++ b/Modules/Compiler/Intel-CXX-FeatureTests.cmake @@ -24,7 +24,7 @@ set(DETECT_CXX14 "((__cplusplus >= 201300L) || ((__cplusplus == 201103L) && !def unset(DETECT_BUGGY_ICC15) set(Intel17_CXX14 "__INTEL_COMPILER >= 1700 && ${DETECT_CXX14}") -set(_cmake_feature_test_cxx_relaxed_constexpr "__cpp_constexpr >= 201304 || (${Intel17_CXX14} && !(__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 5) && !defined(_MSC_VER))") +set(_cmake_feature_test_cxx_relaxed_constexpr "__cpp_constexpr >= 201304 || (${Intel17_CXX14} && !defined(_MSC_VER))") set(Intel16_CXX14 "__INTEL_COMPILER >= 1600 && ${DETECT_CXX14}") set(_cmake_feature_test_cxx_aggregate_default_initializers "${Intel16_CXX14}") diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake index 44b0c3d..b630a6b 100644 --- a/Modules/Compiler/Intel-CXX.cmake +++ b/Modules/Compiler/Intel-CXX.cmake @@ -40,13 +40,7 @@ else() set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17") endif() - # While full C++14 support was first introduced in Intel 17, - # Intel 18.0.0-4 don't have full support as they broke - # support for cxx_relaxed_constexpr. - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 18.0.4) - set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) - elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0.0 - AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.0) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0) set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) endif() diff --git a/Modules/Compiler/MSVC-CXX-FeatureTests.cmake b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake index 9c604f2..125974a 100644 --- a/Modules/Compiler/MSVC-CXX-FeatureTests.cmake +++ b/Modules/Compiler/MSVC-CXX-FeatureTests.cmake @@ -9,10 +9,8 @@ set(_cmake_oldestSupported "_MSC_VER >= 1600") # https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#update_153 set(_cmake_feature_test_cxx_decltype_incomplete_return_types "_MSC_VER >= 1911") -set(MSVC_2017 "_MSC_VER >= 1910") -# VS 2017 introduces support for "N3652 Extended constexpr" -# but as of v15.6 there are still bugs in the implementation -#set(_cmake_feature_test_cxx_relaxed_constexpr "${MSVC_2017}") +# VS 2017 v15.3 fixes support for "N3652 Extended constexpr" +set(_cmake_feature_test_cxx_relaxed_constexpr "_MSC_VER >= 1911") # VS 2017 Preview introduces support for aggregate initializers. set(_cmake_feature_test_cxx_aggregate_default_initializers "_MSC_FULL_VER >= 190024406") diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake index 787c17e..f3a7408 100644 --- a/Modules/Compiler/MSVC-CXX.cmake +++ b/Modules/Compiler/MSVC-CXX.cmake @@ -18,6 +18,7 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std:c++14") if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11.25505) set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++17") set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++17") else() diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake index 1758fb3..76bc873 100644 --- a/Modules/FindProtobuf.cmake +++ b/Modules/FindProtobuf.cmake @@ -207,9 +207,14 @@ function(protobuf_generate) get_filename_component(_basename ${_proto} NAME_WE) file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir}) + set(_possible_rel_dir) + if (NOT protobuf_generate_APPEND_PATH) + set(_possible_rel_dir ${_rel_dir}/) + endif() + set(_generated_srcs) foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS}) - list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_basename}${_ext}") + list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}") endforeach() if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp) diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake index a5e3a37..ae6ae56 100644 --- a/Modules/FindSWIG.cmake +++ b/Modules/FindSWIG.cmake @@ -26,7 +26,7 @@ to be found can be changed from the command line by means of setting ``SWIG_EXECUTABLE`` #]=======================================================================] -find_program(SWIG_EXECUTABLE NAMES swig3.0 swig2.0 swig) +find_program(SWIG_EXECUTABLE NAMES swig4.0 swig3.0 swig2.0 swig) if(SWIG_EXECUTABLE) execute_process(COMMAND ${SWIG_EXECUTABLE} -swiglib diff --git a/Modules/FindXCTest.cmake b/Modules/FindXCTest.cmake index 8497336..15721e1 100644 --- a/Modules/FindXCTest.cmake +++ b/Modules/FindXCTest.cmake @@ -61,6 +61,22 @@ The following variables are set by including this module: #]=======================================================================] +set(_PRESERVED_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}") + +if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple" + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Non-macos systems set the CMAKE_FIND_ROOT_PATH_MODE to "ONLY" which + # restricts the search paths too much to find XCTest.framework. In + # contrast to the regular system frameworks which reside within the + # SDK direectory the XCTest framework is located in the respective + # platform directory which is not added to the CMAKE_FIND_ROOT_PATH + # (only to CMAKE_SYSTEM_FRAMEWORK_PATH) and therefore not searched. + # + # Until this is properly addressed, temporaily add the platform + # directory to CMAKE_FIND_ROOT_PATH. + list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}/../..") +endif() + find_path(XCTest_INCLUDE_DIR NAMES "XCTest/XCTest.h" DOC "XCTest include directory") @@ -71,6 +87,9 @@ find_library(XCTest_LIBRARY DOC "XCTest Framework library") mark_as_advanced(XCTest_LIBRARY) +set(CMAKE_FIND_ROOT_PATH "${_PRESERVED_CMAKE_FIND_ROOT_PATH}") +unset(_PRESERVED_CMAKE_FIND_ROOT_PATH) + execute_process( COMMAND xcrun --find xctest OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE diff --git a/Source/CMakeInstallSignTool.cmake.in b/Source/CMakeInstallSignTool.cmake.in new file mode 100644 index 0000000..fca629c --- /dev/null +++ b/Source/CMakeInstallSignTool.cmake.in @@ -0,0 +1,51 @@ +# The signtool. Default to PATH. +set(CMake_INSTALL_SIGNTOOL "@CMake_INSTALL_SIGNTOOL@") +if(NOT CMake_INSTALL_SIGNTOOL) + set(CMake_INSTALL_SIGNTOOL signtool) +endif() + +# Select a certificate by Subject Name. Default to automatic selection. +set(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME "@CMake_INSTALL_SIGNTOOL_SUBJECT_NAME@") +if(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME) + set(select_cert -n "${CMake_INSTALL_SIGNTOOL_SUBJECT_NAME}") +else() + set(select_cert -a) +endif() + +# Timestamp URL. Default to a common provider. +set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "@CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL@") +if(NOT CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL) + set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "http://timestamp.digicert.com") +endif() + +# Glob files that need a signature. +file(GLOB files "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/*.exe") + +# Sign all files at once. +if(files) + # Run the signtool through 'cmd /c' to enable password prompt popup. + # Some providers have trouble when signtool is invoked with SW_HIDE. + set(cmd cmd /c "${CMake_INSTALL_SIGNTOOL}" sign -v ${select_cert}) + + # Sign with SHA-1 for Windows 7 and below. + execute_process( + COMMAND ${cmd} -t "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" ${files} + RESULT_VARIABLE result + ERROR_VARIABLE stderr + ) + if(NOT result EQUAL 0) + string(REPLACE "\n" "\n " stderr " ${stderr}") + message(WARNING "signtool failed:\n${stderr}") + endif() + + # Sign with SHA-256 for Windows 8 and above. + execute_process( + COMMAND ${cmd} -tr "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" -fd sha256 -td sha256 -as ${files} + RESULT_VARIABLE result + ERROR_VARIABLE stderr + ) + if(NOT result EQUAL 0) + string(REPLACE "\n" "\n " stderr " ${stderr}") + message(WARNING "signtool failed:\n${stderr}") + endif() +endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 01c6cd7..42eed4d 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -388,6 +388,8 @@ set(SRCS cmUuid.cxx cmUVHandlePtr.cxx cmUVHandlePtr.h + cmUVProcessChain.cxx + cmUVProcessChain.h cmUVStreambuf.h cmUVSignalHackRAII.h cmVariableWatch.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 31a220f..9f2754f 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 14) -set(CMake_VERSION_PATCH 20190510) +set(CMake_VERSION_PATCH 20190514) #set(CMake_VERSION_RC 1) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 8223dd1..b08dd1c 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1372,7 +1372,9 @@ bool cmGlobalGenerator::Compute() for (cmLocalGenerator* localGen : this->LocalGenerators) { cmMakefile* mf = localGen->GetMakefile(); for (cmInstallGenerator* g : mf->GetInstallGenerators()) { - g->Compute(localGen); + if (!g->Compute(localGen)) { + return false; + } } } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 4fa6ee6..1b973e0 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -136,17 +136,15 @@ void cmGlobalNinjaGenerator::WriteBuild( { // Make sure there is a rule. if (rule.empty()) { - cmSystemTools::Error("No rule for WriteBuildStatement! called " - "with comment: " + + cmSystemTools::Error("No rule for WriteBuild! called with comment: " + comment); return; } // Make sure there is at least one output file. if (outputs.empty()) { - cmSystemTools::Error("No output files for WriteBuildStatement! called " - "with comment: " + - comment); + cmSystemTools::Error( + "No output files for WriteBuild! called with comment: " + comment); return; } @@ -292,14 +290,8 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( void cmGlobalNinjaGenerator::AddMacOSXContentRule() { - cmLocalGenerator* lg = this->LocalGenerators[0]; - - std::ostringstream cmd; - cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), - cmOutputConverter::SHELL) - << " -E copy $in $out"; - - this->AddRule("COPY_OSX_CONTENT", cmd.str(), "Copying OS X Content $out", + this->AddRule("COPY_OSX_CONTENT", CMakeCmd() + " -E copy $in $out", + "Copying OS X Content $out", "Rule for copying OS X bundle content file.", /*depfile*/ "", /*deptype*/ "", @@ -332,71 +324,57 @@ void cmGlobalNinjaGenerator::WriteRule( const std::string& rspfile, const std::string& rspcontent, const std::string& restat, bool generator) { + // -- Parameter checks // Make sure the rule has a name. if (name.empty()) { - cmSystemTools::Error("No name given for WriteRuleStatement! called " - "with comment: " + + cmSystemTools::Error("No name given for WriteRule! called with comment: " + comment); return; } // Make sure a command is given. if (command.empty()) { - cmSystemTools::Error("No command given for WriteRuleStatement! called " - "with comment: " + - comment); + cmSystemTools::Error( + "No command given for WriteRule! called with comment: " + comment); return; } - cmGlobalNinjaGenerator::WriteComment(os, comment); - - // Write the rule. - os << "rule " << name << "\n"; - - // Write the depfile if any. - if (!depfile.empty()) { - cmGlobalNinjaGenerator::Indent(os, 1); - os << "depfile = " << depfile << "\n"; - } - - // Write the deptype if any. - if (!deptype.empty()) { - cmGlobalNinjaGenerator::Indent(os, 1); - os << "deps = " << deptype << "\n"; + // Make sure response file content is given + if (!rspfile.empty() && rspcontent.empty()) { + cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! " + "called with comment: " + + comment); + return; } - // Write the command. - cmGlobalNinjaGenerator::Indent(os, 1); - os << "command = " << command << "\n"; - - // Write the description if any. - if (!description.empty()) { - cmGlobalNinjaGenerator::Indent(os, 1); - os << "description = " << description << "\n"; - } + // -- Write rule + // Write rule intro + cmGlobalNinjaGenerator::WriteComment(os, comment); + os << "rule " << name << '\n'; - if (!rspfile.empty()) { - if (rspcontent.empty()) { - cmSystemTools::Error("No rspfile_content given!" + comment); - return; + // Write rule key/value pairs + auto writeKV = [&os](const char* key, std::string const& value) { + if (!value.empty()) { + cmGlobalNinjaGenerator::Indent(os, 1); + os << key << " = " << value << '\n'; } - cmGlobalNinjaGenerator::Indent(os, 1); - os << "rspfile = " << rspfile << "\n"; - cmGlobalNinjaGenerator::Indent(os, 1); - os << "rspfile_content = " << rspcontent << "\n"; - } + }; - if (!restat.empty()) { - cmGlobalNinjaGenerator::Indent(os, 1); - os << "restat = " << restat << "\n"; + writeKV("depfile", depfile); + writeKV("deps", deptype); + writeKV("command", command); + writeKV("description", description); + if (!rspfile.empty()) { + writeKV("rspfile", rspfile); + writeKV("rspfile_content", rspcontent); } - + writeKV("restat", restat); if (generator) { - cmGlobalNinjaGenerator::Indent(os, 1); - os << "generator = 1\n"; + writeKV("generator", "1"); } - os << "\n"; + // Finish rule + os << '\n'; } void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os, @@ -446,9 +424,6 @@ void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os, cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) : cmGlobalCommonGenerator(cm) - , BuildFileStream(nullptr) - , RulesFileStream(nullptr) - , CompileCommandsStream(nullptr) , UsingGCCOnWindows(false) , ComputingUnknownDependencies(false) , PolicyCMP0058(cmPolicies::WARN) @@ -509,8 +484,12 @@ void cmGlobalNinjaGenerator::Generate() msg.str()); return; } - this->OpenBuildFileStream(); - this->OpenRulesFileStream(); + if (!this->OpenBuildFileStream()) { + return; + } + if (!this->OpenRulesFileStream()) { + return; + } this->TargetDependsClosures.clear(); @@ -700,11 +679,7 @@ cmGlobalNinjaGenerator::GenerateBuildCommand( makeCommand.Add(makeOptions.begin(), makeOptions.end()); for (const auto& tname : targetNames) { if (!tname.empty()) { - if (tname == "clean") { - makeCommand.Add("-t", "clean"); - } else { - makeCommand.Add(tname); - } + makeCommand.Add(tname); } } return { std::move(makeCommand) }; @@ -720,22 +695,20 @@ void cmGlobalNinjaGenerator::AddRule( const std::string& restat, bool generator) { // Do not add the same rule twice. - if (this->HasRule(name)) { + if (!this->Rules.insert(name).second) { return; } - - this->Rules.insert(name); + // Store command length + this->RuleCmdLength[name] = static_cast<int>(command.size()); + // Write rule cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command, description, comment, depfile, deptype, rspfile, rspcontent, restat, generator); - - this->RuleCmdLength[name] = static_cast<int>(command.size()); } bool cmGlobalNinjaGenerator::HasRule(const std::string& name) { - RulesSetType::const_iterator rule = this->Rules.find(name); - return (rule != this->Rules.end()); + return (this->Rules.find(name) != this->Rules.end()); } // Private virtual overrides @@ -761,7 +734,7 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory( // Private methods -void cmGlobalNinjaGenerator::OpenBuildFileStream() +bool cmGlobalNinjaGenerator::OpenBuildFileStream() { // Compute Ninja's build file path. std::string buildFilePath = @@ -771,12 +744,12 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream() // Get a stream where to generate things. if (!this->BuildFileStream) { - this->BuildFileStream = new cmGeneratedFileStream( + this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>( buildFilePath, false, this->GetMakefileEncoding()); - if (!this->BuildFileStream) { + if (!(*this->BuildFileStream)) { // An error message is generated by the constructor if it cannot // open the file. - return; + return false; } } @@ -787,19 +760,20 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream() *this->BuildFileStream << "# This file contains all the build statements describing the\n" << "# compilation DAG.\n\n"; + + return true; } void cmGlobalNinjaGenerator::CloseBuildFileStream() { if (this->BuildFileStream) { - delete this->BuildFileStream; - this->BuildFileStream = nullptr; + this->BuildFileStream.reset(); } else { cmSystemTools::Error("Build file stream was not open."); } } -void cmGlobalNinjaGenerator::OpenRulesFileStream() +bool cmGlobalNinjaGenerator::OpenRulesFileStream() { // Compute Ninja's build file path. std::string rulesFilePath = @@ -809,12 +783,12 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream() // Get a stream where to generate things. if (!this->RulesFileStream) { - this->RulesFileStream = new cmGeneratedFileStream( + this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>( rulesFilePath, false, this->GetMakefileEncoding()); - if (!this->RulesFileStream) { + if (!(*this->RulesFileStream)) { // An error message is generated by the constructor if it cannot // open the file. - return; + return false; } } @@ -829,13 +803,13 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream() << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n" ; /* clang-format on */ + return true; } void cmGlobalNinjaGenerator::CloseRulesFileStream() { if (this->RulesFileStream) { - delete this->RulesFileStream; - this->RulesFileStream = nullptr; + this->RulesFileStream.reset(); } else { cmSystemTools::Error("Rules file stream was not open."); } @@ -892,7 +866,8 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( } // Get a stream where to generate things. - this->CompileCommandsStream = new cmGeneratedFileStream(buildFilePath); + this->CompileCommandsStream = + cm::make_unique<cmGeneratedFileStream>(buildFilePath); *this->CompileCommandsStream << "["; } else { *this->CompileCommandsStream << "," << std::endl; @@ -920,8 +895,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream() { if (this->CompileCommandsStream) { *this->CompileCommandsStream << "\n]"; - delete this->CompileCommandsStream; - this->CompileCommandsStream = nullptr; + this->CompileCommandsStream.reset(); } } @@ -1017,8 +991,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { // These depend only on other CMake-provided targets, e.g. "all". - std::set<BT<std::string>> const& utils = target->GetUtilities(); - for (BT<std::string> const& util : utils) { + for (BT<std::string> const& util : target->GetUtilities()) { std::string d = target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + util.Value; @@ -1026,8 +999,8 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( } } else { cmNinjaDeps outs; - cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target); - for (cmTargetDepend const& targetDep : targetDeps) { + for (cmTargetDepend const& targetDep : + this->GetTargetDirectDepends(target)) { if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -1061,10 +1034,9 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( // relevant for filling the cache entries properly isolated and a global // result set that is relevant for the result of the top level call to // AppendTargetDependsClosure. - auto const& targetDeps = this->GetTargetDirectDepends(target); cmNinjaOuts this_outs; // this will be the new cache entry - for (auto const& dep_target : targetDeps) { + for (auto const& dep_target : this->GetTargetDirectDepends(target)) { if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -1160,9 +1132,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) // The directory-level rule should depend on the directory-level // rules of the subdirectories. - std::vector<cmStateSnapshot> const& children = - lg->GetStateSnapshot().GetChildren(); - for (cmStateSnapshot const& state : children) { + for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) { std::string const currentBinaryDir = state.GetDirectory().GetCurrentBinary(); @@ -1223,26 +1193,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) for (cmLocalGenerator* lg : this->LocalGenerators) { // get the vector of files created by this makefile and convert them // to ninja paths, which are all relative in respect to the build directory - const std::vector<std::string>& files = - lg->GetMakefile()->GetOutputFiles(); - for (std::string const& file : files) { + for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) { knownDependencies.insert(this->ConvertToNinjaPath(file)); } if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { // get list files which are implicit dependencies as well and will be // phony for rebuild manifest - std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles(); - for (std::string const& j : lf) { + for (std::string const& j : lg->GetMakefile()->GetListFiles()) { knownDependencies.insert(this->ConvertToNinjaPath(j)); } } - std::vector<cmGeneratorExpressionEvaluationFile*> const& ef = - lg->GetMakefile()->GetEvaluationFiles(); - for (cmGeneratorExpressionEvaluationFile* li : ef) { + for (cmGeneratorExpressionEvaluationFile* li : + lg->GetMakefile()->GetEvaluationFiles()) { // get all the files created by generator expressions and convert them // to ninja paths - std::vector<std::string> evaluationFiles = li->GetFiles(); - for (std::string const& evaluationFile : evaluationFiles) { + for (std::string const& evaluationFile : li->GetFiles()) { knownDependencies.insert(this->ConvertToNinjaPath(evaluationFile)); } } @@ -1348,30 +1313,28 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) } cmLocalGenerator* lg = this->LocalGenerators[0]; - std::ostringstream cmd; - cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), - cmOutputConverter::SHELL) - << " -S" - << lg->ConvertToOutputFormat(lg->GetSourceDirectory(), - cmOutputConverter::SHELL) - << " -B" - << lg->ConvertToOutputFormat(lg->GetBinaryDirectory(), - cmOutputConverter::SHELL); - WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd.str(), - "Re-running CMake...", "Rule for re-running cmake.", - /*depfile=*/"", - /*deptype=*/"", - /*rspfile=*/"", - /*rspcontent*/ "", - /*restat=*/"", - /*generator=*/true); + { + std::string cmd = CMakeCmd(); + cmd += " -S"; + cmd += lg->ConvertToOutputFormat(lg->GetSourceDirectory(), + cmOutputConverter::SHELL); + cmd += " -B"; + cmd += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(), + cmOutputConverter::SHELL); + WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd, + "Re-running CMake...", "Rule for re-running cmake.", + /*depfile=*/"", + /*deptype=*/"", + /*rspfile=*/"", + /*rspcontent*/ "", + /*restat=*/"", + /*generator=*/true); + } cmNinjaDeps implicitDeps; cmNinjaDeps explicitDeps; for (cmLocalGenerator* localGen : this->LocalGenerators) { - std::vector<std::string> const& lf = - localGen->GetMakefile()->GetListFiles(); - for (std::string const& fi : lf) { + for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) { implicitDeps.push_back(this->ConvertToNinjaPath(fi)); } } @@ -1386,22 +1349,22 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) cmake* cm = this->GetCMakeInstance(); if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) { - std::ostringstream verify_cmd; - verify_cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), - cmOutputConverter::SHELL) - << " -P " - << lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(), - cmOutputConverter::SHELL); - - WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", verify_cmd.str(), - "Re-checking globbed directories...", - "Rule for re-checking globbed directories.", - /*depfile=*/"", - /*deptype=*/"", - /*rspfile=*/"", - /*rspcontent*/ "", - /*restat=*/"", - /*generator=*/true); + { + std::string cmd = CMakeCmd(); + cmd += " -P "; + cmd += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(), + cmOutputConverter::SHELL); + + WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", cmd, + "Re-checking globbed directories...", + "Rule for re-checking globbed directories.", + /*depfile=*/"", + /*deptype=*/"", + /*rspfile=*/"", + /*rspcontent*/ "", + /*restat=*/"", + /*generator=*/true); + } std::string verifyForce = cm->GetGlobVerifyScript() + "_force"; cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce)); @@ -1464,10 +1427,17 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) missingInputs, cmNinjaDeps()); } -std::string cmGlobalNinjaGenerator::ninjaCmd() const +std::string cmGlobalNinjaGenerator::CMakeCmd() const +{ + cmLocalGenerator* lgen = this->LocalGenerators.at(0); + return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), + cmOutputConverter::SHELL); +} + +std::string cmGlobalNinjaGenerator::NinjaCmd() const { cmLocalGenerator* lgen = this->LocalGenerators[0]; - if (lgen) { + if (lgen != nullptr) { return lgen->ConvertToOutputFormat(this->NinjaCommand, cmOutputConverter::SHELL); } @@ -1496,7 +1466,7 @@ bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) { - WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean", + WriteRule(*this->RulesFileStream, "CLEAN", NinjaCmd() + " -t clean", "Cleaning all built files...", "Rule for cleaning all built files.", /*depfile=*/"", @@ -1516,7 +1486,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) { - WriteRule(*this->RulesFileStream, "HELP", ninjaCmd() + " -t targets", + WriteRule(*this->RulesFileStream, "HELP", NinjaCmd() + " -t targets", "All primary targets available:", "Rule for printing all primary targets available.", /*depfile=*/"", diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index efd1d8f..ffcea60 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -7,12 +7,15 @@ #include <iosfwd> #include <map> +#include <memory> // IWYU pragma: keep #include <set> #include <string> #include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> +#include "cmGeneratedFileStream.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" @@ -21,7 +24,6 @@ #include "cm_codecvt.hxx" class cmCustomCommand; -class cmGeneratedFileStream; class cmGeneratorTarget; class cmLinkLineComputer; class cmLocalGenerator; @@ -41,8 +43,6 @@ struct cmDocumentationEntry; * it is handle by Ninja's -v option. * - We don't care about computing any progress status since Ninja manages * it itself. - * - We don't care about generating a clean target since Ninja already have - * a clean tool. * - We generate one build.ninja and one rules.ninja per project. * - We try to minimize the number of generated rules: one per target and * language. @@ -233,12 +233,12 @@ public: cmGeneratedFileStream* GetBuildFileStream() const { - return this->BuildFileStream; + return this->BuildFileStream.get(); } cmGeneratedFileStream* GetRulesFileStream() const { - return this->RulesFileStream; + return this->RulesFileStream.get(); } std::string const& ConvertToNinjaPath(const std::string& path) const; @@ -378,12 +378,12 @@ private: cmMakefile* mf) const override; bool CheckFortran(cmMakefile* mf) const; - void OpenBuildFileStream(); + bool OpenBuildFileStream(); void CloseBuildFileStream(); void CloseCompileCommandsStream(); - void OpenRulesFileStream(); + bool OpenRulesFileStream(); void CloseRulesFileStream(); /// Write the common disclaimer text at the top of each build file. @@ -405,25 +405,22 @@ private: cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& depends); - std::string ninjaCmd() const; + std::string CMakeCmd() const; + std::string NinjaCmd() const; /// The file containing the build statement. (the relationship of the /// compilation DAG). - cmGeneratedFileStream* BuildFileStream; + std::unique_ptr<cmGeneratedFileStream> BuildFileStream; /// The file containing the rule statements. (The action attached to each /// edge of the compilation DAG). - cmGeneratedFileStream* RulesFileStream; - cmGeneratedFileStream* CompileCommandsStream; - - /// The type used to store the set of rules added to the generated build - /// system. - typedef std::set<std::string> RulesSetType; + std::unique_ptr<cmGeneratedFileStream> RulesFileStream; + std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream; /// The set of rules added to the generated build system. - RulesSetType Rules; + std::unordered_set<std::string> Rules; /// Length of rule command, used by rsp file evaluation - std::map<std::string, int> RuleCmdLength; + std::unordered_map<std::string, int> RuleCmdLength; /// The set of dependencies to add to the "all" target. cmNinjaDeps AllDependencies; diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index 62ce9f2..14288f6 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -43,9 +43,10 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator( cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default; -void cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg) { - LocalGenerator = lg; + this->LocalGenerator = lg; + return true; } void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os, diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h index ac6e504..e30849f 100644 --- a/Source/cmInstallDirectoryGenerator.h +++ b/Source/cmInstallDirectoryGenerator.h @@ -29,7 +29,7 @@ public: bool optional = false); ~cmInstallDirectoryGenerator() override; - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; std::string GetDestination(std::string const& config) const; diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx index 186b9df..7de3dd4 100644 --- a/Source/cmInstallExportAndroidMKGenerator.cxx +++ b/Source/cmInstallExportAndroidMKGenerator.cxx @@ -30,10 +30,11 @@ cmInstallExportAndroidMKGenerator::~cmInstallExportAndroidMKGenerator() { } -void cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; this->ExportSet->Compute(lg); + return true; } void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os) diff --git a/Source/cmInstallExportAndroidMKGenerator.h b/Source/cmInstallExportAndroidMKGenerator.h index 189084a..a92ff27 100644 --- a/Source/cmInstallExportAndroidMKGenerator.h +++ b/Source/cmInstallExportAndroidMKGenerator.h @@ -24,7 +24,7 @@ public: const char* name_space, bool exportOld); ~cmInstallExportAndroidMKGenerator(); - void Compute(cmLocalGenerator* lg); + bool Compute(cmLocalGenerator* lg) override; protected: virtual void GenerateScript(std::ostream& os); diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 73a37cb..f5bedab 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -45,10 +45,11 @@ cmInstallExportGenerator::~cmInstallExportGenerator() delete this->EFGen; } -void cmInstallExportGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; this->ExportSet->Compute(lg); + return true; } void cmInstallExportGenerator::ComputeTempDir() diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index d23cf06..c4d252c 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -34,7 +34,7 @@ public: cmExportSet* GetExportSet() { return this->ExportSet; } - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; } diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index 9eb8ad4..2ed9f73 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -42,9 +42,10 @@ cmInstallFilesGenerator::cmInstallFilesGenerator( cmInstallFilesGenerator::~cmInstallFilesGenerator() = default; -void cmInstallFilesGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; + return true; } std::string cmInstallFilesGenerator::GetDestination( diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h index 0ef2a06..ac462d4 100644 --- a/Source/cmInstallFilesGenerator.h +++ b/Source/cmInstallFilesGenerator.h @@ -29,7 +29,7 @@ public: bool optional = false); ~cmInstallFilesGenerator() override; - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; std::string GetDestination(std::string const& config) const; diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 9bd7ac3..dbe707d 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -60,7 +60,7 @@ public: /** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */ static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false); - virtual void Compute(cmLocalGenerator*) {} + virtual bool Compute(cmLocalGenerator*) { return true; } protected: void GenerateScript(std::ostream& os) override; diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx index a513958..5832d27 100644 --- a/Source/cmInstallScriptGenerator.cxx +++ b/Source/cmInstallScriptGenerator.cxx @@ -29,7 +29,7 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script, cmInstallScriptGenerator::~cmInstallScriptGenerator() = default; -void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; @@ -49,6 +49,8 @@ void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg) break; } } + + return true; } void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os, diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h index 05199d7..6af7371 100644 --- a/Source/cmInstallScriptGenerator.h +++ b/Source/cmInstallScriptGenerator.h @@ -23,7 +23,7 @@ public: const char* component, bool exclude_from_all); ~cmInstallScriptGenerator() override; - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; protected: void GenerateScriptActions(std::ostream& os, Indent indent) override; diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx index ad7121f..1c0512c 100644 --- a/Source/cmInstallSubdirectoryGenerator.cxx +++ b/Source/cmInstallSubdirectoryGenerator.cxx @@ -41,9 +41,10 @@ void cmInstallSubdirectoryGenerator::CheckCMP0082( } } -void cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg) { this->LocalGenerator = lg; + return true; } void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os) diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h index 35471dd..22759d9 100644 --- a/Source/cmInstallSubdirectoryGenerator.h +++ b/Source/cmInstallSubdirectoryGenerator.h @@ -28,7 +28,7 @@ public: void CheckCMP0082(bool& haveSubdirectoryInstall, bool& haveInstallAfterSubdirectory) override; - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; protected: void GenerateScript(std::ostream& os) override; diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 4fefe23..7c5a55b 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -430,7 +430,7 @@ std::string cmInstallTargetGenerator::GetInstallFilename( return fname; } -void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg) +bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg) { // Lookup this target in the current directory. this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName); @@ -439,6 +439,8 @@ void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg) this->Target = lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName); } + + return true; } void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent, diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 6df5b1a..ed3ab52 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -58,7 +58,7 @@ public: const std::string& config, NameType nameType = NameNormal); - void Compute(cmLocalGenerator* lg) override; + bool Compute(cmLocalGenerator* lg) override; cmGeneratorTarget* GetTarget() const { return this->Target; } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index f4e3ed8..e6d4457 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -79,19 +79,17 @@ void cmLocalNinjaGenerator::Generate() } } - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + for (cmGeneratorTarget* target : this->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(target); + auto tg = cmNinjaTargetGenerator::New(target); if (tg) { tg->Generate(); // Add the target to "all" if required. if (!this->GetGlobalNinjaGenerator()->IsExcluded(target)) { this->GetGlobalNinjaGenerator()->AddDependencyToAll(target); } - delete tg; } } @@ -283,8 +281,7 @@ void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target, void cmLocalNinjaGenerator::AppendCustomCommandDeps( cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps) { - const std::vector<std::string>& deps = ccg.GetDepends(); - for (std::string const& i : deps) { + for (std::string const& i : ccg.GetDepends()) { std::string dep; if (this->GetRealDependency(i, this->GetConfigName(), dep)) { ninjaDeps.push_back( diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 2324839..506711a 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -9,7 +9,7 @@ #include <iterator> #include <map> #include <memory> // IWYU pragma: keep -#include <sstream> +#include <ostream> #include <utility> #include "cmAlgorithms.h" @@ -33,7 +33,8 @@ #include "cmSystemTools.h" #include "cmake.h" -cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target) +std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New( + cmGeneratorTarget* target) { switch (target->GetType()) { case cmStateEnums::EXECUTABLE: @@ -41,14 +42,14 @@ cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target) case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: case cmStateEnums::OBJECT_LIBRARY: - return new cmNinjaNormalTargetGenerator(target); + return cm::make_unique<cmNinjaNormalTargetGenerator>(target); case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: - return new cmNinjaUtilityTargetGenerator(target); + return cm::make_unique<cmNinjaUtilityTargetGenerator>(target); default: - return nullptr; + return std::unique_ptr<cmNinjaTargetGenerator>(); } } @@ -496,12 +497,11 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) launcher += " "; } - if (explicitPP) { - // Lookup the explicit preprocessing rule. - std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE"; - std::string const& ppCmd = - this->GetMakefile()->GetRequiredDefinition(ppVar); + std::string const cmakeCmd = + this->GetLocalGenerator()->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); + if (explicitPP) { // Explicit preprocessing always uses a depfile. std::string const ppDeptype; // no deps= for multiple outputs std::string const ppDepfile = "$DEP_FILE"; @@ -535,8 +535,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string ppRspContent; if (!responseFlag.empty()) { ppRspFile = "$RSP_FILE"; - ppRspContent = std::string(" ") + ppVars.Defines + " " + - ppVars.Includes + " " + ppFlags; + ppRspContent = " "; + ppRspContent += ppVars.Defines; + ppRspContent += " "; + ppRspContent += ppVars.Includes; + ppRspContent += " "; + ppRspContent += ppFlags; ppFlags = responseFlag + ppRspFile; ppVars.Defines = ""; ppVars.Includes = ""; @@ -546,7 +550,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) // Rule for preprocessing source file. std::vector<std::string> ppCmds; - cmSystemTools::ExpandListArgument(ppCmd, ppCmds); + { + // Lookup the explicit preprocessing rule. + std::string ppVar = "CMAKE_" + lang; + ppVar += "_PREPROCESS_SOURCE"; + cmSystemTools::ExpandListArgument( + this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds); + } for (std::string& i : ppCmds) { i = launcher + i; @@ -555,67 +565,73 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } // Run CMake dependency scanner on preprocessed output. - std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); - ppCmds.push_back( - cmake + - " -E cmake_ninja_depends" - " --tdi=" + - tdi + " --lang=" + lang + - " --pp=$out" - " --dep=$DEP_FILE" + - (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : "")); - + { + std::string ccmd = cmakeCmd; + ccmd += " -E cmake_ninja_depends --tdi="; + ccmd += tdi; + ccmd += " --lang="; + ccmd += lang; + ccmd += " --pp=$out --dep=$DEP_FILE"; + if (needDyndep) { + ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE"; + } + ppCmds.emplace_back(std::move(ccmd)); + } std::string const ppCmdLine = this->GetLocalGenerator()->BuildCommandLine(ppCmds); // Write the rule for preprocessing file of the given language. - std::ostringstream ppComment; - ppComment << "Rule for preprocessing " << lang << " files."; - std::ostringstream ppDesc; - ppDesc << "Building " << lang << " preprocessed $out"; + std::string ppComment = "Rule for preprocessing "; + ppComment += lang; + ppComment += " files."; + std::string ppDesc = "Building "; + ppDesc += lang; + ppDesc += " preprocessed $out"; this->GetGlobalGenerator()->AddRule( - this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc.str(), - ppComment.str(), ppDepfile, ppDeptype, ppRspFile, ppRspContent, + this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc, ppComment, + ppDepfile, ppDeptype, ppRspFile, ppRspContent, /*restat*/ "", /*generator*/ false); } if (needDyndep) { // Write the rule for ninja dyndep file generation. - std::vector<std::string> ddCmds; // Command line length is almost always limited -> use response file for // dyndep rules std::string ddRspFile = "$out.rsp"; std::string ddRspContent = "$in"; - std::string ddInput = "@" + ddRspFile; + std::string ddCmdLine; // Run CMake dependency scanner on the source file (using the preprocessed // source if that was performed). - std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); - ddCmds.push_back(cmake + - " -E cmake_ninja_dyndep" - " --tdi=" + - tdi + " --lang=" + lang + - " --dd=$out" - " " + - ddInput); - - std::string const ddCmdLine = - this->GetLocalGenerator()->BuildCommandLine(ddCmds); - - std::ostringstream ddComment; - ddComment << "Rule to generate ninja dyndep files for " << lang << "."; - std::ostringstream ddDesc; - ddDesc << "Generating " << lang << " dyndep file $out"; - this->GetGlobalGenerator()->AddRule( - this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(), - /*depfile*/ "", - /*deps*/ "", ddRspFile, ddRspContent, - /*restat*/ "", - /*generator*/ false); + { + std::vector<std::string> ddCmds; + { + std::string ccmd = cmakeCmd; + ccmd += " -E cmake_ninja_dyndep --tdi="; + ccmd += tdi; + ccmd += " --lang="; + ccmd += lang; + ccmd += " --dd=$out "; + ccmd += "@"; + ccmd += ddRspFile; + ddCmds.emplace_back(std::move(ccmd)); + } + ddCmdLine = this->GetLocalGenerator()->BuildCommandLine(ddCmds); + } + std::string ddComment = "Rule to generate ninja dyndep files for "; + ddComment += lang; + ddComment += "."; + std::string ddDesc = "Generating "; + ddDesc += lang; + ddDesc += " dyndep file $out"; + this->GetGlobalGenerator()->AddRule(this->LanguageDyndepRule(lang), + ddCmdLine, ddDesc, ddComment, + /*depfile*/ "", + /*deps*/ "", ddRspFile, ddRspContent, + /*restat*/ "", + /*generator*/ false); } // If using a response file, move defines, includes, and flags into it. @@ -716,8 +732,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { - std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); + std::string run_iwyu = cmakeCmd; run_iwyu += " -E __run_co_compile"; if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied @@ -776,15 +791,17 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) this->GetLocalGenerator()->BuildCommandLine(compileCmds); // Write the rule for compiling file of the given language. - std::ostringstream comment; - comment << "Rule for compiling " << lang << " files."; - std::ostringstream description; - description << "Building " << lang << " object $out"; - this->GetGlobalGenerator()->AddRule( - this->LanguageCompilerRule(lang), cmdLine, description.str(), - comment.str(), depfile, deptype, rspfile, rspcontent, - /*restat*/ "", - /*generator*/ false); + std::string comment = "Rule for compiling "; + comment += lang; + comment += " files."; + std::string description = "Building "; + description += lang; + description += " object $out"; + this->GetGlobalGenerator()->AddRule(this->LanguageCompilerRule(lang), + cmdLine, description, comment, depfile, + deptype, rspfile, rspcontent, + /*restat*/ "", + /*generator*/ false); } void cmNinjaTargetGenerator::WriteObjectBuildStatements() @@ -1212,8 +1229,7 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang) Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] = Json::arrayValue; - std::vector<std::string> linked = this->GetLinkedTargetDirectories(); - for (std::string const& l : linked) { + for (std::string const& l : this->GetLinkedTargetDirectories()) { tdi_linked_target_dirs.append(l); } diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 51c9ac7..3dbc1b5 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -11,6 +11,7 @@ #include "cmOSXBundleGenerator.h" #include <map> +#include <memory> // IWYU pragma: keep #include <set> #include <string> #include <vector> @@ -26,7 +27,8 @@ class cmNinjaTargetGenerator : public cmCommonTargetGenerator { public: /// Create a cmNinjaTargetGenerator according to the @a target's type. - static cmNinjaTargetGenerator* New(cmGeneratorTarget* target); + static std::unique_ptr<cmNinjaTargetGenerator> New( + cmGeneratorTarget* target); /// Build a NinjaTargetGenerator. cmNinjaTargetGenerator(cmGeneratorTarget* target); diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index f7e377d..e1c435b 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -279,10 +279,11 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile, InfoFile_ = infoFile; cmSystemTools::ConvertToUnixSlashes(InfoFile_); if (!InfoFileTime_.Load(InfoFile_)) { - std::string msg = "Autogen: The info file "; + std::string msg = "AutoGen: The info file "; msg += Quoted(InfoFile_); msg += " is not readable\n"; cmSystemTools::Stderr(msg); + return false; } InfoDir_ = cmSystemTools::GetFilenamePath(infoFile); InfoConfig_ = config; diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index bb40c39..7ac7339 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -3,6 +3,8 @@ #include "cmQtAutoRcc.h" #include "cmQtAutoGen.h" +#include <sstream> + #include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmDuration.h" @@ -49,11 +51,16 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); return list; }; + auto LogInfoError = [this](std::string const& msg) -> bool { + std::ostringstream err; + err << "In " << Quoted(this->InfoFile()) << ":\n" << msg; + this->Log().Error(GenT::RCC, err.str()); + return false; + }; // -- Read info file if (!makefile->ReadListFile(InfoFile())) { - Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed."); - return false; + return LogInfoError("File processing failed."); } // - Configurations @@ -63,18 +70,22 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) // - Directories AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty."); - return false; + return LogInfoError("Build directory empty."); } IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR"); if (IncludeDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty."); - return false; + return LogInfoError("Include directory empty."); } // - Rcc executable RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); + if (!RccExecutableTime_.Load(RccExecutable_)) { + std::string error = "The rcc executable "; + error += Quoted(RccExecutable_); + error += " does not exist."; + return LogInfoError(error); + } RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); // - Job @@ -92,28 +103,22 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) // - Validity checks if (LockFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing."); - return false; + return LogInfoError("Lock file name missing."); } if (SettingsFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing."); - return false; + return LogInfoError("Settings file name missing."); } if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing."); - return false; + return LogInfoError("Autogen build directory missing."); } if (RccExecutable_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing."); - return false; + return LogInfoError("rcc executable missing."); } if (QrcFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing."); - return false; + return LogInfoError("rcc input file missing."); } if (RccFileName_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing."); - return false; + return LogInfoError("rcc output file missing."); } // Init derived information @@ -301,12 +306,10 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the rcc output file exists if (!RccFileTime_.Load(RccFileOutput_)) { if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from its source file "; - reason += Quoted(QrcFile_); - reason += " because it doesn't exist"; - Log().Info(GenT::RCC, reason); + Reason = "Generating "; + Reason += Quoted(RccFileOutput_); + Reason += ", because it doesn't exist, from "; + Reason += Quoted(QrcFile_); } generate = true; return true; @@ -315,12 +318,10 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the settings changed if (SettingsChanged_) { if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from "; - reason += Quoted(QrcFile_); - reason += " because the RCC settings changed"; - Log().Info(GenT::RCC, reason); + Reason = "Generating "; + Reason += Quoted(RccFileOutput_); + Reason += ", because the rcc settings changed, from "; + Reason += Quoted(QrcFile_); } generate = true; return true; @@ -329,11 +330,24 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the rcc output file is older than the .qrc file if (RccFileTime_.Older(QrcFileTime_)) { if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " because it is older than "; - reason += Quoted(QrcFile_); - Log().Info(GenT::RCC, reason); + Reason = "Generating "; + Reason += Quoted(RccFileOutput_); + Reason += ", because it is older than "; + Reason += Quoted(QrcFile_); + Reason += ", from "; + Reason += Quoted(QrcFile_); + } + generate = true; + return true; + } + + // Test if the rcc output file is older than the rcc executable + if (RccFileTime_.Older(RccExecutableTime_)) { + if (Log().Verbose()) { + Reason = "Generating "; + Reason += Quoted(RccFileOutput_); + Reason += ", because it is older than the rcc executable, from "; + Reason += Quoted(QrcFile_); } generate = true; return true; @@ -354,6 +368,7 @@ bool cmQtAutoRcc::TestResources(bool& generate) } } + // Check if any resource file is newer than the rcc output file for (std::string const& resFile : Inputs_) { // Check if the resource file exists cmFileTime fileTime; @@ -365,16 +380,15 @@ bool cmQtAutoRcc::TestResources(bool& generate) Log().ErrorFile(GenT::RCC, QrcFile_, error); return false; } - // Check if the resource file is newer than the build file + // Check if the resource file is newer than the rcc output file if (RccFileTime_.Older(fileTime)) { if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from "; - reason += Quoted(QrcFile_); - reason += " because it is older than "; - reason += Quoted(resFile); - Log().Info(GenT::RCC, reason); + Reason = "Generating "; + Reason += Quoted(RccFileOutput_); + Reason += ", because it is older than "; + Reason += Quoted(resFile); + Reason += ", from "; + Reason += Quoted(QrcFile_); } generate = true; break; @@ -386,17 +400,7 @@ bool cmQtAutoRcc::TestResources(bool& generate) bool cmQtAutoRcc::TestInfoFile() { // Test if the rcc output file is older than the info file - - cmFileTime infoFileTime; - if (!infoFileTime.Load(InfoFile())) { - std::string error; - error = "Could not find the info file "; - error += Quoted(InfoFile()); - error += '\n'; - Log().ErrorFile(GenT::RCC, QrcFile_, error); - return false; - } - if (RccFileTime_.Older(infoFileTime)) { + if (RccFileTime_.Older(InfoFileTime())) { if (Log().Verbose()) { std::string reason = "Touching "; reason += Quoted(RccFileOutput_); @@ -424,7 +428,7 @@ bool cmQtAutoRcc::GenerateRcc() return false; } - // Start a rcc process + // Compose rcc command std::vector<std::string> cmd; cmd.push_back(RccExecutable_); cmd.insert(cmd.end(), Options_.begin(), Options_.end()); @@ -432,12 +436,15 @@ bool cmQtAutoRcc::GenerateRcc() cmd.push_back(RccFileOutput_); cmd.push_back(QrcFile_); - // Log command + // Log reason and command if (Log().Verbose()) { - std::string msg = "Running command:\n"; + std::string msg = Reason; + if (!msg.empty() && (msg.back() != '\n')) { + msg += '\n'; + } msg += QuotedCommand(cmd); msg += '\n'; - cmSystemTools::Stdout(msg); + Log().Info(GenT::RCC, msg); } std::string rccStdOut; diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h index 01c3fb9..636a667 100644 --- a/Source/cmQtAutoRcc.h +++ b/Source/cmQtAutoRcc.h @@ -54,6 +54,7 @@ private: std::string IncludeDir_; // -- Qt environment std::string RccExecutable_; + cmFileTime RccExecutableTime_; std::vector<std::string> RccListOptions_; // -- Job std::string LockFile_; @@ -67,6 +68,7 @@ private: std::string RccFileOutput_; std::string RccFilePublic_; cmFileTime RccFileTime_; + std::string Reason; std::vector<std::string> Options_; std::vector<std::string> Inputs_; // -- Settings file diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index 27069ee..db67463 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -211,7 +211,6 @@ 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) { @@ -231,6 +230,7 @@ int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) return uv_timer_start(*this, cb, timeout, repeat); } +#ifdef CMAKE_BUILD_WITH_CMAKE uv_tty_ptr::operator uv_stream_t*() const { return reinterpret_cast<uv_stream_t*>(handle.get()); @@ -255,13 +255,13 @@ 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) +#ifdef CMAKE_BUILD_WITH_CMAKE +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async) + UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty) #endif } diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx new file mode 100644 index 0000000..c4e30d4 --- /dev/null +++ b/Source/cmUVProcessChain.cxx @@ -0,0 +1,392 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmUVProcessChain.h" + +#include "cmAlgorithms.h" +#include "cmGetPipes.h" +#include "cmUVHandlePtr.h" +#include "cmUVStreambuf.h" +#include "cm_uv.h" + +#include <iterator> +#include <memory> +#include <utility> + +struct cmUVProcessChain::InternalData +{ + struct BasicStreamData + { + cmUVStreambuf Streambuf; + cm::uv_pipe_ptr BuiltinStream; + uv_stdio_container_t Stdio; + }; + + template <typename IOStream> + struct StreamData : public BasicStreamData + { + StreamData() + : BuiltinIOStream(&this->Streambuf) + { + } + + IOStream BuiltinIOStream; + + IOStream* GetBuiltinStream() + { + if (this->BuiltinStream.get()) { + return &this->BuiltinIOStream; + } + return nullptr; + } + }; + + struct ProcessData + { + cmUVProcessChain::InternalData* Data; + cm::uv_process_ptr Process; + cm::uv_pipe_ptr OutputPipe; + bool Finished = false; + Status ProcessStatus; + }; + + const cmUVProcessChainBuilder* Builder = nullptr; + + bool Valid = false; + + cm::uv_loop_ptr Loop; + + StreamData<std::istream> OutputStreamData; + StreamData<std::istream> ErrorStreamData; + + unsigned int ProcessesCompleted = 0; + std::vector<std::unique_ptr<ProcessData>> Processes; + + bool Prepare(const cmUVProcessChainBuilder* builder); + bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config, + bool first, bool last); + bool Finish(); + + static const Status* GetStatus(const ProcessData& data); +}; + +cmUVProcessChainBuilder::cmUVProcessChainBuilder() +{ + this->SetNoStream(Stream_INPUT) + .SetNoStream(Stream_OUTPUT) + .SetNoStream(Stream_ERROR); +} + +cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand( + const std::vector<std::string>& arguments) +{ + if (!arguments.empty()) { + this->Processes.emplace_back(); + this->Processes.back().Arguments = arguments; + } + return *this; +} + +cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio) +{ + switch (stdio) { + case Stream_INPUT: + case Stream_OUTPUT: + case Stream_ERROR: { + auto& streamData = this->Stdio[stdio]; + streamData.Type = None; + break; + } + } + return *this; +} + +cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream( + Stream stdio) +{ + switch (stdio) { + case Stream_INPUT: + // FIXME + break; + + case Stream_OUTPUT: + case Stream_ERROR: { + auto& streamData = this->Stdio[stdio]; + streamData.Type = Builtin; + break; + } + } + return *this; +} + +cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( + Stream stdio, int fd) +{ + switch (stdio) { + case Stream_INPUT: + // FIXME + break; + + case Stream_OUTPUT: + case Stream_ERROR: { + auto& streamData = this->Stdio[stdio]; + streamData.Type = External; + streamData.FileDescriptor = fd; + break; + } + } + return *this; +} + +cmUVProcessChain cmUVProcessChainBuilder::Start() const +{ + cmUVProcessChain chain; + + if (!chain.Data->Prepare(this)) { + return chain; + } + + for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) { + if (!chain.Data->AddCommand(*it, it == this->Processes.begin(), + it == std::prev(this->Processes.end()))) { + return chain; + } + } + + chain.Data->Finish(); + + return chain; +} + +const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus( + const cmUVProcessChain::InternalData::ProcessData& data) +{ + if (data.Finished) { + return &data.ProcessStatus; + } + return nullptr; +} + +bool cmUVProcessChain::InternalData::Prepare( + const cmUVProcessChainBuilder* builder) +{ + this->Builder = builder; + + auto const& output = + this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT]; + auto& outputData = this->OutputStreamData; + switch (output.Type) { + case cmUVProcessChainBuilder::None: + outputData.Stdio.flags = UV_IGNORE; + break; + + case cmUVProcessChainBuilder::Builtin: + outputData.BuiltinStream.init(*this->Loop, 0); + outputData.Stdio.flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + outputData.Stdio.data.stream = outputData.BuiltinStream; + break; + + case cmUVProcessChainBuilder::External: + outputData.Stdio.flags = UV_INHERIT_FD; + outputData.Stdio.data.fd = output.FileDescriptor; + break; + } + + auto const& error = + this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR]; + auto& errorData = this->ErrorStreamData; + switch (error.Type) { + case cmUVProcessChainBuilder::None: + errorData.Stdio.flags = UV_IGNORE; + break; + + case cmUVProcessChainBuilder::Builtin: { + int pipeFd[2]; + if (cmGetPipes(pipeFd) < 0) { + return false; + } + + errorData.BuiltinStream.init(*this->Loop, 0); + if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) { + return false; + } + errorData.Stdio.flags = UV_INHERIT_FD; + errorData.Stdio.data.fd = pipeFd[1]; + break; + } + + case cmUVProcessChainBuilder::External: + errorData.Stdio.flags = UV_INHERIT_FD; + errorData.Stdio.data.fd = error.FileDescriptor; + break; + } + + return true; +} + +bool cmUVProcessChain::InternalData::AddCommand( + const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first, + bool last) +{ + this->Processes.emplace_back(cm::make_unique<ProcessData>()); + auto& process = *this->Processes.back(); + process.Data = this; + + auto options = uv_process_options_t(); + + // Bounds were checked at add time, first element is guaranteed to exist + options.file = config.Arguments[0].c_str(); + + std::vector<const char*> arguments; + for (auto const& arg : config.Arguments) { + arguments.push_back(arg.c_str()); + } + arguments.push_back(nullptr); + options.args = const_cast<char**>(arguments.data()); + options.flags = UV_PROCESS_WINDOWS_HIDE; + + std::array<uv_stdio_container_t, 3> stdio; + stdio[0] = uv_stdio_container_t(); + if (first) { + stdio[0].flags = UV_IGNORE; + } else { + auto& prev = **std::prev(this->Processes.end(), 2); + stdio[0].flags = UV_INHERIT_STREAM; + stdio[0].data.stream = prev.OutputPipe; + } + if (last) { + stdio[1] = this->OutputStreamData.Stdio; + } else { + if (process.OutputPipe.init(*this->Loop, 0) < 0) { + return false; + } + stdio[1] = uv_stdio_container_t(); + stdio[1].flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + stdio[1].data.stream = process.OutputPipe; + } + stdio[2] = this->ErrorStreamData.Stdio; + + options.stdio = stdio.data(); + options.stdio_count = 3; + options.exit_cb = [](uv_process_t* handle, int64_t exitStatus, + int termSignal) { + auto* processData = static_cast<ProcessData*>(handle->data); + processData->Finished = true; + processData->ProcessStatus.ExitStatus = exitStatus; + processData->ProcessStatus.TermSignal = termSignal; + processData->Data->ProcessesCompleted++; + }; + + return process.Process.spawn(*this->Loop, options, &process) >= 0; +} + +bool cmUVProcessChain::InternalData::Finish() +{ + if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type == + cmUVProcessChainBuilder::Builtin) { + this->OutputStreamData.Streambuf.open( + this->OutputStreamData.BuiltinStream); + } + + if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type == + cmUVProcessChainBuilder::Builtin) { + cm::uv_pipe_ptr tmpPipe; + if (tmpPipe.init(*this->Loop, 0) < 0) { + return false; + } + if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) { + return false; + } + tmpPipe.reset(); + + this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream); + } + + this->Valid = true; + return true; +} + +cmUVProcessChain::cmUVProcessChain() + : Data(cm::make_unique<InternalData>()) +{ + this->Data->Loop.init(); +} + +cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept + : Data(std::move(other.Data)) +{ +} + +cmUVProcessChain::~cmUVProcessChain() = default; + +cmUVProcessChain& cmUVProcessChain::operator=( + cmUVProcessChain&& other) noexcept +{ + this->Data = std::move(other.Data); + return *this; +} + +uv_loop_t& cmUVProcessChain::GetLoop() +{ + return *this->Data->Loop; +} + +std::istream* cmUVProcessChain::OutputStream() +{ + return this->Data->OutputStreamData.GetBuiltinStream(); +} + +std::istream* cmUVProcessChain::ErrorStream() +{ + return this->Data->ErrorStreamData.GetBuiltinStream(); +} + +bool cmUVProcessChain::Valid() const +{ + return this->Data->Valid; +} + +bool cmUVProcessChain::Wait(int64_t milliseconds) +{ + bool timeout = false; + cm::uv_timer_ptr timer; + + if (milliseconds >= 0) { + timer.init(*this->Data->Loop, &timeout); + timer.start( + [](uv_timer_t* handle) { + auto* timeoutPtr = static_cast<bool*>(handle->data); + *timeoutPtr = true; + }, + milliseconds, 0); + } + + while (!timeout && + this->Data->ProcessesCompleted < this->Data->Processes.size()) { + uv_run(this->Data->Loop, UV_RUN_ONCE); + } + + return !timeout; +} + +std::vector<const cmUVProcessChain::Status*> cmUVProcessChain::GetStatus() + const +{ + std::vector<const cmUVProcessChain::Status*> statuses( + this->Data->Processes.size(), nullptr); + for (std::size_t i = 0; i < statuses.size(); i++) { + statuses[i] = this->GetStatus(i); + } + return statuses; +} + +const cmUVProcessChain::Status* cmUVProcessChain::GetStatus( + std::size_t index) const +{ + auto const& process = *this->Data->Processes[index]; + if (process.Finished) { + return &process.ProcessStatus; + } + return nullptr; +} diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h new file mode 100644 index 0000000..2b33520 --- /dev/null +++ b/Source/cmUVProcessChain.h @@ -0,0 +1,100 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmUVProcessChain_h +#define cmUVProcessChain_h + +#include "cm_uv.h" + +#include <array> +#include <iosfwd> +#include <memory> // IWYU pragma: keep +#include <string> +#include <vector> + +#include <stdint.h> + +class cmUVProcessChain; + +class cmUVProcessChainBuilder +{ +public: + enum Stream + { + Stream_INPUT = 0, + Stream_OUTPUT = 1, + Stream_ERROR = 2, + }; + + cmUVProcessChainBuilder(); + + cmUVProcessChainBuilder& AddCommand( + const std::vector<std::string>& arguments); + cmUVProcessChainBuilder& SetNoStream(Stream stdio); + cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio); + cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd); + + cmUVProcessChain Start() const; + +private: + enum StdioType + { + None, + Builtin, + External, + }; + + friend class cmUVProcessChain; + + struct StdioConfiguration + { + StdioType Type; + int FileDescriptor; + }; + + struct ProcessConfiguration + { + std::vector<std::string> Arguments; + }; + + std::array<StdioConfiguration, 3> Stdio; + std::vector<ProcessConfiguration> Processes; +}; + +class cmUVProcessChain +{ +public: + struct Status + { + int64_t ExitStatus; + int TermSignal; + }; + + cmUVProcessChain(const cmUVProcessChain& other) = delete; + cmUVProcessChain(cmUVProcessChain&& other) noexcept; + + ~cmUVProcessChain(); + + cmUVProcessChain& operator=(const cmUVProcessChain& other) = delete; + cmUVProcessChain& operator=(cmUVProcessChain&& other) noexcept; + + uv_loop_t& GetLoop(); + + // FIXME: Add stdin support + std::istream* OutputStream(); + std::istream* ErrorStream(); + + bool Valid() const; + bool Wait(int64_t milliseconds = -1); + std::vector<const Status*> GetStatus() const; + const Status* GetStatus(std::size_t index) const; + +private: + friend class cmUVProcessChainBuilder; + + cmUVProcessChain(); + + struct InternalData; + std::unique_ptr<InternalData> Data; +}; + +#endif diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h index 29e4fde..873352b 100644 --- a/Source/cmUVStreambuf.h +++ b/Source/cmUVStreambuf.h @@ -68,10 +68,10 @@ protected: private: uv_stream_t* Stream = nullptr; - void* OldStreamData; - const std::size_t PutBack; + void* OldStreamData = nullptr; + const std::size_t PutBack = 0; std::vector<CharT> InputBuffer; - bool EndOfFile; + bool EndOfFile = false; void StreamReadStartStop(); @@ -208,7 +208,7 @@ void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread) this->setg(this->eback(), this->gptr(), this->egptr() + nread / sizeof(CharT)); uv_read_stop(this->Stream); - } else if (nread < 0 || nread == UV_EOF) { + } else if (nread < 0 /*|| nread == UV_EOF*/) { this->EndOfFile = true; uv_read_stop(this->Stream); } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 121d12d..d19de21 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1733,6 +1733,11 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) return ret; } ret = this->Generate(); + if (ret) { + cmSystemTools::Message("CMake Generate step failed. " + "Build files cannot be regenerated correctly."); + return ret; + } std::string message = "Build files have been written to: "; message += this->GetHomeOutputDirectory(); this->UpdateProgress(message, -1); diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index e04bba2..a25f25a 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -15,11 +15,15 @@ set(CMakeLib_TESTS testXMLParser.cxx testXMLSafe.cxx testFindPackageCommand.cxx + testUVProcessChain.cxx testUVRAII.cxx testUVStreambuf.cxx ) +add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx) + set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) +set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>) set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>) if(WIN32) diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx new file mode 100644 index 0000000..72ae602 --- /dev/null +++ b/Tests/CMakeLib/testUVProcessChain.cxx @@ -0,0 +1,335 @@ +#include "cmUVProcessChain.h" + +#include "cmAlgorithms.h" +#include "cmGetPipes.h" +#include "cmUVHandlePtr.h" +#include "cmUVStreambuf.h" + +#include "cm_uv.h" + +#include <algorithm> +#include <functional> +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +#include <csignal> + +struct ExpectedStatus +{ + bool Finished; + bool MatchExitStatus; + bool MatchTermSignal; + cmUVProcessChain::Status Status; +}; + +static const std::vector<ExpectedStatus> status1 = { + { false, false, false, { 0, 0 } }, + { false, false, false, { 0, 0 } }, + { false, false, false, { 0, 0 } }, +}; + +static const std::vector<ExpectedStatus> status2 = { + { true, true, true, { 0, 0 } }, + { false, false, false, { 0, 0 } }, + { false, false, false, { 0, 0 } }, +}; + +static const std::vector<ExpectedStatus> status3 = { + { true, true, true, { 0, 0 } }, + { true, true, true, { 1, 0 } }, +#ifdef _WIN32 + { true, true, true, { 2, 0 } }, +#else + { true, false, true, { 0, SIGABRT } }, +#endif +}; + +bool operator==(const cmUVProcessChain::Status* actual, + const ExpectedStatus& expected) +{ + if (!expected.Finished) { + return !actual; + } else if (!actual) { + return false; + } + if (expected.MatchExitStatus && + expected.Status.ExitStatus != actual->ExitStatus) { + return false; + } + if (expected.MatchTermSignal && + expected.Status.TermSignal != actual->TermSignal) { + return false; + } + return true; +} + +bool resultsMatch(const std::vector<const cmUVProcessChain::Status*>& actual, + const std::vector<ExpectedStatus>& expected) +{ + return actual.size() == expected.size() && + std::equal(actual.begin(), actual.end(), expected.begin()); +} + +std::string getInput(std::istream& input) +{ + char buffer[1024]; + std::ostringstream str; + do { + input.read(buffer, 1024); + str.write(buffer, input.gcount()); + } while (input.gcount() > 0); + return str.str(); +} + +template <typename T> +std::function<std::ostream&(std::ostream&)> printExpected(bool match, + const T& value) +{ + return [match, value](std::ostream& stream) -> std::ostream& { + if (match) { + stream << value; + } else { + stream << "*"; + } + return stream; + }; +} + +std::ostream& operator<<( + std::ostream& stream, + const std::function<std::ostream&(std::ostream&)>& func) +{ + return func(stream); +} + +void printResults(const std::vector<const cmUVProcessChain::Status*>& actual, + const std::vector<ExpectedStatus>& expected) +{ + std::cout << "Expected: " << std::endl; + for (auto const& e : expected) { + if (e.Finished) { + std::cout << " ExitStatus: " + << printExpected(e.MatchExitStatus, e.Status.ExitStatus) + << ", TermSignal: " + << printExpected(e.MatchTermSignal, e.Status.TermSignal) + << std::endl; + } else { + std::cout << " null" << std::endl; + } + } + std::cout << "Actual:" << std::endl; + for (auto const& a : actual) { + if (a) { + std::cout << " ExitStatus: " << a->ExitStatus + << ", TermSignal: " << a->TermSignal << std::endl; + } else { + std::cout << " null" << std::endl; + } + } +} + +bool checkExecution(cmUVProcessChainBuilder& builder, + std::unique_ptr<cmUVProcessChain>& chain) +{ + std::vector<const cmUVProcessChain::Status*> status; + + chain = cm::make_unique<cmUVProcessChain>(builder.Start()); + if (!chain->Valid()) { + std::cout << "Valid() returned false, should be true" << std::endl; + return false; + } + status = chain->GetStatus(); + if (!resultsMatch(status, status1)) { + std::cout << "GetStatus() did not produce expected output" << std::endl; + printResults(status, status1); + return false; + } + + if (chain->Wait(6000)) { + std::cout << "Wait() returned true, should be false" << std::endl; + return false; + } + status = chain->GetStatus(); + if (!resultsMatch(status, status2)) { + std::cout << "GetStatus() did not produce expected output" << std::endl; + printResults(status, status2); + return false; + } + + if (!chain->Wait()) { + std::cout << "Wait() returned false, should be true" << std::endl; + return false; + } + status = chain->GetStatus(); + if (!resultsMatch(status, status3)) { + std::cout << "GetStatus() did not produce expected output" << std::endl; + printResults(status, status3); + return false; + } + + return true; +} + +bool checkOutput(std::istream& outputStream, std::istream& errorStream) +{ + std::string output = getInput(outputStream); + if (output != "HELO WRD!") { + std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\"" + << std::endl; + return false; + } + + std::string error = getInput(errorStream); + if (error.length() != 3 || error.find('1') == std::string::npos || + error.find('2') == std::string::npos || + error.find('3') == std::string::npos) { + std::cout << "Error was \"" << error << "\", expected \"123\"" + << std::endl; + return false; + } + + return true; +} + +bool testUVProcessChainBuiltin(const char* helperCommand) +{ + cmUVProcessChainBuilder builder; + std::unique_ptr<cmUVProcessChain> chain; + builder.AddCommand({ helperCommand, "echo" }) + .AddCommand({ helperCommand, "capitalize" }) + .AddCommand({ helperCommand, "dedup" }) + .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) + .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); + + if (!checkExecution(builder, chain)) { + return false; + } + + if (!chain->OutputStream()) { + std::cout << "OutputStream() was null, expecting not null" << std::endl; + return false; + } + if (!chain->ErrorStream()) { + std::cout << "ErrorStream() was null, expecting not null" << std::endl; + return false; + } + + if (!checkOutput(*chain->OutputStream(), *chain->ErrorStream())) { + return false; + } + + return true; +} + +bool testUVProcessChainExternal(const char* helperCommand) +{ + cmUVProcessChainBuilder builder; + std::unique_ptr<cmUVProcessChain> chain; + int outputPipe[2], errorPipe[2]; + cm::uv_pipe_ptr outputInPipe, outputOutPipe, errorInPipe, errorOutPipe; + + if (cmGetPipes(outputPipe) < 0) { + std::cout << "Error creating pipes" << std::endl; + return false; + } + if (cmGetPipes(errorPipe) < 0) { + std::cout << "Error creating pipes" << std::endl; + return false; + } + + builder.AddCommand({ helperCommand, "echo" }) + .AddCommand({ helperCommand, "capitalize" }) + .AddCommand({ helperCommand, "dedup" }) + .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, outputPipe[1]) + .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, errorPipe[1]); + + if (!checkExecution(builder, chain)) { + return false; + } + + if (chain->OutputStream()) { + std::cout << "OutputStream() was not null, expecting null" << std::endl; + return false; + } + if (chain->ErrorStream()) { + std::cout << "ErrorStream() was not null, expecting null" << std::endl; + return false; + } + + outputOutPipe.init(chain->GetLoop(), 0); + uv_pipe_open(outputOutPipe, outputPipe[1]); + outputOutPipe.reset(); + + errorOutPipe.init(chain->GetLoop(), 0); + uv_pipe_open(errorOutPipe, errorPipe[1]); + errorOutPipe.reset(); + + outputInPipe.init(chain->GetLoop(), 0); + uv_pipe_open(outputInPipe, outputPipe[0]); + cmUVStreambuf outputBuf; + outputBuf.open(outputInPipe); + std::istream outputStream(&outputBuf); + + errorInPipe.init(chain->GetLoop(), 0); + uv_pipe_open(errorInPipe, errorPipe[0]); + cmUVStreambuf errorBuf; + errorBuf.open(errorInPipe); + std::istream errorStream(&errorBuf); + + if (!checkOutput(outputStream, errorStream)) { + return false; + } + + return true; +} + +bool testUVProcessChainNone(const char* helperCommand) +{ + cmUVProcessChainBuilder builder; + std::unique_ptr<cmUVProcessChain> chain; + builder.AddCommand({ helperCommand, "echo" }) + .AddCommand({ helperCommand, "capitalize" }) + .AddCommand({ helperCommand, "dedup" }); + + if (!checkExecution(builder, chain)) { + return false; + } + + if (chain->OutputStream()) { + std::cout << "OutputStream() was not null, expecting null" << std::endl; + return false; + } + if (chain->ErrorStream()) { + std::cout << "ErrorStream() was not null, expecting null" << std::endl; + return false; + } + + return true; +} + +int testUVProcessChain(int argc, char** const argv) +{ + if (argc < 2) { + std::cout << "Invalid arguments.\n"; + return -1; + } + + if (!testUVProcessChainBuiltin(argv[1])) { + std::cout << "While executing testUVProcessChainBuiltin().\n"; + return -1; + } + + if (!testUVProcessChainExternal(argv[1])) { + std::cout << "While executing testUVProcessChainExternal().\n"; + return -1; + } + + if (!testUVProcessChainNone(argv[1])) { + std::cout << "While executing testUVProcessChainNone().\n"; + return -1; + } + + return 0; +} diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx new file mode 100644 index 0000000..263665d --- /dev/null +++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx @@ -0,0 +1,72 @@ +#include <chrono> +#include <iostream> +#include <set> +#include <sstream> +#include <string> +#include <thread> + +#include <cctype> +#include <cstdlib> + +std::string getStdin() +{ + char buffer[1024]; + std::ostringstream str; + do { + std::cin.read(buffer, 1024); + str.write(buffer, std::cin.gcount()); + } while (std::cin.gcount() > 0); + return str.str(); +} + +int main(int argc, char** argv) +{ + if (argc < 2) { + return -1; + } + + std::string command = argv[1]; + if (command == "echo") { + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + std::cout << "HELLO world!" << std::flush; + std::cerr << "1" << std::flush; + return 0; + } + if (command == "capitalize") { + std::this_thread::sleep_for(std::chrono::milliseconds(9000)); + std::string input = getStdin(); + for (auto& c : input) { + c = static_cast<char>(std::toupper(c)); + } + std::cout << input << std::flush; + std::cerr << "2" << std::flush; + return 1; + } + if (command == "dedup") { + // Use a nested scope to free all resources before aborting below. + { + std::string input = getStdin(); + std::set<char> seen; + std::string output; + for (auto c : input) { + if (!seen.count(c)) { + seen.insert(c); + output += c; + } + } + std::cout << output << std::flush; + std::cerr << "3" << std::flush; + } + + // On Windows, the exit code of abort() is different between debug and + // release builds, and does not yield a term_signal in libuv in either + // case. For the sake of simplicity, we just return another non-zero code. +#ifdef _WIN32 + return 2; +#else + std::abort(); +#endif + } + + return -1; +} diff --git a/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp index 7b3602c..953148d 100644 --- a/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp +++ b/Tests/CompileFeatures/cxx_relaxed_constexpr.cpp @@ -22,6 +22,7 @@ constexpr int g(const int (&is)[4]) int someFunc() { - constexpr int k3 = g({ 4, 5, 6, 7 }); + constexpr int values[4] = { 4, 5, 6, 7 }; + constexpr int k3 = g(values); return k3 - 42; } diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt index ddb3cae..87ac88e 100644 --- a/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt +++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-cmake-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at CMP0069-NEW-cmake\.cmake:[0-9]+ \(add_executable\): CMake doesn't support IPO for current compiler Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt index 8decfab..cb9d19b 100644 --- a/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt +++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-compiler-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at CMP0069-NEW-compiler\.cmake:[0-9]+ \(add_executable\): Compiler doesn't support IPO Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt index 0e05ee7..1159ec0 100644 --- a/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt +++ b/Tests/RunCMake/CMP0069/CMP0069-NEW-generator-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at CMP0069-NEW-generator\.cmake:[0-9]+ \(add_executable\): CMake doesn't support IPO for current generator Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt index 0e48ba4..86d3e04 100644 --- a/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadAND-stderr.txt @@ -50,4 +50,6 @@ CMake Error at BadAND.cmake:1 \(add_custom_target\): Parameters to \$<AND> must resolve to either '0' or '1'. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt index 964ea4d..42dd0ce 100644 --- a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt @@ -32,4 +32,6 @@ CMake Error at BadCONFIG.cmake:1 \(add_custom_target\): Expression syntax not recognized. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt index e5e628c..627327c 100644 --- a/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadNOT-stderr.txt @@ -49,4 +49,6 @@ CMake Error at BadNOT.cmake:1 \(add_custom_target\): \$<NOT> parameter must resolve to exactly one '0' or '1' value. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt index eb26328..56e6af0 100644 --- a/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadOR-stderr.txt @@ -50,4 +50,6 @@ CMake Error at BadOR.cmake:1 \(add_custom_target\): Parameters to \$<OR> must resolve to either '0' or '1'. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt index dd0d931..2f04c78 100644 --- a/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadStrEqual-stderr.txt @@ -35,4 +35,6 @@ CMake Error at BadStrEqual.cmake:1 \(add_custom_target\): \$<STREQUAL> expression requires 2 comma separated parameters, but got 3 instead. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt index 969393a..98eed1f 100644 --- a/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt +++ b/Tests/RunCMake/GeneratorExpression/BadTargetName-stderr.txt @@ -5,4 +5,6 @@ CMake Error at BadTargetName.cmake:1 \(add_custom_target\): \$<TARGET_NAME> expression requires literal input. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists.txt:3 \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt index 803058d..9afa461 100644 --- a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt +++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt @@ -1,2 +1,4 @@ ^CMake Error in CMakeLists.txt: - MSVC_RUNTIME_LIBRARY value 'BogusValue' not known for this C compiler.$ + MSVC_RUNTIME_LIBRARY value 'BogusValue' not known for this C compiler. ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt index 40d650e..208f3c9 100644 --- a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt +++ b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt @@ -2,4 +2,6 @@ The SOURCES of "A" use a generator expression that depends on the SOURCES themselves. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt index fec12ae..6da79b7 100644 --- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt @@ -47,4 +47,6 @@ \$<TARGET_PROPERTY:> \$<TARGET_PROPERTY:...> expression requires a non-empty property name. -*)+$ +*)+ ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt index 75865ad..d40b16b 100644 --- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt @@ -5,4 +5,6 @@ CMake Error at BadNonTarget.cmake:7 \(include_directories\): Target "NonExistent" not found. Call Stack \(most recent call first\): - CMakeLists\.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt index f0f71ec..fa26861 100644 --- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt @@ -34,4 +34,6 @@ \$<TARGET_PROPERTY:BadSelfReference6,COMPILE_DEFINITIONS> Self reference on target "BadSelfReference6". -*)+$ +*)+ ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt index 46a294d..69c61e6 100644 --- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceDefinitions-stderr.txt @@ -5,4 +5,6 @@ specified for source: - .*/Tests/RunCMake/XcodeProject/main.c$ + .*/Tests/RunCMake/XcodeProject/main.c ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt index 6500649..c3e9e31 100644 --- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceFlags-stderr.txt @@ -5,4 +5,6 @@ specified for source: - .*/Tests/RunCMake/XcodeProject/main.c$ + .*/Tests/RunCMake/XcodeProject/main.c ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt index f9b8ee7..ff70b95 100644 --- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceIncludeDirs-stderr.txt @@ -5,4 +5,6 @@ specified for source: - .*/Tests/RunCMake/XcodeProject/main.c$ + .*/Tests/RunCMake/XcodeProject/main.c ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt index bfca020..100008a 100644 --- a/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt +++ b/Tests/RunCMake/XcodeProject/PerConfigPerSourceOptions-stderr.txt @@ -5,4 +5,6 @@ specified for source: - .*/Tests/RunCMake/XcodeProject/main.c$ + .*/Tests/RunCMake/XcodeProject/main.c ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index 4918f7c..191f56d 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -256,4 +256,19 @@ if(XCODE_VERSION VERSION_GREATER_EQUAL 8) deployment_target_test(watchOS watchsimulator) endif() +if(XCODE_VERSION VERSION_GREATER_EQUAL 8) + function(xctest_lookup_test SystemName SDK) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XCTestLookup-${SDK}-build) + set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME=${SystemName}" "-DCMAKE_OSX_SYSROOT=${SDK}") + + run_cmake(XCTestLookup) + endfunction() + + xctest_lookup_test(Darwin macosx) + xctest_lookup_test(iOS iphoneos) + xctest_lookup_test(iOS iphonesimulator) + xctest_lookup_test(tvOS appletvos) + xctest_lookup_test(tvOS appletvsimulator) +endif() + # Please add macOS-only tests above before the device-specific tests. diff --git a/Tests/RunCMake/XcodeProject/XCTestLookup.cmake b/Tests/RunCMake/XcodeProject/XCTestLookup.cmake new file mode 100644 index 0000000..77676e5 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XCTestLookup.cmake @@ -0,0 +1,3 @@ +enable_language(C) + +find_package(XCTest REQUIRED) diff --git a/Tests/RunCMake/add_executable/NoSources-stderr.txt b/Tests/RunCMake/add_executable/NoSources-stderr.txt index 4fcfd49..abefc6d 100644 --- a/Tests/RunCMake/add_executable/NoSources-stderr.txt +++ b/Tests/RunCMake/add_executable/NoSources-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at NoSources.cmake:[0-9]+ \(add_executable\): No SOURCES given to target: TestExeWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt index 5561daa..80026bf 100644 --- a/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_executable/NoSourcesButLinkObjects-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at NoSourcesButLinkObjects.cmake:[0-9]+ \(add_executable\): No SOURCES given to target: TestExeWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt b/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt index 41da381..72b92ce 100644 --- a/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt +++ b/Tests/RunCMake/add_library/MODULEwithNoSources-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at MODULEwithNoSources.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestModuleLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt index 67dd87c..1490524 100644 --- a/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_library/MODULEwithNoSourcesButLinkObjects-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at MODULEwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestModuleLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt index 20d3a8a..be7634c 100644 --- a/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt +++ b/Tests/RunCMake/add_library/OBJECTwithNoSources-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at OBJECTwithNoSources.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestObjectLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt index 1bcc114..3f85916 100644 --- a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestObjectLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt b/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt index 5cedd62..471eda1 100644 --- a/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt +++ b/Tests/RunCMake/add_library/SHAREDwithNoSources-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at SHAREDwithNoSources.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestSharedLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt index d621e76..4bec7ae 100644 --- a/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_library/SHAREDwithNoSourcesButLinkObjects-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at SHAREDwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestSharedLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt b/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt index 10b2112..f655221 100644 --- a/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt +++ b/Tests/RunCMake/add_library/STATICwithNoSources-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at STATICwithNoSources.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestStaticLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt index 33c23b2..185aad8 100644 --- a/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_library/STATICwithNoSourcesButLinkObjects-stderr.txt @@ -1,4 +1,6 @@ ^CMake Error at STATICwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\): No SOURCES given to target: TestStaticLibWithoutSources Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists.txt:[0-9]+ \(include\) ++ +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index 2cdd767..ce4cfaf 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeDeveloperReference_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.12 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.14 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake index fa585d7..958ed25 100644 --- a/Utilities/Release/linux64_release.cmake +++ b/Utilities/Release/linux64_release.cmake @@ -44,6 +44,7 @@ CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=${qt_xcb_libs} set(ENV [[ export CMAKE_PREFIX_PATH=/opt/binutils-2.31 ]]) +set(SIGN "") # Exclude Qt5 tests because our Qt5 is static. set(EXTRA_CTEST_ARGS "-E Qt5") diff --git a/Utilities/Release/osx_release.cmake b/Utilities/Release/osx_release.cmake index be11d47..ac35872 100644 --- a/Utilities/Release/osx_release.cmake +++ b/Utilities/Release/osx_release.cmake @@ -29,5 +29,6 @@ CMake_TEST_NO_FindPackageModeMakefileTest:BOOL=TRUE set(ENV [[ export CMAKE_PREFIX_PATH='/Users/kitware/SDKs/qt-5.6.2-clang-x64' ]]) +set(SIGN "") get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) include(${path}/release_cmake.cmake) diff --git a/Utilities/Release/release_cmake.sh.in b/Utilities/Release/release_cmake.sh.in index f363b3d..696a3f4 100755 --- a/Utilities/Release/release_cmake.sh.in +++ b/Utilities/Release/release_cmake.sh.in @@ -150,7 +150,7 @@ for GEN in $generators; do check_exit_value $? "Create $GEN package" || exit 1 done - +@SIGN@ echo "End release" date diff --git a/Utilities/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake index 974c402..468e5f4 100644 --- a/Utilities/Release/win32_release.cmake +++ b/Utilities/Release/win32_release.cmake @@ -45,5 +45,9 @@ set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'") + set(SIGN "") +else() + string(APPEND INITIAL_CACHE "CMake_INSTALL_SIGNTOOL:STRING=signtool\n") + set(SIGN [[signtool sign -v -a -tr http://timestamp.digicert.com -fd sha256 -td sha256 -d "CMake Windows Installer" cmake-*.msi]]) endif() include(${path}/release_cmake.cmake) diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake index 20529f0..5a93ce6 100644 --- a/Utilities/Release/win64_release.cmake +++ b/Utilities/Release/win64_release.cmake @@ -45,5 +45,9 @@ set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'") + set(SIGN "") +else() + string(APPEND INITIAL_CACHE "CMake_INSTALL_SIGNTOOL:STRING=signtool\n") + set(SIGN [[signtool sign -v -a -tr http://timestamp.digicert.com -fd sha256 -td sha256 -d "CMake Windows Installer" cmake-*.msi]]) endif() include(${path}/release_cmake.cmake) diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 15204d6..c5b2bfe 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeHelp_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.12 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.14 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) @@ -329,6 +329,7 @@ CMAKE_CXX_SOURCES="\ cmGetCMakePropertyCommand \ cmGetDirectoryPropertyCommand \ cmGetFilenameComponentCommand \ + cmGetPipes \ cmGetPropertyCommand \ cmGetSourceFilePropertyCommand \ cmGetTargetPropertyCommand \ @@ -427,6 +428,7 @@ CMAKE_CXX_SOURCES="\ cmUnexpectedCommand \ cmUnsetCommand \ cmUVHandlePtr \ + cmUVProcessChain \ cmVersion \ cmWhileCommand \ cmWorkingDirectory \ |