diff options
79 files changed, 1488 insertions, 772 deletions
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index 1b0aa14..d4f644a 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -146,8 +146,10 @@ The options are: Specify the primary input source file to the command. This is treated just like any value given to the ``DEPENDS`` option but also suggests to Visual Studio generators where to hang - the custom command. At most one custom command may specify a - given source file as its main dependency. + the custom command. Each source file may have at most one command + specifying it as its main dependency. A compile command (i.e. for a + library or an executable) counts as an implicit main dependency which + gets silently overwritten by a custom command specification. ``OUTPUT`` Specify the output files the command is expected to produce. diff --git a/Help/command/install.rst b/Help/command/install.rst index f43b2a0..2506f98 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -38,7 +38,21 @@ signatures that specify them. The common options are: ``CONFIGURATIONS`` Specify a list of build configurations for which the install rule - applies (Debug, Release, etc.). + applies (Debug, Release, etc.). Note that the values specified for + this option only apply to options listed AFTER the ``CONFIGURATIONS`` + option. For example, to set separate install paths for the Debug and + Release configurations, do the following: + + .. code-block:: cmake + + install(TARGETS target + CONFIGURATIONS Debug + RUNTIME DESTINATION Debug/bin) + install(TARGETS target + CONFIGURATIONS Release + RUNTIME DESTINATION Release/bin) + + Note that ``CONFIGURATIONS`` appears BEFORE ``RUNTIME DESTINATION``. ``COMPONENT`` Specify an installation component name with which the install rule diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index dc5621a..0f6d4cf 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -97,21 +97,35 @@ Available logical expressions are: compile features and a list of supported compilers. ``$<COMPILE_LANGUAGE:lang>`` ``1`` when the language used for compilation unit matches ``lang``, - otherwise ``0``. This expression may be used to specify compile options for - source files of a particular language in a target. For example, to specify - the use of the ``-fno-exceptions`` compile option (compiler id checks - elided): + otherwise ``0``. This expression may be used to specify compile options, + compile definitions, and include directories for source files of a + particular language in a target. For example: .. code-block:: cmake - add_executable(myapp main.cpp foo.c bar.cpp) + add_executable(myapp main.cpp foo.c bar.cpp zot.cu) target_compile_options(myapp PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions> ) + target_compile_definitions(myapp + PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX> + $<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA> + ) + target_include_directories(myapp + PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers> + ) + + This specifies the use of the ``-fno-exceptions`` compile option, + ``COMPILING_CXX`` compile definition, and ``cxx_headers`` include + directory for C++ only (compiler id checks elided). It also specifies + a ``COMPILING_CUDA`` compile definition for CUDA. - Note that with :ref:`Visual Studio Generators` there is no way to represent + Note that with :ref:`Visual Studio Generators` and :generator:`Xcode` there + is no way to represent target-wide compile definitions or include directories + separately for ``C`` and ``CXX`` languages. + Also, with :ref:`Visual Studio Generators` there is no way to represent target-wide flags separately for ``C`` and ``CXX`` languages. Under these - generators, target-wide flags for both C and C++ sources will be evaluated + generators, expressions for both C and C++ sources will be evaluated using ``CXX`` if there are any C++ sources and otherwise using ``C``. A workaround is to create separate libraries for each source file language instead: @@ -124,20 +138,6 @@ Available logical expressions are: add_executable(myapp main.cpp) target_link_libraries(myapp myapp_c myapp_cxx) - The ``Makefile`` and ``Ninja`` based generators can also use this - expression to specify compile-language specific compile definitions - and include directories: - - .. code-block:: cmake - - add_executable(myapp main.cpp foo.c bar.cpp) - target_compile_definitions(myapp - PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX> - ) - target_include_directories(myapp - PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers> - ) - Informational Expressions ========================= diff --git a/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst b/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst index 690143f..fec6fda 100644 --- a/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst +++ b/Help/prop_gbl/DEBUG_CONFIGURATIONS.rst @@ -4,11 +4,10 @@ DEBUG_CONFIGURATIONS Specify which configurations are for debugging. The value must be a semi-colon separated list of configuration names. -Currently this property is used only by the target_link_libraries -command (see its documentation for details). Additional uses may be -defined in the future. +Currently this property is used only by the :command:`target_link_libraries` +command. Additional uses may be defined in the future. This property must be set at the top level of the project and before -the first target_link_libraries command invocation. If any entry in +the first :command:`target_link_libraries` command invocation. If any entry in the list does not match a valid configuration for the project the behavior is undefined. diff --git a/Help/release/dev/CheckIncludeFile-required-libs.rst b/Help/release/dev/CheckIncludeFile-required-libs.rst new file mode 100644 index 0000000..14c43d1 --- /dev/null +++ b/Help/release/dev/CheckIncludeFile-required-libs.rst @@ -0,0 +1,11 @@ +CheckIncludeFile-required-libs +------------------------------ + +* The :module:`CheckIncludeFile` module ``check_include_file`` macro + learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable. + +* The :module:`CheckIncludeFileCXX` module ``check_include_file_cxx`` macro + learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable. + +* The :module:`CheckIncludeFiles` module ``check_include_files`` macro + learned to honor the ``CMAKE_REQUIRED_LIBRARIES`` variable. diff --git a/Help/release/dev/extend-compile-language-genex.rst b/Help/release/dev/extend-compile-language-genex.rst index 0a0a669..7c09376 100644 --- a/Help/release/dev/extend-compile-language-genex.rst +++ b/Help/release/dev/extend-compile-language-genex.rst @@ -1,7 +1,14 @@ extend-compile-language-genex ----------------------------- -* The ``COMPILE_LANGUAGE`` :manual:`generator expression - <cmake-generator-expressions(7)>` may now be used with - :ref:`Visual Studio Generators` in :prop_tgt:`COMPILE_OPTIONS` - and :command:`file(GENERATE)`. +* :ref:`Visual Studio Generators` learned to support the ``COMPILE_LANGUAGE`` + :manual:`generator expression <cmake-generator-expressions(7)>` in + target-wide :prop_tgt:`COMPILE_DEFINITIONS`, + :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_OPTIONS`, and + :command:`file(GENERATE)`. + +* The :generator:`Xcode` generator learned to support the ``COMPILE_LANGUAGE`` + :manual:`generator expression <cmake-generator-expressions(7)>` in + target-wide :prop_tgt:`COMPILE_DEFINITIONS` and + :prop_tgt:`INCLUDE_DIRECTORIES`. It previously supported only + :prop_tgt:`COMPILE_OPTIONS` and :command:`file(GENERATE)`. diff --git a/Help/release/dev/iphone-deployment-target.rst b/Help/release/dev/iphone-deployment-target.rst index e586df6..7a20a6d 100644 --- a/Help/release/dev/iphone-deployment-target.rst +++ b/Help/release/dev/iphone-deployment-target.rst @@ -7,5 +7,5 @@ iphone-deployment-target set for the target platform selected by :variable:`CMAKE_OSX_SYSROOT`. If for example the sysroot variable specifies an iOS SDK then the - value in ``CMAKE_OSX_DEPLOYMENT_TARGET`` is interpreted as minium + value in ``CMAKE_OSX_DEPLOYMENT_TARGET`` is interpreted as minimum iOS version. diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake index e5554c4..501fc9a 100644 --- a/Modules/CheckIncludeFile.cmake +++ b/Modules/CheckIncludeFile.cmake @@ -27,6 +27,8 @@ # list of macros to define (-DFOO=bar) # ``CMAKE_REQUIRED_INCLUDES`` # list of include directories +# ``CMAKE_REQUIRED_LIBRARIES`` +# list of libraries to link # ``CMAKE_REQUIRED_QUIET`` # execute quietly without messages # @@ -59,6 +61,7 @@ macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE) ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.c COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS} "${CHECK_INCLUDE_FILE_C_INCLUDE_DIRS}" diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake index 7948bab..cdb25fb 100644 --- a/Modules/CheckIncludeFileCXX.cmake +++ b/Modules/CheckIncludeFileCXX.cmake @@ -27,6 +27,8 @@ # list of macros to define (-DFOO=bar) # ``CMAKE_REQUIRED_INCLUDES`` # list of include directories +# ``CMAKE_REQUIRED_LIBRARIES`` +# list of libraries to link # ``CMAKE_REQUIRED_QUIET`` # execute quietly without messages # @@ -58,6 +60,7 @@ macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE) ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS} "${CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS}" diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake index 59afdab..14db68c 100644 --- a/Modules/CheckIncludeFiles.cmake +++ b/Modules/CheckIncludeFiles.cmake @@ -33,6 +33,8 @@ # list of macros to define (-DFOO=bar) # ``CMAKE_REQUIRED_INCLUDES`` # list of include directories +# ``CMAKE_REQUIRED_LIBRARIES`` +# list of libraries to link # ``CMAKE_REQUIRED_QUIET`` # execute quietly without messages # @@ -102,6 +104,7 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE) ${CMAKE_BINARY_DIR} ${src} COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILES_FLAGS} "${CHECK_INCLUDE_FILES_INCLUDE_DIRS}" diff --git a/Modules/Compiler/MSVC-ASM.cmake b/Modules/Compiler/MSVC-ASM.cmake new file mode 100644 index 0000000..45978c5 --- /dev/null +++ b/Modules/Compiler/MSVC-ASM.cmake @@ -0,0 +1 @@ +# This file is loaded when Visual Studio is used for the ASM language. diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index a0fd90f..ca2a9c5 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -791,9 +791,8 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret) set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) endif() - if(NOT Boost_VERSION VERSION_LESS 106600) + if(NOT Boost_VERSION VERSION_LESS 106700) message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") - set(_Boost_IMPORTED_TARGETS FALSE) endif() endif() @@ -825,8 +824,8 @@ function(_Boost_COMPONENT_HEADERS component _hdrs) set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp") set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp") set(_Boost_COROUTINE_HEADERS "boost/coroutine/all.hpp") - set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp") set(_Boost_DATE_TIME_HEADERS "boost/date_time/date.hpp") + set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp") set(_Boost_FIBER_HEADERS "boost/fiber/all.hpp") set(_Boost_FILESYSTEM_HEADERS "boost/filesystem/path.hpp") set(_Boost_GRAPH_HEADERS "boost/graph/adjacency_list.hpp") @@ -925,8 +924,8 @@ endfunction() # `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`. # function(_Boost_COMPILER_FEATURES component _ret) - # Boost >= 1.62 and < 1.65 - if(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106500) + # Boost >= 1.62 and < 1.67 + if(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106700) set(_Boost_FIBER_COMPILER_FEATURES cxx_alias_templates cxx_auto_type @@ -1032,7 +1031,7 @@ else() # _Boost_COMPONENT_HEADERS. See the instructions at the top of # _Boost_COMPONENT_DEPENDENCIES. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} - "1.65.1" "1.65.0" "1.65" + "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" @@ -1379,8 +1378,11 @@ if(Boost_DEBUG) endif() #====================== -# Systematically build up the Boost ABI tag -# http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming +# Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts +# http://boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming +# http://boost.org/doc/libs/1_66_0/boost/config/auto_link.hpp +# http://boost.org/doc/libs/1_66_0/tools/build/src/tools/common.jam +# http://boost.org/doc/libs/1_66_0/boostcpp.jam set( _boost_RELEASE_ABI_TAG "-") set( _boost_DEBUG_ABI_TAG "-") # Key Use this library when: @@ -1412,11 +1414,40 @@ if(Boost_USE_STLPORT) string(APPEND _boost_DEBUG_ABI_TAG "p") endif() # n using the STLport deprecated "native iostreams" feature +# removed from the documentation in 1.43.0 but still present in +# boost/config/auto_link.hpp if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) string(APPEND _boost_RELEASE_ABI_TAG "n") string(APPEND _boost_DEBUG_ABI_TAG "n") endif() +# -x86 Architecture and address model tag +# First character is the architecture, then word-size, either 32 or 64 +# Only used in 'versioned' layout, added in Boost 1.66.0 +set(_boost_ARCHITECTURE_TAG "") +# {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers +if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION VERSION_LESS 106600) + string(APPEND _boost_ARCHITECTURE_TAG "-") + # This needs to be kept in-sync with the section of CMakePlatformId.h.in + # inside 'defined(_WIN32) && defined(_MSC_VER)' + if(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "IA64") + string(APPEND _boost_ARCHITECTURE_TAG "i") + elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "X86" + OR ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "x64") + string(APPEND _boost_ARCHITECTURE_TAG "x") + elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} MATCHES "^ARM") + string(APPEND _boost_ARCHITECTURE_TAG "a") + elseif(${CMAKE_CXX_COMPILER_ARCHITECTURE_ID} STREQUAL "MIPS") + string(APPEND _boost_ARCHITECTURE_TAG "m") + endif() + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + string(APPEND _boost_ARCHITECTURE_TAG "64") + else() + string(APPEND _boost_ARCHITECTURE_TAG "32") + endif() +endif() + if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") @@ -1464,6 +1495,7 @@ foreach(c DEBUG RELEASE) ${Boost_INCLUDE_DIR}/stage/lib ) _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}/..") + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}") if( Boost_NO_SYSTEM_PATHS ) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) else() @@ -1610,22 +1642,22 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS}) unset(_boost_RELEASE_NAMES) foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ) endforeach() list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endforeach() list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") @@ -1660,11 +1692,11 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS}) unset(_boost_DEBUG_NAMES) foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ) endforeach() list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) @@ -1672,11 +1704,11 @@ foreach(COMPONENT ${Boost_FIND_COMPONENTS}) set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") foreach(compiler IN LISTS _boost_COMPILER) list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endforeach() list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 321121c..0decbb5 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -104,7 +104,7 @@ # CUDA_NVCC_FLAGS_<CONFIG> variables. For Visual Studio targets, # the host compiler is constructed with one or more visual studio macros # such as $(VCInstallDir), that expands out to the path when -# the command is run from withing VS. +# the command is run from within VS. # # CUDA_NVCC_FLAGS # CUDA_NVCC_FLAGS_<CONFIG> diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake index db14a89..c5eabbb 100644 --- a/Modules/FindMPI.cmake +++ b/Modules/FindMPI.cmake @@ -744,13 +744,22 @@ function(_MPI_guess_settings LANG) endif() mark_as_advanced(MPI_${LANG}_LIB_NAMES) set(MPI_GUESS_FOUND TRUE) + + if(_MPIEXEC_NOT_GIVEN) + unset(MPIEXEC_EXECUTABLE CACHE) + endif() + + find_program(MPIEXEC_EXECUTABLE + NAMES mpiexec + HINTS $ENV{MSMPI_BIN} "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MPI;InstallRoot]/Bin" + DOC "Executable for running MPI programs.") endif() endif() # At this point there's not many MPIs that we could still consider. # OpenMPI 1.6.x and below supported Windows, but these ship compiler wrappers that still work. # The only other relevant MPI implementation without a wrapper is MPICH2, which had Windows support in 1.4.1p1 and older. - if(NOT MPI_GUESS_LIBRARY_NAME OR "${MPI_GUESS_LIBRARY_NAME}" STREQUAL "MPICH2") + if(NOT MPI_GUESS_FOUND AND (NOT MPI_GUESS_LIBRARY_NAME OR "${MPI_GUESS_LIBRARY_NAME}" STREQUAL "MPICH2")) set(MPI_MPICH_PREFIX_PATHS "$ENV{ProgramW6432}/MPICH2/lib" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH\\SMPD;binary]/../lib" @@ -809,6 +818,17 @@ function(_MPI_guess_settings LANG) unset(MPI_MPICH_ROOT_DIR) endif() set(MPI_GUESS_FOUND TRUE) + + if(_MPIEXEC_NOT_GIVEN) + unset(MPIEXEC_EXECUTABLE CACHE) + endif() + + find_program(MPIEXEC_EXECUTABLE + NAMES ${_MPIEXEC_NAMES} + HINTS "$ENV{ProgramW6432}/MPICH2/bin" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH\\SMPD;binary]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH2;Path]/bin" + DOC "Executable for running MPI programs.") endif() unset(MPI_MPICH_PREFIX_PATHS) endif() @@ -1034,9 +1054,6 @@ if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Linux") # SUSE Linux Enterprise Server stores its MPI implementations under /usr/lib64/mpi/gcc/<name> # We enumerate the subfolders and append each as a prefix MPI_search_mpi_prefix_folder("/usr/lib64/mpi/gcc") -elseif("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - # MSMPI stores its runtime in a special folder, this adds the possible locations to the hints. - list(APPEND MPI_HINT_DIRS $ENV{MSMPI_BIN} "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MPI;InstallRoot]") elseif("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "FreeBSD") # FreeBSD ships mpich under the normal system paths - but available openmpi implementations # will be found in /usr/local/mpi/<name> @@ -1046,6 +1063,15 @@ endif() # Most MPI distributions have some form of mpiexec or mpirun which gives us something we can look for. # The MPI standard does not mandate the existence of either, but instead only makes requirements if a distribution # ships an mpiexec program (mpirun executables are not regulated by the standard). + +# We defer searching for mpiexec binaries belonging to guesses until later. By doing so, mismatches between mpiexec +# and the MPI we found should be reduced. +if(NOT MPIEXEC_EXECUTABLE) + set(_MPIEXEC_NOT_GIVEN TRUE) +else() + set(_MPIEXEC_NOT_GIVEN FALSE) +endif() + find_program(MPIEXEC_EXECUTABLE NAMES ${_MPIEXEC_NAMES} PATH_SUFFIXES bin sbin @@ -1233,17 +1259,21 @@ foreach(LANG IN ITEMS C CXX Fortran) endif() endif() - if(NOT MPI_SKIP_GUESSING AND NOT MPI_${LANG}_WRAPPER_FOUND AND NOT MPI_PINNED_COMPILER) - # For C++, we may use the settings for C. Should a given compiler wrapper for C++ not exist, but one for C does, we copy over the - # settings for C. An MPI distribution that is in this situation would be IBM Platform MPI. - if("${LANG}" STREQUAL "CXX" AND MPI_C_WRAPPER_FOUND) - set(MPI_${LANG}_COMPILE_OPTIONS ${MPI_C_COMPILE_OPTIONS} CACHE STRING "MPI ${LANG} compilation options" ) - set(MPI_${LANG}_COMPILE_DEFINITIONS ${MPI_C_COMPILE_DEFINITIONS} CACHE STRING "MPI ${LANG} compilation definitions" ) - set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_C_INCLUDE_DIRS} CACHE STRING "MPI ${LANG} additional include directories") - set(MPI_${LANG}_LINK_FLAGS ${MPI_C_LINK_FLAGS} CACHE STRING "MPI ${LANG} linker flags" ) - set(MPI_${LANG}_LIB_NAMES ${MPI_C_LIB_NAMES} CACHE STRING "MPI ${LANG} libraries to link against" ) - else() - _MPI_guess_settings(${LANG}) + if(NOT MPI_PINNED_COMPILER AND NOT MPI_${LANG}_WRAPPER_FOUND) + # If MPI_PINNED_COMPILER wasn't given, and the MPI compiler we potentially found didn't work, we withdraw it. + set(MPI_${LANG}_COMPILER "MPI_${LANG}_COMPILER-NOTFOUND" CACHE FILEPATH "MPI compiler for ${LANG}" FORCE) + if(NOT MPI_SKIP_GUESSING) + # For C++, we may use the settings for C. Should a given compiler wrapper for C++ not exist, but one for C does, we copy over the + # settings for C. An MPI distribution that is in this situation would be IBM Platform MPI. + if("${LANG}" STREQUAL "CXX" AND MPI_C_WRAPPER_FOUND) + set(MPI_${LANG}_COMPILE_OPTIONS ${MPI_C_COMPILE_OPTIONS} CACHE STRING "MPI ${LANG} compilation options" ) + set(MPI_${LANG}_COMPILE_DEFINITIONS ${MPI_C_COMPILE_DEFINITIONS} CACHE STRING "MPI ${LANG} compilation definitions" ) + set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_C_INCLUDE_DIRS} CACHE STRING "MPI ${LANG} additional include directories") + set(MPI_${LANG}_LINK_FLAGS ${MPI_C_LINK_FLAGS} CACHE STRING "MPI ${LANG} linker flags" ) + set(MPI_${LANG}_LIB_NAMES ${MPI_C_LIB_NAMES} CACHE STRING "MPI ${LANG} libraries to link against" ) + else() + _MPI_guess_settings(${LANG}) + endif() endif() endif() endif() diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake index 7f08c4a..0abbb61 100644 --- a/Modules/Platform/AIX-GNU.cmake +++ b/Modules/Platform/AIX-GNU.cmake @@ -24,5 +24,7 @@ macro(__aix_compiler_gnu lang) set(CMAKE_${lang}_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH 1) set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath") - unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY) + if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 7 OR CMAKE_SYSTEM_VERSION VERSION_LESS 7.1) + unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY) + endif() endmacro() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 7031d5a..1b46377 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -327,6 +327,7 @@ set(SRCS cmSourceFile.h cmSourceFileLocation.cxx cmSourceFileLocation.h + cmSourceFileLocationKind.h cmSourceGroup.cxx cmSourceGroup.h cmState.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 0a1834f..8fa82c5 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 10) -set(CMake_VERSION_PATCH 20180110) +set(CMake_VERSION_PATCH 20180117) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index ae07feb..53c47a2 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -9,10 +9,14 @@ #include "cmSystemTools.h" #include "cmWorkingDirectory.h" +#include "cm_uv.h" + #include "cmsys/FStream.hxx" #include "cmsys/String.hxx" #include "cmsys/SystemInformation.hxx" + #include <algorithm> +#include <chrono> #include <iomanip> #include <list> #include <math.h> @@ -21,6 +25,43 @@ #include <stdlib.h> #include <utility> +#if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) && \ + UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19 +#define CMAKE_UV_SIGNAL_HACK +/* + libuv does not use SA_RESTART on its signal handler, but C++ streams + depend on it for reliable i/o operations. This RAII helper convinces + libuv to install its handler, and then revises the handler to add the + SA_RESTART flag. We use a distinct uv loop that never runs to avoid + ever really getting a callback. libuv may fill the hack loop's signal + pipe and then stop writing, but that won't break any real loops. + */ +class cmUVSignalHackRAII +{ + uv_loop_t HackLoop; + cm::uv_signal_ptr HackSignal; + static void HackCB(uv_signal_t*, int) {} +public: + cmUVSignalHackRAII() + { + uv_loop_init(&this->HackLoop); + this->HackSignal.init(this->HackLoop); + this->HackSignal.start(HackCB, SIGCHLD); + struct sigaction hack_sa; + sigaction(SIGCHLD, NULL, &hack_sa); + if (!(hack_sa.sa_flags & SA_RESTART)) { + hack_sa.sa_flags |= SA_RESTART; + sigaction(SIGCHLD, &hack_sa, NULL); + } + } + ~cmUVSignalHackRAII() + { + this->HackSignal.stop(); + uv_loop_close(&this->HackLoop); + } +}; +#endif + class TestComparator { public: @@ -95,24 +136,32 @@ void cmCTestMultiProcessHandler::RunTests() if (this->HasCycles) { return; } +#ifdef CMAKE_UV_SIGNAL_HACK + cmUVSignalHackRAII hackRAII; +#endif this->TestHandler->SetMaxIndex(this->FindMaxIndex()); + + uv_loop_init(&this->Loop); this->StartNextTests(); - while (!this->Tests.empty()) { - if (this->StopTimePassed) { - return; - } - this->CheckOutput(); - this->StartNextTests(); - } - // let all running tests finish - while (this->CheckOutput()) { - } + uv_run(&this->Loop, UV_RUN_DEFAULT); + uv_loop_close(&this->Loop); + this->MarkFinished(); this->UpdateCostData(); } -void cmCTestMultiProcessHandler::StartTestProcess(int test) +bool cmCTestMultiProcessHandler::StartTestProcess(int test) { + std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime(); + if (stop_time != std::chrono::system_clock::time_point() && + stop_time <= std::chrono::system_clock::now()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " + "Stopping all tests." + << std::endl); + this->StopTimePassed = true; + return false; + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -120,7 +169,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->EraseTest(test); this->RunningCount += GetProcessorsUsed(test); - cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler); + cmCTestRunTest* testRun = new cmCTestRunTest(*this); if (this->CTest->GetRepeatUntilFail()) { testRun->SetRunUntilFailOn(); testRun->SetNumberOfRuns(this->CTest->GetTestRepeat()); @@ -143,28 +192,11 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->LockResources(test); if (testRun->StartTest(this->Total)) { - this->RunningTests.insert(testRun); - } else if (testRun->IsStopTimePassed()) { - this->StopTimePassed = true; - delete testRun; - return; - } else { - - for (auto& j : this->Tests) { - j.second.erase(test); - } - - this->UnlockResources(test); - this->Completed++; - this->TestFinishMap[test] = true; - this->TestRunningMap[test] = false; - this->RunningCount -= GetProcessorsUsed(test); - testRun->EndTest(this->Completed, this->Total, false); - if (!this->Properties[test]->Disabled) { - this->Failed->push_back(this->Properties[test]->Name); - } - delete testRun; + return true; } + + this->FinishTestProcess(testRun, false); + return false; } void cmCTestMultiProcessHandler::LockResources(int index) @@ -222,8 +254,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test) // if there are no depends left then run this test if (this->Tests[test].empty()) { - this->StartTestProcess(test); - return true; + return this->StartTestProcess(test); } // This test was not able to start because it is waiting // on depends to run @@ -233,6 +264,11 @@ bool cmCTestMultiProcessHandler::StartTest(int test) void cmCTestMultiProcessHandler::StartNextTests() { size_t numToStart = 0; + + if (this->Tests.empty()) { + return; + } + if (this->RunningCount < this->ParallelLevel) { numToStart = this->ParallelLevel - this->RunningCount; } @@ -365,45 +401,42 @@ void cmCTestMultiProcessHandler::StartNextTests() } } -bool cmCTestMultiProcessHandler::CheckOutput() +void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, + bool started) { - // no more output we are done - if (this->RunningTests.empty()) { - return false; - } - std::vector<cmCTestRunTest*> finished; - std::string out, err; - for (cmCTestRunTest* p : this->RunningTests) { - if (!p->CheckOutput()) { - finished.push_back(p); - } - } - for (cmCTestRunTest* p : finished) { - this->Completed++; - int test = p->GetIndex(); + this->Completed++; + + int test = runner->GetIndex(); + auto properties = runner->GetTestProperties(); - bool testResult = p->EndTest(this->Completed, this->Total, true); - if (p->StartAgain()) { + bool testResult = runner->EndTest(this->Completed, this->Total, started); + if (started) { + if (runner->StartAgain()) { this->Completed--; // remove the completed test because run again - continue; - } - if (testResult) { - this->Passed->push_back(p->GetTestProperties()->Name); - } else { - this->Failed->push_back(p->GetTestProperties()->Name); - } - for (auto& t : this->Tests) { - t.second.erase(test); + return; } - this->TestFinishMap[test] = true; - this->TestRunningMap[test] = false; - this->RunningTests.erase(p); - this->WriteCheckpoint(test); - this->UnlockResources(test); - this->RunningCount -= GetProcessorsUsed(test); - delete p; } - return true; + + if (testResult) { + this->Passed->push_back(properties->Name); + } else if (!properties->Disabled) { + this->Failed->push_back(properties->Name); + } + + for (auto& t : this->Tests) { + t.second.erase(test); + } + + this->TestFinishMap[test] = true; + this->TestRunningMap[test] = false; + this->WriteCheckpoint(test); + this->UnlockResources(test); + this->RunningCount -= GetProcessorsUsed(test); + + delete runner; + if (started) { + this->StartNextTests(); + } } void cmCTestMultiProcessHandler::UpdateCostData() @@ -670,7 +703,7 @@ void cmCTestMultiProcessHandler::PrintTestList() cmWorkingDirectory workdir(p.Directory); - cmCTestRunTest testRun(this->TestHandler); + cmCTestRunTest testRun(*this); testRun.SetIndex(p.Index); testRun.SetTestProperties(&p); testRun.ComputeArguments(); // logs the command in verbose mode diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index dccc2c8..7837ff9 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -12,6 +12,8 @@ #include <string> #include <vector> +#include "cm_uv.h" + class cmCTest; class cmCTestRunTest; @@ -23,6 +25,7 @@ class cmCTestRunTest; class cmCTestMultiProcessHandler { friend class TestComparator; + friend class cmCTestRunTest; public: struct TestSet : public std::set<int> @@ -75,7 +78,7 @@ protected: // Start the next test or tests as many as are allowed by // ParallelLevel void StartNextTests(); - void StartTestProcess(int test); + bool StartTestProcess(int test); bool StartTest(int test); // Mark the checkpoint for the given test void WriteCheckpoint(int index); @@ -95,9 +98,8 @@ protected: // Removes the checkpoint file void MarkFinished(); void EraseTest(int index); - // Return true if there are still tests running - // check all running processes for output and exit case - bool CheckOutput(); + void FinishTestProcess(cmCTestRunTest* runner, bool started); + void RemoveTest(int index); // Check if we need to resume an interrupted test set void CheckResume(); @@ -130,7 +132,7 @@ protected: std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults; size_t ParallelLevel; // max number of process that can be run at once unsigned long TestLoad; - std::set<cmCTestRunTest*> RunningTests; // current running tests + uv_loop_t Loop; cmCTestTestHandler* TestHandler; cmCTest* CTest; bool HasCycles; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index dbdefae..baf894e 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -4,28 +4,27 @@ #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" -#include "cmCTestTestHandler.h" +#include "cmCTestMultiProcessHandler.h" #include "cmProcess.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" -#include "cm_curl.h" #include "cm_zlib.h" #include "cmsys/Base64.h" -#include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include <chrono> +#include <cmAlgorithms.h> #include <iomanip> +#include <ratio> #include <sstream> #include <stdio.h> -#include <time.h> #include <utility> -cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) +cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler) + : MultiTestHandler(multiHandler) { - this->CTest = handler->CTest; - this->TestHandler = handler; - this->TestProcess = nullptr; + this->CTest = multiHandler.CTest; + this->TestHandler = multiHandler.TestHandler; this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.ReturnValue = 0; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; @@ -34,60 +33,37 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->ProcessOutput.clear(); this->CompressedOutput.clear(); this->CompressionRatio = 2; - this->StopTimePassed = false; this->NumberOfRunsLeft = 1; // default to 1 run of the test this->RunUntilFail = false; // default to run the test once this->RunAgain = false; // default to not having to run again } -cmCTestRunTest::~cmCTestRunTest() +void cmCTestRunTest::CheckOutput(std::string const& line) { -} - -bool cmCTestRunTest::CheckOutput() -{ - // Read lines for up to 0.1 seconds of total time. - std::chrono::duration<double> timeout = std::chrono::milliseconds(100); - auto timeEnd = std::chrono::steady_clock::now() + timeout; - std::string line; - while ((timeout = timeEnd - std::chrono::steady_clock::now(), - timeout > std::chrono::seconds(0))) { - int p = this->TestProcess->GetNextOutputLine(line, timeout); - if (p == cmsysProcess_Pipe_None) { - // Process has terminated and all output read. - return false; - } - if (p == cmsysProcess_Pipe_STDOUT) { - // Store this line of output. - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " << line << std::endl); - this->ProcessOutput += line; - this->ProcessOutput += "\n"; - - // Check for TIMEOUT_AFTER_MATCH property. - if (!this->TestProperties->TimeoutRegularExpressions.empty()) { - for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { - if (reg.first.find(this->ProcessOutput.c_str())) { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() - << ": " - << "Test timeout changed to " - << std::chrono::duration_cast<std::chrono::seconds>( - this->TestProperties->AlternateTimeout) - .count() - << std::endl); - this->TestProcess->ResetStartTime(); - this->TestProcess->ChangeTimeout( - this->TestProperties->AlternateTimeout); - this->TestProperties->TimeoutRegularExpressions.clear(); - break; - } - } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " << line << std::endl); + this->ProcessOutput += line; + this->ProcessOutput += "\n"; + + // Check for TIMEOUT_AFTER_MATCH property. + if (!this->TestProperties->TimeoutRegularExpressions.empty()) { + for (auto& reg : this->TestProperties->TimeoutRegularExpressions) { + if (reg.first.find(this->ProcessOutput.c_str())) { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() + << ": " + << "Test timeout changed to " + << std::chrono::duration_cast<std::chrono::seconds>( + this->TestProperties->AlternateTimeout) + .count() + << std::endl); + this->TestProcess->ResetStartTime(); + this->TestProcess->ChangeTimeout( + this->TestProperties->AlternateTimeout); + this->TestProperties->TimeoutRegularExpressions.clear(); + break; } - } else { // if(p == cmsysProcess_Pipe_Timeout) - break; } } - return true; } // Streamed compression of test output. The compressed data @@ -160,8 +136,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) this->WriteLogOutputTop(completed, total); std::string reason; bool passed = true; - int res = - started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error; + cmProcess::State res = + started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error; int retVal = this->TestProcess->GetExitValue(); bool forceFail = false; bool skipped = false; @@ -200,7 +176,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } } - if (res == cmsysProcess_State_Exited) { + if (res == cmProcess::State::Exited) { bool success = !forceFail && (retVal == 0 || !this->TestProperties->RequiredRegularExpressions.empty()); @@ -221,29 +197,29 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason); outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; } - } else if (res == cmsysProcess_State_Expired) { + } else if (res == cmProcess::State::Expired) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout "); this->TestResult.Status = cmCTestTestHandler::TIMEOUT; outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; - } else if (res == cmsysProcess_State_Exception) { + } else if (res == cmProcess::State::Exception) { outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: "); this->TestResult.ExceptionStatus = this->TestProcess->GetExitExceptionString(); switch (this->TestProcess->GetExitException()) { - case cmsysProcess_Exception_Fault: + case cmProcess::Exception::Fault: cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault"); this->TestResult.Status = cmCTestTestHandler::SEGFAULT; break; - case cmsysProcess_Exception_Illegal: + case cmProcess::Exception::Illegal: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); this->TestResult.Status = cmCTestTestHandler::ILLEGAL; break; - case cmsysProcess_Exception_Interrupt: + case cmProcess::Exception::Interrupt: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); this->TestResult.Status = cmCTestTestHandler::INTERRUPT; break; - case cmsysProcess_Exception_Numerical: + case cmProcess::Exception::Numerical: cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); this->TestResult.Status = cmCTestTestHandler::NUMERICAL; break; @@ -254,7 +230,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } } else if ("Disabled" == this->TestResult.CompletionStatus) { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run (Disabled) "); - } else // cmsysProcess_State_Error + } else // cmProcess::State::Error { cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run "); } @@ -350,7 +326,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) if (!this->NeedsToRerun()) { this->TestHandler->TestResults.push_back(this->TestResult); } - delete this->TestProcess; + this->TestProcess.reset(); return passed || skipped; } @@ -432,7 +408,7 @@ bool cmCTestRunTest::StartTest(size_t total) this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestResult.Output = "Disabled"; this->TestResult.FullCommandLine.clear(); return false; @@ -453,7 +429,7 @@ bool cmCTestRunTest::StartTest(size_t total) // its arguments are irrelevant. This matters for the case where a fixture // dependency might be creating the executable we want to run. if (!this->FailedDependencies.empty()) { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg = "Failed test dependencies:"; for (std::string const& failedDep : this->FailedDependencies) { msg += " " + failedDep; @@ -470,7 +446,7 @@ bool cmCTestRunTest::StartTest(size_t total) this->ComputeArguments(); std::vector<std::string>& args = this->TestProperties->Args; if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg; if (this->CTest->GetConfigType().empty()) { msg = "Test not available without configuration."; @@ -493,7 +469,7 @@ bool cmCTestRunTest::StartTest(size_t total) for (std::string const& file : this->TestProperties->RequiredFiles) { if (!cmSystemTools::FileExists(file.c_str())) { // Required file was not found - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find required file: " << file << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -509,7 +485,7 @@ bool cmCTestRunTest::StartTest(size_t total) if (this->ActualCommand.empty()) { // if the command was not found create a TestResult object // that has that information - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find executable: " << args[1] << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -522,11 +498,22 @@ bool cmCTestRunTest::StartTest(size_t total) } this->StartTime = this->CTest->CurrentTime(); - auto timeout = this->ResolveTimeout(); + auto timeout = this->TestProperties->Timeout; - if (this->StopTimePassed) { - return false; + std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime(); + if (stop_time != std::chrono::system_clock::time_point()) { + std::chrono::duration<double> stop_timeout = + (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24); + + if (stop_timeout <= std::chrono::duration<double>::zero()) { + stop_timeout = std::chrono::duration<double>::zero(); + } + if (timeout == std::chrono::duration<double>::zero() || + stop_timeout < timeout) { + timeout = stop_timeout; + } } + return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, &this->TestProperties->Environment); } @@ -603,72 +590,11 @@ void cmCTestRunTest::DartProcessing() } } -std::chrono::duration<double> cmCTestRunTest::ResolveTimeout() -{ - auto timeout = this->TestProperties->Timeout; - - if (this->CTest->GetStopTime().empty()) { - return timeout; - } - struct tm* lctime; - time_t current_time = time(nullptr); - lctime = gmtime(¤t_time); - int gm_hour = lctime->tm_hour; - time_t gm_time = mktime(lctime); - lctime = localtime(¤t_time); - int local_hour = lctime->tm_hour; - - int tzone_offset = local_hour - gm_hour; - if (gm_time > current_time && gm_hour < local_hour) { - // this means gm_time is on the next day - tzone_offset -= 24; - } else if (gm_time < current_time && gm_hour > local_hour) { - // this means gm_time is on the previous day - tzone_offset += 24; - } - - tzone_offset *= 100; - char buf[1024]; - // add todays year day and month to the time in str because - // curl_getdate no longer assumes the day is today - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, - this->CTest->GetStopTime().c_str(), tzone_offset); - - time_t stop_time_t = curl_getdate(buf, ¤t_time); - if (stop_time_t == -1) { - return timeout; - } - - auto stop_time = std::chrono::system_clock::from_time_t(stop_time_t); - - // the stop time refers to the next day - if (this->CTest->NextDayStopTime) { - stop_time += std::chrono::hours(24); - } - auto stop_timeout = - (stop_time - std::chrono::system_clock::from_time_t(current_time)) % - std::chrono::hours(24); - this->CTest->LastStopTimeout = stop_timeout; - - if (stop_timeout <= std::chrono::duration<double>::zero() || - stop_timeout > this->CTest->LastStopTimeout) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. " - "Stopping all tests." - << std::endl); - this->StopTimePassed = true; - return std::chrono::duration<double>::zero(); - } - return timeout == std::chrono::duration<double>::zero() - ? stop_timeout - : (timeout < stop_timeout ? timeout : stop_timeout); -} - bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut, bool explicitTimeout, std::vector<std::string>* environment) { - this->TestProcess = new cmProcess; + this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory( this->TestProperties->Directory.c_str()); @@ -720,7 +646,7 @@ bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) @@ -794,3 +720,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name << " ... "); } + +void cmCTestRunTest::FinalizeTest() +{ + this->MultiTestHandler.FinishTestProcess(this, true); +} diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index cd380ca..fbc202f 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -12,9 +12,10 @@ #include <vector> #include "cmCTestTestHandler.h" +#include "cmProcess.h" // IWYU pragma: keep (for unique_ptr) class cmCTest; -class cmProcess; +class cmCTestMultiProcessHandler; /** \class cmRunTest * \brief represents a single test to be run @@ -24,8 +25,9 @@ class cmProcess; class cmCTestRunTest { public: - cmCTestRunTest(cmCTestTestHandler* handler); - ~cmCTestRunTest(); + explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler); + + ~cmCTestRunTest() = default; void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; } void SetRunUntilFailOn() { this->RunUntilFail = true; } @@ -50,15 +52,13 @@ public: std::string GetProcessOutput() { return this->ProcessOutput; } - bool IsStopTimePassed() { return this->StopTimePassed; } - cmCTestTestHandler::cmCTestTestResult GetTestResults() { return this->TestResult; } // Read and store output. Returns true if it must be called again. - bool CheckOutput(); + void CheckOutput(std::string const& line); // Compresses the output, writing to CompressedOutput void CompressOutput(); @@ -74,12 +74,14 @@ public: bool StartAgain(); + cmCTest* GetCTest() const { return this->CTest; } + + void FinalizeTest(); + private: bool NeedsToRerun(); void DartProcessing(); void ExeNotFound(std::string exe); - // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT) - std::chrono::duration<double> ResolveTimeout(); bool ForkProcess(std::chrono::duration<double> testTimeOut, bool explicitTimeout, std::vector<std::string>* environment); @@ -91,26 +93,18 @@ private: // Pointer back to the "parent"; the handler that invoked this test run cmCTestTestHandler* TestHandler; cmCTest* CTest; - cmProcess* TestProcess; - // If the executable to run is ctest, don't create a new process; - // just instantiate a new cmTest. (Can be disabled for a single test - // if this option is set to false.) - // bool OptimizeForCTest; - - bool UsePrefixCommand; - std::string PrefixCommand; - + std::unique_ptr<cmProcess> TestProcess; std::string ProcessOutput; std::string CompressedOutput; double CompressionRatio; // The test results cmCTestTestHandler::cmCTestTestResult TestResult; + cmCTestMultiProcessHandler& MultiTestHandler; int Index; std::set<std::string> FailedDependencies; std::string StartTime; std::string ActualCommand; std::vector<std::string> Arguments; - bool StopTimePassed; bool RunUntilFail; int NumberOfRunsLeft; bool RunAgain; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 0db66c3..c8806a7 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -2,12 +2,65 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmProcess.h" +#include "cmCTest.h" +#include "cmCTestRunTest.h" +#include "cmCTestTestHandler.h" #include "cmProcessOutput.h" +#include "cmsys/Process.h" + +#include <algorithm> +#include <fcntl.h> #include <iostream> +#include <signal.h> +#include <stdint.h> +#include <string> +#if !defined(_WIN32) +#include <unistd.h> +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include <io.h> + +static int cmProcessGetPipes(int* fds) +{ + SECURITY_ATTRIBUTES attr; + HANDLE readh, writeh; + attr.nLength = sizeof(attr); + attr.lpSecurityDescriptor = nullptr; + attr.bInheritHandle = FALSE; + if (!CreatePipe(&readh, &writeh, &attr, 0)) + return uv_translate_sys_error(GetLastError()); + fds[0] = _open_osfhandle((intptr_t)readh, 0); + fds[1] = _open_osfhandle((intptr_t)writeh, 0); + if (fds[0] == -1 || fds[1] == -1) { + CloseHandle(readh); + CloseHandle(writeh); + return uv_translate_sys_error(GetLastError()); + } + return 0; +} +#else +#include <errno.h> -cmProcess::cmProcess() +static int cmProcessGetPipes(int* fds) +{ + if (pipe(fds) == -1) { + return uv_translate_sys_error(errno); + } + + if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) { + close(fds[0]); + close(fds[1]); + return uv_translate_sys_error(errno); + } + return 0; +} +#endif + +cmProcess::cmProcess(cmCTestRunTest& runner) + : Runner(runner) { - this->Process = nullptr; this->Timeout = std::chrono::duration<double>::zero(); this->TotalTime = std::chrono::duration<double>::zero(); this->ExitValue = 0; @@ -17,8 +70,8 @@ cmProcess::cmProcess() cmProcess::~cmProcess() { - cmsysProcess_Delete(this->Process); } + void cmProcess::SetCommand(const char* command) { this->Command = command; @@ -29,8 +82,9 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess() +bool cmProcess::StartProcess(uv_loop_t& loop) { + this->ProcessState = cmProcess::State::Error; if (this->Command.empty()) { return false; } @@ -43,17 +97,83 @@ bool cmProcess::StartProcess() this->ProcessArgs.push_back(arg.c_str()); } this->ProcessArgs.push_back(nullptr); // null terminate the list - this->Process = cmsysProcess_New(); - cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin()); - if (!this->WorkingDirectory.empty()) { - cmsysProcess_SetWorkingDirectory(this->Process, - this->WorkingDirectory.c_str()); + + cm::uv_timer_ptr timer; + int status = timer.init(loop, this); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error initializing timer: " << uv_strerror(status) + << std::endl); + return false; + } + + cm::uv_pipe_ptr pipe_writer; + cm::uv_pipe_ptr pipe_reader; + + pipe_writer.init(loop, 0); + pipe_reader.init(loop, 0, this); + + int fds[2] = { -1, -1 }; + status = cmProcessGetPipes(fds); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error initializing pipe: " << uv_strerror(status) + << std::endl); + return false; + } + + uv_pipe_open(pipe_reader, fds[0]); + uv_pipe_open(pipe_writer, fds[1]); + + uv_stdio_container_t stdio[3]; + stdio[0].flags = UV_IGNORE; + stdio[1].flags = UV_INHERIT_STREAM; + stdio[1].data.stream = pipe_writer; + stdio[2] = stdio[1]; + + uv_process_options_t options = uv_process_options_t(); + options.file = this->Command.data(); + options.args = const_cast<char**>(this->ProcessArgs.data()); + options.stdio_count = 3; // in, out and err + options.exit_cb = &cmProcess::OnExitCB; + options.stdio = stdio; + + status = + uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); + + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error starting read events: " << uv_strerror(status) + << std::endl); + return false; + } + + status = this->Process.spawn(loop, options, this); + if (status != 0) { + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, "Process not started\n " + << this->Command << "\n[" << uv_strerror(status) << "]\n"); + return false; + } + + this->PipeReader = std::move(pipe_reader); + this->Timer = std::move(timer); + + this->StartTimer(); + + this->ProcessState = cmProcess::State::Executing; + return true; +} + +void cmProcess::StartTimer() +{ + auto properties = this->Runner.GetTestProperties(); + auto msec = + std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout); + + if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) { + this->Timer.start(&cmProcess::OnTimeoutCB, + static_cast<uint64_t>(msec.count()), 0); } - cmsysProcess_SetTimeout(this->Process, this->Timeout.count()); - cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1); - cmsysProcess_Execute(this->Process); - return (cmsysProcess_GetState(this->Process) == - cmsysProcess_State_Executing); } bool cmProcess::Buffer::GetLine(std::string& line) @@ -100,51 +220,121 @@ bool cmProcess::Buffer::GetLast(std::string& line) return false; } -int cmProcess::GetNextOutputLine(std::string& line, - std::chrono::duration<double> timeout) +void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf) { - cmProcessOutput processOutput(cmProcessOutput::UTF8); - std::string strdata; - double waitTimeout = timeout.count(); - for (;;) { - // Look for lines already buffered. - if (this->Output.GetLine(line)) { - return cmsysProcess_Pipe_STDOUT; - } + auto self = static_cast<cmProcess*>(stream->data); + self->OnRead(nread, buf); +} - // Check for more data from the process. - char* data; - int length; - int p = - cmsysProcess_WaitForData(this->Process, &data, &length, &waitTimeout); - if (p == cmsysProcess_Pipe_Timeout) { - return cmsysProcess_Pipe_Timeout; - } - if (p == cmsysProcess_Pipe_STDOUT) { - processOutput.DecodeText(data, length, strdata); - this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); - } else { // p == cmsysProcess_Pipe_None - // The process will provide no more data. - break; +void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf) +{ + std::string line; + if (nread > 0) { + std::string strdata; + cmProcessOutput processOutput(cmProcessOutput::UTF8, + static_cast<unsigned int>(buf->len)); + processOutput.DecodeText(buf->base, static_cast<size_t>(nread), strdata); + this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); + + while (this->Output.GetLine(line)) { + this->Runner.CheckOutput(line); + line.clear(); } + + return; } - processOutput.DecodeText(std::string(), strdata); - if (!strdata.empty()) { - this->Output.insert(this->Output.end(), strdata.begin(), strdata.end()); + + // The process will provide no more data. + if (nread != UV_EOF) { + auto error = static_cast<int>(nread); + cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + "Error reading stream: " << uv_strerror(error) << std::endl); } // Look for partial last lines. if (this->Output.GetLast(line)) { - return cmsysProcess_Pipe_STDOUT; + this->Runner.CheckOutput(line); + } + + this->ReadHandleClosed = true; + if (this->ProcessHandleClosed) { + uv_timer_stop(this->Timer); + this->Runner.FinalizeTest(); + } +} + +void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf) +{ + auto self = static_cast<cmProcess*>(handle->data); + self->OnAllocate(suggested_size, buf); +} + +void cmProcess::OnAllocate(size_t suggested_size, uv_buf_t* buf) +{ + if (this->Buf.size() < suggested_size) { + this->Buf.resize(suggested_size); + } + + *buf = + uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size())); +} + +void cmProcess::OnTimeoutCB(uv_timer_t* timer) +{ + auto self = static_cast<cmProcess*>(timer->data); + self->OnTimeout(); +} + +void cmProcess::OnTimeout() +{ + if (this->ProcessState != cmProcess::State::Executing) { + return; + } + this->ProcessState = cmProcess::State::Expired; + bool const was_still_reading = !this->ReadHandleClosed; + if (!this->ReadHandleClosed) { + this->ReadHandleClosed = true; + this->PipeReader.reset(); + } + if (!this->ProcessHandleClosed) { + // Kill the child and let our on-exit handler finish the test. + cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid)); + } else if (was_still_reading) { + // Our on-exit handler already ran but did not finish the test + // because we were still reading output. We've just dropped + // our read handler, so we need to finish the test now. + this->Runner.FinalizeTest(); } +} - // No more data. Wait for process exit. - if (!cmsysProcess_WaitForExit(this->Process, &waitTimeout)) { - return cmsysProcess_Pipe_Timeout; +void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status, + int term_signal) +{ + auto self = static_cast<cmProcess*>(process->data); + self->OnExit(exit_status, term_signal); +} + +void cmProcess::OnExit(int64_t exit_status, int term_signal) +{ + if (this->ProcessState != cmProcess::State::Expired) { + if ( +#if defined(_WIN32) + ((DWORD)exit_status & 0xF0000000) == 0xC0000000 +#else + term_signal != 0 +#endif + ) { + this->ProcessState = cmProcess::State::Exception; + } else { + this->ProcessState = cmProcess::State::Exited; + } } // Record exit information. - this->ExitValue = cmsysProcess_GetExitValue(this->Process); + this->ExitValue = static_cast<int>(exit_status); + this->Signal = term_signal; this->TotalTime = std::chrono::steady_clock::now() - this->StartTime; // Because of a processor clock scew the runtime may become slightly // negative. If someone changed the system clock while the process was @@ -153,95 +343,373 @@ int cmProcess::GetNextOutputLine(std::string& line, if (this->TotalTime <= std::chrono::duration<double>::zero()) { this->TotalTime = std::chrono::duration<double>::zero(); } - // std::cerr << "Time to run: " << this->TotalTime << "\n"; - return cmsysProcess_Pipe_None; -} - -// return the process status -int cmProcess::GetProcessStatus() -{ - if (!this->Process) { - return cmsysProcess_State_Exited; - } - return cmsysProcess_GetState(this->Process); -} - -int cmProcess::ReportStatus() -{ - int result = 1; - switch (cmsysProcess_GetState(this->Process)) { - case cmsysProcess_State_Starting: { - std::cerr << "cmProcess: Never started " << this->Command - << " process.\n"; - } break; - case cmsysProcess_State_Error: { - std::cerr << "cmProcess: Error executing " << this->Command - << " process: " << cmsysProcess_GetErrorString(this->Process) - << "\n"; - } break; - case cmsysProcess_State_Exception: { - std::cerr << "cmProcess: " << this->Command - << " process exited with an exception: "; - switch (cmsysProcess_GetExitException(this->Process)) { - case cmsysProcess_Exception_None: { - std::cerr << "None"; - } break; - case cmsysProcess_Exception_Fault: { - std::cerr << "Segmentation fault"; - } break; - case cmsysProcess_Exception_Illegal: { - std::cerr << "Illegal instruction"; - } break; - case cmsysProcess_Exception_Interrupt: { - std::cerr << "Interrupted by user"; - } break; - case cmsysProcess_Exception_Numerical: { - std::cerr << "Numerical exception"; - } break; - case cmsysProcess_Exception_Other: { - std::cerr << "Unknown"; - } break; - } - std::cerr << "\n"; - } break; - case cmsysProcess_State_Executing: { - std::cerr << "cmProcess: Never terminated " << this->Command - << " process.\n"; - } break; - case cmsysProcess_State_Exited: { - result = cmsysProcess_GetExitValue(this->Process); - std::cerr << "cmProcess: " << this->Command - << " process exited with code " << result << "\n"; - } break; - case cmsysProcess_State_Expired: { - std::cerr << "cmProcess: killed " << this->Command - << " process due to timeout.\n"; - } break; - case cmsysProcess_State_Killed: { - std::cerr << "cmProcess: killed " << this->Command << " process.\n"; - } break; - } - return result; + + this->ProcessHandleClosed = true; + if (this->ReadHandleClosed) { + uv_timer_stop(this->Timer); + this->Runner.FinalizeTest(); + } +} + +cmProcess::State cmProcess::GetProcessStatus() +{ + return this->ProcessState; } void cmProcess::ChangeTimeout(std::chrono::duration<double> t) { this->Timeout = t; - cmsysProcess_SetTimeout(this->Process, this->Timeout.count()); + this->StartTimer(); } void cmProcess::ResetStartTime() { - cmsysProcess_ResetStartTime(this->Process); this->StartTime = std::chrono::steady_clock::now(); } -int cmProcess::GetExitException() +cmProcess::Exception cmProcess::GetExitException() { - return cmsysProcess_GetExitException(this->Process); + auto exception = Exception::None; +#if defined(_WIN32) && !defined(__CYGWIN__) + auto exit_code = (DWORD) this->ExitValue; + if ((exit_code & 0xF0000000) != 0xC0000000) { + return exception; + } + + if (exit_code) { + switch (exit_code) { + case STATUS_DATATYPE_MISALIGNMENT: + case STATUS_ACCESS_VIOLATION: + case STATUS_IN_PAGE_ERROR: + case STATUS_INVALID_HANDLE: + case STATUS_NONCONTINUABLE_EXCEPTION: + case STATUS_INVALID_DISPOSITION: + case STATUS_ARRAY_BOUNDS_EXCEEDED: + case STATUS_STACK_OVERFLOW: + exception = Exception::Fault; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + case STATUS_FLOAT_DIVIDE_BY_ZERO: + case STATUS_FLOAT_INEXACT_RESULT: + case STATUS_FLOAT_INVALID_OPERATION: + case STATUS_FLOAT_OVERFLOW: + case STATUS_FLOAT_STACK_CHECK: + case STATUS_FLOAT_UNDERFLOW: +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + case STATUS_INTEGER_OVERFLOW: + exception = Exception::Numerical; + break; + case STATUS_CONTROL_C_EXIT: + exception = Exception::Interrupt; + break; + case STATUS_ILLEGAL_INSTRUCTION: + case STATUS_PRIVILEGED_INSTRUCTION: + exception = Exception::Illegal; + break; + default: + exception = Exception::Other; + } + } +#else + if (this->Signal) { + switch (this->Signal) { + case SIGSEGV: + exception = Exception::Fault; + break; + case SIGFPE: + exception = Exception::Numerical; + break; + case SIGINT: + exception = Exception::Interrupt; + break; + case SIGILL: + exception = Exception::Illegal; + break; + default: + exception = Exception::Other; + } + } +#endif + return exception; } std::string cmProcess::GetExitExceptionString() { - return cmsysProcess_GetExceptionString(this->Process); + std::string exception_str; +#if defined(_WIN32) + switch (this->ExitValue) { + case STATUS_CONTROL_C_EXIT: + exception_str = "User interrupt"; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + exception_str = "Floating-point exception (denormal operand)"; + break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + exception_str = "Divide-by-zero"; + break; + case STATUS_FLOAT_INEXACT_RESULT: + exception_str = "Floating-point exception (inexact result)"; + break; + case STATUS_FLOAT_INVALID_OPERATION: + exception_str = "Invalid floating-point operation"; + break; + case STATUS_FLOAT_OVERFLOW: + exception_str = "Floating-point overflow"; + break; + case STATUS_FLOAT_STACK_CHECK: + exception_str = "Floating-point stack check failed"; + break; + case STATUS_FLOAT_UNDERFLOW: + exception_str = "Floating-point underflow"; + break; +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: + exception_str = "Floating-point exception (multiple faults)"; + break; +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: + exception_str = "Floating-point exception (multiple traps)"; + break; +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + exception_str = "Integer divide-by-zero"; + break; + case STATUS_INTEGER_OVERFLOW: + exception_str = "Integer overflow"; + break; + + case STATUS_DATATYPE_MISALIGNMENT: + exception_str = "Datatype misalignment"; + break; + case STATUS_ACCESS_VIOLATION: + exception_str = "Access violation"; + break; + case STATUS_IN_PAGE_ERROR: + exception_str = "In-page error"; + break; + case STATUS_INVALID_HANDLE: + exception_str = "Invalid handle"; + break; + case STATUS_NONCONTINUABLE_EXCEPTION: + exception_str = "Noncontinuable exception"; + break; + case STATUS_INVALID_DISPOSITION: + exception_str = "Invalid disposition"; + break; + case STATUS_ARRAY_BOUNDS_EXCEEDED: + exception_str = "Array bounds exceeded"; + break; + case STATUS_STACK_OVERFLOW: + exception_str = "Stack overflow"; + break; + + case STATUS_ILLEGAL_INSTRUCTION: + exception_str = "Illegal instruction"; + break; + case STATUS_PRIVILEGED_INSTRUCTION: + exception_str = "Privileged instruction"; + break; + case STATUS_NO_MEMORY: + default: + char buf[1024]; + _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue); + exception_str.assign(buf); + } +#else + switch (this->Signal) { +#ifdef SIGSEGV + case SIGSEGV: + exception_str = "Segmentation fault"; + break; +#endif +#ifdef SIGBUS +#if !defined(SIGSEGV) || SIGBUS != SIGSEGV + case SIGBUS: + exception_str = "Bus error"; + break; +#endif +#endif +#ifdef SIGFPE + case SIGFPE: + exception_str = "Floating-point exception"; + break; +#endif +#ifdef SIGILL + case SIGILL: + exception_str = "Illegal instruction"; + break; +#endif +#ifdef SIGINT + case SIGINT: + exception_str = "User interrupt"; + break; +#endif +#ifdef SIGABRT + case SIGABRT: + exception_str = "Child aborted"; + break; +#endif +#ifdef SIGKILL + case SIGKILL: + exception_str = "Child killed"; + break; +#endif +#ifdef SIGTERM + case SIGTERM: + exception_str = "Child terminated"; + break; +#endif +#ifdef SIGHUP + case SIGHUP: + exception_str = "SIGHUP"; + break; +#endif +#ifdef SIGQUIT + case SIGQUIT: + exception_str = "SIGQUIT"; + break; +#endif +#ifdef SIGTRAP + case SIGTRAP: + exception_str = "SIGTRAP"; + break; +#endif +#ifdef SIGIOT +#if !defined(SIGABRT) || SIGIOT != SIGABRT + case SIGIOT: + exception_str = "SIGIOT"; + break; +#endif +#endif +#ifdef SIGUSR1 + case SIGUSR1: + exception_str = "SIGUSR1"; + break; +#endif +#ifdef SIGUSR2 + case SIGUSR2: + exception_str = "SIGUSR2"; + break; +#endif +#ifdef SIGPIPE + case SIGPIPE: + exception_str = "SIGPIPE"; + break; +#endif +#ifdef SIGALRM + case SIGALRM: + exception_str = "SIGALRM"; + break; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: + exception_str = "SIGSTKFLT"; + break; +#endif +#ifdef SIGCHLD + case SIGCHLD: + exception_str = "SIGCHLD"; + break; +#elif defined(SIGCLD) + case SIGCLD: + exception_str = "SIGCLD"; + break; +#endif +#ifdef SIGCONT + case SIGCONT: + exception_str = "SIGCONT"; + break; +#endif +#ifdef SIGSTOP + case SIGSTOP: + exception_str = "SIGSTOP"; + break; +#endif +#ifdef SIGTSTP + case SIGTSTP: + exception_str = "SIGTSTP"; + break; +#endif +#ifdef SIGTTIN + case SIGTTIN: + exception_str = "SIGTTIN"; + break; +#endif +#ifdef SIGTTOU + case SIGTTOU: + exception_str = "SIGTTOU"; + break; +#endif +#ifdef SIGURG + case SIGURG: + exception_str = "SIGURG"; + break; +#endif +#ifdef SIGXCPU + case SIGXCPU: + exception_str = "SIGXCPU"; + break; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: + exception_str = "SIGXFSZ"; + break; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: + exception_str = "SIGVTALRM"; + break; +#endif +#ifdef SIGPROF + case SIGPROF: + exception_str = "SIGPROF"; + break; +#endif +#ifdef SIGWINCH + case SIGWINCH: + exception_str = "SIGWINCH"; + break; +#endif +#ifdef SIGPOLL + case SIGPOLL: + exception_str = "SIGPOLL"; + break; +#endif +#ifdef SIGIO +#if !defined(SIGPOLL) || SIGIO != SIGPOLL + case SIGIO: + exception_str = "SIGIO"; + break; +#endif +#endif +#ifdef SIGPWR + case SIGPWR: + exception_str = "SIGPWR"; + break; +#endif +#ifdef SIGSYS + case SIGSYS: + exception_str = "SIGSYS"; + break; +#endif +#ifdef SIGUNUSED +#if !defined(SIGSYS) || SIGUNUSED != SIGSYS + case SIGUNUSED: + exception_str = "SIGUNUSED"; + break; +#endif +#endif + default: + exception_str = "Signal "; + exception_str += std::to_string(this->Signal); + } +#endif + return exception_str; } diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index f3b0bd7..9250896 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -5,11 +5,17 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmsys/Process.h" +#include "cmUVHandlePtr.h" +#include "cm_uv.h" + #include <chrono> +#include <stddef.h> #include <string> +#include <sys/types.h> #include <vector> +class cmCTestRunTest; + /** \class cmProcess * \brief run a process with c++ * @@ -18,7 +24,7 @@ class cmProcess { public: - cmProcess(); + explicit cmProcess(cmCTestRunTest& runner); ~cmProcess(); const char* GetCommand() { return this->Command.c_str(); } void SetCommand(const char* command); @@ -28,33 +34,70 @@ public: void ChangeTimeout(std::chrono::duration<double> t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(); + bool StartProcess(uv_loop_t& loop); + + enum class State + { + Starting, + Error, + Exception, + Executing, + Exited, + Expired, + Killed, + Disowned + }; - // return the process status - int GetProcessStatus(); - // Report the status of the program - int ReportStatus(); + State GetProcessStatus(); int GetId() { return this->Id; } void SetId(int id) { this->Id = id; } int GetExitValue() { return this->ExitValue; } std::chrono::duration<double> GetTotalTime() { return this->TotalTime; } - int GetExitException(); + + enum class Exception + { + None, + Fault, + Illegal, + Interrupt, + Numerical, + Other + }; + + Exception GetExitException(); std::string GetExitExceptionString(); - /** - * Read one line of output but block for no more than timeout. - * Returns: - * cmsysProcess_Pipe_None = Process terminated and all output read - * cmsysProcess_Pipe_STDOUT = Line came from stdout or stderr - * cmsysProcess_Pipe_Timeout = Timeout expired while waiting - */ - int GetNextOutputLine(std::string& line, - std::chrono::duration<double> timeout); private: std::chrono::duration<double> Timeout; std::chrono::steady_clock::time_point StartTime; std::chrono::duration<double> TotalTime; - cmsysProcess* Process; + bool ReadHandleClosed = false; + bool ProcessHandleClosed = false; + + cm::uv_process_ptr Process; + cm::uv_pipe_ptr PipeReader; + cm::uv_timer_ptr Timer; + std::vector<char> Buf; + + cmCTestRunTest& Runner; + int Signal = 0; + cmProcess::State ProcessState = cmProcess::State::Starting; + + static void OnExitCB(uv_process_t* process, int64_t exit_status, + int term_signal); + static void OnTimeoutCB(uv_timer_t* timer); + static void OnReadCB(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf); + static void OnAllocateCB(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf); + + void OnExit(int64_t exit_status, int term_signal); + void OnTimeout(); + void OnRead(ssize_t nread, const uv_buf_t* buf); + void OnAllocate(size_t suggested_size, uv_buf_t* buf); + + void StartTimer(); + class Buffer : public std::vector<char> { // Half-open index range of partial line already scanned. diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt index 6023c83..c51b0dd 100644 --- a/Source/CursesDialog/CMakeLists.txt +++ b/Source/CursesDialog/CMakeLists.txt @@ -2,19 +2,19 @@ # file Copyright.txt or https://cmake.org/licensing for details. set( CURSES_SRCS - CursesDialog/cmCursesOptionsWidget - CursesDialog/cmCursesBoolWidget - CursesDialog/cmCursesCacheEntryComposite - CursesDialog/cmCursesDummyWidget - CursesDialog/cmCursesFilePathWidget - CursesDialog/cmCursesForm - CursesDialog/cmCursesLabelWidget - CursesDialog/cmCursesLongMessageForm - CursesDialog/cmCursesMainForm - CursesDialog/cmCursesPathWidget - CursesDialog/cmCursesStringWidget - CursesDialog/cmCursesWidget - CursesDialog/ccmake + CursesDialog/cmCursesOptionsWidget.cxx + CursesDialog/cmCursesBoolWidget.cxx + CursesDialog/cmCursesCacheEntryComposite.cxx + CursesDialog/cmCursesDummyWidget.cxx + CursesDialog/cmCursesFilePathWidget.cxx + CursesDialog/cmCursesForm.cxx + CursesDialog/cmCursesLabelWidget.cxx + CursesDialog/cmCursesLongMessageForm.cxx + CursesDialog/cmCursesMainForm.cxx + CursesDialog/cmCursesPathWidget.cxx + CursesDialog/cmCursesStringWidget.cxx + CursesDialog/cmCursesWidget.cxx + CursesDialog/ccmake.cxx ) include_directories(${CURSES_INCLUDE_PATH}) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 26e1dcb..fd7c5e8 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -279,11 +279,8 @@ cmCTest::cmCTest() this->InteractiveDebugMode = true; this->TimeOut = std::chrono::duration<double>::zero(); this->GlobalTimeout = std::chrono::duration<double>::zero(); - this->LastStopTimeout = std::chrono::hours(24); this->CompressXMLFiles = false; this->ScheduleType.clear(); - this->StopTime.clear(); - this->NextDayStopTime = false; this->OutputLogFile = nullptr; this->OutputLogFileLastTag = -1; this->SuppressUpdatingCTestConfiguration = false; @@ -2269,10 +2266,41 @@ void cmCTest::SetNotesFiles(const char* notes) this->NotesFiles = notes; } -void cmCTest::SetStopTime(std::string const& time) +void cmCTest::SetStopTime(std::string const& time_str) { - this->StopTime = time; - this->DetermineNextDayStop(); + + struct tm* lctime; + time_t current_time = time(nullptr); + lctime = gmtime(¤t_time); + int gm_hour = lctime->tm_hour; + time_t gm_time = mktime(lctime); + lctime = localtime(¤t_time); + int local_hour = lctime->tm_hour; + + int tzone_offset = local_hour - gm_hour; + if (gm_time > current_time && gm_hour < local_hour) { + // this means gm_time is on the next day + tzone_offset -= 24; + } else if (gm_time < current_time && gm_hour > local_hour) { + // this means gm_time is on the previous day + tzone_offset += 24; + } + + tzone_offset *= 100; + char buf[1024]; + sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, + lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), tzone_offset); + + time_t stop_time = curl_getdate(buf, ¤t_time); + if (stop_time == -1) { + this->StopTime = std::chrono::system_clock::time_point(); + return; + } + this->StopTime = std::chrono::system_clock::from_time_t(stop_time); + + if (stop_time < current_time) { + this->StopTime += std::chrono::hours(24); + } } int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) @@ -2430,38 +2458,6 @@ void cmCTest::EmptyCTestConfiguration() this->CTestConfiguration.clear(); } -void cmCTest::DetermineNextDayStop() -{ - struct tm* lctime; - time_t current_time = time(nullptr); - lctime = gmtime(¤t_time); - int gm_hour = lctime->tm_hour; - time_t gm_time = mktime(lctime); - lctime = localtime(¤t_time); - int local_hour = lctime->tm_hour; - - int tzone_offset = local_hour - gm_hour; - if (gm_time > current_time && gm_hour < local_hour) { - // this means gm_time is on the next day - tzone_offset -= 24; - } else if (gm_time < current_time && gm_hour > local_hour) { - // this means gm_time is on the previous day - tzone_offset += 24; - } - - tzone_offset *= 100; - char buf[1024]; - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, this->StopTime.c_str(), - tzone_offset); - - time_t stop_time = curl_getdate(buf, ¤t_time); - - if (stop_time < current_time) { - this->NextDayStopTime = true; - } -} - void cmCTest::SetCTestConfiguration(const char* name, const char* value, bool suppress) { diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 23d71cb..61487f1 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -226,7 +226,10 @@ public: bool ShouldCompressTestOutput(); bool CompressString(std::string& str); - std::string GetStopTime() { return this->StopTime; } + std::chrono::system_clock::time_point GetStopTime() + { + return this->StopTime; + } void SetStopTime(std::string const& time); /** Used for parallel ctest job scheduling */ @@ -464,8 +467,7 @@ private: bool RepeatUntilFail; std::string ConfigType; std::string ScheduleType; - std::string StopTime; - bool NextDayStopTime; + std::chrono::system_clock::time_point StopTime; bool Verbose; bool ExtraVerbose; bool ProduceXML; @@ -481,8 +483,6 @@ private: int GenerateNotesFile(const char* files); - void DetermineNextDayStop(); - // these are helper classes typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers; t_TestingHandlers TestingHandlers; @@ -512,8 +512,6 @@ private: std::chrono::duration<double> GlobalTimeout; - std::chrono::duration<double> LastStopTimeout; - int MaxTestNameWidth; int ParallelLevel; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 3d311d6..34ef45f 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -805,7 +805,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { if (context->Language.empty()) { reportError( @@ -827,33 +827,14 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode return std::string(); } std::string genName = gg->GetName(); - if (genName.find("Visual Studio") != std::string::npos) { - if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() || - dagChecker->EvaluatingIncludeDirectories())) { - reportError( - context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS " - "and file(GENERATE) with the Visual Studio generator."); - return std::string(); - } - } else if (genName.find("Xcode") != std::string::npos) { - if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() || - dagChecker->EvaluatingIncludeDirectories())) { - reportError( - context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS " - "and file(GENERATE) with the Xcode generator."); - return std::string(); - } - } else { - if (genName.find("Makefiles") == std::string::npos && - genName.find("Ninja") == std::string::npos && - genName.find("Watcom WMake") == std::string::npos) { - reportError( - context, content->GetOriginalExpression(), - "$<COMPILE_LANGUAGE:...> not supported for this generator."); - return std::string(); - } + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { + reportError(context, content->GetOriginalExpression(), + "$<COMPILE_LANGUAGE:...> not supported for this generator."); + return std::string(); } if (parameters.empty()) { return context->Language; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 338c2b4..bd51f60 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1703,6 +1703,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, gtgt->GetName().c_str()); return; } + std::string const& langForPreprocessor = llang; if (gtgt->IsIPOEnabled(llang, configName)) { const char* ltoValue = @@ -1723,7 +1724,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, this->AppendDefines(ppDefs, exportMacro); } std::vector<std::string> targetDefines; - gtgt->GetCompileDefinitions(targetDefines, configName, "C"); + if (!langForPreprocessor.empty()) { + gtgt->GetCompileDefinitions(targetDefines, configName, + langForPreprocessor); + } this->AppendDefines(ppDefs, targetDefines); buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList()); @@ -1996,8 +2000,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, const bool emitSystemIncludes = this->XcodeVersion >= 83; std::vector<std::string> includes; - this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt, "C", - configName); + if (!langForPreprocessor.empty()) { + this->CurrentLocalGenerator->GetIncludeDirectories( + includes, gtgt, langForPreprocessor, configName); + } std::set<std::string> emitted; emitted.insert("/System/Library/Frameworks"); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index eccd4d0..59c20a9 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -637,7 +637,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( configType = projectType; } std::string flags; - if (strcmp(configType, "10") != 0) { + std::string langForClCompile; + if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) { const std::string& linkLanguage = (this->FortranProject ? std::string("Fortran") : target->GetLinkerLanguage(configName)); @@ -647,10 +648,11 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetName().c_str()); return; } - if (linkLanguage == "C" || linkLanguage == "CXX" || - linkLanguage == "Fortran") { + langForClCompile = linkLanguage; + if (langForClCompile == "C" || langForClCompile == "CXX" || + langForClCompile == "Fortran") { std::string baseFlagVar = "CMAKE_"; - baseFlagVar += linkLanguage; + baseFlagVar += langForClCompile; baseFlagVar += "_FLAGS"; flags = this->Makefile->GetRequiredDefinition(baseFlagVar.c_str()); std::string flagVar = @@ -667,7 +669,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } // Add the target-specific flags. - this->AddCompileOptions(flags, target, linkLanguage, configName); + this->AddCompileOptions(flags, target, langForClCompile, configName); // Check IPO related warning/error. target->IsIPOEnabled(linkLanguage, configName); @@ -703,7 +705,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( targetOptions.Parse(defineFlags.c_str()); targetOptions.ParseFinish(); std::vector<std::string> targetDefines; - target->GetCompileDefinitions(targetDefines, configName, "CXX"); + if (!langForClCompile.empty()) { + target->GetCompileDefinitions(targetDefines, configName, langForClCompile); + } targetOptions.AddDefines(targetDefines); targetOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -792,10 +796,13 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( << "\\$(ConfigurationName)\"\n"; } fout << "\t\t\t\tAdditionalIncludeDirectories=\""; - std::vector<std::string> includes; - this->GetIncludeDirectories(includes, target, "C", configName); - std::vector<std::string>::iterator i = includes.begin(); - for (; i != includes.end(); ++i) { + std::vector<std::string> includes_cl; + if (!langForClCompile.empty()) { + this->GetIncludeDirectories(includes_cl, target, langForClCompile, + configName); + } + std::vector<std::string>::iterator i = includes_cl.begin(); + for (; i != includes_cl.end(); ++i) { // output the include path std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); fout << ipath << ";"; @@ -810,7 +817,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } fout << "\"\n"; targetOptions.OutputFlagMap(fout, "\t\t\t\t"); - targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX"); + targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", + langForClCompile); fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) { // Specify the compiler program database file if configured. @@ -829,9 +837,12 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( "\t\t\t\tName=\"MASM\"\n" "\t\t\t\tIncludePaths=\"" ; + std::vector<std::string> includes_masm; + this->GetIncludeDirectories(includes_masm, target, "ASM_MASM", + configName); /* clang-format on */ const char* sep = ""; - for (i = includes.begin(); i != includes.end(); ++i) { + for (i = includes_masm.begin(); i != includes_masm.end(); ++i) { std::string inc = *i; cmConvertToWindowsSlash(inc); fout << sep << this->EscapeForXML(inc); @@ -859,7 +870,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n" << "\t\t\t\tAdditionalIncludeDirectories=\""; - for (i = includes.begin(); i != includes.end(); ++i) { + std::vector<std::string> includes_rc; + this->GetIncludeDirectories(includes_rc, target, "RC", configName); + for (i = includes_rc.begin(); i != includes_rc.end(); ++i) { std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); fout << ipath << ";"; } @@ -873,7 +886,9 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } fout << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\"\n"; fout << "\t\t\t\tAdditionalIncludeDirectories=\""; - for (i = includes.begin(); i != includes.end(); ++i) { + std::vector<std::string> includes_midl; + this->GetIncludeDirectories(includes_midl, target, "MIDL", configName); + for (i = includes_midl.begin(); i != includes_midl.end(); ++i) { std::string ipath = this->ConvertToXMLOutputPath(i->c_str()); fout << ipath << ";"; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 1a728c2..eeeb54f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -855,7 +855,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( std::string outName = gg->GenerateRuleFile(outputs[0]); // Check if the rule file already exists. - file = this->GetSource(outName); + file = this->GetSource(outName, cmSourceFileLocationKind::Known); if (file && file->GetCustomCommand() && !replace) { // The rule file already exists. if (commandLines != file->GetCustomCommand()->GetCommandLines()) { @@ -868,19 +868,22 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( // Create a cmSourceFile for the rule file. if (!file) { - file = this->CreateSource(outName, true); + file = + this->CreateSource(outName, true, cmSourceFileLocationKind::Known); } file->SetProperty("__CMAKE_RULE", "1"); } // Always create the output sources and mark them generated. for (std::string const& o : outputs) { - if (cmSourceFile* out = this->GetOrCreateSource(o, true)) { + if (cmSourceFile* out = + this->GetOrCreateSource(o, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } for (std::string const& o : byproducts) { - if (cmSourceFile* out = this->GetOrCreateSource(o, true)) { + if (cmSourceFile* out = + this->GetOrCreateSource(o, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } @@ -1092,7 +1095,8 @@ cmTarget* cmMakefile::AddUtilityCommand( // Always create the byproduct sources and mark them generated. for (std::string const& byproduct : byproducts) { - if (cmSourceFile* out = this->GetOrCreateSource(byproduct, true)) { + if (cmSourceFile* out = this->GetOrCreateSource( + byproduct, true, cmSourceFileLocationKind::Known)) { out->SetProperty("GENERATED", "1"); } } @@ -3131,9 +3135,10 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) } } -cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const +cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, + cmSourceFileLocationKind kind) const { - cmSourceFileLocation sfl(this, sourceName); + cmSourceFileLocation sfl(this, sourceName, kind); auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); #if defined(_WIN32) || defined(__APPLE__) name = cmSystemTools::LowerCase(name); @@ -3150,9 +3155,10 @@ cmSourceFile* cmMakefile::GetSource(const std::string& sourceName) const } cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, - bool generated) + bool generated, + cmSourceFileLocationKind kind) { - cmSourceFile* sf = new cmSourceFile(this, sourceName); + cmSourceFile* sf = new cmSourceFile(this, sourceName, kind); if (generated) { sf->SetProperty("GENERATED", "1"); } @@ -3169,12 +3175,13 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, } cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName, - bool generated) + bool generated, + cmSourceFileLocationKind kind) { - if (cmSourceFile* esf = this->GetSource(sourceName)) { + if (cmSourceFile* esf = this->GetSource(sourceName, kind)) { return esf; } - return this->CreateSource(sourceName, generated); + return this->CreateSource(sourceName, generated, kind); } void cmMakefile::AddTargetObject(std::string const& tgtName, diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index c92424b..f06e2ff 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -20,6 +20,7 @@ #include "cmListFileCache.h" #include "cmNewLineStyle.h" #include "cmPolicies.h" +#include "cmSourceFileLocationKind.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmTarget.h" @@ -387,22 +388,26 @@ public: /** Get a cmSourceFile pointer for a given source name, if the name is * not found, then a null pointer is returned. */ - cmSourceFile* GetSource(const std::string& sourceName) const; + cmSourceFile* GetSource( + const std::string& sourceName, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous) const; /** Create the source file and return it. generated * indicates if it is a generated file, this is used in determining * how to create the source file instance e.g. name */ - cmSourceFile* CreateSource(const std::string& sourceName, - bool generated = false); + cmSourceFile* CreateSource( + const std::string& sourceName, bool generated = false, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); /** Get a cmSourceFile pointer for a given source name, if the name is * not found, then create the source file and return it. generated * indicates if it is a generated file, this is used in determining * how to create the source file instance e.g. name */ - cmSourceFile* GetOrCreateSource(const std::string& sourceName, - bool generated = false); + cmSourceFile* GetOrCreateSource( + const std::string& sourceName, bool generated = false, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); void AddTargetObject(std::string const& tgtName, std::string const& objFile); diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 14743de..de0ba4f 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -475,10 +475,16 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets() } // Read skip files from makefile sources if (this->MocEnabled || this->UicEnabled) { - const std::vector<cmSourceFile*>& allSources = makefile->GetSourceFiles(); - for (cmSourceFile* sf : allSources) { + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { // sf->GetExtension() is only valid after sf->GetFullPath() ... - std::string const& fPath = sf->GetFullPath(); + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } cmSystemTools::FileFormat const fileType = cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && @@ -1188,9 +1194,16 @@ void cmQtAutoGeneratorInitializer::SetupCustomTargetsUic() std::vector<std::vector<std::string>> uiFileOptions; { std::string const uiExt = "ui"; + std::string pathError; for (cmSourceFile* sf : makefile->GetSourceFiles()) { // sf->GetExtension() is only valid after sf->GetFullPath() ... - std::string const& fPath = sf->GetFullPath(); + // Since we're iterating over source files that might be not in the + // target we need to check for path errors (not existing files). + std::string const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } if (sf->GetExtension() == uiExt) { std::string const absFile = cmSystemTools::GetRealPath(fPath); // Check if the .ui file should be skipped diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index d5475d2..215f974 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -12,8 +12,9 @@ #include "cmSystemTools.h" #include "cmake.h" -cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name) - : Location(mf, name) +cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name, + cmSourceFileLocationKind kind) + : Location(mf, name, kind) { this->CustomCommand = nullptr; this->FindFullPathFailed = false; diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index da722ea..1516d98 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -7,6 +7,7 @@ #include "cmPropertyMap.h" #include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" #include <string> #include <vector> @@ -27,7 +28,9 @@ public: * Construct with the makefile storing the source and the initial * name referencing it. */ - cmSourceFile(cmMakefile* mf, const std::string& name); + cmSourceFile( + cmMakefile* mf, const std::string& name, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); ~cmSourceFile(); diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index 6add7b3..5558ef3 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -27,7 +27,8 @@ cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc) } cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf, - const std::string& name) + const std::string& name, + cmSourceFileLocationKind kind) : Makefile(mf) { this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str()); @@ -37,7 +38,12 @@ cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf, this->Directory = cmSystemTools::CollapseFullPath(this->Directory); } this->Name = cmSystemTools::GetFilenameName(name); - this->UpdateExtension(name); + if (kind == cmSourceFileLocationKind::Known) { + this->DirectoryUseSource(); + this->AmbiguousExtension = false; + } else { + this->UpdateExtension(name); + } } void cmSourceFileLocation::Update(cmSourceFileLocation const& loc) diff --git a/Source/cmSourceFileLocation.h b/Source/cmSourceFileLocation.h index a6819bd..f325e54 100644 --- a/Source/cmSourceFileLocation.h +++ b/Source/cmSourceFileLocation.h @@ -7,6 +7,8 @@ #include <string> +#include "cmSourceFileLocationKind.h" + class cmMakefile; /** \class cmSourceFileLocation @@ -26,7 +28,9 @@ public: * Construct for a source file created in a given cmMakefile * instance with an initial name. */ - cmSourceFileLocation(cmMakefile const* mf, const std::string& name); + cmSourceFileLocation( + cmMakefile const* mf, const std::string& name, + cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); cmSourceFileLocation(); cmSourceFileLocation(const cmSourceFileLocation& loc); diff --git a/Source/cmSourceFileLocationKind.h b/Source/cmSourceFileLocationKind.h new file mode 100644 index 0000000..dd4c6dd --- /dev/null +++ b/Source/cmSourceFileLocationKind.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmSourceFileLocationKind_h +#define cmSourceFileLocationKind_h + +enum class cmSourceFileLocationKind +{ + // The location is user-specified and may be ambiguous. + Ambiguous, + // The location is known to be at the given location; do not try to guess at + // extensions or absolute path. + Known +}; + +#endif diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index de23b08..1974be3 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -23,6 +23,7 @@ #include "cmProperty.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -606,7 +607,8 @@ public: cmSourceFile* cmTarget::AddSource(const std::string& src) { - cmSourceFileLocation sfl(this->Makefile, src); + cmSourceFileLocation sfl(this->Makefile, src, + cmSourceFileLocationKind::Known); if (std::find_if(this->Internal->SourceEntries.begin(), this->Internal->SourceEntries.end(), TargetPropertyEntryFinder(sfl)) == @@ -618,7 +620,8 @@ cmSourceFile* cmTarget::AddSource(const std::string& src) if (cmGeneratorExpression::Find(src) != std::string::npos) { return nullptr; } - return this->Makefile->GetOrCreateSource(src); + return this->Makefile->GetOrCreateSource(src, false, + cmSourceFileLocationKind::Known); } void cmTarget::AddLinkDirectory(const std::string& d) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index f997a11..6d81f95 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2319,6 +2319,18 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( } } +std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes( + std::string const& config, std::string const& lang) const +{ + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, + lang, config); + for (std::string& i : includes) { + this->ConvertToWindowsSlash(i); + } + return includes; +} + bool cmVisualStudio10TargetGenerator::ComputeClOptions() { for (std::string const& i : this->Configurations) { @@ -2379,6 +2391,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } } + this->LangForClCompile = langForClCompile; if (!langForClCompile.empty()) { std::string baseFlagVar = "CMAKE_"; baseFlagVar += langForClCompile; @@ -2422,8 +2435,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::vector<std::string> targetDefines; switch (this->ProjectType) { case vcxproj: - this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, - "CXX"); + if (!langForClCompile.empty()) { + this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, + langForClCompile); + } break; case csproj: this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, @@ -2487,7 +2502,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } void cmVisualStudio10TargetGenerator::WriteClOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { Options& clOptions = *(this->ClOptions[configName]); if (this->ProjectType == csproj) { @@ -2495,12 +2510,16 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } this->WriteString("<ClCompile>\n", 2); clOptions.PrependInheritedString("AdditionalOptions"); - clOptions.AppendFlag("AdditionalIncludeDirectories", includes); + if (!this->LangForClCompile.empty()) { + std::vector<std::string> const includes = + this->GetIncludes(configName, this->LangForClCompile); + clOptions.AppendFlag("AdditionalIncludeDirectories", includes); + } clOptions.AppendFlag("AdditionalIncludeDirectories", "%(AdditionalIncludeDirectories)"); clOptions.OutputFlagMap(*this->BuildFileStream, " "); clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", - "\n", "CXX"); + "\n", this->LangForClCompile); if (this->NsightTegra) { if (const char* processMax = @@ -2581,7 +2600,7 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions( } void cmVisualStudio10TargetGenerator::WriteRCOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools) { return; @@ -2591,6 +2610,8 @@ void cmVisualStudio10TargetGenerator::WriteRCOptions( Options& rcOptions = *(this->RcOptions[configName]); rcOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "RC"); + std::vector<std::string> const includes = + this->GetIncludes(configName, "RC"); rcOptions.AppendFlag("AdditionalIncludeDirectories", includes); rcOptions.AppendFlag("AdditionalIncludeDirectories", "%(AdditionalIncludeDirectories)"); @@ -2640,6 +2661,12 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( cudaOptions.Parse(defineFlags.c_str()); cudaOptions.ParseFinish(); + // If we haven't explicitly enabled GPU debug information + // explicitly disable it + if (!cudaOptions.HasFlag("GPUDebugInfo")) { + cudaOptions.AddFlag("GPUDebugInfo", "false"); + } + if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) { cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true"); } else if (this->GeneratorTarget->GetPropertyAsBool( @@ -2695,7 +2722,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( } void cmVisualStudio10TargetGenerator::WriteCudaOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools || !this->GlobalGenerator->IsCudaEnabled()) { return; @@ -2703,6 +2730,8 @@ void cmVisualStudio10TargetGenerator::WriteCudaOptions( this->WriteString("<CudaCompile>\n", 2); Options& cudaOptions = *(this->CudaOptions[configName]); + std::vector<std::string> const includes = + this->GetIncludes(configName, "CUDA"); cudaOptions.AppendFlag("Include", includes); cudaOptions.AppendFlag("Include", "%(Include)"); cudaOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", @@ -2817,7 +2846,7 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( } void cmVisualStudio10TargetGenerator::WriteMasmOptions( - std::string const& configName, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools || !this->GlobalGenerator->IsMasmEnabled()) { return; @@ -2830,6 +2859,8 @@ void cmVisualStudio10TargetGenerator::WriteMasmOptions( "\n", "ASM_MASM"); Options& masmOptions = *(this->MasmOptions[configName]); + std::vector<std::string> const includes = + this->GetIncludes(configName, "ASM_MASM"); masmOptions.AppendFlag("IncludePaths", includes); masmOptions.AppendFlag("IncludePaths", "%(IncludePaths)"); masmOptions.PrependInheritedString("AdditionalOptions"); @@ -2874,13 +2905,15 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( } void cmVisualStudio10TargetGenerator::WriteNasmOptions( - std::string const& configName, std::vector<std::string> includes) + std::string const& configName) { if (!this->GlobalGenerator->IsNasmEnabled()) { return; } this->WriteString("<NASM>\n", 2); + std::vector<std::string> includes = + this->GetIncludes(configName, "ASM_NASM"); Options& nasmOptions = *(this->NasmOptions[configName]); for (size_t i = 0; i < includes.size(); i++) { includes[i] += "\\"; @@ -3428,7 +3461,7 @@ void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair( } void cmVisualStudio10TargetGenerator::WriteMidlOptions( - std::string const& /*config*/, std::vector<std::string> const& includes) + std::string const& configName) { if (!this->MSTools) { return; @@ -3454,6 +3487,8 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( // on the CMake side? this->WriteString("<Midl>\n", 2); this->WriteString("<AdditionalIncludeDirectories>", 3); + std::vector<std::string> const includes = + this->GetIncludes(configName, "MIDL"); for (std::string const& i : includes) { *this->BuildFileStream << cmVS10EscapeXML(i) << ";"; } @@ -3478,25 +3513,19 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() return; } for (std::string const& i : this->Configurations) { - std::vector<std::string> includes; - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, "C", i); - for (std::string& ii : includes) { - this->ConvertToWindowsSlash(ii); - } this->WritePlatformConfigTag("ItemDefinitionGroup", i, 1); *this->BuildFileStream << "\n"; // output cl compile flags <ClCompile></ClCompile> if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) { - this->WriteClOptions(i, includes); + this->WriteClOptions(i); // output rc compile flags <ResourceCompile></ResourceCompile> - this->WriteRCOptions(i, includes); - this->WriteCudaOptions(i, includes); - this->WriteMasmOptions(i, includes); - this->WriteNasmOptions(i, includes); + this->WriteRCOptions(i); + this->WriteCudaOptions(i); + this->WriteMasmOptions(i); + this->WriteNasmOptions(i); } // output midl flags <Midl></Midl> - this->WriteMidlOptions(i, includes); + this->WriteMidlOptions(i); // write events if (this->ProjectType != csproj) { this->WriteEvents(i); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index fb24f1a..c346164 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -90,18 +90,18 @@ private: void WriteTargetSpecificReferences(); void WriteTargetsFileReferences(); + std::vector<std::string> GetIncludes(std::string const& config, + std::string const& lang) const; + bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); - void WriteClOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteClOptions(std::string const& config); bool ComputeRcOptions(); bool ComputeRcOptions(std::string const& config); - void WriteRCOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteRCOptions(std::string const& config); bool ComputeCudaOptions(); bool ComputeCudaOptions(std::string const& config); - void WriteCudaOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteCudaOptions(std::string const& config); bool ComputeCudaLinkOptions(); bool ComputeCudaLinkOptions(std::string const& config); @@ -109,20 +109,17 @@ private: bool ComputeMasmOptions(); bool ComputeMasmOptions(std::string const& config); - void WriteMasmOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteMasmOptions(std::string const& config); bool ComputeNasmOptions(); bool ComputeNasmOptions(std::string const& config); - void WriteNasmOptions(std::string const& config, - std::vector<std::string> includes); + void WriteNasmOptions(std::string const& config); bool ComputeLinkOptions(); bool ComputeLinkOptions(std::string const& config); bool ComputeLibOptions(); bool ComputeLibOptions(std::string const& config); void WriteLinkOptions(std::string const& config); - void WriteMidlOptions(std::string const& config, - std::vector<std::string> const& includes); + void WriteMidlOptions(std::string const& config); void WriteAntBuildOptions(std::string const& config); void OutputLinkIncremental(std::string const& configName); void WriteCustomRule(cmSourceFile const* source, @@ -180,6 +177,7 @@ private: OptionsMap MasmOptions; OptionsMap NasmOptions; OptionsMap LinkOptions; + std::string LangForClCompile; std::string PathToProjectFile; std::string ProjectFileExtension; enum VsProjectType diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 9a5986c..106bdff 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -239,20 +239,32 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // It translates to -arch=<virtual> -code=<real>. cmSystemTools::ReplaceString(arch_name, "sm_", "compute_"); } - for (std::vector<std::string>::iterator ci = codes.begin(); - ci != codes.end(); ++ci) { - std::string entry = arch_name + "," + *ci; + for (auto const& c : codes) { + std::string entry = arch_name + "," + c; result.push_back(entry); } } - // Now add entries for the -gencode=<arch>,<code> pairs. - for (std::vector<std::string>::iterator ei = gencode.begin(); - ei != gencode.end(); ++ei) { - std::string entry = *ei; + // Now add entries for the following signatures: + // -gencode=<arch>,<code> + // -gencode=<arch>,[<code1>,<code2>] + // -gencode=<arch>,"<code1>,<code2>" + for (auto const& e : gencode) { + std::string entry = e; cmSystemTools::ReplaceString(entry, "arch=", ""); cmSystemTools::ReplaceString(entry, "code=", ""); - result.push_back(entry); + cmSystemTools::ReplaceString(entry, "[", ""); + cmSystemTools::ReplaceString(entry, "]", ""); + cmSystemTools::ReplaceString(entry, "\"", ""); + + std::vector<std::string> codes = cmSystemTools::tokenize(entry, ","); + if (codes.size() >= 2) { + auto gencode_arch = cm::cbegin(codes); + for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) { + std::string code_entry = *gencode_arch + "," + *ci; + result.push_back(code_entry); + } + } } } diff --git a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt index f96283d..7dc7995 100644 --- a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt +++ b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt @@ -26,18 +26,18 @@ target_compile_definitions(consumer PRIVATE ) -if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja") - target_sources(consumer PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c" - ) - target_compile_definitions(consumer - PRIVATE - CONSUMER_LANG_$<COMPILE_LANGUAGE> - LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX> - LANG_IS_C=$<COMPILE_LANGUAGE:C> - ) +target_sources(consumer PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c" +) +target_compile_definitions(consumer + PRIVATE + CONSUMER_LANG_$<COMPILE_LANGUAGE> + LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX> + LANG_IS_C=$<COMPILE_LANGUAGE:C> +) +if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode") target_compile_definitions(consumer - PRIVATE -DTEST_LANG_DEFINES + PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE ) endif() diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.c b/Tests/CMakeCommands/target_compile_definitions/consumer.c index 7931a6f..e134a8b 100644 --- a/Tests/CMakeCommands/target_compile_definitions/consumer.c +++ b/Tests/CMakeCommands/target_compile_definitions/consumer.c @@ -1,5 +1,23 @@ -#ifdef TEST_LANG_DEFINES +// Visual Studio allows only one set of flags for C and C++. +// In a target using C++ we pick the C++ flags even for C sources. +#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE +#ifndef CONSUMER_LANG_CXX +#error Expected CONSUMER_LANG_CXX +#endif + +#ifdef CONSUMER_LANG_C +#error Unexpected CONSUMER_LANG_C +#endif + +#if !LANG_IS_CXX +#error Expected LANG_IS_CXX +#endif + +#if LANG_IS_C +#error Unexpected LANG_IS_C +#endif +#else #ifdef CONSUMER_LANG_CXX #error Unexpected CONSUMER_LANG_CXX #endif diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp index 0202c17..69ea151 100644 --- a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp +++ b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp @@ -15,7 +15,6 @@ #error Expected DASH_D_DEFINE #endif -#ifdef TEST_LANG_DEFINES #ifndef CONSUMER_LANG_CXX #error Expected CONSUMER_LANG_CXX #endif @@ -31,7 +30,6 @@ #if LANG_IS_C #error Unexpected LANG_IS_C #endif -#endif int main() { diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt index d57556a..8713d99 100644 --- a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt +++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt @@ -42,17 +42,17 @@ add_executable(consumer "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" ) -if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja") - target_sources(consumer PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c" - ) - target_include_directories(consumer - PRIVATE - $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only> - $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only> - ) +target_sources(consumer PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c" +) +target_include_directories(consumer + PRIVATE + $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only> + $<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}/c_only> +) +if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode") target_compile_definitions(consumer - PRIVATE -DTEST_LANG_DEFINES + PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE ) endif() diff --git a/Tests/CMakeCommands/target_include_directories/consumer.c b/Tests/CMakeCommands/target_include_directories/consumer.c index ae88f92..419c2d2 100644 --- a/Tests/CMakeCommands/target_include_directories/consumer.c +++ b/Tests/CMakeCommands/target_include_directories/consumer.c @@ -1,5 +1,13 @@ -#ifdef TEST_LANG_DEFINES +// Visual Studio allows only one set of flags for C and C++. +// In a target using C++ we pick the C++ flags even for C sources. +#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO_OR_XCODE +#include "cxx_only.h" + +#ifndef CXX_ONLY_DEFINE +#error Expected CXX_ONLY_DEFINE +#endif +#else #include "c_only.h" #ifndef C_ONLY_DEFINE diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp index 0f8153b..1e018ad 100644 --- a/Tests/CMakeCommands/target_include_directories/consumer.cpp +++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp @@ -1,12 +1,10 @@ #include "consumer.h" #include "common.h" +#include "cxx_only.h" #include "interfaceinclude.h" #include "publicinclude.h" #include "relative_dir.h" -#ifdef TEST_LANG_DEFINES -#include "cxx_only.h" -#endif #ifdef PRIVATEINCLUDE_DEFINE #error Unexpected PRIVATEINCLUDE_DEFINE @@ -32,11 +30,9 @@ #error Expected CONSUMER_DEFINE #endif -#ifdef TEST_LANG_DEFINES #ifndef CXX_ONLY_DEFINE #error Expected CXX_ONLY_DEFINE #endif -#endif int main() { diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 9f09185..06df53f 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -5,21 +5,21 @@ include_directories( ) set(CMakeLib_TESTS - testGeneratedFileStream - testRST - testSystemTools - testUTF8 - testXMLParser - testXMLSafe - testFindPackageCommand - testUVRAII + testGeneratedFileStream.cxx + testRST.cxx + testSystemTools.cxx + testUTF8.cxx + testXMLParser.cxx + testXMLSafe.cxx + testFindPackageCommand.cxx + testUVRAII.cxx ) set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) if(WIN32) list(APPEND CMakeLib_TESTS - testVisualStudioSlnParser + testVisualStudioSlnParser.cxx ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testVisualStudioSlnParser.h.in ${CMAKE_CURRENT_BINARY_DIR}/testVisualStudioSlnParser.h @ONLY) @@ -38,7 +38,8 @@ set_property(TARGET CMakeLibTests PROPERTY CXX_CLANG_TIDY "") add_executable(testEncoding testEncoding.cxx) target_link_libraries(testEncoding cmsys) -foreach(test ${CMakeLib_TESTS}) +foreach(testfile ${CMakeLib_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) add_test(CMakeLib.${test} CMakeLibTests ${test} ${${test}_ARGS}) endforeach() diff --git a/Tests/CMakeServerLib/CMakeLists.txt b/Tests/CMakeServerLib/CMakeLists.txt index 5e1ad0c..2c23c2d 100644 --- a/Tests/CMakeServerLib/CMakeLists.txt +++ b/Tests/CMakeServerLib/CMakeLists.txt @@ -5,7 +5,7 @@ include_directories( ) set(CMakeServerLib_TESTS - testServerBuffering + testServerBuffering.cpp ) create_test_sourcelist(CMakeLib_TEST_SRCS CMakeServerLibTests.cxx ${CMakeServerLib_TESTS}) @@ -15,6 +15,7 @@ target_link_libraries(CMakeServerLibTests CMakeLib CMakeServerLib) SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY C_CLANG_TIDY "") SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY CXX_CLANG_TIDY "") -foreach(test ${CMakeServerLib_TESTS}) +foreach(testfile ${CMakeServerLib_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) add_test(CMakeServerLib.${test} CMakeServerLibTests ${test} ${${test}_ARGS}) endforeach() diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt index 5f456fc..5ad6e6b 100644 --- a/Tests/CudaOnly/CMakeLists.txt +++ b/Tests/CudaOnly/CMakeLists.txt @@ -1,6 +1,7 @@ ADD_TEST_MACRO(CudaOnly.EnableStandard CudaOnlyEnableStandard) ADD_TEST_MACRO(CudaOnly.ExportPTX CudaOnlyExportPTX) +ADD_TEST_MACRO(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag) +ADD_TEST_MACRO(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols) ADD_TEST_MACRO(CudaOnly.SeparateCompilation CudaOnlySeparateCompilation) ADD_TEST_MACRO(CudaOnly.WithDefs CudaOnlyWithDefs) -ADD_TEST_MACRO(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols) diff --git a/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt b/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt new file mode 100644 index 0000000..5b96906 --- /dev/null +++ b/Tests/CudaOnly/GPUDebugFlag/CMakeLists.txt @@ -0,0 +1,23 @@ + +cmake_minimum_required(VERSION 3.7) +project (CudaOnlGPUDebugFlag CUDA) + +#Goal for this example: +#verify that -G enables gpu debug flags +string(APPEND CMAKE_CUDA_FLAGS " -gencode=arch=compute_30,code=compute_30") +string(APPEND CMAKE_CUDA_FLAGS " -G") +set(CMAKE_CUDA_STANDARD 11) + +add_executable(CudaOnlyGPUDebugFlag main.cu) + +if(CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0.0) + #CUDA's __CUDACC_DEBUG__ define was added in 9.0 + #so if we are below 9.0.0 we will manually add the define so that the test + #passes + target_compile_definitions(CudaOnlyGPUDebugFlag PRIVATE "__CUDACC_DEBUG__") +endif() + +if(APPLE) + # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime. + set_property(TARGET CudaOnlyGPUDebugFlag PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) +endif() diff --git a/Tests/CudaOnly/GPUDebugFlag/main.cu b/Tests/CudaOnly/GPUDebugFlag/main.cu new file mode 100644 index 0000000..8b97a3f --- /dev/null +++ b/Tests/CudaOnly/GPUDebugFlag/main.cu @@ -0,0 +1,66 @@ +#include <cuda.h> +#include <cuda_runtime.h> +#include <iostream> + +static __global__ void debug_kernel(bool* has_debug) +{ +// Verify using the return code if we have GPU debug flag enabled +#if defined(__CUDACC__) && defined(__CUDACC_DEBUG__) + *has_debug = true; +#else + *has_debug = false; +#endif +} + +int choose_cuda_device() +{ + int nDevices = 0; + cudaError_t err = cudaGetDeviceCount(&nDevices); + if (err != cudaSuccess) { + std::cerr << "Failed to retrieve the number of CUDA enabled devices" + << std::endl; + return 1; + } + for (int i = 0; i < nDevices; ++i) { + cudaDeviceProp prop; + cudaError_t err = cudaGetDeviceProperties(&prop, i); + if (err != cudaSuccess) { + std::cerr << "Could not retrieve properties from CUDA device " << i + << std::endl; + return 1; + } + if (prop.major >= 3) { + err = cudaSetDevice(i); + if (err != cudaSuccess) { + std::cout << "Could not select CUDA device " << i << std::endl; + } else { + return 0; + } + } + } + + std::cout << "Could not find a CUDA enabled card supporting compute >=3.0" + << std::endl; + + return 1; +} + +int main(int argc, char** argv) +{ + bool* has_debug; + cudaError_t err = cudaMallocManaged(&has_debug, sizeof(bool)); + + debug_kernel<<<1, 1>>>(has_debug); + err = cudaDeviceSynchronize(); + if (err != cudaSuccess) { + std::cerr << "debug_kernel: kernel launch shouldn't have failed\n" + << "reason:\t" << cudaGetErrorString(err) << std::endl; + return 1; + } + if (*has_debug == false) { + std::cerr << "debug_kernel: kernel not compiled with device debug" + << std::endl; + return 1; + } + return 0; +} diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt index 83473ae..0c453a9 100644 --- a/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt +++ b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt @@ -21,7 +21,7 @@ endif() # Resolve the device symbols into that static library # Verify that we can't use those device symbols from anything that links # to the static library -string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30") +string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=[compute_30] -gencode arch=compute_50,code=\\\"compute_50\\\"") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CUDA_STANDARD 11) diff --git a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt index cfca823..c934c51 100644 --- a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt +++ b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt @@ -9,7 +9,8 @@ project (CudaOnlySeparateCompilation CUDA) #and executables. #We complicate the matter by also testing that multiple static libraries #all containing cuda separable compilation code links properly -string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30") +string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=\\\"compute_30,sm_30,sm_35\\\"") +string(APPEND CMAKE_CUDA_FLAGS " --generate-code=arch=compute_50,code=[compute_50,sm_50,sm_52]") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CUDA_STANDARD 11) diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt index 5bd93a4..ffe4859 100644 --- a/Tests/CudaOnly/WithDefs/CMakeLists.txt +++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt @@ -32,8 +32,8 @@ add_executable(CudaOnlyWithDefs ${main}) target_compile_options(CudaOnlyWithDefs PRIVATE - -DCOMPILE_LANG_$<COMPILE_LANGUAGE> - -DLANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA> + -DFLAG_COMPILE_LANG_$<COMPILE_LANGUAGE> + -DFLAG_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA> -Xcompiler=-DHOST_DEFINE $<$<CONFIG:DEBUG>:$<BUILD_INTERFACE:${debug_compile_flags}>> ) @@ -41,8 +41,15 @@ target_compile_options(CudaOnlyWithDefs target_compile_definitions(CudaOnlyWithDefs PRIVATE $<$<CONFIG:RELEASE>:$<BUILD_INTERFACE:${release_compile_defs}>> + -DDEF_COMPILE_LANG_$<COMPILE_LANGUAGE> + -DDEF_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA> ) +target_include_directories(CudaOnlyWithDefs + PRIVATE + $<$<COMPILE_LANGUAGE:CUDA>:${CMAKE_CURRENT_SOURCE_DIR}/inc_cuda> +) + if(APPLE) # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime. set_property(TARGET CudaOnlyWithDefs PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) diff --git a/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h new file mode 100644 index 0000000..e228b58 --- /dev/null +++ b/Tests/CudaOnly/WithDefs/inc_cuda/inc_cuda.h @@ -0,0 +1 @@ +#define INC_CUDA diff --git a/Tests/CudaOnly/WithDefs/main.notcu b/Tests/CudaOnly/WithDefs/main.notcu index bfb3577..3793d74 100644 --- a/Tests/CudaOnly/WithDefs/main.notcu +++ b/Tests/CudaOnly/WithDefs/main.notcu @@ -2,6 +2,11 @@ #include <cuda_runtime.h> #include <iostream> +#include <inc_cuda.h> +#ifndef INC_CUDA +#error "INC_CUDA not defined!" +#endif + #ifndef HOST_DEFINE #error "HOST_DEFINE not defined!" #endif @@ -10,16 +15,28 @@ #error "PACKED_DEFINE not defined!" #endif -#ifndef COMPILE_LANG_CUDA -#error "COMPILE_LANG_CUDA not defined!" +#ifndef FLAG_COMPILE_LANG_CUDA +#error "FLAG_COMPILE_LANG_CUDA not defined!" +#endif + +#ifndef FLAG_LANG_IS_CUDA +#error "FLAG_LANG_IS_CUDA not defined!" +#endif + +#if !FLAG_LANG_IS_CUDA +#error "Expected FLAG_LANG_IS_CUDA" +#endif + +#ifndef DEF_COMPILE_LANG_CUDA +#error "DEF_COMPILE_LANG_CUDA not defined!" #endif -#ifndef LANG_IS_CUDA -#error "LANG_IS_CUDA not defined!" +#ifndef DEF_LANG_IS_CUDA +#error "DEF_LANG_IS_CUDA not defined!" #endif -#if !LANG_IS_CUDA -#error "Expected LANG_IS_CUDA" +#if !DEF_LANG_IS_CUDA +#error "Expected DEF_LANG_IS_CUDA" #endif static __global__ void DetermineIfValidCudaDevice() diff --git a/Tests/FindOpenSSL/rand/main.cc b/Tests/FindOpenSSL/rand/main.cc index d81b318..147044b 100644 --- a/Tests/FindOpenSSL/rand/main.cc +++ b/Tests/FindOpenSSL/rand/main.cc @@ -9,7 +9,7 @@ int main() unsigned char buf[1024]; // random bytes - int rezval = RAND_bytes(buf, sizeof(buf)); /* 1 succes, 0 otherwise */ + int rezval = RAND_bytes(buf, sizeof(buf)); /* 1 success, 0 otherwise */ // check result if (rezval == 1) { diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 0585d0c..4586357 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -269,10 +269,8 @@ set_property(SOURCE srcgenex_flags_COMPILE_LANGUAGE.c PROPERTY COMPILE_FLAGS "$< add_executable(srcgenex_defs srcgenex_defs.c) set_property(SOURCE srcgenex_defs.c PROPERTY COMPILE_DEFINITIONS NAME=$<TARGET_PROPERTY:NAME>) -if (CMAKE_GENERATOR MATCHES "Makefiles|Ninja|Watcom WMake") - add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c) - set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>) -endif() +add_executable(srcgenex_defs_COMPILE_LANGUAGE srcgenex_defs_COMPILE_LANGUAGE.c) +set_property(SOURCE srcgenex_defs_COMPILE_LANGUAGE.c PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:C>:NAME=$<TARGET_PROPERTY:NAME>>) #----------------------------------------------------------------------------- # Cover test properties with generator expressions. diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 8eb8568..edd6c79 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -351,8 +351,6 @@ add_RunCMake_test(IfacePaths_INCLUDE_DIRECTORIES TEST_DIR IfacePaths) set(IfacePaths_SOURCES_ARGS -DTEST_PROP=SOURCES) add_RunCMake_test(IfacePaths_SOURCES TEST_DIR IfacePaths) -add_RunCMake_test(COMPILE_LANGUAGE-genex) - # Matlab module related tests if(CMake_TEST_FindMatlab) add_RunCMake_test(FindMatlab) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt deleted file mode 100644 index ef2163c..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 3.1) -project(${RunCMake_TEST} NONE) -include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt deleted file mode 100644 index 42c1485..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt +++ /dev/null @@ -1,9 +0,0 @@ -CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\): - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Visual Studio generator. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt deleted file mode 100644 index 7879a79..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-Xcode.txt +++ /dev/null @@ -1,9 +0,0 @@ -CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\): - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Xcode generator. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake deleted file mode 100644 index 7935d88..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions.cmake +++ /dev/null @@ -1,5 +0,0 @@ - -enable_language(CXX) - -add_executable(main main.cpp) -target_compile_definitions(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-DANYTHING>) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt deleted file mode 100644 index 3806ed1..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt +++ /dev/null @@ -1,9 +0,0 @@ -CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\): - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Visual Studio generator. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt deleted file mode 100644 index a3fb9c5..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt +++ /dev/null @@ -1,9 +0,0 @@ -CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\): - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Xcode generator. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake deleted file mode 100644 index 31771f6..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake +++ /dev/null @@ -1,5 +0,0 @@ - -enable_language(CXX) - -add_executable(main main.cpp) -target_include_directories(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:anydir>) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt deleted file mode 100644 index 5d19153..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-VS.txt +++ /dev/null @@ -1,7 +0,0 @@ -CMake Error: - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Visual Studio generator. diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt deleted file mode 100644 index 4a4564e..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions-stderr-Xcode.txt +++ /dev/null @@ -1,7 +0,0 @@ -CMake Error: - Error evaluating generator expression: - - \$<COMPILE_LANGUAGE:CXX> - - \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and - file\(GENERATE\) with the Xcode generator. diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake deleted file mode 100644 index 3a07d7d..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/PerSourceCompileDefinitions.cmake +++ /dev/null @@ -1,5 +0,0 @@ - -enable_language(CXX) - -add_executable(main main.cpp) -set_property(SOURCE main.cpp PROPERTY COMPILE_DEFINITIONS $<$<COMPILE_LANGUAGE:CXX>:ANYTHING>) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake deleted file mode 100644 index 1a93dcd..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake +++ /dev/null @@ -1,23 +0,0 @@ -include(RunCMake) - -if (RunCMake_GENERATOR STREQUAL "Xcode") - set(RunCMake-stderr-file CompileDefinitions-stderr-Xcode.txt) - run_cmake(CompileDefinitions) -elseif (RunCMake_GENERATOR MATCHES "Visual Studio") - set(RunCMake-stderr-file CompileDefinitions-stderr-VS.txt) - run_cmake(CompileDefinitions) -endif() -if (RunCMake_GENERATOR STREQUAL "Xcode") - set(RunCMake-stderr-file IncludeDirectories-stderr-Xcode.txt) - run_cmake(IncludeDirectories) -elseif (RunCMake_GENERATOR MATCHES "Visual Studio") - set(RunCMake-stderr-file IncludeDirectories-stderr-VS.txt) - run_cmake(IncludeDirectories) -endif() -if (RunCMake_GENERATOR STREQUAL "Xcode") - set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-Xcode.txt) - run_cmake(PerSourceCompileDefinitions) -elseif (RunCMake_GENERATOR MATCHES "Visual Studio") - set(RunCMake-stderr-file PerSourceCompileDefinitions-stderr-VS.txt) - run_cmake(PerSourceCompileDefinitions) -endif() diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp b/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp deleted file mode 100644 index 766b775..0000000 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/main.cpp +++ /dev/null @@ -1,5 +0,0 @@ - -int main() -{ - return 0; -} diff --git a/Tests/RunCMake/GenerateExportHeader/GEH.cmake b/Tests/RunCMake/GenerateExportHeader/GEH.cmake index cfca8fe..cf81f36 100644 --- a/Tests/RunCMake/GenerateExportHeader/GEH.cmake +++ b/Tests/RunCMake/GenerateExportHeader/GEH.cmake @@ -53,7 +53,16 @@ endif() add_subdirectory(lib_shared_and_static) -add_compiler_export_flags() +if(CMAKE_SYSTEM_NAME MATCHES "AIX" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + AND CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY) + # With GNU 7 on AIX, passing -fvisibility=hidden when driving the + # linker for a shared library drops the so init/destruct symbols. + # Just use the modern approach instead of testing the macro. + set(CMAKE_CXX_VISIBILITY_PRESET hidden) + set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) +else() + add_compiler_export_flags() +endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt b/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt index c4a761c..9516a5a 100644 --- a/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt +++ b/Tests/RunCMake/GenerateExportHeader/libshared/CMakeLists.txt @@ -1,7 +1,5 @@ include(GenerateExportHeader) -add_compiler_export_flags() - set(CMAKE_INCLUDE_CURRENT_DIR ON) add_library(libshared SHARED libshared.cpp) diff --git a/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt b/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt index 0fd136c..56e8335 100644 --- a/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt +++ b/Tests/RunCMake/GenerateExportHeader/libstatic/CMakeLists.txt @@ -2,8 +2,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) include(GenerateExportHeader) -add_compiler_export_flags() - # Show that the export header has no effect on a static library. add_library(libstatic STATIC libstatic.cpp) diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c index cb09ead..3759778 100644 --- a/Utilities/cmlibuv/src/unix/signal.c +++ b/Utilities/cmlibuv/src/unix/signal.c @@ -28,6 +28,9 @@ #include <string.h> #include <unistd.h> +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif typedef struct { uv_signal_t* handle; @@ -216,7 +219,9 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (sigfillset(&sa.sa_mask)) abort(); sa.sa_handler = uv__signal_handler; - sa.sa_flags = oneshot ? SA_RESETHAND : 0; + sa.sa_flags = SA_RESTART; + if (oneshot) + sa.sa_flags |= SA_RESETHAND; /* XXX save old action so we can restore it later on? */ if (sigaction(signum, &sa, NULL)) |