diff options
114 files changed, 2050 insertions, 651 deletions
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake index 8c0c5e8..638b1c4 100644 --- a/Auxiliary/bash-completion/cmake +++ b/Auxiliary/bash-completion/cmake @@ -116,6 +116,9 @@ _cmake() 2>/dev/null )' -- "$quoted" ) ) return ;; + --loglevel) + COMPREPLY=( $(compgen -W 'error warning notice status verbose debug trace' -- $cur ) ) + ;; --help-command) COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null| grep -v "^cmake version " )' -- "$cur" ) ) diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst index 2d71352..e6ad037 100644 --- a/Help/command/execute_process.rst +++ b/Help/command/execute_process.rst @@ -18,6 +18,7 @@ Execute one or more child processes. [ERROR_FILE <file>] [OUTPUT_QUIET] [ERROR_QUIET] + [COMMAND_ECHO <where>] [OUTPUT_STRIP_TRAILING_WHITESPACE] [ERROR_STRIP_TRAILING_WHITESPACE] [ENCODING <name>]) @@ -77,6 +78,10 @@ Options: ``OUTPUT_QUIET``, ``ERROR_QUIET`` The standard output or standard error results will be quietly ignored. +``COMMAND_ECHO <where>`` + The command being run will be echo'ed to ``<where>`` with ``<where>`` + being set to ``STDERR``|``STDOUT``|``NONE``. + ``ENCODING <name>`` On Windows, the encoding that is used to decode output from the process. Ignored on other platforms. diff --git a/Help/command/message.rst b/Help/command/message.rst index a3c3a89..3f9216a 100644 --- a/Help/command/message.rst +++ b/Help/command/message.rst @@ -9,24 +9,56 @@ Display a message to the user. The optional ``<mode>`` keyword determines the type of message: -:: - - (none) = Important information - STATUS = Incidental information - WARNING = CMake Warning, continue processing - AUTHOR_WARNING = CMake Warning (dev), continue processing - SEND_ERROR = CMake Error, continue processing, - but skip generation - FATAL_ERROR = CMake Error, stop processing and generation - DEPRECATION = CMake Deprecation Error or Warning if variable - CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED - is enabled, respectively, else no message. - -The CMake command-line tool displays STATUS messages on stdout and all -other message types on stderr. The CMake GUI displays all messages in -its log area. The interactive dialogs (ccmake and CMakeSetup) show -``STATUS`` messages one at a time on a status line and other messages in -interactive pop-up boxes. +``FATAL_ERROR`` + CMake Error, stop processing and generation. + +``SEND_ERROR`` + CMake Error, continue processing, but skip generation. + +``WARNING`` + CMake Warning, continue processing. + +``AUTHOR_WARNING`` + CMake Warning (dev), continue processing. + +``DEPRECATION`` + CMake Deprecation Error or Warning if variable + :variable:`CMAKE_ERROR_DEPRECATED` or :variable:`CMAKE_WARN_DEPRECATED` + is enabled, respectively, else no message. + +(none) or ``NOTICE`` + Important message printed to stderr to attract user's attention. + +``STATUS`` + The main interesting messages that project users might be interested in. + Ideally these should be concise, no more than a single line, but still + informative. + +``VERBOSE`` + Detailed informational messages intended for project users. These messages + should provide additional details that won't be of interest in most cases, + but which may be useful to those building the project when they want deeper + insight into what's happening. + +``DEBUG`` + Detailed informational messages intended for developers working on the + project itself as opposed to users who just want to build it. These messages + will not typically be of interest to other users building the project and + will often be closely related to internal implementation details. + +``TRACE`` + Fine-grained messages with very low-level implementation details. Messages + using this log level would normally only be temporary and would expect to be + removed before releasing the project, packaging up the files, etc. + +The CMake command-line tool displays ``STATUS`` to ``TRACE`` messages on stdout +with the message preceded by two hyphens and a space. All other message types +are sent to stderr and are not prefixed with hyphens. The CMake GUI displays +all messages in its log area. The interactive dialogs (:manual:`ccmake(1)` +and :manual:`cmake-gui(1)`) show ``STATUS`` to ``TRACE`` messages one at a +time on a status line and other messages in interactive pop-up boxes. +The ``--loglevel`` command-line option to each of these tools can be used to +control which messages will be shown. CMake Warning and Error message text displays using a simple markup language. Non-indented text is formatted in line-wrapped paragraphs diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 7f4761f..ce62893 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -404,16 +404,25 @@ Target-Dependent Queries :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>` and :prop_tgt:`RUNTIME_OUTPUT_NAME_<CONFIG>`. + The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target + properties can also be considered. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_FILE_PREFIX:tgt>`` Prefix of main file where ``tgt`` is the name of a target. + See also the :prop_tgt:`PREFIX` target property. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_FILE_SUFFIX:tgt>`` Suffix of main file where ``tgt`` is the name of a target. + The suffix corresponds to the file extension (such as ".so" or ".exe"). + + See also the :prop_tgt:`SUFFIX` target property. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_FILE_NAME:tgt>`` @@ -435,16 +444,27 @@ Target-Dependent Queries :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` and :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>`. + The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target + properties can also be considered. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_LINKER_FILE_PREFIX:tgt>`` Prefix of file used to link where ``tgt`` is the name of a target. + See also the :prop_tgt:`PREFIX` and :prop_tgt:`IMPORT_PREFIX` target + properties. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_LINKER_FILE_SUFFIX:tgt>`` Suffix of file used to link where ``tgt`` is the name of a target. + The suffix corresponds to the file extension (such as ".so" or ".lib"). + + See also the :prop_tgt:`SUFFIX` and :prop_tgt:`IMPORT_SUFFIX` target + properties. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_LINKER_FILE_NAME:tgt>`` @@ -475,6 +495,9 @@ Target-Dependent Queries See also the :prop_tgt:`PDB_NAME` target property and its configuration specific variant :prop_tgt:`PDB_NAME_<CONFIG>`. + The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target + properties can also be considered. + Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on. ``$<TARGET_PDB_FILE_NAME:tgt>`` @@ -530,8 +553,7 @@ Output-Related Expressions Content of ``...`` converted to a C identifier. The conversion follows the same behavior as :command:`string(MAKE_C_IDENTIFIER)`. ``$<TARGET_OBJECTS:objLib>`` - List of objects resulting from build of ``objLib``. ``objLib`` must be an - object of type ``OBJECT_LIBRARY``. + List of objects resulting from build of ``objLib``. ``$<SHELL_PATH:...>`` Content of ``...`` converted to shell path style. For example, slashes are converted to backslashes in Windows shells and drive letters are converted diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index 25d364c..8f10b9f 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -7,6 +7,11 @@ cmake-server(7) .. contents:: +.. deprecated:: 3.15 + + This will be removed from a future version of CMake. + Clients should use the :manual:`cmake-file-api(7)` instead. + Introduction ============ diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 3e8c884..6d93ae9 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -159,6 +159,7 @@ Variables that Change Behavior /variable/CMAKE_ECLIPSE_VERSION /variable/CMAKE_ERROR_DEPRECATED /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION + /variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO /variable/CMAKE_EXPORT_COMPILE_COMMANDS /variable/CMAKE_EXPORT_PACKAGE_REGISTRY /variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 5b88694..df0d4c5 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -200,6 +200,12 @@ Options from the top of a binary tree for a CMake project it will dump additional information such as the cache, log files etc. +``--loglevel=<error|warning|notice|status|verbose|debug|trace>`` + Set the log level. + + The :command:`message` command will only output messages of the specified + log level or higher. The default log level is ``status``. + ``--debug-trycompile`` Do not delete the :command:`try_compile` build tree. Only useful on one :command:`try_compile` at a time. @@ -280,6 +286,9 @@ following options: The :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` environment variable, if set, specifies a default parallel level when this option is not given. + Some native build tools always build in parallel. The use of ``<jobs>`` + value of ``1`` can be used to limit to a single job. + ``--target <tgt>..., -t <tgt>...`` Build ``<tgt>`` instead of default targets. May be specified multiple times. diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt index 2bf71a9..6c61341 100644 --- a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt +++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt @@ -13,3 +13,8 @@ The value is ignored on non-MSVC compilers but an unsupported value will be rejected as an error when using a compiler targeting the MSVC ABI. + +The value may also be the empty string (``""``) in which case no runtime +library selection flag will be added explicitly by CMake. Note that with +:ref:`Visual Studio Generators` the native build system may choose to +add its own default runtime library selection flag. diff --git a/Help/release/dev/add-execute_process-command-echo.rst b/Help/release/dev/add-execute_process-command-echo.rst new file mode 100644 index 0000000..a44e40e --- /dev/null +++ b/Help/release/dev/add-execute_process-command-echo.rst @@ -0,0 +1,6 @@ +add-execute_process-command-echo +-------------------------------- + +* The :command:`execute_process` command gained a `COMMAND_ECHO` option + and supporting :variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ECHO` variable + to enable echoing of the command-line string before execution. diff --git a/Help/release/dev/new-message-types-and-logging.rst b/Help/release/dev/new-message-types-and-logging.rst new file mode 100644 index 0000000..cd470bb --- /dev/null +++ b/Help/release/dev/new-message-types-and-logging.rst @@ -0,0 +1,7 @@ +new-message-types-and-logging +----------------------------- + +* The :command:`message` command learned new types: ``NOTICE``, ``VERBOSE``, + ``DEBUG`` and ``TRACE``. + +* The :manual:`cmake(1)` command learned a new CLI option ``--loglevel``. diff --git a/Help/release/dev/relax-TARGET_OBJECTS-generator-expression.rst b/Help/release/dev/relax-TARGET_OBJECTS-generator-expression.rst new file mode 100644 index 0000000..25ca0c9 --- /dev/null +++ b/Help/release/dev/relax-TARGET_OBJECTS-generator-expression.rst @@ -0,0 +1,5 @@ +relax-TARGET_OBJECTS-generator-expression +----------------------------------------- + +* The ``TARGET_OBJECTS`` :manual:`generator expression <cmake-generator-expressions(7)>` + is now supported on ``SHARED``, ``STATIC``, ``MODULE`` libraries and executables. diff --git a/Help/release/dev/server-deprecate.rst b/Help/release/dev/server-deprecate.rst new file mode 100644 index 0000000..65c86e1 --- /dev/null +++ b/Help/release/dev/server-deprecate.rst @@ -0,0 +1,6 @@ +server-deprecate +---------------- + +* The :manual:`cmake-server(7)` mode has been deprecated and will be + removed from a future version of CMake. Please port clients to use + the :manual:`cmake-file-api(7)` instead. diff --git a/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst new file mode 100644 index 0000000..4a3121c --- /dev/null +++ b/Help/variable/CMAKE_EXECUTE_PROCESS_COMMAND_ECHO.rst @@ -0,0 +1,6 @@ +CMAKE_EXECUTE_PROCESS_COMMAND_ECHO +---------------------------------- + +If this variable is set to ``STDERR``|``STDOUT``|``NONE`` then commands in +:command:`execute_process` calls will be printed to either stderr or stdout +or not at all. diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index c1c9982..746a806 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -189,7 +189,7 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS} set(id_platform ${CMAKE_VS_PLATFORM_NAME}) set(id_lang "${lang}") set(id_PostBuildEvent_Command "") - if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm]$") + if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$") set(id_cl_var "ClangClExecutable") elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*") set(id_cl clang.exe) diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake index d34d494..2042360 100644 --- a/Modules/Compiler/AppleClang-CXX.cmake +++ b/Modules/Compiler/AppleClang-CXX.cmake @@ -28,4 +28,9 @@ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") endif() + +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) + set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) +endif() + __compiler_check_default_language_standard(CXX 4.0 98) diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake index 34ffd66..c116078 100644 --- a/Modules/Compiler/Clang-CXX.cmake +++ b/Modules/Compiler/Clang-CXX.cmake @@ -17,9 +17,10 @@ if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") endif() if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.1) + set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON) set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") - set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON) + set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1) set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x") set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x") @@ -28,9 +29,11 @@ if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) endif() set(_clang_version_std17 5.0) diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake index 7202607..fcaaeab 100644 --- a/Modules/Compiler/GNU-CXX.cmake +++ b/Modules/Compiler/GNU-CXX.cmake @@ -17,15 +17,19 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) endif() if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) + set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON) set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") - set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON) elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) # 4.3 supports 0x variants set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x") set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x") endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.1) + set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) +endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") @@ -34,6 +38,10 @@ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) +endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17") set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17") diff --git a/Modules/Compiler/IAR-C.cmake b/Modules/Compiler/IAR-C.cmake index cb10020..af5874c 100644 --- a/Modules/Compiler/IAR-C.cmake +++ b/Modules/Compiler/IAR-C.cmake @@ -10,7 +10,7 @@ endif() set(CMAKE_C_EXTENSION_COMPILE_OPTION -e) -if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7) +if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 7) set(CMAKE_C90_STANDARD_COMPILE_OPTION --c89) set(CMAKE_C90_EXTENSION_COMPILE_OPTION --c89 -e) set(CMAKE_C99_STANDARD_COMPILE_OPTION "") @@ -20,13 +20,17 @@ elseif() set(CMAKE_C90_EXTENSION_COMPILE_OPTION -e) endif() -if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8) +if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_GREATER 8) set(CMAKE_C11_STANDARD_COMPILE_OPTION "") set(CMAKE_C11_EXTENSION_COMPILE_OPTION -e) endif() # Architecture specific if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") + if(CMAKE_C_COMPILER_VERSION_INTERNAL VERSION_LESS 7) + # IAR ARM 4.X uses xlink.exe, detection is not yet implemented + message(FATAL_ERROR "CMAKE_C_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.") + endif() __compiler_iar_ilink(C) __compiler_check_default_language_standard(C 1.10 90 6.10 99 8.10 11) diff --git a/Modules/Compiler/IAR-CXX.cmake b/Modules/Compiler/IAR-CXX.cmake index eb27e3c..04ccbe5 100644 --- a/Modules/Compiler/IAR-CXX.cmake +++ b/Modules/Compiler/IAR-CXX.cmake @@ -8,7 +8,8 @@ if(NOT CMAKE_IAR_CXX_FLAG) if(NOT CMAKE_CXX_COMPILER_VERSION) message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION not detected. This should be automatic.") endif() - if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 8) + + if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_GREATER 7) set(CMAKE_IAR_CXX_FLAG --c++) else() set(CMAKE_IAR_CXX_FLAG --eec++) @@ -33,6 +34,10 @@ endif() # Architecture specific if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") + if(CMAKE_CXX_COMPILER_VERSION_INTERNAL VERSION_LESS 7) + # IAR ARM 4.X uses xlink.exe, detection is not yet implemented + message(FATAL_ERROR "CMAKE_CXX_COMPILER_VERSION = ${CMAKE_C_COMPILER_VERSION} not supported by CMake.") + endif() __compiler_iar_ilink(CXX) __compiler_check_default_language_standard(CXX 6.10 98 8.10 14) diff --git a/Modules/Compiler/IAR-FindBinUtils.cmake b/Modules/Compiler/IAR-FindBinUtils.cmake index e8f5e6b..7fc6b59 100644 --- a/Modules/Compiler/IAR-FindBinUtils.cmake +++ b/Modules/Compiler/IAR-FindBinUtils.cmake @@ -2,7 +2,7 @@ if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set") endif() -# Try to find tools in the same directory as Clang itself +# Try to find tools in the same directory as the compiler itself get_filename_component(__iar_hint_1 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" REALPATH) get_filename_component(__iar_hint_1 "${__iar_hint_1}" DIRECTORY) @@ -12,20 +12,23 @@ set(__iar_hints "${__iar_hint_1}" "${__iar_hint_2}") if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM" OR "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") - # could allow using normal binutils ar, since objects are normal ELF files? - find_program(CMAKE_IAR_LINKER ilink${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.exe HINTS ${__iar_hints} + + string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _archid_lower) + + # Find linker + find_program(CMAKE_IAR_LINKER ilink${_archid_lower} HINTS ${__iar_hints} DOC "The IAR ILINK linker") - find_program(CMAKE_IAR_ARCHIVE iarchive.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_ARCHIVE iarchive HINTS ${__iar_hints} DOC "The IAR archiver") - # find auxiliary tools - find_program(CMAKE_IAR_ELFTOOL ielftool.exe HINTS ${__iar_hints} + # Find utility tools + find_program(CMAKE_IAR_ELFTOOL ielftool HINTS ${__iar_hints} DOC "The IAR ELF Tool") - find_program(CMAKE_IAR_ELFDUMP ielfdump${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_ELFDUMP ielfdump${_archid_lower} HINTS ${__iar_hints} DOC "The IAR ELF Dumper") - find_program(CMAKE_IAR_OBJMANIP iobjmanip.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_OBJMANIP iobjmanip HINTS ${__iar_hints} DOC "The IAR ELF Object Tool") - find_program(CMAKE_IAR_SYMEXPORT isymexport.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_SYMEXPORT isymexport HINTS ${__iar_hints} DOC "The IAR Absolute Symbol Exporter") mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_ARCHIVE CMAKE_IAR_ELFTOOL CMAKE_IAR_ELFDUMP CMAKE_IAR_OBJMANIP CMAKE_IAR_SYMEXPORT) @@ -41,9 +44,9 @@ set(CMAKE_IAR_LINKER \"${CMAKE_IAR_LINKER}\") elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") # For AVR and AVR32, IAR uses the "xlink" linker and the "xar" archiver: - find_program(CMAKE_IAR_LINKER xlink.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_LINKER xlink HINTS ${__iar_hints} DOC "The IAR XLINK linker") - find_program(CMAKE_IAR_AR xar.exe HINTS ${__iar_hints} + find_program(CMAKE_IAR_AR xar HINTS ${__iar_hints} DOC "The IAR archiver") mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR) diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake index 471dd4a..44b0c3d 100644 --- a/Modules/Compiler/Intel-CXX.cmake +++ b/Modules/Compiler/Intel-CXX.cmake @@ -40,6 +40,16 @@ else() set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17") endif() + # While full C++14 support was first introduced in Intel 17, + # Intel 18.0.0-4 don't have full support as they broke + # support for cxx_relaxed_constexpr. + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 18.0.4) + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) + elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0.0 + AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.0) + set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON) + endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0) @@ -54,6 +64,10 @@ else() set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0) + set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) + endif() + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake index a722130..f56227b 100644 --- a/Modules/Compiler/MSVC-C.cmake +++ b/Modules/Compiler/MSVC-C.cmake @@ -21,9 +21,13 @@ macro(cmake_record_c_compile_features) c_std_99 c_std_11 c_function_prototypes - c_variadic_macros ) list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes) - list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99 c_variadic_macros) + list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99) list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11) + if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0) + list(APPEND CMAKE_C_COMPILE_FEATURES c_variadic_macros) + list(APPEND CMAKE_C99_COMPILE_FEATURES c_variadic_macros) + endif() + set(_result 0) # expected by cmake_determine_compile_features endmacro() diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake index 691926f..787c17e 100644 --- a/Modules/Compiler/MSVC-CXX.cmake +++ b/Modules/Compiler/MSVC-CXX.cmake @@ -17,6 +17,7 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14") set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std:c++14") if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11.25505) + set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON) set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++17") set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++17") else() @@ -30,21 +31,6 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND __compiler_check_default_language_standard(CXX 19.0 14) - # All features that we define are available in the base mode, except - # for meta-features for C++14 and above. Override the default macro - # to avoid doing unnecessary work. - macro(cmake_record_cxx_compile_features) - if (DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION) - list(APPEND CMAKE_CXX20_COMPILE_FEATURES cxx_std_20) - endif() - # The main cmake_record_cxx_compile_features macro makes all - # these conditional on CMAKE_CXX##_STANDARD_COMPILE_OPTION, - # but we can skip the conditions because we set them above. - list(APPEND CMAKE_CXX17_COMPILE_FEATURES cxx_std_17) - list(APPEND CMAKE_CXX14_COMPILE_FEATURES cxx_std_14) - list(APPEND CMAKE_CXX98_COMPILE_FEATURES cxx_std_11) # no flag needed for 11 - _record_compiler_features_cxx(98) - endmacro() elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) # MSVC has no specific options to set language standards, but set them as # empty strings anyways so the feature test infrastructure can at least check diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index 7325eca..023cc8d 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -1054,11 +1054,17 @@ endfunction() # Some boost libraries may require particular set of compler features. # The very first one was `boost::fiber` introduced in Boost 1.62. # One can check required compiler features of it in -# `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`. +# - `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`; +# - `${Boost_ROOT}/libs/context/build/Jamfile.v2`. +# +# TODO (Re)Check compiler features on (every?) release ??? +# One may use the following command to get the files to check: +# +# $ find . -name Jamfile.v2 | grep build | xargs grep -l cxx1 # function(_Boost_COMPILER_FEATURES component _ret) - # Boost >= 1.62 and < 1.67 - if(NOT Boost_VERSION VERSION_LESS 106200 AND Boost_VERSION VERSION_LESS 106700) + # Boost >= 1.62 + if(NOT Boost_VERSION VERSION_LESS 106200) set(_Boost_FIBER_COMPILER_FEATURES cxx_alias_templates cxx_auto_type @@ -1072,6 +1078,8 @@ function(_Boost_COMPILER_FEATURES component _ret) cxx_thread_local cxx_variadic_templates ) + # Compiler feature for `context` same as for `fiber`. + set(_Boost_CONTEXT_COMPILER_FEATURES ${_Boost_FIBER_COMPILER_FEATURES}) endif() string(TOUPPER ${component} uppercomponent) set(${_ret} ${_Boost_${uppercomponent}_COMPILER_FEATURES} PARENT_SCOPE) diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake index 8c45a8c..5288640 100644 --- a/Modules/FindMPI.cmake +++ b/Modules/FindMPI.cmake @@ -770,18 +770,20 @@ function (_MPI_interrogate_compiler LANG) endforeach() # Add the link directories given explicitly that we haven't used back as linker directories. - foreach(_MPI_LINK_DIRECTORY IN LISTS MPI_LINK_DIRECTORIES_LEFTOVER) - file(TO_NATIVE_PATH "${_MPI_LINK_DIRECTORY}" _MPI_LINK_DIRECTORY_ACTUAL) - string(FIND "${_MPI_LINK_DIRECTORY_ACTUAL}" " " _MPI_LINK_DIRECTORY_CONTAINS_SPACE) - if(NOT _MPI_LINK_DIRECTORY_CONTAINS_SPACE EQUAL -1) - set(_MPI_LINK_DIRECTORY_ACTUAL "\"${_MPI_LINK_DIRECTORY_ACTUAL}\"") - endif() - if(MPI_LINK_FLAGS_WORK) - string(APPEND MPI_LINK_FLAGS_WORK " ${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}") - else() - set(MPI_LINK_FLAGS_WORK "${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}") - endif() - endforeach() + if(NOT WIN32) + foreach(_MPI_LINK_DIRECTORY IN LISTS MPI_LINK_DIRECTORIES_LEFTOVER) + file(TO_NATIVE_PATH "${_MPI_LINK_DIRECTORY}" _MPI_LINK_DIRECTORY_ACTUAL) + string(FIND "${_MPI_LINK_DIRECTORY_ACTUAL}" " " _MPI_LINK_DIRECTORY_CONTAINS_SPACE) + if(NOT _MPI_LINK_DIRECTORY_CONTAINS_SPACE EQUAL -1) + set(_MPI_LINK_DIRECTORY_ACTUAL "\"${_MPI_LINK_DIRECTORY_ACTUAL}\"") + endif() + if(MPI_LINK_FLAGS_WORK) + string(APPEND MPI_LINK_FLAGS_WORK " ${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}") + else() + set(MPI_LINK_FLAGS_WORK "${CMAKE_LIBRARY_PATH_FLAG}${_MPI_LINK_DIRECTORY_ACTUAL}") + endif() + endforeach() + endif() # Deal with the libraries given with full path next unset(MPI_DIRECT_LIB_NAMES_WORK) diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index 0868989..8bd5eb3 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -321,9 +321,9 @@ unset (_${_PYTHON_PREFIX}_CACHED_VARS) # first step, search for the interpreter if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) endif() set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) @@ -589,9 +589,9 @@ endif() # second step, search for compiler (IronPython) if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_COMPILER) if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_COMPILER) endif() # IronPython specific artifacts @@ -700,15 +700,15 @@ endif() ## Development environment is not compatible with IronPython interpreter if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_LIBRARY + ${_PYTHON_PREFIX}_LIBRARY_RELEASE + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE + ${_PYTHON_PREFIX}_LIBRARY_DEBUG + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG + ${_PYTHON_PREFIX}_INCLUDE_DIR) if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARY ${_PYTHON_PREFIX}_INCLUDE_DIR) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_LIBRARY - ${_PYTHON_PREFIX}_LIBRARY_RELEASE - ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE - ${_PYTHON_PREFIX}_LIBRARY_DEBUG - ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG - ${_PYTHON_PREFIX}_INCLUDE_DIR) endif() # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES @@ -1182,9 +1182,9 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS endif() if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) endif() execute_process( COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c @@ -1213,6 +1213,10 @@ if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Inte set(${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}") endif() endif() + # final step: set NumPy founded only if Development component is founded as well + if (NOT ${_PYTHON_PREFIX}_Development_FOUND) + set(${_PYTHON_PREFIX}_NumPy_FOUND FALSE) + endif() endif() # final validation diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake index 26b2517..ffb24e2 100644 --- a/Modules/Internal/CPack/CPackRPM.cmake +++ b/Modules/Internal/CPack/CPackRPM.cmake @@ -1158,7 +1158,9 @@ function(cpack_rpm_generate_package) # Now we may create the RPM build tree structure set(CPACK_RPM_ROOTDIR "${CPACK_TOPLEVEL_DIRECTORY}") - message(STATUS "CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=${CPACK_RPM_ROOTDIR}") + if(CPACK_RPM_PACKAGE_DEBUG) + message("CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=${CPACK_RPM_ROOTDIR}") + endif() # Prepare RPM build tree file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}) file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/tmp) diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake index 5590433..7e02814 100644 --- a/Modules/Platform/Darwin.cmake +++ b/Modules/Platform/Darwin.cmake @@ -1,11 +1,20 @@ set(APPLE 1) if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS") - set(CMAKE_MACOSX_BUNDLE ON) + if(NOT DEFINED CMAKE_MACOSX_BUNDLE) + set(CMAKE_MACOSX_BUNDLE ON) + endif() - set(CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}") - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}") + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + endif() + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + endif() + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + endif() endif() # Darwin versions: diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 49f237f..01c6cd7 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -264,6 +264,8 @@ set(SRCS cmGeneratorExpression.h cmGeneratorTarget.cxx cmGeneratorTarget.h + cmGetPipes.cxx + cmGetPipes.h cmGlobalCommonGenerator.cxx cmGlobalCommonGenerator.h cmGlobalGenerator.cxx @@ -386,6 +388,7 @@ set(SRCS cmUuid.cxx cmUVHandlePtr.cxx cmUVHandlePtr.h + cmUVStreambuf.h cmUVSignalHackRAII.h cmVariableWatch.cxx cmVariableWatch.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 51b69ba..a6c9d01 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 14) -set(CMake_VERSION_PATCH 20190429) +set(CMake_VERSION_PATCH 20190503) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index bfe8d70..a2c30bb 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -5,61 +5,19 @@ #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestTestHandler.h" +#include "cmGetPipes.h" #include "cmsys/Process.h" -#include <fcntl.h> #include <iostream> #include <signal.h> #include <string> #if defined(_WIN32) # include "cm_kwiml.h" -#else -# include <unistd.h> #endif #include <utility> #define CM_PROCESS_BUF_SIZE 65536 -#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> - -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) , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE) @@ -120,7 +78,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) pipe_reader.init(loop, 0, this); int fds[2] = { -1, -1 }; - status = cmProcessGetPipes(fds); + status = cmGetPipes(fds); if (status != 0) { cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, "Error initializing pipe: " << uv_strerror(status) diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index ff6340f..0d9859e 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -6,11 +6,13 @@ #include "cmsys/Process.h" #include <algorithm> #include <ctype.h> /* isspace */ +#include <iostream> #include <stdio.h> #include "cmAlgorithms.h" #include "cmArgumentParser.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmProcessOutput.h" #include "cmSystemTools.h" @@ -47,6 +49,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, std::string OutputFile; std::string ErrorFile; std::string Timeout; + std::string CommandEcho; bool OutputQuiet = false; bool ErrorQuiet = false; bool OutputStripTrailingWhitespace = false; @@ -57,6 +60,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, static auto const parser = cmArgumentParser<Arguments>{} .Bind("COMMAND"_s, &Arguments::Commands) + .Bind("COMMAND_ECHO"_s, &Arguments::CommandEcho) .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable) .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable) .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable) @@ -117,9 +121,10 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, return false; } } - // Create a process instance. - cmsysProcess* cp = cmsysProcess_New(); + std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr( + cmsysProcess_New(), cmsysProcess_Delete); + cmsysProcess* cp = cp_ptr.get(); // Set the command sequence. for (std::vector<std::string> const& cmd : arguments.Commands) { @@ -169,6 +174,51 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, cmsysProcess_SetTimeout(cp, timeout); } + bool echo_stdout = false; + bool echo_stderr = false; + bool echo_output_from_variable = true; + std::string echo_output = + this->Makefile->GetSafeDefinition("CMAKE_EXECUTE_PROCESS_COMMAND_ECHO"); + if (!arguments.CommandEcho.empty()) { + echo_output_from_variable = false; + echo_output = arguments.CommandEcho; + } + + if (!echo_output.empty()) { + if (echo_output == "STDERR") { + echo_stderr = true; + } else if (echo_output == "STDOUT") { + echo_stdout = true; + } else if (echo_output != "NONE") { + std::string error; + if (echo_output_from_variable) { + error = "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to '"; + } else { + error = " called with '"; + } + error += echo_output; + error += "' expected STDERR|STDOUT|NONE"; + if (!echo_output_from_variable) { + error += " for COMMAND_ECHO."; + } + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, error); + return true; + } + } + if (echo_stdout || echo_stderr) { + std::string command; + for (auto& cmd : arguments.Commands) { + command += "'"; + command += cmJoin(cmd, "' '"); + command += "'"; + command += "\n"; + } + if (echo_stdout) { + std::cout << command; + } else if (echo_stderr) { + std::cerr << command; + } + } // Start the process. cmsysProcess_Execute(cp); @@ -297,9 +347,6 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, } } - // Delete the process instance. - cmsysProcess_Delete(cp); - return true; } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 8b3d9d6..8c6fb34 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -21,10 +21,13 @@ #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmake.h" #include "cmsys/RegularExpression.hxx" #include "cmsys/String.h" + #include <algorithm> #include <assert.h> #include <errno.h> @@ -96,36 +99,42 @@ static const struct OneNode buildInterfaceNode; static const struct ZeroNode installInterfaceNode; -#define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \ - static const struct OP##Node : public cmGeneratorExpressionNode \ - { \ - OP##Node() {} /* NOLINT(modernize-use-equals-default) */ \ - virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \ - \ - std::string Evaluate(const std::vector<std::string>& parameters, \ - cmGeneratorExpressionContext* context, \ - const GeneratorExpressionContent* content, \ - cmGeneratorExpressionDAGChecker*) const \ - { \ - for (std::string const& param : parameters) { \ - if (param == #FAILURE_VALUE) { \ - return #FAILURE_VALUE; \ - } \ - if (param != #SUCCESS_VALUE) { \ - reportError(context, content->GetOriginalExpression(), \ - "Parameters to $<" #OP \ - "> must resolve to either '0' or '1'."); \ - return std::string(); \ - } \ - } \ - return #SUCCESS_VALUE; \ - } \ - } OPNAME; - -BOOLEAN_OP_NODE(andNode, AND, 1, 0) -BOOLEAN_OP_NODE(orNode, OR, 0, 1) - -#undef BOOLEAN_OP_NODE +struct BooleanOpNode : public cmGeneratorExpressionNode +{ + BooleanOpNode(const char* op_, const char* successVal_, + const char* failureVal_) + : op(op_) + , successVal(successVal_) + , failureVal(failureVal_) + { + } + + int NumExpectedParameters() const override { return OneOrMoreParameters; } + + std::string Evaluate(const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker*) const override + { + for (std::string const& param : parameters) { + if (param == this->failureVal) { + return this->failureVal; + } + if (param != this->successVal) { + std::ostringstream e; + e << "Parameters to $<" << this->op; + e << "> must resolve to either '0' or '1'."; + reportError(context, content->GetOriginalExpression(), e.str()); + return std::string(); + } + } + return this->successVal; + } + + const char *const op, *const successVal, *const failureVal; +}; + +static const BooleanOpNode andNode("AND", "1", "0"), orNode("OR", "0", "1"); static const struct NotNode : public cmGeneratorExpressionNode { @@ -212,69 +221,44 @@ static const struct EqualNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - char* pEnd; - - int base = 0; - bool flipSign = false; - - const char* lhs = parameters[0].c_str(); - if (cmHasLiteralPrefix(lhs, "0b") || cmHasLiteralPrefix(lhs, "0B")) { - base = 2; - lhs += 2; - } - if (cmHasLiteralPrefix(lhs, "-0b") || cmHasLiteralPrefix(lhs, "-0B")) { - base = 2; - lhs += 3; - flipSign = true; - } - if (cmHasLiteralPrefix(lhs, "+0b") || cmHasLiteralPrefix(lhs, "+0B")) { - base = 2; - lhs += 3; - } - - long lnum = strtol(lhs, &pEnd, base); - if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) { - reportError(context, content->GetOriginalExpression(), - "$<EQUAL> parameter " + parameters[0] + - " is not a valid integer."); - return std::string(); - } - - if (flipSign) { - lnum = -lnum; + long numbers[2]; + for (int i = 0; i < 2; ++i) { + if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) { + reportError(context, content->GetOriginalExpression(), + "$<EQUAL> parameter " + parameters[i] + + " is not a valid integer."); + return {}; + } } + return numbers[0] == numbers[1] ? "1" : "0"; + } - base = 0; - flipSign = false; + static bool ParameterToLong(const char* param, long* outResult) + { + const char isNegative = param[0] == '-'; - const char* rhs = parameters[1].c_str(); - if (cmHasLiteralPrefix(rhs, "0b") || cmHasLiteralPrefix(rhs, "0B")) { - base = 2; - rhs += 2; - } - if (cmHasLiteralPrefix(rhs, "-0b") || cmHasLiteralPrefix(rhs, "-0B")) { + int base = 0; + if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) { base = 2; - rhs += 3; - flipSign = true; - } - if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) { + param += 2; + } else if (cmHasLiteralPrefix(param, "-0b") || + cmHasLiteralPrefix(param, "-0B") || + cmHasLiteralPrefix(param, "+0b") || + cmHasLiteralPrefix(param, "+0B")) { base = 2; - rhs += 3; + param += 3; } - long rnum = strtol(rhs, &pEnd, base); - if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) { - reportError(context, content->GetOriginalExpression(), - "$<EQUAL> parameter " + parameters[1] + - " is not a valid integer."); - return std::string(); + char* pEnd; + long result = strtol(param, &pEnd, base); + if (pEnd == param || *pEnd != '\0' || errno == ERANGE) { + return false; } - - if (flipSign) { - rnum = -rnum; + if (isNegative && result > 0) { + result *= -1; } - - return lnum == rnum ? "1" : "0"; + *outResult = result; + return true; } } equalNode; @@ -621,9 +605,10 @@ static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode } } makeCIdentifierNode; -static const struct Angle_RNode : public cmGeneratorExpressionNode +template <char C> +struct CharacterNode : public cmGeneratorExpressionNode { - Angle_RNode() {} // NOLINT(modernize-use-equals-default) + CharacterNode() {} // NOLINT(modernize-use-equals-default) int NumExpectedParameters() const override { return 0; } @@ -633,47 +618,39 @@ static const struct Angle_RNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - return ">"; + return { C }; } -} angle_rNode; +}; +static const CharacterNode<'>'> angle_rNode; +static const CharacterNode<','> commaNode; +static const CharacterNode<';'> semicolonNode; -static const struct CommaNode : public cmGeneratorExpressionNode +struct CompilerIdNode : public cmGeneratorExpressionNode { - CommaNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 0; } - - std::string Evaluate( - const std::vector<std::string>& /*parameters*/, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + CompilerIdNode(const char* compilerLang) + : CompilerLanguage(compilerLang) { - return ","; } -} commaNode; -static const struct SemicolonNode : public cmGeneratorExpressionNode -{ - SemicolonNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 0; } + int NumExpectedParameters() const override { return OneOrZeroParameters; } std::string Evaluate( - const std::vector<std::string>& /*parameters*/, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override { - return ";"; + if (!context->HeadTarget) { + std::ostringstream e; + e << "$<" << this->CompilerLanguage + << "_COMPILER_ID> may only be used with binary targets. It may " + "not be used with add_custom_command or add_custom_target."; + reportError(context, content->GetOriginalExpression(), e.str()); + return {}; + } + return this->EvaluateWithLanguage(parameters, context, content, dagChecker, + this->CompilerLanguage); } -} semicolonNode; - -struct CompilerIdNode : public cmGeneratorExpressionNode -{ - CompilerIdNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return OneOrZeroParameters; } std::string EvaluateWithLanguage(const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, @@ -721,77 +698,21 @@ struct CompilerIdNode : public cmGeneratorExpressionNode } return "0"; } -}; - -static const struct CCompilerIdNode : public CompilerIdNode -{ - CCompilerIdNode() {} // NOLINT(modernize-use-equals-default) - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<C_COMPILER_ID> may only be used with binary targets. It may " - "not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "C"); - } -} cCompilerIdNode; + const char* const CompilerLanguage; +}; -static const struct CXXCompilerIdNode : public CompilerIdNode -{ - CXXCompilerIdNode() {} // NOLINT(modernize-use-equals-default) +static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"), + cudaCompilerIdNode("CUDA"), fortranCompilerIdNode("Fortran"); - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<CXX_COMPILER_ID> may only be used with binary targets. It may " - "not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "CXX"); - } -} cxxCompilerIdNode; - -static const struct CUDACompilerIdNode : public CompilerIdNode +struct CompilerVersionNode : public cmGeneratorExpressionNode { - CUDACompilerIdNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override + CompilerVersionNode(const char* compilerLang) + : CompilerLanguage(compilerLang) { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<CUDA_COMPILER_ID> may only be used with binary targets. It may " - "not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "CUDA"); } -} cudaCompilerIdNode; -static const struct FortranCompilerIdNode : public CompilerIdNode -{ - FortranCompilerIdNode() {} // NOLINT(modernize-use-equals-default) + int NumExpectedParameters() const override { return OneOrZeroParameters; } std::string Evaluate( const std::vector<std::string>& parameters, @@ -800,22 +721,16 @@ static const struct FortranCompilerIdNode : public CompilerIdNode cmGeneratorExpressionDAGChecker* dagChecker) const override { if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<Fortran_COMPILER_ID> may only be used with binary targets. It may " - "not be used with add_custom_command or add_custom_target."); - return std::string(); + std::ostringstream e; + e << "$<" << this->CompilerLanguage + << "_COMPILER_VERSION> may only be used with binary targets. It " + "may not be used with add_custom_command or add_custom_target."; + reportError(context, content->GetOriginalExpression(), e.str()); + return {}; } return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "Fortran"); + this->CompilerLanguage); } -} fortranCompilerIdNode; - -struct CompilerVersionNode : public cmGeneratorExpressionNode -{ - CompilerVersionNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return OneOrZeroParameters; } std::string EvaluateWithLanguage(const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, @@ -834,7 +749,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode if (!compilerIdValidator.find(parameters.front())) { reportError(context, content->GetOriginalExpression(), "Expression syntax not recognized."); - return std::string(); + return {}; } if (compilerVersion.empty()) { return parameters.front().empty() ? "1" : "0"; @@ -846,95 +761,13 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode ? "1" : "0"; } -}; - -static const struct CCompilerVersionNode : public CompilerVersionNode -{ - CCompilerVersionNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<C_COMPILER_VERSION> may only be used with binary targets. It " - "may not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "C"); - } -} cCompilerVersionNode; -static const struct CXXCompilerVersionNode : public CompilerVersionNode -{ - CXXCompilerVersionNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<CXX_COMPILER_VERSION> may only be used with binary targets. It " - "may not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "CXX"); - } -} cxxCompilerVersionNode; - -static const struct CUDACompilerVersionNode : public CompilerVersionNode -{ - CUDACompilerVersionNode() {} // NOLINT(modernize-use-equals-default) - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<CUDA_COMPILER_VERSION> may only be used with binary targets. It " - "may not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "CUDA"); - } -} cudaCompilerVersionNode; - -static const struct FortranCompilerVersionNode : public CompilerVersionNode -{ - FortranCompilerVersionNode() {} // NOLINT(modernize-use-equals-default) + const char* const CompilerLanguage; +}; - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* context, - const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* dagChecker) const override - { - if (!context->HeadTarget) { - reportError( - context, content->GetOriginalExpression(), - "$<Fortran_COMPILER_VERSION> may only be used with binary targets. " - "It may not be used with add_custom_command or add_custom_target."); - return std::string(); - } - return this->EvaluateWithLanguage(parameters, context, content, dagChecker, - "Fortran"); - } -} fortranCompilerVersionNode; +static const CompilerVersionNode cCompilerVersionNode("C"), + cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"), + fortranCompilerVersionNode("Fortran"); struct PlatformIdNode : public cmGeneratorExpressionNode { @@ -965,69 +798,10 @@ struct PlatformIdNode : public cmGeneratorExpressionNode } } platformIdNode; -static const struct VersionGreaterNode : public cmGeneratorExpressionNode -{ - VersionGreaterNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 2; } - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override - { - return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, - parameters.front().c_str(), - parameters[1].c_str()) - ? "1" - : "0"; - } -} versionGreaterNode; - -static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode -{ - VersionGreaterEqNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 2; } - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override - { - return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, - parameters.front().c_str(), - parameters[1].c_str()) - ? "1" - : "0"; - } -} versionGreaterEqNode; - -static const struct VersionLessNode : public cmGeneratorExpressionNode -{ - VersionLessNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 2; } - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override - { - return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, - parameters.front().c_str(), - parameters[1].c_str()) - ? "1" - : "0"; - } -} versionLessNode; - -static const struct VersionLessEqNode : public cmGeneratorExpressionNode +template <cmSystemTools::CompareOp Op> +struct VersionNode : public cmGeneratorExpressionNode { - VersionLessEqNode() {} // NOLINT(modernize-use-equals-default) + VersionNode() {} // NOLINT(modernize-use-equals-default) int NumExpectedParameters() const override { return 2; } @@ -1037,33 +811,18 @@ static const struct VersionLessEqNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, - parameters.front().c_str(), + return cmSystemTools::VersionCompare(Op, parameters.front().c_str(), parameters[1].c_str()) ? "1" : "0"; } -} versionLessEqNode; +}; -static const struct VersionEqualNode : public cmGeneratorExpressionNode -{ - VersionEqualNode() {} // NOLINT(modernize-use-equals-default) - - int NumExpectedParameters() const override { return 2; } - - std::string Evaluate( - const std::vector<std::string>& parameters, - cmGeneratorExpressionContext* /*context*/, - const GeneratorExpressionContent* /*content*/, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override - { - return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, - parameters.front().c_str(), - parameters[1].c_str()) - ? "1" - : "0"; - } -} versionEqualNode; +static const VersionNode<cmSystemTools::OP_GREATER> versionGreaterNode; +static const VersionNode<cmSystemTools::OP_GREATER_EQUAL> versionGreaterEqNode; +static const VersionNode<cmSystemTools::OP_LESS> versionLessNode; +static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode; +static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode; static const struct LinkOnlyNode : public cmGeneratorExpressionNode { @@ -1270,73 +1029,54 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode // This node handles errors on parameter count itself. int NumExpectedParameters() const override { return OneOrMoreParameters; } + static const char* GetErrorText(std::string const& targetName, + std::string const& propertyName) + { + static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$"); + if (targetName.empty() && propertyName.empty()) { + return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " + "target name and property name."; + } + if (targetName.empty()) { + return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " + "target name."; + } + if (!cmGeneratorExpression::IsValidTargetName(targetName)) { + if (!propertyNameValidator.find(propertyName)) { + return "Target name and property name not supported."; + } + return "Target name not supported."; + } + return nullptr; + } + std::string Evaluate( const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* dagCheckerParent) const override { - if (parameters.size() != 1 && parameters.size() != 2) { - reportError( - context, content->GetOriginalExpression(), - "$<TARGET_PROPERTY:...> expression requires one or two parameters"); - return std::string(); - } static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$"); - cmGeneratorTarget const* target = context->HeadTarget; - std::string propertyName = parameters.front(); - - if (parameters.size() == 1) { - context->HadHeadSensitiveCondition = true; - } - if (!target && parameters.size() == 1) { - reportError( - context, content->GetOriginalExpression(), - "$<TARGET_PROPERTY:prop> may only be used with binary targets. " - "It may not be used with add_custom_command or add_custom_target. " - "Specify the target to read a property from using the " - "$<TARGET_PROPERTY:tgt,prop> signature instead."); - return std::string(); - } + cmGeneratorTarget const* target = nullptr; + std::string targetName, propertyName; if (parameters.size() == 2) { - if (parameters.front().empty() && parameters[1].empty()) { - reportError( - context, content->GetOriginalExpression(), - "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " - "target name and property name."); - return std::string(); - } - if (parameters.front().empty()) { - reportError( - context, content->GetOriginalExpression(), - "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty " - "target name."); - return std::string(); - } - - std::string targetName = parameters.front(); + targetName = parameters[0]; propertyName = parameters[1]; - if (!cmGeneratorExpression::IsValidTargetName(targetName)) { - if (!propertyNameValidator.find(propertyName)) { - ::reportError(context, content->GetOriginalExpression(), - "Target name and property name not supported."); - return std::string(); - } - ::reportError(context, content->GetOriginalExpression(), - "Target name not supported."); + + if (const char* e = GetErrorText(targetName, propertyName)) { + reportError(context, content->GetOriginalExpression(), e); return std::string(); } - static const std::string propALIASED_TARGET = "ALIASED_TARGET"; - if (propertyName == propALIASED_TARGET) { + if (propertyName == "ALIASED_TARGET"_s) { if (context->LG->GetMakefile()->IsAlias(targetName)) { if (cmGeneratorTarget* tgt = context->LG->FindGeneratorTargetToUse(targetName)) { return tgt->GetName(); } } - return ""; + return std::string(); } target = context->LG->FindGeneratorTargetToUse(targetName); @@ -1347,15 +1087,34 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return std::string(); } context->AllTargets.insert(target); - } - if (target == context->HeadTarget) { + } else if (parameters.size() == 1) { + target = context->HeadTarget; + propertyName = parameters[0]; + // Keep track of the properties seen while processing. // The evaluation of the LINK_LIBRARIES generator expressions // will check this to ensure that properties have one consistent // value for all evaluations. context->SeenTargetProperties.insert(propertyName); + + context->HadHeadSensitiveCondition = true; + if (!target) { + reportError( + context, content->GetOriginalExpression(), + "$<TARGET_PROPERTY:prop> may only be used with binary targets. " + "It may not be used with add_custom_command or add_custom_target. " + "Specify the target to read a property from using the " + "$<TARGET_PROPERTY:tgt,prop> signature instead."); + return std::string(); + } + } else { + reportError( + context, content->GetOriginalExpression(), + "$<TARGET_PROPERTY:...> expression requires one or two parameters"); + return std::string(); } + if (propertyName == "SOURCES") { context->SourceSensitiveTargets.insert(target); } @@ -1600,10 +1359,16 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode reportError(context, content->GetOriginalExpression(), e.str()); return std::string(); } - if (gt->GetType() != cmStateEnums::OBJECT_LIBRARY) { + cmStateEnums::TargetType type = gt->GetType(); + if (type != cmStateEnums::EXECUTABLE && + type != cmStateEnums::STATIC_LIBRARY && + type != cmStateEnums::SHARED_LIBRARY && + type != cmStateEnums::MODULE_LIBRARY && + type != cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Objects of target \"" << tgtName - << "\" referenced but is not an OBJECT library."; + << "\" referenced but is not an allowed library types (EXECUTABLE, " + << "STATIC, SHARED, MODULE, OBJECT)."; reportError(context, content->GetOriginalExpression(), e.str()); return std::string(); } @@ -2196,7 +1961,8 @@ struct TargetOutputNameArtifactResultGetter<ArtifactNameTag> const GeneratorExpressionContent* /*unused*/) { return target->GetOutputName(context->Config, - cmStateEnums::RuntimeBinaryArtifact); + cmStateEnums::RuntimeBinaryArtifact) + + target->GetFilePostfix(context->Config); } }; @@ -2218,7 +1984,8 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag> target->HasImportLibrary(context->Config) ? cmStateEnums::ImportLibraryArtifact : cmStateEnums::RuntimeBinaryArtifact; - return target->GetOutputName(context->Config, artifact); + return target->GetOutputName(context->Config, artifact) + + target->GetFilePostfix(context->Config); } }; @@ -2258,7 +2025,8 @@ struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag> return std::string(); } - return target->GetPDBOutputName(context->Config); + return target->GetPDBOutputName(context->Config) + + target->GetFilePostfix(context->Config); } }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 3fb95bf..036a07d 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -491,6 +491,22 @@ std::string cmGeneratorTarget::GetFileSuffix( return suffix; } +std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const +{ + const char* postfix = nullptr; + if (!config.empty()) { + std::string configProp = cmSystemTools::UpperCase(config); + configProp += "_POSTFIX"; + postfix = this->GetProperty(configProp); + // Mac application bundles and frameworks have no postfix. + if (!this->IsImported() && postfix && + (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) { + postfix = nullptr; + } + } + return postfix ? postfix : std::string(); +} + const char* cmGeneratorTarget::GetFilePrefixInternal( cmStateEnums::ArtifactType artifact, const std::string& language) const { @@ -3930,17 +3946,7 @@ void cmGeneratorTarget::GetFullNameInternal( } // Compute the full name for main target types. - const char* configPostfix = nullptr; - if (!config.empty()) { - std::string configProp = cmSystemTools::UpperCase(config); - configProp += "_POSTFIX"; - configPostfix = this->GetProperty(configProp); - // Mac application bundles and frameworks have no postfix. - if (configPostfix && - (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) { - configPostfix = nullptr; - } - } + const std::string configPostfix = this->GetFilePostfix(config); // frameworks have directory prefix but no suffix std::string fw_prefix; @@ -3965,7 +3971,7 @@ void cmGeneratorTarget::GetFullNameInternal( outBase += this->GetOutputName(config, artifact); // Append the per-configuration postfix. - outBase += configPostfix ? configPostfix : ""; + outBase += configPostfix; // Name shared libraries with their version number on some platforms. if (const char* soversion = this->GetProperty("SOVERSION")) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 81f5255..0e0ee6a 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -543,6 +543,9 @@ public: cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact) const; + /** Get target file postfix */ + std::string GetFilePostfix(const std::string& config) const; + /** Clears cached meta data for local and external source files. * The meta data will be recomputed on demand. */ diff --git a/Source/cmGetPipes.cxx b/Source/cmGetPipes.cxx new file mode 100644 index 0000000..ad323f7 --- /dev/null +++ b/Source/cmGetPipes.cxx @@ -0,0 +1,48 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmGetPipes.h" + +#include "cm_uv.h" + +#include <fcntl.h> + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include <io.h> + +int cmGetPipes(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> +# include <unistd.h> + +int cmGetPipes(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 diff --git a/Source/cmGetPipes.h b/Source/cmGetPipes.h new file mode 100644 index 0000000..2a46b51 --- /dev/null +++ b/Source/cmGetPipes.h @@ -0,0 +1,8 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmGetPipes_h +#define cmGetPipes_h + +int cmGetPipes(int* fds); + +#endif diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 39c325c..cd0355f 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -203,9 +203,7 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() // Now make all targets depend on the ALL_BUILD target for (cmLocalGenerator const* i : gen) { - std::vector<cmGeneratorTarget*> const& targets = - i->GetGeneratorTargets(); - for (cmGeneratorTarget* tgt : targets) { + for (cmGeneratorTarget* tgt : i->GetGeneratorTargets()) { if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET || tgt->IsImported()) { continue; @@ -318,17 +316,7 @@ void cmGlobalVisualStudioGenerator::CallVisualStudioMacro( std::vector<std::string> filenames; this->GetFilesReplacedDuringGenerate(filenames); if (!filenames.empty()) { - // Convert vector to semi-colon delimited string of filenames: - std::string projects; - std::vector<std::string>::iterator it = filenames.begin(); - if (it != filenames.end()) { - projects = *it; - ++it; - } - for (; it != filenames.end(); ++it) { - projects += ";"; - projects += *it; - } + std::string projects = cmJoin(filenames, ";"); cmCallVisualStudioMacro::CallMacro( topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects, this->GetCMakeInstance()->GetDebugOutput()); @@ -368,7 +356,7 @@ void cmGlobalVisualStudioGenerator::FillLinkClosure( cmGlobalVisualStudioGenerator::TargetSet const& cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target) { - TargetSetMap::iterator i = this->TargetLinkClosure.find(target); + auto i = this->TargetLinkClosure.find(target); if (i == this->TargetLinkClosure.end()) { TargetSetMap::value_type entry(target, TargetSet()); i = this->TargetLinkClosure.insert(entry).first; @@ -402,11 +390,8 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends() return false; } for (auto const& it : this->ProjectMap) { - std::vector<cmLocalGenerator*> const& gen = it.second; - for (const cmLocalGenerator* i : gen) { - std::vector<cmGeneratorTarget*> const& targets = - i->GetGeneratorTargets(); - for (cmGeneratorTarget* ti : targets) { + for (const cmLocalGenerator* i : it.second) { + for (cmGeneratorTarget* ti : i->GetGeneratorTargets()) { this->ComputeVSTargetDepends(ti); } } @@ -458,8 +443,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends( std::set<cmGeneratorTarget const*> linkDepends; if (target->GetType() != cmStateEnums::STATIC_LIBRARY) { for (cmTargetDepend const& di : depends) { - cmTargetDepend dep = di; - if (dep.IsLink()) { + if (di.IsLink()) { this->FollowLinkDepends(di, linkDepends); } } @@ -468,8 +452,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends( // Collect explicit util dependencies (add_dependencies). std::set<cmGeneratorTarget const*> utilDepends; for (cmTargetDepend const& di : depends) { - cmTargetDepend dep = di; - if (dep.IsUtil()) { + if (di.IsUtil()) { this->FollowLinkDepends(di, utilDepends); } } @@ -513,7 +496,7 @@ bool cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf) std::string cmGlobalVisualStudioGenerator::GetUtilityDepend( cmGeneratorTarget const* target) { - UtilityDependsMap::iterator i = this->UtilityDepends.find(target); + auto i = this->UtilityDepends.find(target); if (i == this->UtilityDepends.end()) { std::string name = this->WriteUtilityDepend(target); UtilityDependsMap::value_type entry(target, name); @@ -939,11 +922,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( std::vector<std::string> objs; for (cmSourceFile const* it : objectSources) { // Find the object file name corresponding to this source file. - std::map<cmSourceFile const*, std::string>::const_iterator map_it = - mapping.find(it); // It must exist because we populated the mapping just above. - assert(!map_it->second.empty()); - std::string objFile = obj_dir + map_it->second; + const auto& v = mapping[it]; + assert(!v.empty()); + std::string objFile = obj_dir + v; objs.push_back(objFile); } std::vector<cmSourceFile const*> externalObjectSources; diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 2724030..5320ec5 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -8,6 +8,9 @@ #include "cmMessenger.h" #include "cmRange.h" #include "cmSystemTools.h" +#include "cmake.h" + +#include <cassert> class cmExecutionStatus; @@ -19,49 +22,88 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, this->SetError("called with incorrect number of arguments"); return false; } - std::vector<std::string>::const_iterator i = args.begin(); + auto i = args.cbegin(); - MessageType type = MessageType::MESSAGE; - bool status = false; - bool fatal = false; + auto type = MessageType::MESSAGE; + auto status = false; + auto fatal = false; + auto level = cmake::LogLevel::LOG_UNDEFINED; if (*i == "SEND_ERROR") { type = MessageType::FATAL_ERROR; + level = cmake::LogLevel::LOG_ERROR; ++i; } else if (*i == "FATAL_ERROR") { fatal = true; type = MessageType::FATAL_ERROR; + level = cmake::LogLevel::LOG_ERROR; ++i; } else if (*i == "WARNING") { type = MessageType::WARNING; + level = cmake::LogLevel::LOG_WARNING; ++i; } else if (*i == "AUTHOR_WARNING") { if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") && !this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) { fatal = true; type = MessageType::AUTHOR_ERROR; + level = cmake::LogLevel::LOG_ERROR; } else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) { type = MessageType::AUTHOR_WARNING; + level = cmake::LogLevel::LOG_WARNING; } else { return true; } ++i; } else if (*i == "STATUS") { status = true; + level = cmake::LogLevel::LOG_STATUS; + ++i; + } else if (*i == "VERBOSE") { + status = true; + level = cmake::LogLevel::LOG_VERBOSE; + ++i; + } else if (*i == "DEBUG") { + status = true; + level = cmake::LogLevel::LOG_DEBUG; + ++i; + } else if (*i == "TRACE") { + status = true; + level = cmake::LogLevel::LOG_TRACE; ++i; } else if (*i == "DEPRECATION") { if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) { fatal = true; type = MessageType::DEPRECATION_ERROR; + level = cmake::LogLevel::LOG_ERROR; } else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") || this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) { type = MessageType::DEPRECATION_WARNING; + level = cmake::LogLevel::LOG_WARNING; } else { return true; } ++i; + } else if (*i == "NOTICE") { + // `NOTICE` message type is going to be output to stderr + level = cmake::LogLevel::LOG_NOTICE; + ++i; + } else { + // Messages w/o any type are `NOTICE`s + level = cmake::LogLevel::LOG_NOTICE; + } + assert("Message log level expected to be set" && + level != cmake::LogLevel::LOG_UNDEFINED); + + auto desiredLevel = this->Makefile->GetCMakeInstance()->GetLogLevel(); + assert("Expected a valid log level here" && + desiredLevel != cmake::LogLevel::LOG_UNDEFINED); + + if (desiredLevel < level) { + // Suppress the message + return true; } - std::string message = cmJoin(cmMakeRange(i, args.end()), std::string()); + auto message = cmJoin(cmMakeRange(i, args.cend()), ""); if (type != MessageType::MESSAGE) { // we've overridden the message type, above, so display it directly diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 203ee93..dad8821 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -8,6 +8,7 @@ #include "cmGlobalGenerator.h" #include "cmJsonObjectDictionary.h" #include "cmJsonObjects.h" +#include "cmMessageType.h" #include "cmServer.h" #include "cmServerDictionary.h" #include "cmState.h" @@ -600,6 +601,10 @@ cmServerResponse cmServerProtocol1::ProcessConfigure( } int ret = cm->Configure(); + cm->IssueMessage( + MessageType::DEPRECATION_WARNING, + "The 'cmake-server(7)' is deprecated. " + "Please port clients to use the 'cmake-file-api(7)' instead."); if (ret < 0) { return request.ReportError("Configuration failed."); } diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 2bc4c39..5cdacaa 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -80,7 +80,10 @@ std::vector<std::string> prepareFilesPathsForTree( prepared.reserve(filesPaths.size()); for (auto const& filePath : filesPaths) { - prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir)); + // If provided file path is actually not a file, silently ignore it. + if (cmSystemTools::FileExists(filePath, /*isFile=*/true)) { + prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir)); + } } return prepared; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 212608d..bc853b7 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -168,7 +168,6 @@ bool cmSystemTools::s_RunCommandHideConsole = false; bool cmSystemTools::s_DisableRunCommandOutput = false; bool cmSystemTools::s_ErrorOccured = false; bool cmSystemTools::s_FatalErrorOccured = false; -bool cmSystemTools::s_DisableMessages = false; bool cmSystemTools::s_ForceUnixPaths = false; // replace replace with with as many times as it shows up in source. @@ -326,14 +325,11 @@ void cmSystemTools::Stdout(const std::string& s) void cmSystemTools::Message(const std::string& m, const char* title) { - if (s_DisableMessages) { - return; - } if (s_MessageCallback) { s_MessageCallback(m, title); - return; + } else { + std::cerr << m << std::endl; } - std::cerr << m << std::endl << std::flush; } void cmSystemTools::ReportLastSystemError(const char* msg) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index a8b2d37..05bd351 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -266,8 +266,6 @@ public: static size_t CalculateCommandLineLengthLimit(); - static void EnableMessages() { s_DisableMessages = false; } - static void DisableMessages() { s_DisableMessages = true; } static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; } static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; } static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; } @@ -540,7 +538,6 @@ private: static bool s_RunCommandHideConsole; static bool s_ErrorOccured; static bool s_FatalErrorOccured; - static bool s_DisableMessages; static bool s_DisableRunCommandOutput; }; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 5c7b95c..3883b52 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -456,8 +456,8 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::string configLib = this->Target->GetDebugGeneratorExpressions(libRef, llt); - if (cmGeneratorExpression::IsValidTargetName(libRef) || - cmGeneratorExpression::Find(libRef) != std::string::npos) { + if (cmGeneratorExpression::IsValidTargetName(lib) || + cmGeneratorExpression::Find(lib) != std::string::npos) { configLib = "$<LINK_ONLY:" + configLib + ">"; } this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index fd07d2d..27069ee 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -11,19 +11,59 @@ namespace cm { -static void close_delete(uv_handle_t* h) +struct uv_loop_deleter { - free(h); + void operator()(uv_loop_t* loop) const; +}; + +void uv_loop_deleter::operator()(uv_loop_t* loop) const +{ + uv_run(loop, UV_RUN_DEFAULT); + int result = uv_loop_close(loop); + (void)result; + assert(result >= 0); + free(loop); +} + +int uv_loop_ptr::init(void* data) +{ + this->reset(); + + this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))), + uv_loop_deleter()); + this->loop->data = data; + + return uv_loop_init(this->loop.get()); +} + +void uv_loop_ptr::reset() +{ + this->loop.reset(); +} + +uv_loop_ptr::operator uv_loop_t*() +{ + return this->loop.get(); +} + +uv_loop_t* uv_loop_ptr::operator->() const noexcept +{ + return this->loop.get(); +} + +uv_loop_t* uv_loop_ptr::get() const +{ + return this->loop.get(); } template <typename T> -static void default_delete(T* type_handle) +static void handle_default_delete(T* type_handle) { auto handle = reinterpret_cast<uv_handle_t*>(type_handle); if (handle) { assert(!uv_is_closing(handle)); if (!uv_is_closing(handle)) { - uv_close(handle, &close_delete); + uv_close(handle, [](uv_handle_t* h) { free(h); }); } } } @@ -34,7 +74,7 @@ static void default_delete(T* type_handle) template <typename T> struct uv_handle_deleter { - void operator()(T* type_handle) const { default_delete(type_handle); } + void operator()(T* type_handle) const { handle_default_delete(type_handle); } }; template <typename T> @@ -107,7 +147,7 @@ struct uv_handle_deleter<uv_async_t> void operator()(uv_async_t* handle) { std::lock_guard<std::mutex> lock(*handleMutex); - default_delete(handle); + handle_default_delete(handle); } }; @@ -136,7 +176,7 @@ struct uv_handle_deleter<uv_signal_t> { if (handle) { uv_signal_stop(handle); - default_delete(handle); + handle_default_delete(handle); } } }; diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h index 992c429..c09e4bf 100644 --- a/Source/cmUVHandlePtr.h +++ b/Source/cmUVHandlePtr.h @@ -30,7 +30,45 @@ namespace cm { /*** - * RAII class to simplify and insure the safe usage of uv_*_t types. This + * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes + * making sure resources are properly freed. + */ +class uv_loop_ptr +{ +protected: + std::shared_ptr<uv_loop_t> loop; + +public: + uv_loop_ptr(uv_loop_ptr const&) = delete; + uv_loop_ptr& operator=(uv_loop_ptr const&) = delete; + uv_loop_ptr(uv_loop_ptr&&) noexcept; + uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept; + + // Dtor and ctor need to be inline defined like this for default ctors and + // dtors to work. Some compilers do not like '= default' here. + uv_loop_ptr() {} // NOLINT(modernize-use-equals-default) + uv_loop_ptr(std::nullptr_t) {} + ~uv_loop_ptr() { this->reset(); } + + int init(void* data = nullptr); + + /** + * Properly close the handle if needed and sets the inner handle to nullptr + */ + void reset(); + + /** + * Allow less verbose calling of uv_loop_* functions + * @return reinterpreted handle + */ + operator uv_loop_t*(); + + uv_loop_t* get() const; + uv_loop_t* operator->() const noexcept; +}; + +/*** + * RAII class to simplify and ensure the safe usage of uv_*_t types. This * includes making sure resources are properly freed and contains casting * operators which allow for passing into relevant uv_* functions. * diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h new file mode 100644 index 0000000..29e4fde --- /dev/null +++ b/Source/cmUVStreambuf.h @@ -0,0 +1,219 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmUVStreambuf_h +#define cmUVStreambuf_h + +#include "cmUVHandlePtr.h" + +#include "cm_uv.h" + +#include <algorithm> +#include <cstring> +#include <streambuf> +#include <vector> + +/* + * This file is based on example code from: + * + * http://www.voidcn.com/article/p-vjnlygmc-gy.html + * + * The example code was distributed under the following license: + * + * Copyright 2007 Edd Dawson. + * Distributed under the Boost Software License, Version 1.0. + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +template <typename CharT, typename Traits = std::char_traits<CharT>> +class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits> +{ +public: + cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8); + ~cmBasicUVStreambuf() override; + + bool is_open() const; + + cmBasicUVStreambuf* open(uv_stream_t* stream); + + cmBasicUVStreambuf* close(); + +protected: + typename cmBasicUVStreambuf::int_type underflow() override; + std::streamsize showmanyc() override; + + // FIXME: Add write support + +private: + uv_stream_t* Stream = nullptr; + void* OldStreamData; + const std::size_t PutBack; + std::vector<CharT> InputBuffer; + bool EndOfFile; + + void StreamReadStartStop(); + + void StreamRead(ssize_t nread); + void HandleAlloc(uv_buf_t* buf); +}; + +template <typename CharT, typename Traits> +cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize, + std::size_t putBack) + : PutBack(std::max<std::size_t>(putBack, 1)) + , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack) +{ + this->close(); +} + +template <typename CharT, typename Traits> +cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf() +{ + this->close(); +} + +template <typename CharT, typename Traits> +bool cmBasicUVStreambuf<CharT, Traits>::is_open() const +{ + return this->Stream != nullptr; +} + +template <typename CharT, typename Traits> +cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open( + uv_stream_t* stream) +{ + this->close(); + this->Stream = stream; + this->EndOfFile = false; + if (this->Stream) { + this->OldStreamData = this->Stream->data; + this->Stream->data = this; + } + this->StreamReadStartStop(); + return this; +} + +template <typename CharT, typename Traits> +cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close() +{ + if (this->Stream) { + uv_read_stop(this->Stream); + this->Stream->data = this->OldStreamData; + } + this->Stream = nullptr; + CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size(); + this->setg(readEnd, readEnd, readEnd); + return this; +} + +template <typename CharT, typename Traits> +typename cmBasicUVStreambuf<CharT, Traits>::int_type +cmBasicUVStreambuf<CharT, Traits>::underflow() +{ + if (!this->is_open()) { + return Traits::eof(); + } + + if (this->gptr() < this->egptr()) { + return Traits::to_int_type(*this->gptr()); + } + + this->StreamReadStartStop(); + while (this->in_avail() == 0) { + uv_run(this->Stream->loop, UV_RUN_ONCE); + } + if (this->in_avail() == -1) { + return Traits::eof(); + } + return Traits::to_int_type(*this->gptr()); +} + +template <typename CharT, typename Traits> +std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc() +{ + if (!this->is_open() || this->EndOfFile) { + return -1; + } + return 0; +} + +template <typename CharT, typename Traits> +void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop() +{ + if (this->Stream) { + uv_read_stop(this->Stream); + if (this->gptr() >= this->egptr()) { + uv_read_start( + this->Stream, + [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) { + auto streambuf = + static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data); + streambuf->HandleAlloc(buf); + }, + [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) { + auto streambuf = + static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data); + streambuf->StreamRead(nread); + }); + } + } +} + +template <typename CharT, typename Traits> +void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf) +{ + auto size = this->egptr() - this->gptr(); + std::memmove(this->InputBuffer.data(), this->gptr(), + this->egptr() - this->gptr()); + this->setg(this->InputBuffer.data(), this->InputBuffer.data(), + this->InputBuffer.data() + size); + buf->base = this->egptr(); +#ifdef _WIN32 +# define BUF_LEN_TYPE ULONG +#else +# define BUF_LEN_TYPE size_t +#endif + buf->len = BUF_LEN_TYPE( + (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) * + sizeof(CharT)); +#undef BUF_LEN_TYPE +} + +template <typename CharT, typename Traits> +void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread) +{ + if (nread > 0) { + this->setg(this->eback(), this->gptr(), + this->egptr() + nread / sizeof(CharT)); + uv_read_stop(this->Stream); + } else if (nread < 0 || nread == UV_EOF) { + this->EndOfFile = true; + uv_read_stop(this->Stream); + } +} + +using cmUVStreambuf = cmBasicUVStreambuf<char>; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fc24ac0..121d12d 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -718,6 +718,14 @@ void cmake::SetArgs(const std::vector<std::string>& args) } else if (arg.find("--debug-output", 0) == 0) { std::cout << "Running with debug output on.\n"; this->SetDebugOutputOn(true); + } else if (arg.find("--loglevel=", 0) == 0) { + const auto logLevel = + StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1)); + if (logLevel == LogLevel::LOG_UNDEFINED) { + cmSystemTools::Error("Invalid level specified for --loglevel"); + return; + } + this->SetLogLevel(logLevel); } else if (arg.find("--trace-expand", 0) == 0) { std::cout << "Running with expanded trace output on.\n"; this->SetTrace(true); @@ -828,6 +836,25 @@ void cmake::SetArgs(const std::vector<std::string>& args) } } +cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr) +{ + using LevelsPair = std::pair<std::string, LogLevel>; + static const std::vector<LevelsPair> levels = { + { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING }, + { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS }, + { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG }, + { "trace", LogLevel::LOG_TRACE } + }; + + const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr); + + const auto it = std::find_if(levels.cbegin(), levels.cend(), + [&levelStrLowCase](const LevelsPair& p) { + return p.first == levelStrLowCase; + }); + return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED; +} + void cmake::SetDirectoriesFromFile(const char* arg) { // Check if the argument refers to a CMakeCache.txt or diff --git a/Source/cmake.h b/Source/cmake.h index 8b4b396..4a345cf 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -96,6 +96,19 @@ public: FIND_PACKAGE_MODE }; + /** \brief Define log level constants. */ + enum LogLevel + { + LOG_UNDEFINED, + LOG_ERROR, + LOG_WARNING, + LOG_NOTICE, + LOG_STATUS, + LOG_VERBOSE, + LOG_DEBUG, + LOG_TRACE + }; + struct GeneratorInfo { std::string name; @@ -331,6 +344,11 @@ public: */ cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; } + // Get the selected log level for `message()` commands during the cmake run. + LogLevel GetLogLevel() const { return this->MessageLogLevel; } + void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; } + static LogLevel StringToLogLevel(const std::string& levelStr); + // Do we want debug output during the cmake run. bool GetDebugOutput() { return this->DebugOutput; } void SetDebugOutputOn(bool b) { this->DebugOutput = b; } @@ -524,6 +542,8 @@ private: std::vector<std::string> TraceOnlyThisSources; + LogLevel MessageLogLevel = LogLevel::LOG_STATUS; + void UpdateConversionPathTable(); // Print a list of valid generators to stderr. diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index d70c9d9..49d160c 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -24,6 +24,7 @@ #endif #include <cassert> +#include <climits> #include <ctype.h> #include <iostream> #include <string.h> @@ -69,7 +70,7 @@ static const char* cmDocumentationUsageNote[][2] = { " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \ " --clean-first = Build target 'clean' first, then build.\n" \ " (To clean only, use --target 'clean'.)\n" \ - " --verbose, -v = Enable verbose output - if supported - including\n" \ + " --verbose, -v = Enable verbose output - if supported - including\n" \ " the build commands to be executed. \n" \ " -- = Pass remaining options to the native tool.\n" @@ -95,6 +96,8 @@ static const char* cmDocumentationOptions[][2] = { "Generate graphviz of dependencies, see " "CMakeGraphVizOptions.cmake for more." }, { "--system-information [file]", "Dump information about this system." }, + { "--loglevel=<error|warn|notice|status|verbose|debug|trace>", + "Set the verbosity of messages from CMake files." }, { "--debug-trycompile", "Do not delete the try_compile build tree. Only " "useful on one try_compile at a time." }, @@ -393,7 +396,14 @@ int extract_job_number(int& index, char const* current, char const* next, if (jobString.empty()) { jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL; } else if (cmSystemTools::StringToULong(jobString.c_str(), &numJobs)) { - jobs = int(numJobs); + if (numJobs == 0) { + std::cerr + << "The <jobs> value requires a positive integer argument.\n\n"; + } else if (numJobs > INT_MAX) { + std::cerr << "The <jobs> value is too large.\n\n"; + } else { + jobs = int(numJobs); + } } else { std::cerr << "'" << command.substr(0, len_of_flag) << "' invalid number '" << jobString << "' given.\n\n"; @@ -505,7 +515,17 @@ static int do_build(int ac, char const* const* av) } else { unsigned long numJobs = 0; if (cmSystemTools::StringToULong(parallel.c_str(), &numJobs)) { - jobs = int(numJobs); + if (numJobs == 0) { + std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable " + "requires a positive integer argument.\n\n"; + dir.clear(); + } else if (numJobs > INT_MAX) { + std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable " + "is too large.\n\n"; + dir.clear(); + } else { + jobs = int(numJobs); + } } else { std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n" << "invalid number '" << parallel << "' given.\n\n"; diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt index 85ce1f7..5c704ac 100644 --- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt +++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt @@ -134,11 +134,15 @@ assert_property(newsignature1 LINK_LIBRARIES "depC;depB;subdirlib") #---------------------------------------------------------------------------- # Test cross-directory linking. cmake_policy(PUSH) +cmake_policy(SET CMP0022 NEW) cmake_policy(SET CMP0079 NEW) add_executable(TopDir TopDir.c) add_subdirectory(SubDirA) add_subdirectory(SubDirB) target_link_libraries(SubDirB TopDirImported) +add_subdirectory(SubDirC) +target_link_libraries(SubDirC PRIVATE SubDirC2) +target_link_libraries(TopDir SubDirC) add_library(TopDirImported IMPORTED INTERFACE) target_compile_definitions(TopDirImported INTERFACE DEF_TopDirImported) cmake_policy(POP) diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt new file mode 100644 index 0000000..54bcc51 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/SubDirC/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(SubDirC STATIC SubDirC.c) + +add_library(SubDirC1 INTERFACE) +target_compile_definitions(SubDirC1 INTERFACE DEF_SubDirC1) + +add_library(SubDirC2 INTERFACE) +target_compile_definitions(SubDirC2 INTERFACE DEF_SubDirC2) + +target_link_libraries(SubDirC PRIVATE SubDirC1) diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c b/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c new file mode 100644 index 0000000..c5536dc --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/SubDirC/SubDirC.c @@ -0,0 +1,11 @@ +#ifndef DEF_SubDirC1 +# error "DEF_SubDirC1 not defined" +#endif +#ifndef DEF_SubDirC2 +# error "DEF_SubDirC2 not defined" +#endif + +int SubDirC(void) +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_libraries/TopDir.c b/Tests/CMakeCommands/target_link_libraries/TopDir.c index 4706bb9..d8066e5 100644 --- a/Tests/CMakeCommands/target_link_libraries/TopDir.c +++ b/Tests/CMakeCommands/target_link_libraries/TopDir.c @@ -7,6 +7,12 @@ #ifdef DEF_TopDirImported # error "DEF_TopDirImported is defined but should not be!" #endif +#ifdef DEF_SubDirC1 +# error "DEF_SubDirC1 defined but should not be" +#endif +#ifdef DEF_SubDirC2 +# error "DEF_SubDirC2 defined but should not be" +#endif int main(void) { diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 031ab01..e04bba2 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -16,9 +16,11 @@ set(CMakeLib_TESTS testXMLSafe.cxx testFindPackageCommand.cxx testUVRAII.cxx + testUVStreambuf.cxx ) set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) +set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>) if(WIN32) list(APPEND CMakeLib_TESTS @@ -43,7 +45,7 @@ target_link_libraries(testEncoding cmsys) foreach(testfile ${CMakeLib_TESTS}) get_filename_component(test "${testfile}" NAME_WE) - add_test(CMakeLib.${test} CMakeLibTests ${test} ${${test}_ARGS}) + add_test(NAME CMakeLib.${test} COMMAND CMakeLibTests ${test} ${${test}_ARGS}) endforeach() if(TEST_CompileCommandOutput) diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx index 1c1da76..2aeaf2c 100644 --- a/Tests/CMakeLib/testUVRAII.cxx +++ b/Tests/CMakeLib/testUVRAII.cxx @@ -171,11 +171,59 @@ static bool testAllMoves() return true; }; +static bool testLoopReset() +{ + bool closed = false; + cm::uv_loop_ptr loop; + loop.init(); + + uv_timer_t timer; + uv_timer_init(loop, &timer); + timer.data = &closed; + uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) { + auto closedPtr = static_cast<bool*>(handle->data); + *closedPtr = true; + }); + + loop.reset(); + if (!closed) { + std::cerr << "uv_loop_ptr did not finish" << std::endl; + return false; + } + + return true; +}; + +static bool testLoopDestructor() +{ + bool closed = false; + + uv_timer_t timer; + { + cm::uv_loop_ptr loop; + loop.init(); + + uv_timer_init(loop, &timer); + timer.data = &closed; + uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) { + auto closedPtr = static_cast<bool*>(handle->data); + *closedPtr = true; + }); + } + + if (!closed) { + std::cerr << "uv_loop_ptr did not finish" << std::endl; + return false; + } + + return true; +}; + int testUVRAII(int, char** const) { if ((testAsyncShutdown() && testAsyncDtor() & testAsyncMove() & testCrossAssignment() & - testAllMoves()) == 0) { + testAllMoves() & testLoopReset() & testLoopDestructor()) == 0) { return -1; } return 0; diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx new file mode 100644 index 0000000..39655f3 --- /dev/null +++ b/Tests/CMakeLib/testUVStreambuf.cxx @@ -0,0 +1,457 @@ +#include "cmUVStreambuf.h" + +#include "cmGetPipes.h" +#include "cmUVHandlePtr.h" + +#include "cm_uv.h" + +#include <iostream> +#include <string> +#include <vector> + +#include <cstring> + +#include <stdint.h> + +#define TEST_STR_LINE_1 "This string must be exactly 128 characters long so" +#define TEST_STR_LINE_2 "that we can test CMake's std::streambuf integration" +#define TEST_STR_LINE_3 "with libuv's uv_stream_t." +#define TEST_STR TEST_STR_LINE_1 "\n" TEST_STR_LINE_2 "\n" TEST_STR_LINE_3 + +bool writeDataToStreamPipe(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, + char* outputData, unsigned int outputDataLength, + const char* /* unused */) +{ + int err; + + // Create the pipe + int pipeHandles[2]; + if (cmGetPipes(pipeHandles) < 0) { + std::cout << "Could not open pipe" << std::endl; + return false; + } + + cm::uv_pipe_ptr outputPipe; + inputPipe.init(loop, 0); + outputPipe.init(loop, 0); + uv_pipe_open(inputPipe, pipeHandles[0]); + uv_pipe_open(outputPipe, pipeHandles[1]); + + // Write data for reading + uv_write_t writeReq; + struct WriteCallbackData + { + bool Finished = false; + int Status; + } writeData; + writeReq.data = &writeData; + uv_buf_t outputBuf; + outputBuf.base = outputData; + outputBuf.len = outputDataLength; + if ((err = uv_write(&writeReq, outputPipe, &outputBuf, 1, + [](uv_write_t* req, int status) { + auto data = static_cast<WriteCallbackData*>(req->data); + data->Finished = true; + data->Status = status; + })) < 0) { + std::cout << "Could not write to pipe: " << uv_strerror(err) << std::endl; + return false; + } + while (!writeData.Finished) { + uv_run(&loop, UV_RUN_ONCE); + } + if (writeData.Status < 0) { + std::cout << "Status is " << uv_strerror(writeData.Status) + << ", should be 0" << std::endl; + return false; + } + + return true; +} + +bool writeDataToStreamProcess(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, + char* outputData, unsigned int /* unused */, + const char* cmakeCommand) +{ + int err; + + inputPipe.init(loop, 0); + std::vector<std::string> arguments = { cmakeCommand, "-E", "echo_append", + outputData }; + std::vector<const char*> processArgs; + for (auto const& arg : arguments) { + processArgs.push_back(arg.c_str()); + } + processArgs.push_back(nullptr); + std::vector<uv_stdio_container_t> stdio(3); + stdio[0].flags = UV_IGNORE; + stdio[0].data.stream = nullptr; + stdio[1].flags = + static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + stdio[1].data.stream = inputPipe; + stdio[2].flags = UV_IGNORE; + stdio[2].data.stream = nullptr; + + struct ProcessExitData + { + bool Finished = false; + int64_t ExitStatus; + int TermSignal; + } exitData; + cm::uv_process_ptr process; + auto options = uv_process_options_t(); + options.file = cmakeCommand; + options.args = const_cast<char**>(processArgs.data()); + options.flags = UV_PROCESS_WINDOWS_HIDE; + options.stdio = stdio.data(); + options.stdio_count = static_cast<int>(stdio.size()); + options.exit_cb = [](uv_process_t* handle, int64_t exitStatus, + int termSignal) { + auto data = static_cast<ProcessExitData*>(handle->data); + data->Finished = true; + data->ExitStatus = exitStatus; + data->TermSignal = termSignal; + }; + if ((err = process.spawn(loop, options, &exitData)) < 0) { + std::cout << "Could not spawn process: " << uv_strerror(err) << std::endl; + return false; + } + while (!exitData.Finished) { + uv_run(&loop, UV_RUN_ONCE); + } + if (exitData.ExitStatus != 0) { + std::cout << "Process exit status is " << exitData.ExitStatus + << ", should be 0" << std::endl; + return false; + } + if (exitData.TermSignal != 0) { + std::cout << "Process term signal is " << exitData.TermSignal + << ", should be 0" << std::endl; + return false; + } + + return true; +} + +bool testUVStreambufRead( + bool (*cb)(uv_loop_t& loop, cm::uv_pipe_ptr& inputPipe, char* outputData, + unsigned int outputDataLength, const char* cmakeCommand), + const char* cmakeCommand) +{ + char outputData[] = TEST_STR; + bool success = false; + cm::uv_loop_ptr loop; + loop.init(); + cm::uv_pipe_ptr inputPipe; + std::vector<char> inputData(128); + std::streamsize readLen; + std::string line; + cm::uv_timer_ptr timer; + + // Create the streambuf + cmUVStreambuf inputBuf(64); + std::istream inputStream(&inputBuf); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform first read test - read all the data + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if (std::memcmp(inputData.data(), outputData, 128)) { + std::cout << "Read data does not match write data" << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + inputData.assign(128, char{}); + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + + // Perform second read test - read some data and then close + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 64)) != 64) { + std::cout << "sgetn() returned " << readLen << ", should be 64" + << std::endl; + goto end; + } + if (std::memcmp(inputData.data(), outputData, 64)) { + std::cout << "Read data does not match write data" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 8) { + std::cout << "in_avail() returned " << readLen << ", should be 8" + << std::endl; + goto end; + } + inputData.assign(128, char{}); + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform third read test - read line by line + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_1) { + std::cout << "Line 1 is \"" << line + << "\", should be \"" TEST_STR_LINE_1 "\"" << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_2) { + std::cout << "Line 2 is \"" << line + << "\", should be \"" TEST_STR_LINE_2 "\"" << std::endl; + goto end; + } + + if (!std::getline(inputStream, line)) { + std::cout << "getline returned false, should be true" << std::endl; + goto end; + } + if (line != TEST_STR_LINE_3) { + std::cout << "Line 3 is \"" << line + << "\", should be \"" TEST_STR_LINE_3 "\"" << std::endl; + goto end; + } + + if (std::getline(inputStream, line)) { + std::cout << "getline returned true, should be false" << std::endl; + goto end; + } + + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform fourth read test - run the event loop outside of underflow() + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + uv_run(loop, UV_RUN_DEFAULT); + if ((readLen = inputBuf.in_avail()) != 72) { + std::cout << "in_avail() returned " << readLen << ", should be 72" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 128) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 128" + << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + + inputBuf.close(); + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + // Perform fifth read test - close the streambuf in the middle of a read + timer.init(*loop, &inputBuf); + if (!cb(*loop, inputPipe, outputData, 128, cmakeCommand)) { + goto end; + } + inputBuf.open(inputPipe); + if (!inputBuf.is_open()) { + std::cout << "is_open() is false, should be true" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != 0) { + std::cout << "in_avail() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + uv_timer_start(timer, + [](uv_timer_t* handle) { + auto buf = static_cast<cmUVStreambuf*>(handle->data); + buf->close(); + }, + 0, 0); + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + if (inputBuf.is_open()) { + std::cout << "is_open() is true, should be false" << std::endl; + goto end; + } + if ((readLen = inputBuf.in_avail()) != -1) { + std::cout << "in_avail() returned " << readLen << ", should be -1" + << std::endl; + goto end; + } + if ((readLen = inputBuf.sgetn(inputData.data(), 128)) != 0) { + std::cout << "sgetn() returned " << readLen << ", should be 0" + << std::endl; + goto end; + } + + success = true; + +end: + return success; +} + +int testUVStreambuf(int argc, char** const argv) +{ + if (argc < 2) { + std::cout << "Invalid arguments.\n"; + return -1; + } + + if (!testUVStreambufRead(writeDataToStreamPipe, argv[1])) { + std::cout << "While executing testUVStreambufRead() with pipe.\n"; + return -1; + } + + if (!testUVStreambufRead(writeDataToStreamProcess, argv[1])) { + std::cout << "While executing testUVStreambufRead() with process.\n"; + return -1; + } + + return 0; +} diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index df0c78d..5ba0dc0 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -374,4 +374,49 @@ if(NOT CMAKE_GENERATOR STREQUAL Xcode OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[; -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" DEPENDS objlib ) + + + add_library(sharedlib SHARED objlib1.c objlib2.c) + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>" + CONTENT "$<JOIN:$<TARGET_OBJECTS:sharedlib>,\n>\n" + ) + + add_custom_target(check_sharedlib_objs ALL + COMMAND ${CMAKE_COMMAND} + "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/sharedlib_files_$<CONFIGURATION>" + -DEXPECTED_NUM_OBJECTFILES=2 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + DEPENDS sharedlib + ) + + + add_library(staticlib STATIC objlib1.c objlib2.c) + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>" + CONTENT "$<JOIN:$<TARGET_OBJECTS:staticlib>,\n>\n" + ) + + add_custom_target(check_staticlib_objs ALL + COMMAND ${CMAKE_COMMAND} + "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/staticlib_files_$<CONFIGURATION>" + -DEXPECTED_NUM_OBJECTFILES=2 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + DEPENDS staticlib + ) + + + add_executable(execobjs objlib1.c objlib2.c echo.c) + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>" + CONTENT "$<JOIN:$<TARGET_OBJECTS:execobjs>,\n>\n" + ) + + add_custom_target(check_exec_objs ALL + COMMAND ${CMAKE_COMMAND} + "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/execobjs_files_$<CONFIGURATION>" + -DEXPECTED_NUM_OBJECTFILES=3 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + DEPENDS execobjs + ) endif() diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt index b7a6e86..6994d8d 100644 --- a/Tests/MSVCRuntimeLibrary/CMakeLists.txt +++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt @@ -42,7 +42,22 @@ endfunction() function(verify lang src) add_library(default-${lang} ${src}) target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>") + verify_combinations(MultiThreaded ${lang} ${src}) + + # Test known MSVC default behavior when no flag is given. + if(CMAKE_${lang}_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_MSVC_RUNTIME_LIBRARY "") + add_library(empty-${lang} ${src}) + if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 14) + # VS 2005 and above default to multi-threaded. + target_compile_definitions(empty-${lang} PRIVATE VERIFY_MT) + endif() + if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])") + # VS 2010 and above have a different default runtime library for projects than 'cl'. + target_compile_definitions(empty-${lang} PRIVATE VERIFY_DLL) + endif() + endif() endfunction() verify(C verify.c) diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt index 4bffd12..7897ab9 100644 --- a/Tests/ObjectLibrary/CMakeLists.txt +++ b/Tests/ObjectLibrary/CMakeLists.txt @@ -62,4 +62,14 @@ add_custom_target(UseABinternalDep COMMAND ${CMAKE_COMMAND} -E touch UseABintern add_custom_command(TARGET UseABinternal POST_BUILD COMMAND ${CMAKE_COMMAND} -P UseABinternalDep.cmake) add_dependencies(UseABinternal UseABinternalDep) +# Test a static library with sources from a different static library +add_library(UseCstaticObjs STATIC $<TARGET_OBJECTS:Cstatic> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>) + +# Test a shared library with sources from a different shared library +add_library(UseCsharedObjs SHARED $<TARGET_OBJECTS:Cshared> $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:Bexport>) + +# Test a shared executable with sources from a different shared library +add_executable(UseABstaticObjs $<TARGET_OBJECTS:UseABstatic>) +target_link_libraries(UseABstaticObjs ABstatic) + add_subdirectory(ExportLanguages) diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt new file mode 100644 index 0000000..94fc157 --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt @@ -0,0 +1,3 @@ +^The <jobs> value is too large\. ++ +Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt new file mode 100644 index 0000000..8ed4fee --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt @@ -0,0 +1,3 @@ +^The <jobs> value requires a positive integer argument\. ++ +Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt new file mode 100644 index 0000000..94fc157 --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt @@ -0,0 +1,3 @@ +^The <jobs> value is too large\. ++ +Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt new file mode 100644 index 0000000..8ed4fee --- /dev/null +++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt @@ -0,0 +1,3 @@ +^The <jobs> value requires a positive integer argument\. ++ +Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index ea749ea..49d3608 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -149,6 +149,14 @@ function(run_BuildDir) ${CMAKE_COMMAND} --build BuildDir-build --parallel2) run_cmake_command(BuildDir--build--parallel-no-space-good-number-trailing--target ${CMAKE_COMMAND} -E chdir .. ${CMAKE_COMMAND} --build BuildDir-build --parallel2 --target CustomTarget) + run_cmake_command(BuildDir--build-jobs-zero ${CMAKE_COMMAND} -E chdir .. + ${CMAKE_COMMAND} --build BuildDir-build -j 0) + run_cmake_command(BuildDir--build--parallel-zero ${CMAKE_COMMAND} -E chdir .. + ${CMAKE_COMMAND} --build BuildDir-build --parallel 0) + run_cmake_command(BuildDir--build-jobs-large ${CMAKE_COMMAND} -E chdir .. + ${CMAKE_COMMAND} --build BuildDir-build -j 4294967293) + run_cmake_command(BuildDir--build--parallel-large ${CMAKE_COMMAND} -E chdir .. + ${CMAKE_COMMAND} --build BuildDir-build --parallel 4294967293) # No default jobs for Xcode and FreeBSD build command if(NOT RunCMake_GENERATOR MATCHES "Xcode" AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt index b08ef5a..4c2e35f 100644 --- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt +++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt @@ -3,6 +3,7 @@ CMake Error at OutputNameMatchesObjects.cmake:[0-9]+ \(file\): \$<TARGET_OBJECTS:foo> - Objects of target "foo" referenced but is not an OBJECT library. + Objects of target "foo" referenced but is not an allowed library types + \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\). Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake index daa7c49..84825fe 100644 --- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake +++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake @@ -1,11 +1,8 @@ enable_language(CXX) file(GENERATE - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<BOOL:$<TARGET_OBJECTS:foo>>somefile.cpp" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>/somefile.cpp" CONTENT "static const char content[] = \"$<TARGET_OBJECTS:foo>\";\n" ) -add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/input.txt" - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/input.txt" "${CMAKE_CURRENT_BINARY_DIR}") - -add_executable(foo empty.cpp "${CMAKE_CURRENT_BINARY_DIR}/1somefile.cpp" "${CMAKE_CURRENT_BINARY_DIR}/input.txt") +add_library(foo INTERFACE ) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 477b593..a491e99 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -41,8 +41,8 @@ run_cmake(TARGET_FILE_SUFFIX) run_cmake(TARGET_FILE_SUFFIX-imported-target) run_cmake(TARGET_FILE_SUFFIX-non-valid-target) run_cmake(TARGET_LINKER_FILE_SUFFIX-non-valid-target) -run_cmake(TARGET_FILE_BASE_NAME) -run_cmake(TARGET_FILE_BASE_NAME-imported-target) +run_cmake_with_options(TARGET_FILE_BASE_NAME -DCMAKE_BUILD_TYPE:STRING=Debug) +run_cmake_with_options(TARGET_FILE_BASE_NAME-imported-target -DCMAKE_BUILD_TYPE:STRING=Debug) run_cmake(TARGET_FILE_BASE_NAME-non-valid-target) run_cmake(TARGET_LINKER_FILE_BASE_NAME-non-valid-target) run_cmake(TARGET_PROPERTY-LOCATION) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake index aa54b31..40f7c66 100644 --- a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake +++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME-imported-target.cmake @@ -46,17 +46,14 @@ add_executable (exec3 IMPORTED) set_property (TARGET exec3 PROPERTY RUNTIME_OUTPUT_NAME exec3_runtime) set_property (TARGET exec3 PROPERTY LIBRARY_OUTPUT_NAME exec3_library) set_property (TARGET exec3 PROPERTY ARCHIVE_OUTPUT_NAME exec3_archive) -set_property (TARGET exec3 PROPERTY PDB_NAME exec3_pdb) add_library (shared3 SHARED IMPORTED) set_property (TARGET shared3 PROPERTY RUNTIME_OUTPUT_NAME shared3_runtime) set_property (TARGET shared3 PROPERTY LIBRARY_OUTPUT_NAME shared3_library) set_property (TARGET shared3 PROPERTY ARCHIVE_OUTPUT_NAME shared3_archive) -set_property (TARGET shared3 PROPERTY PDB_NAME shared3_pdb) add_library (static3 STATIC IMPORTED) set_property (TARGET static3 PROPERTY RUNTIME_OUTPUT_NAME static3_runtime) set_property (TARGET static3 PROPERTY LIBRARY_OUTPUT_NAME static3_library) set_property (TARGET static3 PROPERTY ARCHIVE_OUTPUT_NAME static3_archive) -set_property (TARGET static3 PROPERTY PDB_NAME static3_pdb) string (APPEND GENERATE_CONTENT [[ @@ -73,7 +70,37 @@ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig) list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG) set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>) +else() + set (FIRST_CONFIG ${CMAKE_BUILD_TYPE}) endif() +string (TOUPPER "${FIRST_CONFIG}" FIRST_CONFIG) + + +add_executable (exec4 IMPORTED) +set_property (TARGET exec4 PROPERTY RUNTIME_OUTPUT_NAME exec4_runtime) +set_property (TARGET exec4 PROPERTY LIBRARY_OUTPUT_NAME exec4_library) +set_property (TARGET exec4 PROPERTY ARCHIVE_OUTPUT_NAME exec4_archive) +set_property (TARGET exec4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) +add_library (shared4 SHARED IMPORTED) +set_property (TARGET shared4 PROPERTY RUNTIME_OUTPUT_NAME shared4_runtime) +set_property (TARGET shared4 PROPERTY LIBRARY_OUTPUT_NAME shared4_library) +set_property (TARGET shared4 PROPERTY ARCHIVE_OUTPUT_NAME shared4_archive) +set_property (TARGET shared4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) +add_library (static4 STATIC IMPORTED) +set_property (TARGET static4 PROPERTY RUNTIME_OUTPUT_NAME static4_runtime) +set_property (TARGET static4 PROPERTY LIBRARY_OUTPUT_NAME static4_library) +set_property (TARGET static4 PROPERTY ARCHIVE_OUTPUT_NAME static4_archive) +set_property (TARGET static4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) + +string (APPEND GENERATE_CONTENT [[ + +check_value ("TARGET_FILE_BASE_NAME executable all properties + postfix" "$<TARGET_FILE_BASE_NAME:exec4>" "exec4_runtime_postfix") +check_value ("TARGET_FILE_BASE_NAME shared all properties + postfix" "$<TARGET_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_runtime,shared4_library>_postfix") +check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_archive,shared4_library>_postfix") +check_value ("TARGET_FILE_BASE_NAME static all properties + postfix" "$<TARGET_FILE_BASE_NAME:static4>" "static4_archive_postfix") +check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:static4>" "static4_archive_postfix") +]]) + file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake" CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION}) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake index 5ea53a0..f88d710 100644 --- a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake +++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_BASE_NAME.cmake @@ -90,7 +90,46 @@ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig) list(GET CMAKE_CONFIGURATION_TYPES 0 FIRST_CONFIG) set(GENERATE_CONDITION CONDITION $<CONFIG:${FIRST_CONFIG}>) +else() + set (FIRST_CONFIG ${CMAKE_BUILD_TYPE}) endif() +string (TOUPPER "${FIRST_CONFIG}" FIRST_CONFIG) + + +add_executable (exec4 empty.c) +set_property (TARGET exec4 PROPERTY RUNTIME_OUTPUT_NAME exec4_runtime) +set_property (TARGET exec4 PROPERTY LIBRARY_OUTPUT_NAME exec4_library) +set_property (TARGET exec4 PROPERTY ARCHIVE_OUTPUT_NAME exec4_archive) +set_property (TARGET exec4 PROPERTY PDB_NAME exec4_pdb) +set_property (TARGET exec4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) +add_library (shared4 SHARED empty.c) +set_property (TARGET shared4 PROPERTY RUNTIME_OUTPUT_NAME shared4_runtime) +set_property (TARGET shared4 PROPERTY LIBRARY_OUTPUT_NAME shared4_library) +set_property (TARGET shared4 PROPERTY ARCHIVE_OUTPUT_NAME shared4_archive) +set_property (TARGET shared4 PROPERTY PDB_NAME shared4_pdb) +set_property (TARGET shared4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) +add_library (static4 STATIC empty.c) +set_property (TARGET static4 PROPERTY RUNTIME_OUTPUT_NAME static4_runtime) +set_property (TARGET static4 PROPERTY LIBRARY_OUTPUT_NAME static4_library) +set_property (TARGET static4 PROPERTY ARCHIVE_OUTPUT_NAME static4_archive) +set_property (TARGET static4 PROPERTY PDB_NAME static4_pdb) +set_property (TARGET static4 PROPERTY ${FIRST_CONFIG}_POSTFIX _postfix) + +string (APPEND GENERATE_CONTENT [[ + +check_value ("TARGET_FILE_BASE_NAME executable all properties + postfix" "$<TARGET_FILE_BASE_NAME:exec4>" "exec4_runtime_postfix") +check_value ("TARGET_FILE_BASE_NAME shared all properties + postfix" "$<TARGET_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_runtime,shared4_library>_postfix") +check_value ("TARGET_LINKER_FILE_BASE_NAME shared linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:shared4>" "$<IF:$<IN_LIST:$<PLATFORM_ID>,Windows$<SEMICOLON>CYGWIN>,shared4_archive,shared4_library>_postfix") +check_value ("TARGET_FILE_BASE_NAME static all properties + postfix" "$<TARGET_FILE_BASE_NAME:static4>" "static4_archive_postfix") +check_value ("TARGET_LINKER_FILE_BASE_NAME static linker all properties + postfix" "$<TARGET_LINKER_FILE_BASE_NAME:static4>" "static4_archive_postfix") +]]) +if (CMAKE_C_LINKER_SUPPORTS_PDB) + string (APPEND GENERATE_CONTENT [[ +check_value ("TARGET_PDB_FILE_BASE_NAME executable PDB all properties + postfix" "$<TARGET_PDB_FILE_BASE_NAME:exec4>" "exec4_pdb_postfix") +check_value ("TARGET_PDB_FILE_BASE_NAME shared PDB all properties + postfix" "$<TARGET_PDB_FILE_BASE_NAME:shared4>" "shared4_pdb_postfix") +]]) +endif() + file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_BASE_NAME-generated.cmake" CONTENT "${GENERATE_CONTENT}" ${GENERATE_CONDITION}) diff --git a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt index 838b3d8..4dbd861 100644 --- a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt +++ b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt @@ -3,6 +3,7 @@ CMake Error at BadSourceExpression3.cmake:2 \(add_library\): \$<TARGET_OBJECTS:NotObjLib> - Objects of target "NotObjLib" referenced but is not an OBJECT library. + Objects of target "NotObjLib" referenced but is not an allowed library + types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\). Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake index c3d9a62..4e07ea6 100644 --- a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake +++ b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3.cmake @@ -1,2 +1,2 @@ -add_library(NotObjLib STATIC a.c) +add_library(NotObjLib INTERFACE) add_library(A STATIC a.c $<TARGET_OBJECTS:NotObjLib>) diff --git a/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake b/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake new file mode 100644 index 0000000..0c85c72 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/CheckTargetObjects.cmake @@ -0,0 +1,32 @@ +add_library(StaticLib STATIC a.c) + +add_custom_command(TARGET StaticLib POST_BUILD + VERBATIM + COMMAND ${CMAKE_COMMAND} + "-DTARGET_OBJECTS=$<TARGET_OBJECTS:StaticLib>" + -DEXPECTED_NUM_OBJECTFILES=2 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + ) + +add_library(SharedLib SHARED a.c b.c) +target_compile_definitions(SharedLib PRIVATE REQUIRED) + +add_custom_command(TARGET SharedLib POST_BUILD + VERBATIM + COMMAND ${CMAKE_COMMAND} + "-DTARGET_OBJECTS:STRING=$<TARGET_OBJECTS:SharedLib>" + -DEXPECTED_NUM_OBJECTFILES=2 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + ) + +add_executable(ExecObjs a.c b.c exe.c) +target_compile_definitions(ExecObjs PRIVATE REQUIRED) + +add_custom_target(check_exec_objs ALL + VERBATIM + COMMAND ${CMAKE_COMMAND} + "-DTARGET_OBJECTS=$<TARGET_OBJECTS:ExecObjs>" + -DEXPECTED_NUM_OBJECTFILES=3 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + DEPENDS ExecObjs + ) diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake index 6ca33b8..5ec4018 100644 --- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake +++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake @@ -37,6 +37,10 @@ function (run_object_lib_build2 name) run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .) endfunction () +if(NOT (RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")) + run_object_lib_build(CheckTargetObjects) +endif() + run_object_lib_build(LinkObjLHSShared) run_object_lib_build(LinkObjLHSStatic) run_object_lib_build(LinkObjRHSShared) @@ -54,6 +58,7 @@ run_cmake(PostBuild) run_cmake(PreBuild) run_cmake(PreLink) + function(run_Dependencies) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Dependencies-build) set(RunCMake_TEST_NO_CLEAN 1) diff --git a/Tests/RunCMake/ObjectLibrary/check_object_files.cmake b/Tests/RunCMake/ObjectLibrary/check_object_files.cmake new file mode 100644 index 0000000..3c34229 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/check_object_files.cmake @@ -0,0 +1,17 @@ + +if (NOT TARGET_OBJECTS) + message(SEND_ERROR "Object not passed as -DTARGET_OBJECTS") +endif() + +foreach(objlib_file IN LISTS objects) + message(STATUS "objlib_file: =${objlib_file}=") + + set(file_exists False) + if (EXISTS "${objlib_file}") + set(file_exists True) + endif() + + if (NOT file_exists) + message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}") + endif() +endforeach() diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt index a66794c..77c4afd 100644 --- a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt +++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt @@ -1,8 +1,9 @@ -CMake Error at NotObjlibTarget.cmake:3 \(file\): +CMake Error at NotObjlibTarget.cmake:[0-9]+ \(file\): Error evaluating generator expression: - \$<TARGET_OBJECTS:StaticLib> + \$<TARGET_OBJECTS:IFaceLib> - Objects of target "StaticLib" referenced but is not an OBJECT library. + Objects of target "IFaceLib" referenced but is not an allowed library types + \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\). Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake index 3bb3e37..9fec369 100644 --- a/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake +++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake @@ -1,3 +1,3 @@ -add_library(StaticLib empty.cpp) +add_library(IFaceLib INTERFACE ) -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_output CONTENT $<TARGET_OBJECTS:StaticLib>) +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_output CONTENT $<TARGET_OBJECTS:IFaceLib>) diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake index 6b43d47..689b35f 100644 --- a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake +++ b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake @@ -20,7 +20,7 @@ macro(RuntimeLibrary_check tgt rtl_expect) endif() endforeach() - if(NOT HAVE_Runtimelibrary) + if(NOT HAVE_Runtimelibrary AND NOT "${rtl_expect}" STREQUAL "") set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a RuntimeLibrary field.") return() endif() @@ -28,6 +28,8 @@ endmacro() RuntimeLibrary_check(default-C MultiThreadedDebugDLL) RuntimeLibrary_check(default-CXX MultiThreadedDebugDLL) +RuntimeLibrary_check(empty-C "") +RuntimeLibrary_check(empty-CXX "") RuntimeLibrary_check(MTd-C MultiThreadedDebug) RuntimeLibrary_check(MTd-CXX MultiThreadedDebug) RuntimeLibrary_check(MT-C MultiThreaded) diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake index 6c77a25..d7787c8 100644 --- a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake +++ b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake @@ -6,6 +6,10 @@ enable_language(CXX) add_library(default-C empty.c) add_library(default-CXX empty.cxx) +set(CMAKE_MSVC_RUNTIME_LIBRARY "") +add_library(empty-C empty.c) +add_library(empty-CXX empty.cxx) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug") add_library(MTd-C empty.c) add_library(MTd-CXX empty.cxx) diff --git a/Tests/RunCMake/execute_process/EchoCommand-result.txt b/Tests/RunCMake/execute_process/EchoCommand-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/EchoCommand-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand-stderr.txt new file mode 100644 index 0000000..f10ece8 --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand-stderr.txt @@ -0,0 +1,5 @@ +.*cmake.*-E' 'echo' '-- 2 COMMAND_ECHO STDERR' +.*cmake.*-E' 'echo' '-- 4 COMMAND_ECHO STDERR' +.*cmake.*-E' 'echo' '-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR' +CMake Error at .*EchoCommand.cmake:.* \(execute_process\): + CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to 'BAD' expected STDERR|STDOUT|NONE$ diff --git a/Tests/RunCMake/execute_process/EchoCommand-stdout.txt b/Tests/RunCMake/execute_process/EchoCommand-stdout.txt new file mode 100644 index 0000000..0954b3b --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand-stdout.txt @@ -0,0 +1,12 @@ +.*cmake.*-E' 'echo' '-- 1 COMMAND_ECHO STDOUT' +-- 1 COMMAND_ECHO STDOUT +-- 2 COMMAND_ECHO STDERR +.*cmake.* '-E' 'echo' '-- 3 COMMAND_ECHO STDOUT' +-- 3 COMMAND_ECHO STDOUT +-- 4 COMMAND_ECHO STDERR +.*cmake.* '-E' 'echo' '-- 5 COMMAND_ECHO STDOUT' +-- 5 COMMAND_ECHO STDOUT +-- 6 COMMAND_ECHO NONE +.*cmake.* '-E' 'echo' '-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT' +-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT +-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR$ diff --git a/Tests/RunCMake/execute_process/EchoCommand.cmake b/Tests/RunCMake/execute_process/EchoCommand.cmake new file mode 100644 index 0000000..9c7d13d --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand.cmake @@ -0,0 +1,41 @@ +if(CHECK_ERROR_OUTPUT_LOCATION) + execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 1 COMMAND_ECHO " COMMAND_ECHO ) +endif() +# test COMMAND_ECHO STDOUT +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 1 COMMAND_ECHO STDOUT" COMMAND_ECHO STDOUT ) +# test COMMAND_ECHO STDERR +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 2 COMMAND_ECHO STDERR" COMMAND_ECHO STDERR ) +# test CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT +set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT) +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 3 COMMAND_ECHO STDOUT" ) +# test CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDERR +set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDERR) +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 4 COMMAND_ECHO STDERR" ) +# make sure local will override global settings +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 5 COMMAND_ECHO STDOUT" COMMAND_ECHO STDOUT ) +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 6 COMMAND_ECHO NONE" COMMAND_ECHO NONE) +# test both and make sure override works +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT" COMMAND_ECHO STDERR + COMMAND_ECHO STDOUT) +execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR" COMMAND_ECHO STDOUT + COMMAND_ECHO STDERR) + +# check for bad arguments to global and local +if(CHECK_GLOBAL) + # make sure a non STDERR or STDOUT value is an error + set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO BAD) + execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 9 - 1 CMAKE_EXECUTE_PROCESS_COMMAND_ECHO BAD" ) +else() + execute_process(COMMAND ${CMAKE_COMMAND} -E echo + "-- 9 - 2 COMMAND_ECHO BAD" COMMAND_ECHO BAD) +endif() diff --git a/Tests/RunCMake/execute_process/EchoCommand2-result.txt b/Tests/RunCMake/execute_process/EchoCommand2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt new file mode 100644 index 0000000..4ae01c4 --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand2-stderr.txt @@ -0,0 +1,5 @@ +.*cmake.*-E' 'echo' '-- 2 COMMAND_ECHO STDERR' +.*cmake.*-E' 'echo' '-- 4 COMMAND_ECHO STDERR' +.*cmake.*-E' 'echo' '-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR' +CMake Error at .*EchoCommand.cmake:.* \(execute_process\): + called with 'BAD' expected STDERR|STDOUT|NONE for COMMAND_ECHO.$ diff --git a/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt b/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt new file mode 100644 index 0000000..0954b3b --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand2-stdout.txt @@ -0,0 +1,12 @@ +.*cmake.*-E' 'echo' '-- 1 COMMAND_ECHO STDOUT' +-- 1 COMMAND_ECHO STDOUT +-- 2 COMMAND_ECHO STDERR +.*cmake.* '-E' 'echo' '-- 3 COMMAND_ECHO STDOUT' +-- 3 COMMAND_ECHO STDOUT +-- 4 COMMAND_ECHO STDERR +.*cmake.* '-E' 'echo' '-- 5 COMMAND_ECHO STDOUT' +-- 5 COMMAND_ECHO STDOUT +-- 6 COMMAND_ECHO NONE +.*cmake.* '-E' 'echo' '-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT' +-- 7 COMMAND_ECHO STDERR COMMAND_ECHO STDOUT +-- 8 COMMAND_ECHO STDOUT COMMAND_ECHO STDERR$ diff --git a/Tests/RunCMake/execute_process/EchoCommand3-result.txt b/Tests/RunCMake/execute_process/EchoCommand3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt new file mode 100644 index 0000000..e27f1e6 --- /dev/null +++ b/Tests/RunCMake/execute_process/EchoCommand3-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*EchoCommand.cmake:.*\(execute_process\): + execute_process called with no value for COMMAND_ECHO. diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake index cb40b40..b203aab 100644 --- a/Tests/RunCMake/execute_process/RunCMakeTest.cmake +++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake @@ -16,3 +16,11 @@ endif() if(EXIT_CODE_EXE) run_cmake_command(ExitValues ${CMAKE_COMMAND} -DEXIT_CODE_EXE=${EXIT_CODE_EXE} -P ${RunCMake_SOURCE_DIR}/ExitValues.cmake) endif() + +run_cmake_command(EchoCommand ${CMAKE_COMMAND} -DCHECK_GLOBAL=TRUE + -P ${RunCMake_SOURCE_DIR}/EchoCommand.cmake) +run_cmake_command(EchoCommand2 ${CMAKE_COMMAND} -P + ${RunCMake_SOURCE_DIR}/EchoCommand.cmake) +run_cmake_command(EchoCommand3 ${CMAKE_COMMAND} + -DCHECK_ERROR_OUTPUT_LOCATION=TRUE -P + ${RunCMake_SOURCE_DIR}/EchoCommand.cmake) diff --git a/Tests/RunCMake/message/RunCMakeTest.cmake b/Tests/RunCMake/message/RunCMakeTest.cmake index 24dad03..cecfc7f 100644 --- a/Tests/RunCMake/message/RunCMakeTest.cmake +++ b/Tests/RunCMake/message/RunCMakeTest.cmake @@ -10,3 +10,45 @@ run_cmake(warnmessage) # separately run_cmake(errormessage_deprecated) run_cmake(errormessage_dev) + +run_cmake_command( + message-loglevel-invalid + ${CMAKE_COMMAND} --loglevel=blah -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) + +# Checking various combinations of `message(...)` and log levels `WARNING` to `TRACE` +# - no CLI option -> `WARNING` to `STATUS` output +run_cmake_command( + message-loglevel-default + ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - Only `WARNING` output +run_cmake_command( + message-loglevel-warning + ${CMAKE_COMMAND} --loglevel=warning -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - Only `WARNING` and `NOTICE` output +run_cmake_command( + message-loglevel-notice + ${CMAKE_COMMAND} --loglevel=notice -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - `WARNING` to `STATUS` output +run_cmake_command( + message-loglevel-status + ${CMAKE_COMMAND} --loglevel=status -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - `WARNING` to `VERBOSE` output +run_cmake_command( + message-loglevel-verbose + ${CMAKE_COMMAND} --loglevel=verbose -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - `WARNING` to `DEBUG` output +run_cmake_command( + message-loglevel-debug + ${CMAKE_COMMAND} --loglevel=debug -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) +# - `WARNING` to `TRACE` output +run_cmake_command( + message-loglevel-trace + ${CMAKE_COMMAND} --loglevel=trace -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake + ) diff --git a/Tests/RunCMake/message/message-all-loglevels.cmake b/Tests/RunCMake/message/message-all-loglevels.cmake new file mode 100644 index 0000000..f8d8841 --- /dev/null +++ b/Tests/RunCMake/message/message-all-loglevels.cmake @@ -0,0 +1,10 @@ +# Produce a message for everything except FATAL_ERROR and SEND_ERROR +message(DEPRECATION "Deprecation warning") +message(AUTHOR_WARNING "Author warning message") +message(WARNING "Warning message") +message("Default NOTICE message") +message(NOTICE "NOTICE message") +message(STATUS "STATUS message") +message(VERBOSE "VERBOSE message") +message(DEBUG "DEBUG message") +message(TRACE "TRACE message") diff --git a/Tests/RunCMake/message/message-loglevel-debug-stderr.txt b/Tests/RunCMake/message/message-loglevel-debug-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-debug-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-debug-stdout.txt b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt new file mode 100644 index 0000000..1452137 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt @@ -0,0 +1,3 @@ +-- STATUS message +-- VERBOSE message +-- DEBUG message diff --git a/Tests/RunCMake/message/message-loglevel-default-stderr.txt b/Tests/RunCMake/message/message-loglevel-default-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-default-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-default-stdout.txt b/Tests/RunCMake/message/message-loglevel-default-stdout.txt new file mode 100644 index 0000000..809f4cc --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-default-stdout.txt @@ -0,0 +1 @@ +-- STATUS message diff --git a/Tests/RunCMake/message/message-loglevel-invalid-result.txt b/Tests/RunCMake/message/message-loglevel-invalid-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-invalid-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt b/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt new file mode 100644 index 0000000..f54d0f8 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-invalid-stderr.txt @@ -0,0 +1 @@ +CMake Error: Invalid level specified for --loglevel diff --git a/Tests/RunCMake/message/message-loglevel-notice-stderr.txt b/Tests/RunCMake/message/message-loglevel-notice-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-notice-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-status-stderr.txt b/Tests/RunCMake/message/message-loglevel-status-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-status-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-status-stdout.txt b/Tests/RunCMake/message/message-loglevel-status-stdout.txt new file mode 100644 index 0000000..809f4cc --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-status-stdout.txt @@ -0,0 +1 @@ +-- STATUS message diff --git a/Tests/RunCMake/message/message-loglevel-trace-stderr.txt b/Tests/RunCMake/message/message-loglevel-trace-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-trace-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-trace-stdout.txt b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt new file mode 100644 index 0000000..1cfce6f --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt @@ -0,0 +1,4 @@ +-- STATUS message +-- VERBOSE message +-- DEBUG message +-- TRACE message diff --git a/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt b/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt new file mode 100644 index 0000000..efec736 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-verbose-stderr.txt @@ -0,0 +1,12 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message ++ +Default NOTICE message +NOTICE message$ diff --git a/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt new file mode 100644 index 0000000..c15d43f --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt @@ -0,0 +1,2 @@ +-- STATUS message +-- VERBOSE message diff --git a/Tests/RunCMake/message/message-loglevel-warning-stderr.txt b/Tests/RunCMake/message/message-loglevel-warning-stderr.txt new file mode 100644 index 0000000..c721b06 --- /dev/null +++ b/Tests/RunCMake/message/message-loglevel-warning-stderr.txt @@ -0,0 +1,9 @@ +^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\): + Deprecation warning ++ +CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\): + Author warning message +This warning is for project developers\. Use -Wno-dev to suppress it\. ++ +CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\): + Warning message$ diff --git a/Tests/SourceGroups/CMakeLists.txt b/Tests/SourceGroups/CMakeLists.txt index 813774d..a5740bb 100644 --- a/Tests/SourceGroups/CMakeLists.txt +++ b/Tests/SourceGroups/CMakeLists.txt @@ -42,8 +42,16 @@ set(tree_files_with_prefix ${root}/tree_prefix_foo.c set(tree_files_with_empty_prefix ${root}/tree_empty_prefix_foo.c tree_empty_prefix_bar.c) +set(tree_files_which_are_actually_directories ${root} + ${root}/ + ${root}/sub1 + ${root}/sub1/) + source_group(TREE ${root} FILES ${tree_files_without_prefix}) +# Should not crash and not add any files - just silently ignore the directories +source_group(TREE ${root} FILES ${tree_files_which_are_actually_directories}) + source_group(FILES ${tree_files_with_prefix} PREFIX tree_root/subgroup TREE ${root}) source_group(PREFIX "" FILES ${tree_files_with_empty_prefix} TREE ${root}) diff --git a/Tests/SwiftMix/CMain.c b/Tests/SwiftMix/CMain.c index 8877da4..519058e 100644 --- a/Tests/SwiftMix/CMain.c +++ b/Tests/SwiftMix/CMain.c @@ -1,5 +1,5 @@ -extern int ObjCMain(int argc, char const* const argv[]); -int main(int argc, char* argv[]) +extern int ObjCMain(void); +int main(void) { - return ObjCMain(argc, argv); + return ObjCMain(); } diff --git a/Tests/SwiftMix/CMakeLists.txt b/Tests/SwiftMix/CMakeLists.txt index 5e50470..6d8e48b 100644 --- a/Tests/SwiftMix/CMakeLists.txt +++ b/Tests/SwiftMix/CMakeLists.txt @@ -3,3 +3,4 @@ project(SwiftMix C Swift) add_executable(SwiftMix CMain.c ObjCMain.m SwiftMain.swift ObjC-Swift.h) set_property(TARGET SwiftMix PROPERTY XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "ObjC-Swift.h") +target_compile_options(SwiftMix PRIVATE "$<$<COMPILE_LANGUAGE:C>:-Werror=objc-method-access>") diff --git a/Tests/SwiftMix/ObjCMain.m b/Tests/SwiftMix/ObjCMain.m index 20f0bf1..afc92438 100644 --- a/Tests/SwiftMix/ObjCMain.m +++ b/Tests/SwiftMix/ObjCMain.m @@ -1,4 +1,4 @@ #import "SwiftMix-Swift.h" -int ObjCMain(int argc, char const* const argv[]) { +int ObjCMain(void) { return [SwiftMainClass SwiftMain]; } diff --git a/Tests/SwiftMix/SwiftMain.swift b/Tests/SwiftMix/SwiftMain.swift index a4a0a62..d9c8cd7 100644 --- a/Tests/SwiftMix/SwiftMain.swift +++ b/Tests/SwiftMix/SwiftMain.swift @@ -1,7 +1,7 @@ import Foundation @objc class SwiftMainClass : NSObject { - class func SwiftMain() -> Int32 { + @objc class func SwiftMain() -> Int32 { dump("Hello World!"); return 0; } |